//+------------------------------------------------------------------+ //| DictT.mqh | //| Copyright 2026, Niquel Mendoza. | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza." #property link "https://www.mql5.com/" #property strict #ifndef FASTCOLLECTIONSBYLEO_COLHASH_DICT_DICTT_MQH #define FASTCOLLECTIONSBYLEO_COLHASH_DICT_DICTT_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "Defines.mqh" //+------------------------------------------------------------------+ //| Clase CDictSValue | //+------------------------------------------------------------------+ // Dict (string)->(TValue) + metodos template class CDictSValue { private: //--- Lo definimos aqui para compatiblidad con otras clases como el hashmap struct DictSlot { string key; ulong hash_code; TValue val; }; struct DictBucket { DictSlot slots[MQLARTICLES_DICT_SLOT_SIZE]; int size; }; //--- DictBucket m_buckets[]; int m_buckets_size; int m_count; //--- void Resize(); void Asignar(string& v, const uchar& text[], const int start, const int end); bool Iguales(const uchar& val[], const int start, const int end, const string& val2) const; public: CDictSValue(void) { Init(64, 4); } ~CDictSValue(void) {} //--- Init void Init(int buckets_size, int slots_reserve); //--- Metodos // Set bool Set(const string& key, TValue val); bool Set(const uchar& text[], const int start, const int end, TValue val); // Add bool Add(const string& key, TValue val); bool Add(const uchar& text[], const int start, const int end, TValue val); // Try get bool TryGet(const string& key, TValue& val) const; bool TryGet(const uchar& text[], const int start, const int end, TValue& val) const; // Get int GetValues(TValue& out[], string& keys[]) const; int GetKeys(string& keys[]) const; //--- Utils bool Contains(const string& key) const; bool Contains(const uchar& text[], const int start, const int end) const; bool Remove(const string& key); void Clear(); __forceinline int Count() const { return m_count; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template void CDictSValue::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; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template void CDictSValue::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; } //--- 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 = uint(m_buckets[i].slots[j].hash_code % (ulong)new_size); new_buckets[idx].slots[new_buckets[idx].size++] = m_buckets[i].slots[j]; } } //--- ArraySwap(m_buckets, new_buckets); m_buckets_size = new_size; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::Iguales(const uchar& val[], const int start, const int end, const string& val2) const { const int len = StringLen(val2); const int l = (end - start) + 1; if(len != l) return false; for(int i = 0; i < len; i++) { if(val[start + i] != val2[i]) return false; } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template void CDictSValue::Asignar(string& v, const uchar& text[], const int start, const int end) { const int l = (end - start) + 1; StringSetLength(v, l); for(int i = 0; i < l; i++) { v.SetChar(i, text[start + i]); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // Notas: // - En caso no exista lo crea // - En caso se supera el factor de crecimiento 75% entonces resize al doble template bool CDictSValue::Add(const string& key, TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) Resize(); //--- ulong hash = FNV_OFFSET_BASIS; const int len = StringLen(key); FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) { // Existe return false; } } //--- if(m_buckets[idx].size + 1 >= MQLARTICLES_DICT_SLOT_SIZE) { Resize(); return false; } //--- 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 CDictSValue::Add(const uchar& text[], const int start, const int end, TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) Resize(); //--- ulong hash = FNV_OFFSET_BASIS; FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) { // Existe return false; } } //--- if(m_buckets[idx].size + 1 >= MQLARTICLES_DICT_SLOT_SIZE) { Resize(); return false; } //--- m_buckets[idx].slots[m_buckets[idx].size].hash_code = hash; Asignar(m_buckets[idx].slots[m_buckets[idx].size].key, text, start, end); m_buckets[idx].slots[m_buckets[idx].size].val = val; m_buckets[idx].size++; m_count++; return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::Set(const string& key, TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) Resize(); //--- ulong hash = FNV_OFFSET_BASIS; const int len = StringLen(key); FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) { // Existe m_buckets[idx].slots[i].val = val; return true; } } //--- return false; } //+------------------------------------------------------------------+ template bool CDictSValue::Set(const uchar& text[], const int start, const int end, TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) Resize(); //--- ulong hash = FNV_OFFSET_BASIS; FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) { // Existe m_buckets[idx].slots[i].val = val; return true; } } //--- return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::TryGet(const string& key, TValue& val) const { //--- ulong hash = FNV_OFFSET_BASIS; const int len = StringLen(key); FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) { val = m_buckets[idx].slots[i].val; return true; } } return false; } //+------------------------------------------------------------------+ template bool CDictSValue::TryGet(const uchar& text[], const int start, const int end, TValue& val) const { //--- ulong hash = FNV_OFFSET_BASIS; FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) { val = m_buckets[idx].slots[i].val; return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::Contains(const string& key) const { //--- ulong hash = FNV_OFFSET_BASIS; const int len = StringLen(key); FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) return true; return false; } //+------------------------------------------------------------------+ template bool CDictSValue::Contains(const uchar& text[], const int start, const int end) const { //--- ulong hash = FNV_OFFSET_BASIS; FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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) return true; return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::Remove(const string& key) { //--- ulong hash = FNV_OFFSET_BASIS; const int len = StringLen(key); FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME) //--- const uint idx = uint(hash % (ulong)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] = m_buckets[idx].slots[--m_buckets[idx].size]; m_count--; return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template void CDictSValue::Clear() { for(int i = 0; i < m_buckets_size; i++) m_buckets[i].size = 0; m_count = 0; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template int CDictSValue::GetValues(TValue& out[], string& keys[]) const { //--- int r = ArrayResize(out, m_buckets_size); ArrayResize(keys, r); int f = 0; //--- for(int i = 0; i < m_buckets_size; i++) { if(m_buckets[i].size > 0) { for(int k = 0; k < m_buckets[i].size; k++) { out[f] = m_buckets[i].slots[k].val; keys[f++] = m_buckets[i].slots[k].key; if(f >= r) { r <<= 1; ArrayResize(out, r, r); } } } } //--- ArrayResize(keys, f); return ArrayResize(out, f); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template int CDictSValue::GetKeys(string& keys[]) const { //--- int r = ArrayResize(keys, m_buckets_size); ArrayResize(keys, r); int f = 0; //--- for(int i = 0; i < m_buckets_size; i++) { if(m_buckets[i].size > 0) { for(int k = 0; k < m_buckets[i].size; k++) { keys[f++] = m_buckets[i].slots[k].key; if(f >= r) { r <<= 1; ArrayResize(keys, r, r); } } } } //--- return ArrayResize(keys, f); } //+------------------------------------------------------------------+ #endif // FASTCOLLECTIONSBYLEO_COLHASH_DICT_DICTT_MQH