#pragma once /* * HashTable File * Version 1.22 2019-02-25 * Description: * * */ #include #include #include #include "../Utils.h" inline std::string trim(const std::string& s) { char p[] = " \t\r\n"; long sp = 0; long ep = (long)s.length() - 1; for (; sp <= ep; ++sp) if (!strchr(p, s[sp])) break; for (; ep >= 0; --ep) if (!strchr(p, s[ep])) break; return s.substr(sp, ep-sp+1); } //struct stCfgCtrl //ÅäÖÃÎļþÏîºÍ¿Ø¼þ¶ÔÓ¦¹Øϵ //{ // CStringA sKeyName; // UINT nCtrlId; //}; enum enVtype //±äÁ¿ÀàÐÍ { vtNone = 0, vtbool =1, vtInt = 2, vtFloat = 3, vtDouble = 4, vtString = 5, }; enum enCType //¿Ø¼þÀàÐÍ { ctNone =0, ctStatic=1, ctEdit=2, ctCheckBox=3, ctRadio=4, ctComboBoxIndex=5, //ComboBox Index; ctComboBoxString = 6, // ComboBox String; ctListBox = 6, ctListCtrl=7, }; struct stCfgValCtrl //ÅäÖÃÎļþÏîºÍ±äÁ¿ÒÔ¼°¿Ø¼þ¶ÔÓ¦¹Øϵ { CStringA sKeyName; int vType; void * var; UINT nCtrlId; int cType; }; template char(&_ArraySizeHelper(T(&array)[N]))[N]; #define countof(array) (sizeof(_ArraySizeHelper(array))) #define MAX_HASH_KEY 3000 #define MAX_MHASH_SEGMENT 300 class Hashelement { public: int HashValue; CString * Key; CString * Value; Hashelement() { HashValue = 0; Key = NULL; Value = NULL; } ~Hashelement() { delete Key; delete Value; Key = NULL; Value = NULL; } Hashelement(const Hashelement& elem) { *this = elem; } Hashelement& operator = (const Hashelement& elem) { if (this == &elem) { return *this; } HashValue = elem.HashValue; delete Key; delete Value; Key = new CString(*(elem.Key)); Value = new CString(*(elem.Value)); return *this; } operator int () { return _tstoi(*Value); } operator float() { return float(_tstof(*Value)); } operator double() { return _tstof(*Value); } operator LPCTSTR() { return *Value; } //operator CString() //{ // return *Value; //} //operator TCHAR *() //{ // return *Value; //} int operator =(int i) { if (Value == nullptr) { Value = new CString; } (*Value).Format(_T("%d"),i); return i; } float operator =(float f) { if (Value == nullptr) { Value = new CString; } (*Value).Format(_T("%f"), f); return f; } double operator =(double d) { if (Value == nullptr) { Value = new CString; } (*Value).Format(_T("%f"), d); return d; } CString operator =(CString s) { if (Value == nullptr) { Value = new CString; } *Value = s; return s; } }; class Hash { public: CString Name; int TotalKey; Hashelement elements[MAX_HASH_KEY]; Hashelement OverFlow; public: Hash::~Hash() { } Hash::Hash(void) { TotalKey=0; OverFlow = _T("OverFlow"); }; Hash::Hash(CString thisName) { TotalKey=0; this->Name=thisName; OverFlow = _T("OverFlow"); }; Hash(const Hash& hash) { *this = hash; OverFlow = _T("OverFlow"); } Hash& operator = (const Hash& hash) { if (this == &hash) { return *this; } Name = hash.Name; TotalKey = hash.TotalKey; for (int i=0; iTotalKey;i++) { delete elements[i].Key; delete elements[i].Value; } TotalKey=0; } Hashelement & Hash::operator [] (const char * str) { CString s1(str); return this->operator [] (s1); }; Hashelement & Hash::operator [] (CString s) { int left = 0; int right = TotalKey - 1; int mid; int index = -1; while (left <= right) { mid = (left + right) / 2; int r = elements[mid].Key->CompareNoCase(s); if (r < 0) {//keyÔÚÓÒ±ß left = mid + 1; } else if (r > 0) {//keyÔÚ×ó±ß right = mid - 1; } else { index = mid; break; } } if (index == -1 && TotalKey < MAX_HASH_KEY) { index = left; for (int i = TotalKey; i > index; --i) { elements[i].Key = elements[i-1].Key; elements[i].Value = elements[i-1].Value; } elements[index].Key = new CString(s); elements[index].Value = new CString(s); TotalKey++; } if (index==-1) { return OverFlow; } return elements[index]; }; Hashelement & Hash::operator [] (int k) { return elements[k]; }; template int inline SetVarList(T(&pCfgs)[N]) { return SetVarList(pCfgs, N); } int SetVarList(stCfgValCtrl *pCfgs, int nCount) { for (int i = 0; i < nCount; i++) { int vtype = pCfgs[i].vType; void * pvar = pCfgs[i].var; int nCtrlId = pCfgs[i].nCtrlId; if (pvar==nullptr) continue; switch (vtype) { case vtbool: case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break; default: break; } } return nCount; } int SetCtrl(const char * str, CWnd * pWnd, int nCtrlId, int nCtrlType) { CString s1(str); return SetCtrl(s1, pWnd, nCtrlId,nCtrlType); } int SetCtrl(CString str, CWnd * pWnd, int nCtrlId, int nCtrlType) { if (nCtrlId == 0) return 0; CWnd * pCtrl = pWnd->GetDlgItem(nCtrlId); if (pCtrl == nullptr) return -1; switch (nCtrlType) { case ctEdit: pWnd->SetDlgItemText(nCtrlId, this->operator [] (str)); break; case ctCheckBox: ((CButton *)pCtrl)->SetCheck(this->operator [] (str)); break; case ctComboBoxIndex: ((CComboBox*)pCtrl)->SetCurSel(this->operator [] (str)); break; case ctComboBoxString: ((CComboBox*)pCtrl)->SelectString(0,this->operator [] (str)); pWnd->SetDlgItemText(nCtrlId, this->operator [] (str)); break; default: break; } return 0; } template int inline SetCtrlList(CWnd * pWnd, T (&pCfgs)[N]) { return SetCtrlList(pWnd, pCfgs, N); } int SetCtrlList(CWnd * pWnd, stCfgValCtrl * pCfgs, int nCount) { for (int i = 0; i < nCount; i++) { int vtype = pCfgs[i].vType; void * pvar = pCfgs[i].var; int nCtrlId = pCfgs[i].nCtrlId; int nCtrlType = pCfgs[i].cType; SetCtrl(pCfgs[i].sKeyName, pWnd, nCtrlId,nCtrlType); if (pvar == nullptr) continue; switch (vtype) { case vtbool: case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break; default: break; } } return nCount; } template int inline GetCtrlList(CWnd * pWnd, T(&pCfgs)[N]) { return GetCtrlList(pWnd, pCfgs, N); } int GetCtrl(const char * str, CWnd * pWnd, int nCtrlId, int nCtrlType) { CString s1(str); return GetCtrl(s1, pWnd, nCtrlId, nCtrlType); } int GetCtrl(CString str, CWnd * pWnd, int nCtrlId, int nCtrlType) { if (nCtrlId == 0) return 0; CString s1; CWnd * pCtrl = pWnd->GetDlgItem(nCtrlId); if (pCtrl == nullptr) return -1; switch (nCtrlType) { case ctEdit: pWnd->GetDlgItemText(nCtrlId, s1); this->operator [] (str) = s1; break; case ctCheckBox: this->operator [] (str) = ((CButton *)pCtrl)->GetCheck(); break; case ctComboBoxIndex: this->operator [] (str)=((CComboBox *)pCtrl)->GetCurSel(); break; case ctComboBoxString: pWnd->GetDlgItemText(nCtrlId, s1); this->operator [] (str) = s1; break; default: break; } return 0; } int GetCtrlList(CWnd * pWnd, stCfgValCtrl * pCfgs, int nCount) { for (int i = 0; i < nCount; i++) { int vtype = pCfgs[i].vType; void * pvar = pCfgs[i].var; int nCtrlId = pCfgs[i].nCtrlId; int nCtrlType = pCfgs[i].cType; GetCtrl(pCfgs[i].sKeyName, pWnd, nCtrlId,nCtrlType); if (pvar == nullptr) continue; switch (vtype) { case vtbool: case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break; case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break; default: break; } } return nCount; } int Hash::SaveToFile(CString FilePathName,CString Section) { int i; CString Key,Value; CString CurrentDirectory; for (i=0;i")); Value.Replace(_T("\r"),_T("")); Value.Replace(_T("\n"),_T("")); WritePrivateProfileString(Section,Key,Value,FilePathName); } return 1; }; int Hash::LoadFromFile(CString FilePathName,CString Section) { CString Key; CString value,value1,value2; CString Defaultstr; Defaultstr=_T(""); int k,l; CString s1,s2,s3; k=GetPrivateProfileString(NULL,NULL,Defaultstr,value1.GetBuffer(40960),40960,FilePathName); value1.ReleaseBuffer(k); TCHAR * p2; int n1,n2,n3; n3=GetPrivateProfileString(Section,NULL,Defaultstr,value2.GetBuffer(40960),40960,FilePathName); for (n1=0;n1"),_T("\r\n")); value.Replace(_T(""),_T("\r")); value.Replace(_T(""),_T("\n")); this->operator [](Key)=value; n1+=n2; } return 1; }; }; class MHashelement { public: int HashValue; CString SegmentName; Hash * Segment; MHashelement() { HashValue = 0; SegmentName = _T(""); Segment = NULL; } ~MHashelement() { delete Segment; Segment = NULL; } MHashelement(const MHashelement& elem) { *this = elem; } MHashelement& operator = (const MHashelement& elem) { if (this == &elem) { return *this; } HashValue = elem.HashValue; SegmentName = elem.SegmentName; delete Segment; Segment = new Hash(*(elem.Segment)); return *this; }; }; class MHash { public: int TotalSegment; MHashelement elements[MAX_MHASH_SEGMENT]; Hash OverFlow; ~MHash() { }; MHash(void) { TotalSegment=0; OverFlow = Hash(_T("OverFlow")); }; MHash(const MHash& mhash) { *this = mhash; OverFlow = Hash(_T("OverFlow")); } MHash& operator = (const MHash& mhash) { if (this == &mhash) { return *this; } TotalSegment=mhash.TotalSegment; for (int i=0;ioperator [] (s1); }; Hash & operator [] (CString s) { int left = 0; int right = TotalSegment - 1; int mid; int index = -1; while (left <= right) { mid = (left + right) / 2; int r = elements[mid].SegmentName.CompareNoCase(s); if (r < 0) {//keyÔÚÓÒ±ß left = mid + 1; } else if (r > 0) {//keyÔÚ×ó±ß right = mid - 1; } else { index = mid; break; } } if (index == -1 && TotalSegment < MAX_MHASH_SEGMENT) { index = left; for (int i = TotalSegment; i > index; --i) { elements[i].Segment = elements[i-1].Segment; elements[i].SegmentName = elements[i-1].SegmentName; } elements[index].Segment= new Hash(s); elements[index].SegmentName = s; TotalSegment++; } if (index==-1) { return OverFlow; } return *(elements[index].Segment); }; Hash & operator [] (int k) { return *(elements[k].Segment); }; int SaveToFileOld(CString FilePathName) { int i,j; CString Section; CString Key,Value; CString CurrentDirectory; for (i=0;ioperator [](i).TotalKey;j++) { Key=*(this->operator [](i).elements[j].Key) ; Value=*(this->operator [](i).elements[j].Value); Value.Replace(_T("\r\n"),_T("")); Value.Replace(_T("\r"),_T("")); Value.Replace(_T("\n"),_T("")); WritePrivateProfileString(Section,Key,Value,FilePathName); } } return 1; }; int LoadFromFileOld(CString FilePathName) { CString Key; CString Value,value1,value2; CString Section; CString Defaultstr; Defaultstr=_T(""); this->Empty(); int i,j,k,l; CString s1,s2,s3; k=GetPrivateProfileString(NULL,NULL,Defaultstr,value1.GetBuffer(40960),40960,FilePathName); value1.ReleaseBuffer(k); TCHAR * p1; TCHAR * p2; int n1,n2,n3; for (i=0;i"),_T("\r\n")); Value.Replace(_T(""),_T("\r")); Value.Replace(_T(""),_T("\n")); this->operator [](Section)[Key]=Value; n1+=n2; } i+=j; } return k; }; int SaveToFile(CString FilePathName) { std::string filename = CString2String(FilePathName); std::ofstream ofs(filename); if (!ofs.is_open()) { std::cerr << "Save MHash error, open file" << filename << " fail." << std::endl; return -1; } int i,j; CString Section; CString Key,Value; for (i=0;ioperator [](i).TotalKey;j++) { Key=*(this->operator [](i).elements[j].Key) ; Value=*(this->operator [](i).elements[j].Value); Value.Replace(_T("\r\n"),_T("")); Value.Replace(_T("\r"),_T("")); Value.Replace(_T("\n"),_T("")); ofs << CString2String(Key) << "=" << CString2String(Value) << std::endl; } } ofs.close(); return 1; }; int LoadFromFile(CString FilePathName) { this->Empty(); std::string filename = CString2String(FilePathName); std::ifstream ifs(filename); if(!ifs.is_open()) { std::cerr << "Load MHash error, open file" << filename << " fail." << std::endl; return -1; } std::string segment; std::string line; size_t line_count=0; while (std::getline(ifs, line)) { //to skip BOM if (line_count++ == 0 && line.size() > 3) { if (static_cast(line[0]) == 0xEF && static_cast(line[1]) == 0xBB && static_cast(line[2]) == 0xBF) { for (int i = 0; i < 3; i++) { line.erase(line.begin()); } } } if (line[0] == '#' || line[0] == ';') continue; line = trim(line); if (line.empty()) continue; if (line[0] == '[') { segment = trim(line.substr(1,line.length()-2)); } else if(segment.length()>0) { size_t n = line.find('='); if (n == std::string::npos) continue; std::string k = line.substr(0,n); std::string v = trim(line.substr(n+1, line.length()-n-1)); CString Value = String2CString(v); Value.Replace(_T(""),_T("\r\n")); Value.Replace(_T(""),_T("\r")); Value.Replace(_T(""),_T("\n")); this->operator [](segment.c_str())[k.c_str()] = Value; } } ifs.close(); return TotalSegment; } }; typedef void DiffCallBack(const CString& section, const CString& key, const CString oldValue, const CString newValue); //±È½ÏÁ½¸öHashµÄÇø±ð,µÚ¶þ¸ö¿ÉÄÜÔÚµÚÒ»¸öµÄ»ù´¡ÉÏÓбä¸ü inline void HashDiff(Hash& h1, Hash& h2, DiffCallBack callback) { CString s1; for (int i=0; i256 || value2.GetLength()>256) { continue; } if (0!=value1.CompareNoCase(value2)) { callback(h2.Name, key, value1, value2); } } } //±È½ÏÁ½¸öMHashµÄÇø±ð,µÚ¶þ¸ö¿ÉÄÜÔÚµÚÒ»¸öµÄ»ù´¡ÉÏÓбä¸ü inline void MHashDiff(MHash& mh1, MHash& mh2, DiffCallBack callback) { for (int i=0; i