UTE/Strategy/Dictionary.mqh

532 lines
38 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:34:43 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| CDictionary.mqh |
//| Copyright 2015, Vasiliy Sokolov. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link "http://www.mql5.com"
#include <Object.mqh>
#include <Arrays\List.mqh>
//+------------------------------------------------------------------+
//| >=B59=5@ 4;O E@0=5=8O M;5<5=B>2 CObject |
//+------------------------------------------------------------------+
class KeyValuePair : public CObject
{
private:
string m_string_key; // %@0=8B AB@>:>2K9 :;NG.
double m_double_key; // %@0=8B :;NG A ?;020NI59 70?OB>9.
ulong m_ulong_key; // %@0=8B 157=0:>2K9 F5;>G8A;5==K9 :;NG.
ulong m_hash;
bool m_free_mode; // 568< >A2>1>645=8O ?0<OB8 >1J5:B0
public:
CObject *object;
KeyValuePair *next_kvp;
KeyValuePair *prev_kvp;
template<typename T>
KeyValuePair(T key,ulong hash,CObject *obj);
~KeyValuePair();
template<typename T>
bool EqualKey(T key);
template<typename T>
void GetKey(T &gkey);
ulong GetHash(){return m_hash;}
void FreeMode(bool free_mode){m_free_mode=free_mode;}
bool FreeMode(void){return m_free_mode;}
};
//+------------------------------------------------------------------+
//| >=AB@C:B>@ ?> C<>;G0=8N. |
//+------------------------------------------------------------------+
template<typename T>
void KeyValuePair::KeyValuePair(T key,ulong hash,CObject *obj)
{
m_hash=hash;
string name=typename(key);
if(name=="string")
m_string_key=(string)key;
else if(name=="double" || name=="float")
m_double_key=(double)key;
else
m_ulong_key=(ulong)key;
object=obj;
m_free_mode=true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template<typename T>
void KeyValuePair::GetKey(T &gkey)
{
string name=typename(gkey);
if(name=="string")
gkey=(T)m_string_key;
else if(name=="double" || name=="float")
gkey=(T)m_double_key;
else
gkey=(T)m_ulong_key;
}
//+------------------------------------------------------------------+
//| 8AB@C:B>@. |
//+------------------------------------------------------------------+
KeyValuePair::~KeyValuePair()
{
if(m_free_mode)
delete object;
}
//+------------------------------------------------------------------+
//| >72@0I05B 8AB8=C, 5A;8 :;NG8 @02=K. |
//+------------------------------------------------------------------+
template<typename T>
bool KeyValuePair::EqualKey(T key)
{
string name=typename(key);
if(name=="string")
return m_string_key == (string)key;
if(name=="double" || name=="float")
return m_double_key == (double)key;
else
return m_ulong_key == (ulong)key;
}
//+------------------------------------------------------------------+
//| AA>F80B82=K9 <0AA82 8;8 A;>20@L, E@0=OI89 M;5<5=BK 2 2845 |
//| <:;NG - 7=0G5=85>. 45 :;NG>< <>65B O2;OBLAO ;N1>9 107>2K9 B8?, |
//| 0 7=0G5=85< - >1J5:B B8?0 CObject. |
//+------------------------------------------------------------------+
class CDictionary : public CObject
{
private:
int m_array_size;
int m_total;
bool m_free_mode;
bool m_auto_free;
int m_index;
ulong m_hash;
CList *m_array[];
union casting_struct
{
double d_value;
ulong l_value;
}casting;
KeyValuePair *m_first_kvp;
KeyValuePair *m_current_kvp;
KeyValuePair *m_last_kvp;
ulong Adler32(string line);
int GetIndexByHash(ulong hash);
template<typename T>
ulong GetHashByKey(T key);
void Resize();
int FindNextSimpleNumber(int number);
int FindNextLevel();
void Init(int capacity);
public:
CDictionary();
CDictionary(int capacity);
~CDictionary();
void Compress(void);
///
/// Returns the total number of items.
///
int Total(void){return m_total;}
/// Returns the element at key<EFBFBD><EFBFBD><EFBFBD>
template<typename T>
CObject *GetObjectByKey(T key);
template<typename T>
bool AddObject(T key,CObject *value);
template<typename T>
bool DeleteObjectByKey(T key);
template<typename T>
bool ContainsKey(T key);
template<typename T>
void GetCurrentKey(T &key);
bool DeleteCurrentNode(void);
bool FreeMode(void) { return(m_free_mode); }
void FreeMode(bool free_mode);
void AutoFreeMemory(bool autoFree){m_auto_free=autoFree;}
void Clear();
CObject *GetNextNode(void);
CObject *GetPrevNode(void);
CObject *GetCurrentNode(void);
CObject *GetFirstNode(void);
CObject *GetLastNode(void);
};
//+------------------------------------------------------------------+
//| >=AB@C:B>@ ?> C<>;G0=8N. |
//+------------------------------------------------------------------+
CDictionary::CDictionary()
{
Init(3);
m_free_mode = true;
m_auto_free=true;
}
//+------------------------------------------------------------------+
//| !>7405B A;>20@L, A 70@0=55 >?@545;5==>9 5<:>ABLN capacity. |
//+------------------------------------------------------------------+
CDictionary::CDictionary(int capacity)
{
if(capacity < 3)
Init(3);
else
Init(capacity);
m_free_mode = true;
m_auto_free=true;
}
//+------------------------------------------------------------------+
//| 8AB@C:B>@. |
//+------------------------------------------------------------------+
CDictionary::~CDictionary()
{
Clear();
}
//+------------------------------------------------------------------+
//| 568< CAB0=02;8205B @568< ?0<OB8 4;O 2A5E ?>4C7;>2 |
//+------------------------------------------------------------------+
void CDictionary::FreeMode(bool free_mode)
{
if(free_mode==m_free_mode)
return;
m_free_mode=free_mode;
for(int i=0; i<ArraySize(m_array); i++)
{
CList *list=m_array[i];
if(CheckPointer(list)==POINTER_INVALID)
continue;
for(KeyValuePair *kvp=list.GetFirstNode(); kvp!=NULL; kvp=list.GetNextNode())
kvp.FreeMode(m_free_mode);
}
}
//+------------------------------------------------------------------+
//| K?>;=O5B 8=8F80;870F8N A;>20@O. |
//+------------------------------------------------------------------+
void CDictionary::Init(int capacity)
{
m_array_size=ArrayResize(m_array,capacity);
m_index= 0;
m_hash = 0;
m_total=0;
}
//+------------------------------------------------------------------+
//| 0E>48B A;54CNI89 @07<5@ 4;O A;>20@O. |
//+------------------------------------------------------------------+
int CDictionary::FindNextLevel()
{
double value=4;
for(int i=2; i<=31; i++)
{
value=MathPow(2.0,(double)i);
if(value > m_total)return (int)value;
}
return (int)value;
}
//+------------------------------------------------------------------+
//| @8=8<05B AB@>:C 8 2>72@0I05B EMH8@CNI55 32 18B=>5 G8A;>, |
//| E0@0:B5@87CNI55 MBC AB@>:C. |
//+------------------------------------------------------------------+
ulong CDictionary::Adler32(string line)
{
ulong s1 = 1;
ulong s2 = 0;
uint buflength=StringLen(line);
uchar char_array[];
ArrayResize(char_array,buflength,0);
StringToCharArray(line,char_array,0,-1,CP_ACP);
for(uint n=0; n<buflength; n++)
{
s1 = (s1 + char_array[n]) % 65521;
s2 = (s2 + s1) % 65521;
}
return ((s2 << 16) + s1);
}
//+------------------------------------------------------------------+
//| 0AAG8BK205B EMH =0 >A=>25 ?5@540==>3> :;NG0. ;NG>< <>65B 1KBL |
//| ;N1>9 107>2K9 MQL B8?.
//+------------------------------------------------------------------+
template<typename T>
ulong CDictionary::GetHashByKey(T key)
{
ulong ukey = 0;
string name=typename(key);
if(name=="string")
return Adler32((string)key);
if(name=="double" || name=="float")
{
casting.d_value = (double)key;
ukey=casting.l_value;
}
else
ukey=(ulong)key;
return ukey;
}
//+------------------------------------------------------------------+
//| >72@0I05B :;NG B5:CI53> M;5<5=B0. |
//+------------------------------------------------------------------+
template<typename T>
void CDictionary::GetCurrentKey(T &key)
{
m_current_kvp.GetKey(key);
}
//+------------------------------------------------------------------+
//| >72@0I05B 8=45:A ?> :;NGC. |
//+------------------------------------------------------------------+
int CDictionary::GetIndexByHash(ulong key)
{
return (int)(key%m_array_size);
}
//+------------------------------------------------------------------+
//| G8I05B A;>20@L >B 2A5E 7=0G5=89. |
//+------------------------------------------------------------------+
void CDictionary::Clear(void)
{
int size=ArraySize(m_array);
for(int i=0; i<size; i++)
{
if(CheckPointer(m_array[i])!=POINTER_INVALID)
{
m_array[i].FreeMode(true); // -;5<5=BK B8?0 KeyValuePair C40;ONBAO 2A5340
delete m_array[i];
}
}
ArrayFree(m_array);
if(m_auto_free)
Init(3);
else
Init(size);
m_first_kvp=m_last_kvp=m_current_kvp=NULL;
}
//+------------------------------------------------------------------+
//| 5@5@07<5G05B :>=B59=5@ E@0=5=8O 40==KE. |
//+------------------------------------------------------------------+
void CDictionary::Resize(void)
{
int level=FindNextLevel();
int n=level;
CList *temp_array[];
ArrayCopy(temp_array,m_array);
ArrayFree(m_array);
m_array_size=ArrayResize(m_array,n);
int total=ArraySize(temp_array);
KeyValuePair *kv=NULL;
for(int i=0; i<total; i++)
{
if(temp_array[i]==NULL)continue;
CList *list=temp_array[i];
int count=list.Total();
list.FreeMode(false);
kv=list.GetFirstNode();
while(kv!=NULL)
{
int index=GetIndexByHash(kv.GetHash());
if(CheckPointer(m_array[index])==POINTER_INVALID)
{
m_array[index]=new CList();
m_array[index].FreeMode(true); // -;5<5=BK KeyValuePair C40;ONBAO 2A5340
}
list.DetachCurrent();
m_array[index].Add(kv);
kv=list.GetCurrentNode();
}
delete list;
}
int size=ArraySize(temp_array);
ArrayFree(temp_array);
}
//+------------------------------------------------------------------+
//| !68<05B A;>20@L. |
//+------------------------------------------------------------------+
void CDictionary::Compress(void)
{
if(!m_auto_free)return;
double koeff=m_array_size/(double)(m_total+1);
if(koeff < 2.0 || m_total <= 4)return;
Resize();
}
//+------------------------------------------------------------------+
//| >72@0I5B >1J5:B ?> :;NGC. |
//+------------------------------------------------------------------+
template<typename T>
CObject *CDictionary::GetObjectByKey(T key)
{
if(!ContainsKey(key))
return NULL;
CObject *obj=m_current_kvp.object;
return obj;
}
//+------------------------------------------------------------------+
//| @>25@O5B A>45@68B ;8 A;>20@L :;NG ?@>872>;L=>3> B8?0 T. |
//| RETURNS: |
//| >72@0I05B 8AB8=C, 5A;8 >1J5:B A B0:8< :;NG>< C65 ACI5AB2C5B |
//| 8 ;>6L 2 ?@>B82=>< A;CG05. |
//+------------------------------------------------------------------+
template<typename T>
bool CDictionary::ContainsKey(T key)
{
m_hash=GetHashByKey(key);
m_index=GetIndexByHash(m_hash);
if(CheckPointer(m_array[m_index])==POINTER_INVALID)
return false;
CList *list=m_array[m_index];
KeyValuePair *current_kvp=list.GetCurrentNode();
if(current_kvp == NULL)return false;
if(current_kvp.EqualKey(key))
{
m_current_kvp=current_kvp;
return true;
}
current_kvp=list.GetFirstNode();
while(true)
{
if(current_kvp.EqualKey(key))
{
m_current_kvp=current_kvp;
return true;
}
current_kvp=list.GetNextNode();
if(current_kvp==NULL)
return false;
}
return false;
}
//+------------------------------------------------------------------+
//| >102;O5B 2 A;>20@L M;5<5=B B8?0 CObject A :;NG>< T key. |
//| INPUT PARAMETRS: |
//| T key - ;N1>9 107>2K9 B8?, =0?@8<5@ int, double 8;8 string. |
//| value - :;0AA, ?@>872>4=K9 >B CObject. |
//| RETURNS: |
//| AB8=0, 5A;8 M;5<5=B 1K; 4>102;5= 8 ;>6L 2 ?@>B82=>< A;CG05. |
//+------------------------------------------------------------------+
template<typename T>
bool CDictionary::AddObject(T key,CObject *value)
{
if(ContainsKey(key))
return false;
if(m_total==m_array_size)
{
Resize();
ContainsKey(key);
}
if(CheckPointer(m_array[m_index])==POINTER_INVALID)
{
m_array[m_index]=new CList();
m_array[m_index].FreeMode(true); // -;5<5=BK KeyValuePair C40;ONBAO 2A5340
}
KeyValuePair *kv=new KeyValuePair(key,m_hash,value);
kv.FreeMode(m_free_mode);
if(m_array[m_index].Add(kv)!=-1)
m_total++;
if(CheckPointer(m_current_kvp)==POINTER_INVALID)
{
m_first_kvp=kv;
m_current_kvp=kv;
m_last_kvp=kv;
}
else
{
//4>102;O5< 2 A0<K9 :>=5F, B.:. B5:CI89 C75; <>65B 1KBL 345 C3>4=>
while(m_current_kvp.next_kvp!=NULL)
m_current_kvp=m_current_kvp.next_kvp;
m_current_kvp.next_kvp=kv;
kv.prev_kvp=m_current_kvp;
m_current_kvp=kv;
m_last_kvp=kv;
}
return true;
}
//+------------------------------------------------------------------+
//| >72@0I05B B5:CI89 >1J5:B. A;8 >1J5:B =5 2K1@0= 2>72@0I05B |
//| NULL. |
//+------------------------------------------------------------------+
CObject *CDictionary::GetCurrentNode(void)
{
if(m_current_kvp==NULL)
return NULL;
return m_current_kvp.object;
}
//+------------------------------------------------------------------+
//| >72@0I05B ?@54K4CI89 >1J5:B. >A;5 2K7>20 <5B>40 B5:CI89 |
//| >1J5:B AB0=>28BLAO ?@54K4CI8<. A;8 >1J5:B =5 2K1@0=, 2>72@0I05B |
//| NULL. |
//+------------------------------------------------------------------+
CObject *CDictionary:: GetPrevNode(void)
{
if(m_current_kvp==NULL)
return NULL;
if(m_current_kvp.prev_kvp==NULL)
return NULL;
KeyValuePair *kvp=m_current_kvp.prev_kvp;
m_current_kvp=kvp;
return kvp.object;
}
//+------------------------------------------------------------------+
//| >72@0I05B A;54CNI89 >1J5:B. >A;5 2K7>20 <5B>40 B5:CI89 |
//| >1J5:B AB0=>28BLAO A;54CNI8<. A;8 >1J5:B =5 2K1@0=, 2>72@0I05B |
//| NULL. |
//+------------------------------------------------------------------+
CObject *CDictionary::GetNextNode(void)
{
if(m_current_kvp==NULL)
return NULL;
if(m_current_kvp.next_kvp==NULL)
return NULL;
m_current_kvp=m_current_kvp.next_kvp;
return m_current_kvp.object;
}
//+------------------------------------------------------------------+
//| >72@0I05B ?5@2K9 C75; 2 A?8A:5 C7;>2. A;8 2 A;>20@5 C7;>2 =5B, |
//| 2>72@0I05B NULL. |
//+------------------------------------------------------------------+
CObject *CDictionary::GetFirstNode(void)
{
if(m_first_kvp==NULL)
return NULL;
m_current_kvp=m_first_kvp;
return m_first_kvp.object;
}
//+------------------------------------------------------------------+
//| >72@0I05B ?>A;54=89 C75; 2 A?8A:5 C7;>2. A;8 2 A;>20@5 C7;>2 |
//| =5B 2>72@0I05B NULL. |
//+------------------------------------------------------------------+
CObject *CDictionary::GetLastNode(void)
{
if(m_last_kvp==NULL)
return NULL;
m_current_kvp=m_last_kvp;
return m_last_kvp.object;
}
//+------------------------------------------------------------------+
//| #40;O5B B5:CI89 C75; |
//+------------------------------------------------------------------+
bool CDictionary::DeleteCurrentNode(void)
{
if(m_current_kvp==NULL)
return false;
KeyValuePair* p_kvp = m_current_kvp.prev_kvp;
KeyValuePair* n_kvp = m_current_kvp.next_kvp;
if(CheckPointer(p_kvp)!=POINTER_INVALID)
p_kvp.next_kvp=n_kvp;
if(CheckPointer(n_kvp)!=POINTER_INVALID)
n_kvp.prev_kvp=p_kvp;
m_array[m_index].FreeMode(m_free_mode);
bool res=m_array[m_index].DeleteCurrent();
if(res)
{
m_total--;
Compress();
}
return res;
}
//+------------------------------------------------------------------+
//| #40;O5B >1J5:B A :;NG>< key 87 A;>20@O. |
//+------------------------------------------------------------------+
template<typename T>
bool CDictionary::DeleteObjectByKey(T key)
{
if(!ContainsKey(key))
return false;
return DeleteCurrentNode();
}
#define FOREACH_DICT(dict) for(CObject* node = (dict).GetFirstNode(); node != NULL; node = (dict).GetNextNode())
//+------------------------------------------------------------------+