//+------------------------------------------------------------------+ //| 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 MQLARTICLES_UTILS_DICT_DICTT_MQH #define MQLARTICLES_UTILS_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 { uint hash_code; string key; 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, const TValue val); bool Set(const uchar& text[], const int start, const int end, const TValue val); // Add bool Add(const string& key, const TValue val); bool Add(const uchar& text[], const int start, const int end, const 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; //--- 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 = m_buckets[i].slots[j].hash_code % 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, const TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) 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) { // 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, const TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) Resize(); //--- uint hash; CDICT_HASH_U(text, start, end, 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 && Iguales(text, start, end, m_buckets[idx].slots[i].key)) { // 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, const TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) 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) { // 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, const TValue val) { //--- Check if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO) Resize(); //--- uint hash; CDICT_HASH_U(text, start, end, 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 && Iguales(text, start, end, m_buckets[idx].slots[i].key)) { // Existe m_buckets[idx].slots[i].val = val; return true; } } //--- return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::TryGet(const string& key, TValue& 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; } //+------------------------------------------------------------------+ template bool CDictSValue::TryGet(const uchar& text[], const int start, const int end, TValue& val) const { //--- uint hash; CDICT_HASH_U(text, start, end, 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 && Iguales(text, start, end, m_buckets[idx].slots[i].key)) { val = m_buckets[idx].slots[i].val; return true; } } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::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; } //+------------------------------------------------------------------+ template bool CDictSValue::Contains(const uchar& text[], const int start, const int end) const { //--- uint hash; CDICT_HASH_U(text, start, end, 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 && Iguales(text, start, end, m_buckets[idx].slots[i].key)) return true; return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CDictSValue::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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template void CDictSValue::Clear() { for(int i = 0; i < m_buckets_size; i++) m_buckets[i].size = 0; m_count = 0; } //+------------------------------------------------------------------+ #endif // MQLARTICLES_UTILS_DICT_DICTT_MQH