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