FastCollections-FastHashMap/Src/ColHash/Dict/DictT.mqh

520 lines
14 KiB
MQL5
Raw Permalink Normal View History

2026-07-19 08:34:18 -05:00
//+------------------------------------------------------------------+
//| DictT.mqh |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza."
#property link "https://www.mql5.com/"
#property strict
2026-07-21 11:09:28 -05:00
#ifndef FASTCOLLECTIONSBYLEO_COLHASH_DICT_DICTT_MQH
#define FASTCOLLECTIONSBYLEO_COLHASH_DICT_DICTT_MQH
2026-07-19 08:34:18 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#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
{
string key;
ulong hash_code;
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, TValue val);
bool Set(const uchar& text[], const int start, const int end, TValue val);
// Add
bool Add(const string& key, TValue val);
bool Add(const uchar& text[], const int start, const int end, 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;
// Get
int GetValues(TValue& out[], string& keys[]) const;
int GetKeys(string& keys[]) 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 = uint(m_buckets[i].slots[j].hash_code % (ulong)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, TValue val)
{
//--- Check
if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO)
Resize();
//---
ulong hash = FNV_OFFSET_BASIS;
const int len = StringLen(key);
FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
{
// 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, TValue val)
{
//--- Check
if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO)
Resize();
//---
ulong hash = FNV_OFFSET_BASIS;
FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
{
// 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, TValue val)
{
//--- Check
if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO)
Resize();
//---
ulong hash = FNV_OFFSET_BASIS;
const int len = StringLen(key);
FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
{
// 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, TValue val)
{
//--- Check
if(m_count > 0 && float(m_count) / float(m_buckets_size) > MQLARTICLES_DICT_FACTOR_CRECIMIENTO)
Resize();
//---
ulong hash = FNV_OFFSET_BASIS;
FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
{
// Existe
m_buckets[idx].slots[i].val = val;
return true;
}
}
//---
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TValue>
bool CDictSValue::TryGet(const string& key, TValue& val) const
{
//---
ulong hash = FNV_OFFSET_BASIS;
const int len = StringLen(key);
FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
{
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
{
//---
ulong hash = FNV_OFFSET_BASIS;
FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
{
val = m_buckets[idx].slots[i].val;
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TValue>
bool CDictSValue::Contains(const string& key) const
{
//---
ulong hash = FNV_OFFSET_BASIS;
const int len = StringLen(key);
FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
return true;
return false;
}
//+------------------------------------------------------------------+
template <typename TValue>
bool CDictSValue::Contains(const uchar& text[], const int start, const int end) const
{
//---
ulong hash = FNV_OFFSET_BASIS;
FNV1a_64_AsM_U_range(text, start, end, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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)
return true;
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TValue>
bool CDictSValue::Remove(const string& key)
{
//---
ulong hash = FNV_OFFSET_BASIS;
const int len = StringLen(key);
FNV1a_64_AsM_Str(key, len, hash, FNV_PRIME)
//---
const uint idx = uint(hash % (ulong)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] = 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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TValue>
int CDictSValue::GetValues(TValue& out[], string& keys[]) const
{
//---
int r = ArrayResize(out, m_buckets_size);
ArrayResize(keys, r);
int f = 0;
//---
for(int i = 0; i < m_buckets_size; i++)
{
if(m_buckets[i].size > 0)
{
for(int k = 0; k < m_buckets[i].size; k++)
{
out[f] = m_buckets[i].slots[k].val;
keys[f++] = m_buckets[i].slots[k].key;
if(f >= r)
{
r <<= 1;
ArrayResize(out, r, r);
}
}
}
}
//---
ArrayResize(keys, f);
return ArrayResize(out, f);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TValue>
int CDictSValue::GetKeys(string& keys[]) const
{
//---
int r = ArrayResize(keys, m_buckets_size);
ArrayResize(keys, r);
int f = 0;
//---
for(int i = 0; i < m_buckets_size; i++)
{
if(m_buckets[i].size > 0)
{
for(int k = 0; k < m_buckets[i].size; k++)
{
keys[f++] = m_buckets[i].slots[k].key;
if(f >= r)
{
r <<= 1;
ArrayResize(keys, r, r);
}
}
}
}
//---
return ArrayResize(keys, f);
}
//+------------------------------------------------------------------+
2026-07-21 11:09:28 -05:00
#endif // FASTCOLLECTIONSBYLEO_COLHASH_DICT_DICTT_MQH