434 lines
12 KiB
MQL5
434 lines
12 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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 <typename TValue>
|
|
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
|