forked from nique_372/MQLArticles
338 lines
10 KiB
MQL5
338 lines
10 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| 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
| |
void SetStr(const string& key, const string& val);
| |
template<typename TValue>
| |
void Set(const string& key, TValue val);
| |
| |
//--- SetV (la diferencia es que retorna true\util si se desea usar en vairalbes globales)
| |
bool SetStrV(const string& key, const string& val);
| |
template<typename TValue>
| |
bool SetV(const string& key, TValue val);
| |
| |
| |
//--- 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
| |
void CDict::SetStr(const string& key, const string& val)
| |
{
| |
//--- 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);
| |
SetStr(key, temp);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
// Notas:
| |
// - En caso no exista lo crea
| |
// - En caso se supera el factor de crecimiento 75% entonces resize al doble
| |
bool CDict::SetStrV(const string& key, const string& val)
| |
{
| |
//--- 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);
| |
return SetStrV(key, temp);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
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;
| |
}
| |
//+------------------------------------------------------------------+
| |
#endif // MQLARTICLES_UTILS_DICT_MAIN_MQH
|