//+------------------------------------------------------------------+ //| Main.mqh | //| Copyright 2026,Niquel Mendoza. | //| https://www.mql5.com/en/users/nique_372 | //+------------------------------------------------------------------+ #property copyright "Copyright 2026,Niquel Mendoza." #property link "https://www.mql5.com/en/users/nique_372" #property strict #ifndef MQLARTICLES_UTILS_DICT_MAIN_MQH #define MQLARTICLES_UTILS_DICT_MAIN_MQH //+------------------------------------------------------------------+ //| Funciones hash base | //+------------------------------------------------------------------+ #ifndef CDICT_HASH #define CDICT_HASH(key, hash) \ const int _len = StringLen(key); \ hash = 2166136261; \ for(int _i = 0; _i < _len; _i++) \ { \ hash ^= (uint)key[_i]; \ hash *= 16777619; \ } #endif // CDICT_HASH, se da la posiblidad de definir un hash custom //+------------------------------------------------------------------+ //| Clase CDict | //+------------------------------------------------------------------+ // Esta clase implementa un dict donde el val peude ser cualquier cosa (menos structs\unions\clases) // SImple y rapida class CDict { private: //--- Lo definimos aqui para compatiblidad con otras clases como el hashmap struct DictSlot { uint hash_code; string key; string val; }; struct DictBucket { DictSlot slots[]; int size; int reserve; }; //--- DictBucket m_buckets[]; int m_buckets_size; int m_count; //--- void Resize(); public: CDict(void) { Init(64, 4); } ~CDict(void) {} //--- Init void Init(int buckets_size, int slots_reserve); //--- Set void SetStr(const string& key, const string& val); template void Set(const string& key, TValue val); //--- SetV (la diferencia es que retorna true\util si se desea usar en vairalbes globales) bool SetStrV(const string& key, const string& val); template bool SetV(const string& key, TValue val); //--- Get bool TryGetStr(const string& key, string& val) const; bool TryGetBool(const string& key, bool& val) const; template bool TryGetAs(const string& key, TValue& val) const; //--- Utils bool Contains(const string& key) const; bool Remove(const string& key); void Clear(); __forceinline int Count() const { return m_count; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CDict::Init(int buckets_size, int slots_reserve) { m_buckets_size = fmax(buckets_size, 32); slots_reserve = fmax(slots_reserve, 4); m_count = 0; ArrayResize(m_buckets, m_buckets_size); for(int i = 0; i < m_buckets_size; i++) { m_buckets[i].size = 0; m_buckets[i].reserve = slots_reserve; ArrayResize(m_buckets[i].slots, slots_reserve); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CDict::Resize() { const int new_size = m_buckets_size << 1; DictBucket new_buckets[]; ArrayResize(new_buckets, new_size); for(int i = 0; i < new_size; i++) { new_buckets[i].size = 0; new_buckets[i].reserve = 4; ArrayResize(new_buckets[i].slots, 4); } for(int i = 0; i < m_buckets_size; i++) { const int t = m_buckets[i].size; for(int j = 0; j < t; j++) { const uint idx = m_buckets[i].slots[j].hash_code % new_size; if(new_buckets[idx].size + 1 >= new_buckets[idx].reserve) { new_buckets[idx].reserve <<= 1; ArrayResize(new_buckets[idx].slots, new_buckets[idx].reserve); } new_buckets[idx].slots[new_buckets[idx].size++] = m_buckets[i].slots[j]; } } ArraySwap(m_buckets, new_buckets); m_buckets_size = new_size; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // Notas: // - En caso no exista lo crea // - En caso se supera el factor de crecimiento 75% entonces resize al doble void CDict::SetStr(const string& key, const string& val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > 0.75f) Resize(); //--- uint hash; CDICT_HASH(key, hash) //--- const uint idx = hash % m_buckets_size; const int t = m_buckets[idx].size; //--- for(int i = 0; i < t; i++) { if(m_buckets[idx].slots[i].hash_code == hash && m_buckets[idx].slots[i].key == key) { m_buckets[idx].slots[i].val = val; return; } } //--- if(m_buckets[idx].size + 1 >= m_buckets[idx].reserve) { m_buckets[idx].reserve <<= 1; ArrayResize(m_buckets[idx].slots, m_buckets[idx].reserve); } //--- m_buckets[idx].slots[m_buckets[idx].size].hash_code = hash; m_buckets[idx].slots[m_buckets[idx].size].key = key; m_buckets[idx].slots[m_buckets[idx].size].val = val; m_buckets[idx].size++; m_count++; } //+------------------------------------------------------------------+ template void CDict::Set(const string& key, TValue val) { static string temp; temp = string(val); SetStr(key, temp); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // Notas: // - En caso no exista lo crea // - En caso se supera el factor de crecimiento 75% entonces resize al doble bool CDict::SetStrV(const string& key, const string& val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > 0.75f) Resize(); //--- uint hash; CDICT_HASH(key, hash) //--- const uint idx = hash % m_buckets_size; const int t = m_buckets[idx].size; //--- for(int i = 0; i < t; i++) { if(m_buckets[idx].slots[i].hash_code == hash && m_buckets[idx].slots[i].key == key) { m_buckets[idx].slots[i].val = val; return true; } } //--- if(m_buckets[idx].size + 1 >= m_buckets[idx].reserve) { m_buckets[idx].reserve <<= 1; ArrayResize(m_buckets[idx].slots, m_buckets[idx].reserve); } //--- m_buckets[idx].slots[m_buckets[idx].size].hash_code = hash; m_buckets[idx].slots[m_buckets[idx].size].key = key; m_buckets[idx].slots[m_buckets[idx].size].val = val; m_buckets[idx].size++; m_count++; return true; } //+------------------------------------------------------------------+ template bool CDict::SetV(const string& key, TValue val) { static string temp; temp = string(val); return SetStrV(key, temp); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDict::TryGetStr(const string& key, string& val) const { //--- uint hash; CDICT_HASH(key, hash) const uint idx = hash % m_buckets_size; const int t = m_buckets[idx].size; //--- for(int i = 0; i < t; i++) { if(m_buckets[idx].slots[i].hash_code == hash && m_buckets[idx].slots[i].key == key) { val = m_buckets[idx].slots[i].val; return true; } } return false; } //+------------------------------------------------------------------+ bool CDict::TryGetBool(const string& key, bool& val) const { static string raw; if(!TryGetStr(key, raw)) return false; val = (raw == "true" || int(raw) != 0); return true; } //+------------------------------------------------------------------+ template bool CDict::TryGetAs(const string& key, TValue& val) const { static string raw; if(!TryGetStr(key, raw)) return false; val = TValue(raw); return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDict::Contains(const string& key) const { uint hash; CDICT_HASH(key, hash) const uint idx = hash % m_buckets_size; const int t = m_buckets[idx].size; for(int i = 0; i < t; i++) if(m_buckets[idx].slots[i].hash_code == hash && m_buckets[idx].slots[i].key == key) return true; return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDict::Remove(const string& key) { uint hash; CDICT_HASH(key, hash) const uint idx = hash % m_buckets_size; const int t = m_buckets[idx].size; for(int i = 0; i < t; i++) { if(m_buckets[idx].slots[i].hash_code == hash && m_buckets[idx].slots[i].key == key) { m_buckets[idx].slots[i] = m_buckets[idx].slots[--m_buckets[idx].size]; m_count--; return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CDict::Clear() { for(int i = 0; i < m_buckets_size; i++) m_buckets[i].size = 0; m_count = 0; } //+------------------------------------------------------------------+ #endif // MQLARTICLES_UTILS_DICT_MAIN_MQH