//+------------------------------------------------------------------+ //| Dictionary.mqh | //| Enrico Lambino | //| https://www.mql5.com/en/users/iceron | //+------------------------------------------------------------------+ #property copyright "Enrico Lambino." #property link "https://www.mql5.com/en/users/iceron" #include #include //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CDictionaryEntryBase : public CObject { protected: string m_key; public: CDictionaryEntryBase(string key); ~CDictionaryEntryBase(); void Key(const string key); string Key(void) const; virtual string TypeName(void) const; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CDictionaryEntryBase::CDictionaryEntryBase(string key) : m_key(key) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CDictionaryEntryBase::~CDictionaryEntryBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CDictionaryEntryBase::Key(const string key) { m_key=key; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CDictionaryEntryBase::Key(void) const { return m_key; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CDictionaryEntryBase::TypeName(void) const { return NULL; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template class CDictionaryEntry : public CDictionaryEntryBase { protected: T m_value; public: CDictionaryEntry(string key,T value); ~CDictionaryEntry(void); virtual int Compare(const CObject *node,const int mode=0) const; virtual string TypeName(void) const; bool Value(string key,T value); T Value(string key); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template CDictionaryEntry::CDictionaryEntry(string key,T value) : CDictionaryEntryBase(key) { m_value=value; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template CDictionaryEntry::~CDictionaryEntry(void) { CObject *object=dynamic_cast(m_value); if(CheckPointer(object)==POINTER_DYNAMIC) delete object; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template int CDictionaryEntry::Compare(const CObject *node,const int mode=0) const { const CDictionaryEntryBase *node_entry=node; string str1 = Key()+TypeName(); string str2 = node_entry.Key()+node_entry.TypeName(); return StringCompare(str1,str2); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template string CDictionaryEntry::TypeName(void) const { return typename(T); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictionaryEntry::Value(string key,T value) { CObject *m_object=dynamic_cast(m_value); if(CheckPointer(m_object)==POINTER_DYNAMIC) { CObject *object=dynamic_cast(value); if(CheckPointer(object) && m_object!=object) { delete m_object; m_object=object; } } else m_value=value; return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template T CDictionaryEntry::Value(string key) { return m_value; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CDictionary : public CArrayObj { protected: int m_initial_capacity; double m_resize_threshold; int m_multiplier; public: CDictionary(int initial_capacity=500,double resize_threshold=0.6,int multiplier=3); ~CDictionary(void); bool Add(CDictionaryEntryBase *entry); template bool Contains(string key); template bool Delete(string key); template T Get(string key); template bool Get(string key,T &value); bool Reset(); template bool Set(string key,T value); protected: bool Allocate(void); uint Hash(string str); int Index(uint key); bool Recalculate(); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CDictionary::CDictionary(int initial_capacity=500,double resize_threshold=0.6,int multiplier=3) : m_initial_capacity(initial_capacity), m_resize_threshold(resize_threshold), m_multiplier(multiplier) { Reset(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CDictionary::~CDictionary(void) { if(m_free_mode) for(int i=0;i=0) { list.Sort(0); m_data_total++; return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDictionary::Allocate(void) { if(m_data_total>m_data_max*m_resize_threshold) { int new_size= ArrayResize(m_data,m_data_max*m_multiplier); if(new_size!=m_data_max*m_multiplier) return false; m_data_max=new_size; return Recalculate(); } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictionary::Contains(string key) { bool res=false; T value=NULL; int index=Index(Hash(key+typename(T))); CList *list=m_data[index]; if(CheckPointer(list)) { CDictionaryEntryBase *model=new CDictionaryEntry(key,value); if(CheckPointer(list.Search(model))) res=true; delete model; } return res; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictionary::Delete(string key) { bool res=false; T value=NULL; int index=Index(Hash(key+typename(T))); CList *list=m_data[index]; if(CheckPointer(list)) { CDictionaryEntryBase *model=new CDictionaryEntry(key,value); CDictionaryEntryBase *result=list.Search(model); if(CheckPointer(result)) { list.Delete(list.IndexOf(result)); res=true; } delete model; } return res; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictionary::Get(string key,T &value) { bool res=false; int index=Index(Hash(key+typename(T))); CList *list=m_data[index]; if(CheckPointer(list)) { CDictionaryEntryBase *model=new CDictionaryEntry(key,value); CDictionaryEntryBase *result=list.Search(model); if(CheckPointer(result)) { CDictionaryEntry*model_entry=result; value=model_entry.Value(key); res=true; } delete model; } return res; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template T CDictionary::Get(string key) { T value; Get(key,value); return value; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ uint CDictionary::Hash(string str) { uint fnv_prime=16777619; uint offset_basis=2166136261; uint hash=offset_basis; uchar arr[]; StringToCharArray(str,arr); uint len=StringLen(str); for(uint n=0; n=0) { list2.Sort(0); m_data_total++; } } } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDictionary::Reset(void) { if(m_data_total>0) for(int i=0;i bool CDictionary::Set(string key,T value) { if(Allocate()) { int index=Index(Hash(key+typename(T))); CDictionaryEntryBase *model=new CDictionaryEntry(key,value); CList *list=m_data[index]; if(CheckPointer(list)) { CDictionaryEntryBase *result=list.Search(model); if(CheckPointer(result)) { if (list.Delete(list.IndexOf(result))) m_data_total--; else { delete model; return false; } } if(list.Add(model)>=0) { list.Sort(0); m_data_total++; return true; } } else { list=new CList(); m_data[index]=list; if(list.Add(model)>=0) { list.Sort(0); m_data_total++; } return true; } } return false; } //+------------------------------------------------------------------+