xref: /MusicPlayer2/MusicPlayer2/Common.h (revision 965ce478a79b0d21e8a6e2ade0490efa175855dd)
1 //CCommon类为全局函数的定义
2 #pragma once
3 #include "CVariant.h"
4 #include <initializer_list>
5 #include <numeric>
6 #include <gdiplus.h>
7 
8 enum class Command
9 {
10     OPEN,
11     PLAY,
12     CLOSE,
13     PAUSE,
14     STOP,
15     PLAY_PAUSE,
16     FF,	//快进
17     REW,		//快倒
18     VOLUME_ADJ,
19     SEEK
20 };
21 
22 namespace ControlCmd
23 {
24     const int NONE = 0;
25     const int PLAY_PAUSE = 1 << 1;
26     const int _PREVIOUS = 1 << 2;
27     const int _NEXT = 1 << 3;
28     const int STOP = 1 << 4;
29     const int FF = 1 << 5;
30     const int REW = 1 << 6;
31     const int VOLUME_UP = 1 << 7;
32     const int VOLUME_DOWM = 1 << 8;
33     const int MINI_MODE = 1 << 9;
34 }
35 
36 enum class CodeType
37 {
38     ANSI,
39     UTF8,
40     UTF8_NO_BOM,
41     UTF16LE,
42     UTF16BE,
43     AUTO
44 };
45 
46 class CCommon
47 {
48 public:
49     CCommon();
50     ~CCommon();
51 
52     // 判断文件是否存在,file为文件绝对路径,is_case_sensitive为true时对文件名区分大小写(路径仍然不区分)
53     static bool FileExist(const wstring& file, bool is_case_sensitive = false);
54 
55     //判断文件夹是否存在
56     static bool FolderExist(const wstring& file);
57 
58     //判断是否是文件夹
59     static bool IsFolder(const wstring& path);
60 
61     // 判断文件是否存在,file为文件绝对路径,如果存在会更正文件名大小写到与实际文件一致
62     static bool CheckAndFixFile(wstring& file);
63 
64     // 读取文件的修改时间属性(FILETIME),返回文件是否存在
65     static bool GetFileLastModified(const wstring& file_path, unsigned __int64& modified_time);
66     // 读取文件的创建时间属性(FILETIME),返回文件是否存在
67     static bool GetFileCreateTime(const wstring& file_path, unsigned __int64& create_time);
68 
69     //将FILETIME表示的时间转换为time_t(自1970年1月1日以来的秒数)
70     static time_t FileTimeToTimeT(unsigned __int64 file_time);
71 
72     //判断文件是否隐藏
73     static bool IsFileHidden(const wstring& file_path);
74 
75     //设置文件是否隐藏
76     static void SetFileHidden(const wstring& file_path, bool hidden);
77 
78     //规范化字符串,即删除字符串前面和后面的空格或控制字符(模板类型只能是string或wstring)
79     template<class T>
80     static bool StringNormalize(T& str);
81 
82     //删除字符串前面的bom
83     static void DeleteStringBom(string& str);
84 
85     //删除字符串末尾的空格
86     template<class T>
87     static bool DeleteEndSpace(T& str);
88 
89     //将字符串转换成符合Csv文件格式规范的字符串
90     static bool StringCsvNormalize(CString& str);
91 
92     //自定义的字符串拷贝函数
93     static void StringCopy(char* dest, int size, string source);
94 
95     //转换字符串大小写,如果upper为true,则转换成大写,否则转换成小写
96     template<class T>
97     static bool StringTransform(T& str, bool upper);
98 
99     //字符串比较,忽略大小写
100     template<class T>
101     static bool StringCompareNoCase(const T& str1, const T& str2);
102 
103     //字符串查找,忽略大小写
104     template<class T>
105     static size_t StringFindNoCase(const T& str, const T& find_str, size_t index = 0);
106 
107     //字符串查找,全词匹配
108     template<class T>
109     static size_t StringNatchWholeWord(const T& str, const T& find_str);
110 
111     //判断一个字符是否是在全词匹配时的单词分割字符(除了字母、数字和256以上的Unicode字符外的字符)
112     static bool IsDivideChar(wchar_t ch);
113 
114     //判断一个字符串是否是数字
115     static bool StrIsNumber(const wstring& str);
116 
117     static bool CharIsNumber(wchar_t ch);
118 
119     //将字符串转换成整数,从字符串中提取第最先出现的数字
120     static int StringToInt(const wstring& str);
121 
122     // 按换行分割字符串,自适应CR/LF/CRLF换行
123     static void StringSplitLine(const wstring& source_str, vector<wstring>& results, bool skip_empty = true, bool trim = true);
124 
125     //将一个字符串分割成若干个字符串
126     //str: 原始字符串
127     //div_ch: 用于分割的字符
128     //result: 接收分割后的结果
129     static void StringSplit(const wstring& str, wchar_t div_ch, vector<wstring>& results, bool skip_empty = true, bool trim = true);
130     static void StringSplit(const wstring& str, const wstring& div_str, vector<wstring>& results, bool skip_empty = true, bool trim = true);
131     static void StringSplit(const string& str, char div_ch, vector<string>& result, bool skip_empty = true, bool trim = true);
132     static void StringSplit(const string& str, const string& div_str, vector<string>& results, bool skip_empty = true, bool trim = true);
133 
134     //将一个字符串分割成若干个字符串,可以指定多个分隔字符
135     //str: 原始字符串
136     //div_ch: 字符串中任意一个字符作为分割字符
137     //result: 接收分割后的结果
138     static void StringSplitWithMulitChars(const wstring& str, const wstring& div_ch, vector<wstring>& results, bool skip_empty = true);
139 
140     //使用指定的分割符分割字符串,将按每个分割符中的顺序分割字符串,每个分割符只用一次
141     //str: 原始字符串
142     //separators: 指定的分割符,
143     //result: 接收分割后的结果
144     static void StringSplitWithSeparators(const wstring& str, const vector<wstring>& separators, vector<wstring>& results, bool skip_empty = true);
145 
146     //将若干个字符串合并成一个字符串
147     //div_ch: 用于分割的字符
148     static wstring StringMerge(const vector<wstring>& strings, wchar_t div_ch);
149 
150     // 合并字符串,"aa","bb","cc"模式,skip_empty,trim
151     static wstring MergeStringList(const vector<wstring>& values);
152     // 分割字符串,"aa","bb","cc"模式,skip_empty,trim
153     static void SplitStringList(vector<wstring>& values, const wstring& str_value);
154 
155     //中文繁简转换
156     static wstring TranslateToSimplifiedChinese(const wstring& str);
157     static wstring TranslateToTranditionalChinese(const wstring& str);
158 
159     //替换一个文件名中的无效字符
160     static void FileNameNormalize(wstring& file_name);
161 
162     static bool IsFileNameValid(const wstring& file_name);
163 
164     //计算文件大小
165     static size_t GetFileSize(const wstring& file_name);
166 
167     //将string类型的字符串转换成Unicode编码的wstring字符串
168     static wstring StrToUnicode(const string& str, CodeType code_type = CodeType::AUTO, bool auto_utf8 = false);
169 
170     //进行UTF16的BE、LE之间的转换
convertBE_LE(wchar_t * bigEndianBuffer,unsigned int length)171     static inline void convertBE_LE(wchar_t* bigEndianBuffer, unsigned int length)
172     {
173         for (unsigned int i = 0; i < length; ++i)
174         {
175             unsigned char* chr = (unsigned char*)(bigEndianBuffer + i);
176             unsigned char temp = *chr;
177             *chr = *(chr + 1);
178             *(chr + 1) = temp;
179         }
180     }
181 
182     //将Unicode编码的wstring字符串转换成string类型的字符串,如果有字符无法转换,将参数char_cannot_convert指向的bool变量置为true
183     //当有可能转换带有BOM的类型时需注意
184     //UTF8若自行处理BOM可使用UTF8_NO_BOM分段处理否则请一次转换
185     //UTF16LE请一次转换,或不使用此方法并自行处理BOM
186     //UTF16BE请一次转换,特别的,自行处理需注意大小端问题
187     static string UnicodeToStr(const wstring& wstr, CodeType code_type, bool* char_cannot_convert = nullptr);
188 
189     //将一个只有ASCII码组成的字符串转换成Unicode
190     static wstring ASCIIToUnicode(const string& ascii);
191 
192     //判断一个字符串是否UTF8编码
193     static bool IsUTF8Bytes(const char* data);
194 
195     //判断一个字符串的编码格式。auto_utf8:是否自动猜测UTF8编码
196     static CodeType JudgeCodeType(const string& str, CodeType default_code = CodeType::ANSI, bool auto_utf8 = false);
197 
198     static bool IsURL(const wstring& str);
199 private:
200     //判断一个字符串是否符合Windows路径的格式
201     static bool IsWindowsPath(const wstring& str);
202 public:
203     //判断一个字符串是否符合绝对路径的格式(而不是判断路径是否有效)
204     static bool IsPath(const wstring& str);
205 
206     //替换一个字符串中指定的字符
207     static bool StringCharacterReplace(wstring& str, wchar_t ch, wchar_t ch_replaced);
208 
209     static bool StringReplace(wstring& str, const wstring& str_old, const wstring& str_new);
210 
211     static CString DataSizeToString(size_t data_size);
212 
213     //获取当前进程exe文件的路径
214     static wstring GetExePath();
215 
216     //获取桌面的路径
217     static wstring GetDesktopPath();
218 
219     //获取临时文件夹路径
220     static wstring GetTemplatePath();
221 
222     //获取Appdata/Local/MusicPlayer2的目录,如果不存在,则会自动创建
223     static wstring GetAppDataConfigDir();
224 
225     //获取系统特殊文件夹的位置
226     //csidl: 含义同SHGetSpecialFolderLocation函数的参数
227     static wstring GetSpecialDir(int csidl);
228 
229     static bool CreateDir(const _tstring& path);
230 
231     //文件/文件夹重命名
232     //file_path: 文件或文件夹的路径
233     //new_file_name: 新的文件名(不含扩展名),如果操作对象为文件夹,则为新文件夹名
234     //成功则返回新文件/文件夹的路径,否则返回空字符串
235     static _tstring FileRename(const _tstring& file_path, const _tstring& new_file_name);
236 
237     //将相对路径转换成绝对路径
238     //会自动判断路径是否为相对路径,如果不是则直接返回原路径
239     //relative_path:要转换的路径
240     //cur_dir:当前目录
241     static _tstring RelativePathToAbsolutePath(const _tstring& relative_path, const _tstring& cur_dir);
242 
243     //将一个字符串保存到剪贴板
244     static bool CopyStringToClipboard(const wstring& str);
245 
246     //从剪贴板获取字符串
247     static wstring GetStringFromClipboard();
248 
249     // 写入日志(对同一日志文件并发写入会丢失,请确保参数path指定的文件同一时刻只有一个线程能够写入)
250     static void WriteLog(const wchar_t* path, const wstring& content);
251 
252     // 将通过命令行参数传递过来的多个文件路径拆分,并保存到file容器里
253     static void DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& files);
254 
255     //解析命令行参数中的命令
256     static bool GetCmdLineCommand(const wstring& cmd_line, int& command);
257 
258     /*
259     函数功能:对指定文件在指定的目录下创建其快捷方式
260     函数参数:
261     lpszLnkFileDir  指定目录,不能为NULL。
262     lpszFileName    指定文件,为NULL表示当前进程的EXE文件。
263     lpszLnkFileName 快捷方式名称,为NULL表示EXE文件名。
264     lpszWorkDir		快捷方式工作目录,为NULL表示快捷方式目标所在位置
265     wHotkey         为0表示不设置快捷键
266     pszDescription  备注
267     iShowCmd        运行方式,默认为常规窗口
268     lpszArguments	命令行参数
269     nIconOffset		使用的图标为应用程序中第几个图标
270     */
271     static bool CreateFileShortcut(LPCTSTR lpszLnkFileDir, LPCTSTR lpszFileName = NULL, LPCTSTR lpszLnkFileName = NULL, LPCTSTR lpszWorkDir = NULL, WORD wHotkey = 0, LPCTSTR lpszDescription = NULL, int iShowCmd = SW_SHOWNORMAL, LPCTSTR lpszArguments = NULL, int nIconOffset = 0);
272 
273     //查找指定文件,并将文件名保存在files容器
274     //file_name:例如 D:\\Music\\*abc*.mp3,则将查找D:\Music目录下所有包含abc的mp3文件
275     //fun_is_valid: 一个函数对象,用于判断找到的文件是否要添加到files中,参数为文件名。默认全部返回true
276     static void GetFiles(wstring file_name, vector<wstring>& files, std::function<bool(const wstring&)> fun_is_valid = [](const wstring& file_path) { return true; });
277 
278     //查找指定的图片文件,并保存在files容器中,参数含义同GetFiles函数
279     static void GetImageFiles(wstring file_name, vector<wstring>& files);
280 
281     //判断一个文件夹及其子文件夹是否匹配一个关键字
282     static bool IsFolderMatchKeyWord(wstring dir, const wstring& key_word);
283 
284     //根据文件扩展名判断一个文件是否为图片文件
285     static bool FileIsImage(const wstring& file_name);
286 
287     //获取一个随机的字符串
288     static wstring GetRandomString(int length);
289 
290     //判断一个元素是否在vector中
291     template<class T>
292     static bool IsItemInVector(const vector<T>& items, const T& item);
293 
294     //判断一个元素是否在vector中
295     //其中func的原型是 bool func(const T&)
296     template<class T, class Func>
297     static bool IsItemInVector(const vector<T>& items, Func func);
298 
299     //判断文件名是末尾是否符合“(数字)”的形式
300     //file_name: 要判断的文件名,不包含扩展名
301     //number: 接收括号中的数字
302     //index: 接收左括号在字符串中的索引
303     static bool IsFileNameNumbered(const wstring& file_name, int& number, size_t& index);
304 
305     //删除一个非模态对话框
306     template<class T>
307     static void DeleteModelessDialog(T*& dlg);
308 
309     //将一个CSize对象在保持长宽比的情况下缩放,使其长边等side
310     static void SizeZoom(CSize& size, int side);
311 
312     static COLORREF GetWindowsThemeColor();
313 
314     //将hSrc中的所有菜单项添加到菜单hDst中(来自 https://blog.csdn.net/zgl7903/article/details/71077441
315     static int AppendMenuOp(HMENU hDst, HMENU hSrc);
316 
317     //判断一个菜单项是否在菜单中(检查子菜单)
318     static bool IsMenuItemInMenu(CMenu* pMenu, UINT id);
319 
320     //获取一个菜单项的序号
321     static int GetMenuItemPosition(CMenu* pMenu, UINT id);
322 
323     /**
324      * @brief   遍历一个菜单
325      * @param   CMenu * pMenu 遍历的菜单
326      * @param   func 一个函数对象或lambda表达式,第1个参数是被遍历菜单项的菜单对象,第2个参数是被遍历菜单项的id
327      */
328     static void IterateMenuItem(CMenu* pMenu, std::function<void(CMenu*, UINT)> func);
329 
330     //判断str的左侧是否匹配matched_str
331     static bool StringLeftMatch(const std::wstring& str, const std::wstring& matched_str);
332 
333     // 获取当前线程首选 UI 语言列表
334     static bool GetThreadLanguageList(vector<wstring>& language_tag);
335 
336     // 设置当前线程的线程首选 UI 语言
337     static bool SetThreadLanguageList(const vector<wstring>& language_tag);
338 
339     // 获取当前系统的默认UI字体
340     static wstring GetSystemDefaultUIFont();
341 
342     //安全的字符串复制函数
343     static void WStringCopy(wchar_t* str_dest, int dest_size, const wchar_t* str_source, int source_size = INT_MAX);
344 
345     //删除字体名称后面的Bold、Light等字符串,并根据这些字符串设置字体粗细
346     static void NormalizeFont(LOGFONT& font);
347 
348     //获取菜单栏的高度。hWnd:菜单栏所在的窗口句柄
349     static int GetMenuBarHeight(HWND hWnd);
350 
351     //对一个double按指定位数四舍五入
352     static double DoubleRound(double dVal, int format);
353 
354     //将一个图标的尺寸改为标准尺寸。给定一个像素值,然后在标准尺寸列表中查找最相近的尺寸,并返回
355     static int IconSizeNormalize(int size);
356 
357     //设置窗口不透明度
358     static void SetWindowOpacity(HWND hWnd, int opacity);
359 
360     static bool StringIsVersion(LPCTSTR str);
361 
362     //读取文件内容
363     static bool GetFileContent(const wchar_t* file_path, string& contents_buff, size_t max_size = 0x500000);
364 
365     //读取文件内容
366     //file_path: 文件的路径
367     //length: 文件的长度
368     //返回值: 读取成功返回读取到的文件内容的const char类型的指针,在使用完毕后这个指针需要自行使用delete释放。读取失败返回nullptr
369     static const char* GetFileContent(const wchar_t* file_path, size_t& length);
370 
371     //将数据保存到文件
372     static bool SaveDataToFile(const string& data, const wstring& file_path);
373 
374     //打开一个文件对话框,并将用户选择的文件路径保存到path_list中
375     static void DoOpenFileDlg(const wstring& filter, vector<wstring>& path_list, CWnd* pParent = nullptr);
376 
377     //为一个对话框设置字体
378     static void SetDialogFont(CWnd* pDlg, CFont* pFont);
379 
380     //对一个文件路径自动重命名,如果file_path存在,则在其后面加上“(1)”,如果文件名后面存在带括号的数字的形式,则括号内的数字加1
381     static void FileAutoRename(wstring& file_path);
382 
383     template<class T>
Min3(T v1,T v2,T v3)384     static T Min3(T v1, T v2, T v3)
385     {
386         T min = v1;
387         if (v2 < min)
388             min = v2;
389         if (v3 < min)
390             min = v3;
391         return min;
392     }
393 
394     template<class T>
Max3(T v1,T v2,T v3)395     static T Max3(T v1, T v2, T v3)
396     {
397         T max = v1;
398         if (v2 > max)
399             max = v2;
400         if (v3 > max)
401             max = v3;
402         return max;
403     }
404 
405     template<class T>
SetNumRange(T & num,const T & min_value,const T & max_value)406     static void SetNumRange(T& num, const T& min_value, const T& max_value)
407     {
408         if (num > max_value)
409             num = max_value;
410         if (num < min_value)
411             num = min_value;
412     }
413 
414     //以当前语言比较两个字符串
415     //返回值:0:相同;-1:小于;1:大于
416     static int StringCompareInLocalLanguage(const wstring& str1, const wstring& str2, bool no_case = false);
417 
418     //设置一个数字的某个bit位
419     static void SetNumberBit(unsigned short& num, int bit, bool value);
420 
421     //获取一个数字的某个bit位
422     static bool GetNumberBit(unsigned short num, int bit);
423 
424     //从资源加载自定义文本资源,并返回原始数据
425     static std::string GetTextResourceRawData(UINT id);
426 
427     //从资源加载自定义文本资源。id:资源的ID,code_type:文本的编码格式
428     static wstring GetTextResource(UINT id, CodeType code_type);
429 
430     //从资源加载png图片资源
431     //https://www.cnblogs.com/a-live/p/3222567.html
432     static Gdiplus::Image* GetPngImageResource(UINT id);
433 
434     //从资源加载png图片资源,保存到
435     static string GetPngImageResourceData(UINT id);
436 
437     static int Random(int min, int max);        //生成一个随机数,范围是大于或等于min,小于max
438 
439     static CString GetDesktopBackgroundPath();  //获取桌面壁纸的路径
440 
441     //返回使窗口显示在一个监视器内所需移动距离最小的偏移量 (当check_rect在某方向上大于screen_rects时向左或向上对齐)
442     static POINT CalculateWindowMoveOffset(CRect& check_rect, vector<CRect>& screen_rects);
443 
444     //从资源文件读取上次编译时间
445     static void GetLastCompileTime(wstring& time_str, wstring& hash_str);
446 
447     static unsigned __int64 GetCurTimeElapse();
448 
449     static wstring EncodeURIComponent(wstring uri);
450 
451     static void OutputDebugStringFormat(LPCTSTR str, ...);
452 
453     /**
454      * @brief Replace all pattern to new_content
455      * @param input Input string
456      * @param pattern Pattern
457      * @param new_content New content
458      * @return Result string
459     */
460     static std::wstring StrReplace(std::wstring& input, std::wstring pattern, std::wstring new_content);
461 
462     // https://stackoverflow.com/questions/17074324
463     template <typename T, typename Compare>
464     static std::vector<std::size_t> sort_permutation(const std::vector<T>& vec, Compare compare);
465 
466     template <typename T>
467     static std::vector<T> apply_permutation(const std::vector<T>& vec, const std::vector<std::size_t>& p);
468 };
469 
470 template<class T>
StringNormalize(T & str)471 inline bool CCommon::StringNormalize(T& str)
472 {
473     if (str.empty()) return false;
474 
475     int size = str.size();	//字符串的长度
476     if (size < 0) return false;
477     int index1 = 0;		//字符串中第1个不是空格或控制字符的位置
478     int index2 = size - 1;	//字符串中最后一个不是空格或控制字符的位置
479     while (index1 < size && ((str[index1] >= 0 && str[index1] <= 32) || str[index1] == 0x3000u || str[index1] == 0xfffdu))
480         index1++;
481     while (index2 >= 0 && ((str[index2] >= 0 && str[index2] <= 32) || str[index1] == 0x3000u || str[index2] == 0xfffdu))
482         index2--;
483     if (index1 > index2)	//如果index1 > index2,说明字符串全是空格或控制字符
484         str.clear();
485     else if (index1 == 0 && index2 == size - 1)	//如果index1和index2的值分别为0和size - 1,说明字符串前后没有空格或控制字符,直接返回
486         return true;
487     else
488         str = str.substr(index1, index2 - index1 + 1);
489     return true;
490 }
491 
492 template<class T>
DeleteEndSpace(T & str)493 inline bool CCommon::DeleteEndSpace(T& str)
494 {
495     if (str.empty()) return false;
496     while (!str.empty() && str.back() == L' ')
497         str.pop_back();
498     return true;
499 }
500 
501 template<class T>
StringTransform(T & str,bool upper)502 inline bool CCommon::StringTransform(T& str, bool upper)
503 {
504     if (str.empty()) return false;
505     //if (upper)
506     //	std::transform(str.begin(), str.end(), str.begin(), toupper);
507     //else
508     //	std::transform(str.begin(), str.end(), str.begin(), tolower);
509     if (upper)
510     {
511         for (auto& ch : str)
512         {
513             {
514                 if (ch >= 'a' && ch <= 'z')
515                     ch -= 32;
516             }
517         }
518     }
519     else
520     {
521         for (auto& ch : str)
522         {
523             if (ch >= 'A' && ch <= 'Z')
524                 ch += 32;
525         }
526     }
527     return true;
528 }
529 
530 template<class T>
StringCompareNoCase(const T & str1,const T & str2)531 inline bool CCommon::StringCompareNoCase(const T& str1, const T& str2)
532 {
533     T _str1{ str1 }, _str2{ str2 };
534     StringTransform(_str1, false);
535     StringTransform(_str2, false);
536     return (_str1 == _str2);
537 }
538 
539 template<class T>
StringFindNoCase(const T & str,const T & find_str,size_t index)540 inline size_t CCommon::StringFindNoCase(const T& str, const T& find_str, size_t index)
541 {
542     if (str.empty() || find_str.empty())
543         return -1;
544     T _str{ str }, _find_str{ find_str };
545     StringTransform(_str, false);
546     StringTransform(_find_str, false);
547     return _str.find(_find_str, index);
548 }
549 
550 template<class T>
StringNatchWholeWord(const T & str,const T & find_str)551 inline size_t CCommon::StringNatchWholeWord(const T& str, const T& find_str)
552 {
553     if (str.empty() || find_str.empty())
554         return -1;
555     //下面3句代码由于太消耗时间和CPU,因此去掉
556     //T _str{ str }, _find_str{ find_str };
557     //StringTransform(str, false);
558     //StringTransform(find_str, false);
559     int index{ -1 };
560     int find_str_front_pos, find_str_back_pos;		//找到的字符串在原字符串中前面和后面一个字符的位置
561     int size = str.size();
562     int find_str_size = find_str.size();
563     while (true)
564     {
565         index = str.find(find_str, index + 1);
566         if (index == T::npos) break;
567         find_str_front_pos = index - 1;
568         find_str_back_pos = index + find_str_size;
569         if ((find_str_front_pos < 0 || IsDivideChar(str[find_str_front_pos])) && (find_str_back_pos >= size || IsDivideChar(str[find_str_back_pos])))
570             return index;
571         else
572             continue;
573     }
574     return -1;
575 }
576 
577 template<class T, class Func>
IsItemInVector(const vector<T> & items,Func func)578 inline bool CCommon::IsItemInVector(const vector<T>& items, Func func)
579 {
580     for (const auto& an_item : items)
581     {
582         if (func(an_item))
583             return true;
584     }
585     return false;
586 }
587 
588 template<class T>
IsItemInVector(const vector<T> & items,const T & item)589 inline bool CCommon::IsItemInVector(const vector<T>& items, const T& item)
590 {
591     for (const auto& an_item : items)
592     {
593         if (an_item == item)
594             return true;
595     }
596     return false;
597 }
598 
599 template<class T>
DeleteModelessDialog(T * & dlg)600 inline void CCommon::DeleteModelessDialog(T*& dlg)
601 {
602     if (dlg != nullptr)
603     {
604         dlg->OnCancel();
605         delete dlg;
606         dlg = nullptr;
607     }
608 }
609 
610 template <typename T, typename Compare>
sort_permutation(const std::vector<T> & vec,Compare compare)611 inline std::vector<std::size_t> CCommon::sort_permutation(const std::vector<T>& vec, Compare compare)
612 {
613     std::vector<std::size_t> p(vec.size());
614     std::iota(p.begin(), p.end(), 0);
615     std::sort(p.begin(), p.end(),
616         [&](std::size_t i, std::size_t j) { return compare(std::cref(vec[i]), std::cref(vec[j])); });
617     return p;
618 }
619 
620 template <typename T>
apply_permutation(const std::vector<T> & vec,const std::vector<std::size_t> & p)621 inline std::vector<T> CCommon::apply_permutation(const std::vector<T>& vec, const std::vector<std::size_t>& p)
622 {
623     std::vector<T> sorted_vec(vec.size());
624     std::transform(p.begin(), p.end(), sorted_vec.begin(),
625         [&](std::size_t i) { return vec[i]; });
626     return sorted_vec;
627 }
628