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
|