MQLArticles/Utils/Dict/Main.mqh

338 Zeilen
10 KiB
MQL5

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