#pragma once #include #include #include #include #include #include #pragma warning (disable:4150) // 删除指向不完整“boost::property_tree::basic_ptree>”类型的指针;没有调用析构函数 #pragma warning (disable:4251) // ECOM::Utility::BSTTree::m_Root: class“XDWHolder”需要有 dll 接口由 class“ECOM::Utility::BSTTree”的客户端使用 namespace boost { namespace property_tree { template < class Key, class Data, class KeyCompare> class basic_ptree; typedef basic_ptree > ptree; typedef ptree tTree; // typedef basic_ptree tTree; // typedef basic_ptree tTree; }; }; using namespace boost::property_tree; #include "XDWHolder.tlh" #include "XDWHolder.tli" #ifndef BSTTree_EXPORTS #define _BSTTree_API _declspec(dllimport) #else #define _BSTTree_API _declspec(dllexport) #endif #ifndef BSTTree_EXPORTS #ifdef _WIN64 #ifdef _DEBUG #pragma comment (lib, "ECOM.Utility.BSTTree64D.lib") #else #pragma comment (lib, "ECOM.Utility.BSTTree64.lib") #endif #else // X86 #ifdef _DEBUG #pragma comment (lib, "ECOM.Utility.BSTTreeD.lib") #else #pragma comment (lib, "ECOM.Utility.BSTTree.lib") #endif #endif #endif // BSTTree_EXPORTS //----------------------------------------------------------------------------- // BSTTree // 对 tTree 的封装 // // 不能用 std::unique_ptr, 因为 unique_ptr 需要知道 tTree 才能析构 // 因此这里用 XDWHolder //----------------------------------------------------------------------------- namespace ECOM::Utility { class BSTTreeArray; class _BSTTree_API BSTTree { template static constexpr bool dependent_false = false; protected: tTree * m_Tree; XDWHolder m_Root; bool m_bAttrib; friend class BSTXML; friend class BSTJSON; friend class BSTINI; friend class BSTSSV; friend class BSTTreeArray; private: BSTTree (XDWHolder && from); public: BSTTree (); BSTTree (BSTTree && from); BSTTree (const BSTTree & from) = delete; virtual ~BSTTree (); BSTTree & operator = (BSTTree && from); BSTTree & operator = (const BSTTree & from) = delete; public: bool IsEmpty () const; operator bool () const { return ! IsEmpty (); } // 返回儿子节点的数量 int Size () const; // 数一数其中有多少个路径 int Count (const std::string & path) const; int Count (const std::string_view & path) const { return Count (std::string (path)); } protected: BSTTree __Into (const std::string & path) const; BSTTree __Into (const std::string & path, char sep) const; public: BSTTree Into (const std::string & path) const; // BSTTree Into (const eSTR::DString & path) const; BSTTree Into (const std::string_view & path) const { return Into (std::string (path)); } public: BSTTree Into (const std::string & path, char sep) const { return __Into (path, sep); } public: BSTTree Attrib () const; protected: std::string TryAttribOf (const std::string & path, LPCSTR Def) const; std::string TryAttribOf (const std::string & path, const std::string & Def) const; public: #if 1 template T AttribOf (const std::string & path) const { return Attrib ().Get (path); } template T AttribOf (const std::string_view & path) const { return Attrib ().Get (path); } #endif // 如果不写类型转换, 默认返回 std::string 类型 std::string AttribOf (const std::string & path) const { return (TryAttribOf (path, std::string ())); } std::string AttribOf (const std::string_view & _path) const { std::string path { _path }; return (TryAttribOf (path, std::string ())); } std::string AttribOf (const char * _path) const { std::string path { _path }; return (TryAttribOf (path, std::string ())); } // 给定路径, 获取 Value public: /// // 类型转换, 默认用的就是 eSTR::DString 的转换函数/模版 template T Get (const std::string_view & path) const { static_assert (dependent_false); } // 偏特化 // template <> std::string Get (const std::string_view & path) const; template <> std::string Get (const std::string_view & path) const { return TryGet (path, std::string ()); } template <> int Get (const std::string_view & path) const { return TryGet (path, static_cast (0)); } template <> unsigned int Get (const std::string_view & path) const { return TryGet (path, static_cast (0)); } template <> __int64 Get (const std::string_view & path) const { return TryGet (path, static_cast <__int64> (0)); } template <> unsigned __int64 Get (const std::string_view & path) const { return TryGet (path, static_cast (0)); } template <> long Get (const std::string_view & path) const { return TryGet (path, static_cast (0)); } template <> unsigned long Get (const std::string_view & path) const { return TryGet (path, static_cast (0)); } template <> double Get (const std::string_view & path) const { return TryGet (path, static_cast (0.0)); } template <> float Get (const std::string_view & path) const { return TryGet (path, static_cast (0.0f)); } template <> bool Get (const std::string_view & path) const { return TryGet (path, false); } // 如果不写类型转换, 默认返回 std::string 类型 std::string Get (const std::string & path) const { return Get (path); } std::string Get (const std::string_view & path) const { return Get (path); } // std::string Get (const char * path) const { return Get (path); } // 上述函数引起编译器错误: 重载函数定义不明, 因此注释掉 /// // 给定路径, 获取 Value, 但是返回 optional public: std::optional GetOpt (const std::string_view & path) const { return GetOpt (std::string (path)); } std::optional GetOpt (const std::string & path) const; public: int GetArray (const std::string_view & Key, std::vector * arStr); int GetArray (const std::string_view & Key, std::list * arStr); public: // 带默认值的函数操作符重载 // eSTR::DString operator () (const std::string_view & path, LPCSTR Def) const { return eSTR::DString (TryGet (path, Def)); } bool operator () (const std::string_view & path, bool Def) const { return TryGet (path, Def); } int operator () (const std::string_view & path, int Def) const { return TryGet (path, Def); } unsigned int operator () (const std::string_view & path, unsigned int Def) const { return TryGet (path, Def); } __int64 operator () (const std::string_view & path, __int64 Def) const { return TryGet (path, Def); } long operator () (const std::string_view & path, long Def) const { return TryGet (path, Def); } float operator () (const std::string_view & path, float Def) const { return TryGet (path, Def); } double operator () (const std::string_view & path, double Def) const { return TryGet (path, Def); } protected: /// 如果找不到, 就用 Def 代替 std::string TryGet (const std::string_view & path, const char * Def) const; std::string TryGet (const std::string_view & path, const std::string_view & Def) const; std::string TryGet (const std::string_view & path, const std::string & Def) const; int TryGet (const std::string_view & path, int Def) const; unsigned int TryGet (const std::string_view & path, unsigned int Def) const; __int64 TryGet (const std::string_view & path, __int64 Def) const; unsigned __int64 TryGet (const std::string_view & path, unsigned __int64 Def) const; long TryGet (const std::string_view & path, long Def) const; unsigned long TryGet (const std::string_view & path, unsigned long Def) const; double TryGet (const std::string_view & path, double Def) const; float TryGet (const std::string_view & path, float Def) const; bool TryGet (const std::string_view & path, bool Def) const; template TR _TryGet (const std::string_view & path, const T & Def) const; /// public: template T GetIf (const std::string_view & path, const T & Def) const { auto rc = TryGet (path, Def); return rc; } //< 针对 LPCSTR Def 的特殊处理, 例如 int Port = CH.GetIf ("Port", "22"); template T GetIf (const std::string_view & path, LPCSTR Def) const { auto rc = TryGet (path, Def); return rc; } // 例如 DString AE = Ch.GetIf ("AE", "DROC"); template <> std::string GetIf (const std::string_view & path, LPCSTR Def) const { auto rc = TryGet (path, Def); return (rc); } std::string GetIf (const std::string_view & path, LPCSTR Def) const { return GetIf (path, Def); } //> std::string GetIf (const std::string_view & path, const std::string & Def) const { return GetIf (path, Def.c_str ()); } //< 针对 StringView 的特殊处理, 不能返回 StringView std::string GetIf (const std::string_view & path, const std::string_view & Def) const { auto rc = TryGet (path, Def); return (rc); } //> public: template T GetData () const { static_assert (dependent_false, "Invalid type in BSTTtee.GetData ()"); } template <> std::string GetData () const; std::string GetData () const { return GetData (); } protected: template std::optional _GetValue () const; public: template std::optional GetValue () const { static_assert (dependent_false, "Invalid type in BSTTtee.GetValue ()"); } template <> std::optional GetValue () const; template <> std::optional GetValue () const; template <> std::optional GetValue () const; template <> std::optional GetValue () const; template <> std::optional GetValue () const; template <> std::optional <__int64> GetValue () const; template <> std::optional GetValue () const; template <> std::optional GetValue () const; template <> std::optional GetValue () const; template <> std::optional GetValue () const; std::optional GetValue () const { return GetValue (); } public: // 如果原来没有这一项, 就增加, 如果原来有, 就更新. 返回 this BSTTree & SetValue (LPCSTR value); BSTTree & SetValue (const std::string & value); // BSTTree & SetValue (const eSTR::DString & value); BSTTree & SetValue (const std::string_view & value); BSTTree & SetValue (int value); BSTTree & SetValue (unsigned int value); BSTTree & SetValue (long value); BSTTree & SetValue (unsigned long value); BSTTree & SetValue (__int64 value); BSTTree & SetValue (unsigned __int64 value); BSTTree & SetValue (double value); BSTTree & SetValue (bool value); BSTTree & SetValue (void * ptr); public: // 如果原来没有这一项, 就增加, 如果原来有, 就更新. 返回 this BSTTree & Put (const std::string_view & path, LPCSTR value); BSTTree & Put (const std::string_view & path, const std::string & value); BSTTree & Put (const std::string_view & path, const std::string_view & value); BSTTree & Put (const std::string_view & path, int value); BSTTree & Put (const std::string_view & path, unsigned int value); BSTTree & Put (const std::string_view & path, long value); BSTTree & Put (const std::string_view & path, unsigned long value); BSTTree & Put (const std::string_view & path, __int64 value); BSTTree & Put (const std::string_view & path, unsigned __int64 value); BSTTree & Put (const std::string_view & path, double value); BSTTree & Put (const std::string_view & path, bool value); BSTTree & Put (const std::string_view & path, void * ptr); public: // 添加新项, 返回 this BSTTree & Add (const std::string_view & path, LPCSTR value); BSTTree & Add (const std::string_view & path, const std::string & value); BSTTree & Add (const std::string_view & path, const std::string_view & value); BSTTree & Add (const std::string_view & path, int value); BSTTree & Add (const std::string_view & path, unsigned int value); BSTTree & Add (const std::string_view & path, long value); BSTTree & Add (const std::string_view & path, unsigned long value); BSTTree & Add (const std::string_view & path, __int64 value); BSTTree & Add (const std::string_view & path, unsigned __int64 value); BSTTree & Add (const std::string_view & path, double value); BSTTree & Add (const std::string_view & path, bool value); BSTTree & Add (const std::string_view & path, void * ptr); // 数组/列表 public: template BSTTree & Add (const std::string_view & path, const std::list & lst); template BSTTree & Add (const std::string_view & path, const std::vector & lst); protected: template BSTTree & __Add (const std::string_view & path, const T & value); template BSTTree & __Put (const std::string_view & path, const T & value); public: // 特殊用途, 把 child 作为子节点 bool Add (const std::string & name, const BSTTree & child); protected: class Proxy { public: Proxy (BSTTree * Tree, std::string_view Key) { m_Tree = Tree; m_Key = Key; } Proxy (BSTTree * Tree, const std::string & Key) { m_Tree = Tree; m_Key = Key; } Proxy (const Proxy & from) { m_Tree = from.m_Tree; m_Key = from.m_Key; } Proxy (Proxy && from) { m_Tree = from.m_Tree; m_Key = from.m_Key; } ~Proxy () = default; public: inline std::string Get () const { return m_Tree->Get (m_Key); } inline operator std::string () const { return m_Tree->Get (m_Key); } inline operator void * () const { return reinterpret_cast (m_Tree->Get (m_Key)); } inline operator DWORD () const { return m_Tree->Get (m_Key); } inline operator __int64 () const { return m_Tree->Get <__int64> (m_Key); } inline operator unsigned __int64 () const { return m_Tree->Get (m_Key); } inline operator int () const { return m_Tree->Get (m_Key); } inline operator unsigned int () const { return m_Tree->Get (m_Key); } inline operator long () const { return m_Tree->Get (m_Key); } inline operator bool () const { return m_Tree->Get (m_Key); } inline operator float () const { return m_Tree->Get (m_Key); } inline operator double () const { return m_Tree->Get (m_Key); } public: inline Proxy & operator = (LPCSTR Value) { m_Tree->Put (m_Key, Value); return (*this); } #if 0 inline Proxy & operator = (PCWSTR Value) { m_Tree->Put (m_Key, Value); return (*this); } #endif inline Proxy & operator = (const std::string_view & Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (const std::string & Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (__int64 Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (UINT_PTR Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (DWORD Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (int Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (bool Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (void * Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (float Value) { m_Tree->Put (m_Key, Value); return (*this); } inline Proxy & operator = (double Value) { m_Tree->Put (m_Key, Value); return (*this); } protected: BSTTree * m_Tree; std::string_view m_Key; }; // 函数操作符重载, 下标操作符重载 public: Proxy operator [] (std::string_view Key) { return Proxy (this, Key); } Proxy operator () (std::string_view Key) { return Proxy (this, Key); } public: // 添加一个子节点, 返回的是这个子节点 BSTTree AddChild (const std::string & path); BSTTree AddChild (const std::string_view path) { return AddChild (std::string (path)); } public: // 如果原来没有这一项, 就增加, 如果原来有, 就更新, 返回的是这个子节点 BSTTree PutChild (const std::string & path); BSTTree PutChild (const std::string_view & path) { return PutChild (std::string (path)); } public: // 增加子节点, 但是子节点是一个数组 BSTTreeArray AddChildArray (const std::string & path); BSTTreeArray AddChildArray (const std::string_view & path); //BSTTreeArray AddChildArray (LPCSTR path); // 易导致编译错误: 重载调用不明确 public: // 无条件删除指定的项, 当然包括下面的全部子项 bool Delete (const std::string_view & path); // 当 Pred 返回 true 时, 删除 bool Delete (std::function pred); public: // 查找, 判断某个路径是否存在 bool IsExist (const std::string & path); bool IsExist (const std::string_view & path) { return IsExist (std::string (path)); } public: // 如果非空, 就执行指定的函数 template inline bool Do (const Fun & fun, arg... e) { if (IsEmpty ()) return false; fun (*this, e...); return true; } public: // 获取第一个/最后一个, 如果存在, 就调用指定指定的函数 // bool OnFirst (std::function fun); // bool OnLast (std::function fun); // 返回第一个子节点/最后一个子节点. 如果不存在, 或者为空, 返回的 XML 将是空白的 BSTTree First (); BSTTree Last (); /// 非模板版本 (2021-11-04) // 测试表明, 如果用之前版本的模板, 可能导致断言失败. // 具体原因很难找, 可能是因为 Iter 内部的实例是在本模块内分配的, 但是却由调用者来释放. /// // 类似迭代器的调用, 返回调用次数 int ForEach (std::function ); // 搜索指定的 tagname, 如果找到, 就执行对应的函数 int ForEachOn (const std::string & tagname, std::function ); int ForEachOn (const std::string_view & tagname, std::function ); private: template int _ForEachOn (const T & tagname, std::function ); public: // 寻找满足条件的第一个, 如果找到, 就执行对应的函数 bool First (std::function pred); public: // 转换成 容器, 比如 std::list template inline T To () { T rc; if (IsEmpty ()) return rc; auto Iter = GetIterator (); for (;;) { auto pair = Iter (); auto & name = pair.first; auto & ptr = pair.second; BSTTree * xml = ptr.get (); if (xml == nullptr) // 迭代结束 break; rc.push_back (std::move (*xml)); } return rc; } // 转换成 vector inline std::vector ToVector () { return To > (); } // 转换成 list inline std::list ToList () { return To > (); } public: static bool IsAttrib (const std::string & tagName); // return tagName == XMLATTR private: // 迭代函数返回 pair, 参数 2 用指针, 其目的是让上层知道: 何时迭代结束 using IterArgType = std::pair >; using IterFuncType = std::function ; IterFuncType GetIterator (); static BSTTree _TreeNodeToMe (tTree & node); static const std::string XMLATTR_DOT; // = "."; static const std::string XMLATTR; // = ""; }; //----------------------------------------------------------------------------- // BSTTreeArray //----------------------------------------------------------------------------- class _BSTTree_API BSTTreeArray : public BSTTree { private: BSTTreeArray (BSTTree & parent, const std::string & path); public: BSTTreeArray (BSTTreeArray && with); private: BSTTree & m_Parent; const std::string m_Path; friend class BSTTree; public: ~BSTTreeArray (); public: BSTTreeArray & Add (const BSTTree & tree); template BSTTreeArray & Add (const std::string_view & key, const T & value) { BSTTree CH; CH.Add (key, value); return Add (std::move (CH)); } // 最后应该调用 End, 调用 End 之后, 就无法调用 Add 了 (即使调用也无效) // 析构函数也会调用 End void End (); }; } namespace ECOM::Utility { //----------------------------------------------------------------------------- // BSTXML, BSTJSON, BSTINI // 全部是 public 的静态函数 // 以下函数被删除, 因为容易引起编译错误: 决策不明 (例如 LoadFile (DString xx)); // static BSTTree LoadFile (const wchar_t * szFileName) // static BSTTree LoadFile (LPCSTR szFileName) // static int SaveFile (BSTTree & Tree, const wchar_t * szFileName) // static int SaveFile (BSTTree & Tree, LPCSTR szFileName) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // BSTXML //----------------------------------------------------------------------------- class _BSTTree_API BSTXML { public: // 文件和字符串, 默认是 UTF8 编码 static BSTTree LoadFile (const std::wstring & szFileName); static BSTTree LoadFile (const std::wstring_view & szFileName) { return LoadFile (std::wstring (szFileName)); } static BSTTree LoadFile (const std::string & szFileName); static BSTTree LoadFile (const std::string_view & szFileName) { return LoadFile (std::string (szFileName)); } static BSTTree FromString (const std::string & doc); static BSTTree FromString (const std::string_view & doc); // 返回: 写入的字节数 static int SaveFile (const BSTTree & Tree, const std::wstring_view & szFileName); static int SaveFile (const BSTTree & Tree, const std::wstring & szFileName) { return SaveFile (Tree, std::wstring_view (szFileName)); } static int SaveFile (const BSTTree & Tree, const std::string_view & szFileName); static int SaveFile (const BSTTree & Tree, const std::string & szFileName) { return SaveFile (Tree, std::string_view (szFileName)); } public: // 转换成字符串, 默认是 UTF8 编码 static std::string ToString (const BSTTree & Tree); }; //----------------------------------------------------------------------------- // BSTJSON //----------------------------------------------------------------------------- class _BSTTree_API BSTJSON { public: // 文件和字符串, 默认是 UTF8 编码 static BSTTree LoadFile (const std::wstring & szFileName); static BSTTree LoadFile (const std::wstring_view & szFileName) { return LoadFile (std::wstring (szFileName)); } static BSTTree LoadFile (const std::string & szFileName); static BSTTree LoadFile (const std::string_view & szFileName) { return LoadFile (std::string (szFileName)); } static int SaveFile (const BSTTree & Tree, const std::string_view & szFileName); static int SaveFile (const BSTTree & Tree, const std::string & szFileName) { return SaveFile (Tree, std::string_view (szFileName)); } static BSTTree FromString (const std::string & doc); static BSTTree FromString (const std::string_view & doc); //static BSTTree FromString (LPCSTR doc); // 返回: 写入的字节数 static int SaveFile (const BSTTree & Tree, const std::wstring & szFileName); static int SaveFile (const BSTTree & Tree, const std::wstring_view & szFileName) { return SaveFile (Tree, std::wstring (szFileName)); } public: // 转换成字符串, 默认是 UTF8 编码 static std::string ToString (const BSTTree & Tree); }; //----------------------------------------------------------------------------- // BSTINI //----------------------------------------------------------------------------- class _BSTTree_API BSTINI { public: // 文件和字符串, 默认是 UTF8 编码 static BSTTree LoadFile (const std::wstring & szFileName); static BSTTree LoadFile (const std::wstring_view & szFileName) { return LoadFile (std::wstring (szFileName)); } static BSTTree LoadFile (const std::string & szFileName); static BSTTree LoadFile (const std::string_view & szFileName) { return LoadFile (std::string (szFileName)); } static BSTTree FromString (const std::string & doc); static BSTTree FromString (const std::string_view & doc); //static BSTTree FromString (LPCSTR doc); // 返回: 写入的字节数 static int SaveFile (const BSTTree & Tree, const std::wstring & szFileName); static int SaveFile (const BSTTree & Tree, const std::wstring_view & szFileName) { return SaveFile (Tree, std::wstring (szFileName)); } static int SaveFile (const BSTTree & Tree, const std::string_view & szFileName); static int SaveFile (const BSTTree & Tree, const std::string & szFileName) { return SaveFile (Tree, std::string_view (szFileName)); } public: // 转换成字符串, 默认是 UTF8 编码 static std::string ToString (const BSTTree & Tree); }; //----------------------------------------------------------------------------- // BSTSSV // 以分号分隔, 例如 K1=V1; K2=V2; K3=V3 //----------------------------------------------------------------------------- class _BSTTree_API BSTSSV { public: // 文件和字符串, 默认是 UTF8 编码 static BSTTree LoadFile (const std::wstring & szFileName); static BSTTree LoadFile (const std::wstring_view & szFileName) { return LoadFile (std::wstring (szFileName)); } static BSTTree LoadFile (const std::string & szFileName); static BSTTree LoadFile (const std::string_view & szFileName) { return LoadFile (std::string (szFileName)); } static BSTTree FromString (const std::string & doc); static BSTTree FromString (const std::string_view & doc); //static BSTTree FromString (LPCSTR doc); // 返回: 写入的字节数 static int SaveFile (const BSTTree & Tree, const std::wstring & szFileName); static int SaveFile (const BSTTree & Tree, const std::wstring_view & szFileName) { return SaveFile (Tree, std::wstring (szFileName)); } static int SaveFile (const BSTTree & Tree, const std::string_view & szFileName); static int SaveFile (const BSTTree & Tree, const std::string & szFileName) { return SaveFile (Tree, std::string_view (szFileName)); } public: // 转换成字符串, 默认是 UTF8 编码 static std::string ToString (const BSTTree & Tree); }; } namespace ECOM::Utility { template inline BSTTree & BSTTree::Add (const std::string_view & path, const std::list & lst) { if (! m_Tree) return (*this); try { auto CHArray = this->AddChildArray (path); std::string emp; for (const auto & it : lst) { ECOM::Utility::BSTTree CH; CH.Put (emp, it); CHArray.Add (std::move (CH)); } CHArray.End (); } catch (...) { } return (*this); } template inline BSTTree & BSTTree::Add (const std::string_view & path, const std::vector & lst) { if (! m_Tree) return (*this); try { auto CHArray = this->AddChildArray (path); std::string emp; for (const auto & it : lst) { ECOM::Utility::BSTTree CH; CH.Put (emp, it); CHArray.Add (std::move (CH)); } CHArray.End (); } catch (...) { } return (*this); } }