532 lines
38 KiB
Plaintext
532 lines
38 KiB
Plaintext
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| 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>
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Container to store CObject elements |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
class KeyValuePair : public CObject
|
|||
|
|
{
|
|||
|
|
private:
|
|||
|
|
string m_string_key; // Stores a string key.
|
|||
|
|
double m_double_key; // Stores a floating-point coma.
|
|||
|
|
ulong m_ulong_key; // Stores an unsigned integer key.
|
|||
|
|
ulong m_hash;
|
|||
|
|
bool m_free_mode; // Object memory freeing mode
|
|||
|
|
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;}
|
|||
|
|
};
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Default constructor. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Destructor. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
KeyValuePair::~KeyValuePair()
|
|||
|
|
{
|
|||
|
|
if(m_free_mode)
|
|||
|
|
delete object;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns true, if keys are equal. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| An associative array or dictionary storing elements as |
|
|||
|
|
//| <key - value>. Where a key may be represented by any base type, |
|
|||
|
|
//| and a value may be represented be a CObject type object. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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
|
|||
|
|
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);
|
|||
|
|
|
|||
|
|
};
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Default constructor. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
CDictionary::CDictionary()
|
|||
|
|
{
|
|||
|
|
Init(3);
|
|||
|
|
m_free_mode = true;
|
|||
|
|
m_auto_free=true;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Creates a dictionary with predefined capacity. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
CDictionary::CDictionary(int capacity)
|
|||
|
|
{
|
|||
|
|
if(capacity < 3)
|
|||
|
|
Init(3);
|
|||
|
|
else
|
|||
|
|
Init(capacity);
|
|||
|
|
m_free_mode = true;
|
|||
|
|
m_auto_free=true;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Destructor. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
CDictionary::~CDictionary()
|
|||
|
|
{
|
|||
|
|
Clear();
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| The mode sets the memory freeing for all subnodes |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Initializes the dictionary. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
void CDictionary::Init(int capacity)
|
|||
|
|
{
|
|||
|
|
m_array_size=ArrayResize(m_array,capacity);
|
|||
|
|
m_index= 0;
|
|||
|
|
m_hash = 0;
|
|||
|
|
m_total=0;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Identifies the next size of the dictionary. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Accepts a string and returns a hashing 32-bit number |
|
|||
|
|
//| characterizing this string. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Calculates hash based on a transferred key. A key can be |
|
|||
|
|
//| any basic MQL type.
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns the key of current element |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
template<typename T>
|
|||
|
|
void CDictionary::GetCurrentKey(T &key)
|
|||
|
|
{
|
|||
|
|
m_current_kvp.GetKey(key);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns index according to a key. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
int CDictionary::GetIndexByHash(ulong key)
|
|||
|
|
{
|
|||
|
|
return (int)(key%m_array_size);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Remove all values from dictionary |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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); // The elements of type KeyValuePair are always removed
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Resizes data storage container. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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); // The KeyValuePair elements are always removed
|
|||
|
|
}
|
|||
|
|
list.DetachCurrent();
|
|||
|
|
m_array[index].Add(kv);
|
|||
|
|
kv=list.GetCurrentNode();
|
|||
|
|
}
|
|||
|
|
delete list;
|
|||
|
|
}
|
|||
|
|
int size=ArraySize(temp_array);
|
|||
|
|
ArrayFree(temp_array);
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Compresses the dictionary. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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();
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns an object according to the key. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
template<typename T>
|
|||
|
|
CObject *CDictionary::GetObjectByKey(T key)
|
|||
|
|
{
|
|||
|
|
if(!ContainsKey(key))
|
|||
|
|
return NULL;
|
|||
|
|
CObject *obj=m_current_kvp.object;
|
|||
|
|
return obj;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Checks whether the dictionary contains a key of T arbitrary type. |
|
|||
|
|
//| RETURNS: |
|
|||
|
|
//| Returns true, if an object with this key already exists, |
|
|||
|
|
//| and lie, if otherwise. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Adds CObject type element with a T key to the dictionary. |
|
|||
|
|
//| INPUT PARAMETRS: |
|
|||
|
|
//| T key - any base type, for instance int, double or string. |
|
|||
|
|
//| value - a class that derives from CObject. |
|
|||
|
|
//| RETURNS: |
|
|||
|
|
//| True value, if element has been added, and false, if otherwise. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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); // The KeyValuePair elements are always removed
|
|||
|
|
}
|
|||
|
|
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
|
|||
|
|
{
|
|||
|
|
//we add to the very end, because the current node can be anywhere
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns current object. If an object is not selected, it returns |
|
|||
|
|
//| NULL. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
CObject *CDictionary::GetCurrentNode(void)
|
|||
|
|
{
|
|||
|
|
if(m_current_kvp==NULL)
|
|||
|
|
return NULL;
|
|||
|
|
return m_current_kvp.object;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns the previous object. After call of method current |
|
|||
|
|
//| object becomes the previous one. If an object is not selected, it returns |
|
|||
|
|
//| 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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns next object. After call of method current |
|
|||
|
|
//| after call of the method. If object not selected, returns |
|
|||
|
|
//| 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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns first node in the node list. If there are no nodes in the dictionary, |
|
|||
|
|
//| it returns NULL. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
CObject *CDictionary::GetFirstNode(void)
|
|||
|
|
{
|
|||
|
|
if(m_first_kvp==NULL)
|
|||
|
|
return NULL;
|
|||
|
|
m_current_kvp=m_first_kvp;
|
|||
|
|
return m_first_kvp.object;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Returns the last node in the node list. If there are no nodes in the dictionary, |
|
|||
|
|
//| it returns NULL. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
CObject *CDictionary::GetLastNode(void)
|
|||
|
|
{
|
|||
|
|
if(m_last_kvp==NULL)
|
|||
|
|
return NULL;
|
|||
|
|
m_current_kvp=m_last_kvp;
|
|||
|
|
return m_last_kvp.object;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Deletes the current node |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
//| Deletes an object with a key from the dictionary. |
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
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())
|
|||
|
|
//+------------------------------------------------------------------+
|
|||
|
|
�
|