2026-04-09 15:05:49 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| 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
|
2026-04-09 21:48:03 -05:00 | | | void SetStr(const string& key, const string& val);
|
2026-04-09 15:05:49 -05:00 | | | template<typename TValue>
|
| | | void Set(const string& key, TValue val);
|
| | |
|
2026-04-09 15:46:22 -05:00 | | | //--- SetV (la diferencia es que retorna true\util si se desea usar en vairalbes globales)
|
2026-04-09 21:48:03 -05:00 | | | bool SetStrV(const string& key, const string& val);
|
2026-04-09 15:46:22 -05:00 | | | template<typename TValue>
|
| | | bool SetV(const string& key, TValue val);
|
| | |
|
| | |
|
2026-04-09 15:05:49 -05:00 | | | //--- Get
|
| | | bool TryGetStr(const string& key, string& val) const;
|
| | | bool TryGetBool(const string& key, bool& val) const;
|
| | | template<typename TValue>
|
| | | 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
|
2026-04-09 21:48:03 -05:00 | | | void CDict::SetStr(const string& key, const string& val)
|
2026-04-09 15:05:49 -05:00 | | | {
|
| | | //--- 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<typename TValue>
|
| | | void CDict::Set(const string& key, TValue val)
|
| | | {
|
| | | static string temp;
|
| | | temp = string(val);
|
2026-04-09 21:48:03 -05:00 | | | SetStr(key, temp);
|
2026-04-09 15:05:49 -05:00 | | | }
|
| | |
|
| | |
|
2026-04-09 15:46:22 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // Notas:
|
| | | // - En caso no exista lo crea
|
| | | // - En caso se supera el factor de crecimiento 75% entonces resize al doble
|
2026-04-09 21:48:03 -05:00 | | | bool CDict::SetStrV(const string& key, const string& val)
|
2026-04-09 15:46:22 -05:00 | | | {
|
| | | //--- 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<typename TValue>
|
| | | bool CDict::SetV(const string& key, TValue val)
|
| | | {
|
| | | static string temp;
|
| | | temp = string(val);
|
2026-04-09 21:48:03 -05:00 | | | return SetStrV(key, temp);
|
2026-04-09 15:46:22 -05:00 | | | }
|
| | |
|
2026-04-09 15:05:49 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | 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<typename TValue>
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
2026-04-09 15:46:22 -05:00 | | | #endif // MQLARTICLES_UTILS_DICT_MAIN_MQH
|