|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <afx.h>
|
|
|
|
|
|
#include "TypeDefine.h"
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* CList 遍历宏
|
|
|
|
|
|
*
|
|
|
|
|
|
* \list CList 链表
|
|
|
|
|
|
* \pos POSITION 变量,元素的位置,要取对应的请使用 list.GetAt(pos)
|
|
|
|
|
|
*/
|
|
|
|
|
|
#define CListForEach(pos, list) \
|
|
|
|
|
|
for (POSITION pos = (list).GetHeadPosition(); pos != nullptr; (list).GetNext(pos))
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 检查一个CString是否以给定的前缀开头
|
|
|
|
|
|
* \param str 要检查的CString
|
|
|
|
|
|
* \param prefix 前缀字符串
|
|
|
|
|
|
* \return 如果CString以前缀开头,则返回true;否则返回false
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline bool StartsWith(const CString& str, const TCHAR *prefix)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert(prefix != nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
size_t prefixLength = _tcslen(prefix);
|
|
|
|
|
|
if (str.GetLength() < prefixLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return _tcsncmp(str.GetString(), prefix, prefixLength) == 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 检查一个CString是否以另一个CString作为前缀开头
|
|
|
|
|
|
* \param str 要检查的CString
|
|
|
|
|
|
* \param prefix 前缀CString
|
|
|
|
|
|
* \return 如果CString以前缀开头,则返回true;否则返回false
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline bool StartsWith(const CString& str, const CString &prefix)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (str.GetLength() < prefix.GetLength())
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return _tcsncmp(str.GetString(), prefix.GetString(), prefix.GetLength()) == 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 检查一个CString是否以另一个CString作为后缀结尾
|
|
|
|
|
|
* \param str 要检查的CString
|
|
|
|
|
|
* \param suffix 后缀CString
|
|
|
|
|
|
* \return 如果CString以后缀结尾,则返回true;否则返回false
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline bool EndsWith(const CString& str, const CString& suffix)
|
|
|
|
|
|
{
|
|
|
|
|
|
int strLength = str.GetLength();
|
|
|
|
|
|
int suffixLength = suffix.GetLength();
|
|
|
|
|
|
|
|
|
|
|
|
if (strLength < suffixLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (str.Right(suffixLength) == suffix);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 将一个CString的向量用指定的分隔符连接起来
|
|
|
|
|
|
* \param strings 包含多个CString的向量
|
|
|
|
|
|
* \param delimiter 分隔符CString
|
|
|
|
|
|
* \return 连接后的CString
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline CString Join(const std::vector<CString>& strings, const CString& delimiter)
|
|
|
|
|
|
{
|
|
|
|
|
|
CString joinedString;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < strings.size(); i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
joinedString += strings[i];
|
|
|
|
|
|
|
|
|
|
|
|
if (i != strings.size() - 1)
|
|
|
|
|
|
joinedString += delimiter;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return joinedString;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 获取 path 的父路径
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param path
|
|
|
|
|
|
* \return
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline CString LayerParentPath(CString& path)
|
|
|
|
|
|
{
|
|
|
|
|
|
int pos = path.ReverseFind(_T('\\'));
|
|
|
|
|
|
if (pos != -1) {
|
|
|
|
|
|
return path.Left(pos);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 判断两个路径父路径是否相同
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param path1
|
|
|
|
|
|
* \param path2
|
|
|
|
|
|
* \return
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline bool IsSameParentPath(CString& path1, CString& path2)
|
|
|
|
|
|
{
|
|
|
|
|
|
CString parentPath1 = LayerParentPath(path1);
|
|
|
|
|
|
CString parentPath2 = LayerParentPath(path2);
|
|
|
|
|
|
|
|
|
|
|
|
return parentPath1.CompareNoCase(parentPath2) == 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief 判断一个路径是否是另一个路径的下级(下下级...)路径
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param childPath 子路径
|
|
|
|
|
|
* \param parentPath 父级路径
|
|
|
|
|
|
* \return
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline bool IsSubPath(const CString& childPath, const CString& parentPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (EndsWith(parentPath, _T("\\")))
|
|
|
|
|
|
{
|
|
|
|
|
|
return StartsWith(childPath, parentPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
return StartsWith(childPath, parentPath + _T("\\"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void MarkSectionBegin(CArchive& ar, const short& ver)
|
|
|
|
|
|
{
|
|
|
|
|
|
int beginType = SECTION_BEGIN;
|
|
|
|
|
|
pf.WriteElementType(ar, beginType, ver);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void MarkSectionEnd(CArchive& ar, const short& ver)
|
|
|
|
|
|
{
|
|
|
|
|
|
int endType = SECTION_END;
|
|
|
|
|
|
pf.WriteElementType(ar, endType, ver);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void VerifySectionBegin(CArchive& ar, const short& ver)
|
|
|
|
|
|
{
|
|
|
|
|
|
int beginType = 0;
|
|
|
|
|
|
pf.ReadElementType(ar, beginType, ver);
|
|
|
|
|
|
if (beginType != SECTION_BEGIN)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new CArchiveException(CArchiveException::badClass);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void VerifySectionEnd(CArchive& ar, const short& ver)
|
|
|
|
|
|
{
|
|
|
|
|
|
int endType = 0;
|
|
|
|
|
|
pf.ReadElementType(ar, endType, ver);
|
|
|
|
|
|
if (endType != SECTION_END)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new CArchiveException(CArchiveException::badClass);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 将小数保留指定小数位数
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param value 要被截断的数字
|
|
|
|
|
|
* \param precision 保留几位小数,如果 < 0 什么也不做
|
|
|
|
|
|
* \return
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline double TruncToPrecision(double value, int precision)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (precision < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (precision == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return std::trunc(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double factor = std::pow(10.0, precision); // 10^n
|
|
|
|
|
|
return std::trunc(value * factor) / factor; // 截断到指定小数位
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct CStringHash
|
|
|
|
|
|
{
|
|
|
|
|
|
size_t operator()(const CString& str) const
|
|
|
|
|
|
{
|
|
|
|
|
|
// 使用 CString 的底层字符串进行哈希计算
|
|
|
|
|
|
return std::hash<std::string>()(str.GetString());
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除对象并将指针置为 nullptr
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param pointer
|
|
|
|
|
|
*/
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
void SafeDelete(T*& pointer)
|
|
|
|
|
|
{
|
|
|
|
|
|
delete pointer;
|
|
|
|
|
|
pointer = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 用于删除数组并将指针设置为 nullptr
|
|
|
|
|
|
*
|
|
|
|
|
|
* \param pointer
|
|
|
|
|
|
*/
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
void SafeDeleteArray(T*& pointer)
|
|
|
|
|
|
{
|
|
|
|
|
|
delete[] pointer;
|
|
|
|
|
|
pointer = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
void ClonePointer(T*& destination, const T* source)
|
|
|
|
|
|
{
|
|
|
|
|
|
delete destination;
|
|
|
|
|
|
destination = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
if (source != nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
destination = new T();
|
|
|
|
|
|
*destination = const_cast<T&>(*source);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|