MobinMQL/Include/Generic/SortedMap.mqh
2025-07-22 14:47:41 +03:00

341 lines
14 KiB
MQL5

//+------------------------------------------------------------------+
//| SortedMap.mqh |
//| Copyright 2000-2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Generic\Interfaces\IMap.mqh>
#include <Generic\Interfaces\IComparer.mqh>
#include <Generic\Internal\DefaultComparer.mqh>
#include <Generic\Internal\CompareFunction.mqh>
#include "HashMap.mqh"
#include "SortedSet.mqh"
//+------------------------------------------------------------------+
//| Class CSortedMap<TKey, TValue>. |
//| Usage: Represents a collection of key/value pairs that are sorted|
//| on the key. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
class CSortedMap: public IMap<TKey,TValue>
{
protected:
CRedBlackTree<CKeyValuePair<TKey,TValue>*>*m_tree;
IComparer<TKey>*m_comparer;
bool m_delete_comparer;
public:
CSortedMap(void);
CSortedMap(IComparer<TKey>*comparer);
CSortedMap(IMap<TKey,TValue>*map);
CSortedMap(IMap<TKey,TValue>*map,IComparer<TKey>*comparer);
~CSortedMap(void);
//--- methods of filling data
bool Add(CKeyValuePair<TKey,TValue>*value) { return m_tree.Add(value); }
bool Add(TKey key,TValue value);
//--- methods of access to protected data
int Count(void) { return m_tree.Count(); }
bool Contains(CKeyValuePair<TKey,TValue>*item) { return m_tree.Contains(item); }
bool Contains(TKey key,TValue value);
bool ContainsKey(TKey key);
bool ContainsValue(TValue value);
IComparer<TKey> *Comparer(void) const { return(m_comparer); }
//--- methods of copy data from collection
int CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0);
int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
//--- methods of cleaning and deleting
void Clear(void);
bool Remove(CKeyValuePair<TKey,TValue>*item) { return m_tree.Remove(item); }
bool Remove(TKey key);
//--- method of access to the data
bool TryGetValue(TKey key,TValue &value);
bool TrySetValue(TKey key,TValue value);
private:
static void ClearNodes(CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node);
};
//+------------------------------------------------------------------+
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
//| that is empty, has the default initial capacity, and uses the |
//| default comparer for the key type. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
CSortedMap::CSortedMap(void)
{
//--- use default comaprer
m_comparer=new CDefaultComparer<TKey>();
m_delete_comparer=true;
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(new CKeyValuePairComparer<TKey,TValue>(m_comparer));
}
//+------------------------------------------------------------------+
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
//| that is empty, has the default initial capacity, and uses the |
//| specified IComparer<TKey>. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
CSortedMap::CSortedMap(IComparer<TKey>*comparer)
{
//--- check comaprer
if(CheckPointer(comparer)==POINTER_INVALID)
{
//--- use default comaprer
m_comparer=new CDefaultComparer<TKey>();
m_delete_comparer=true;
}
else
{
//--- use specified comaprer
m_comparer=comparer;
m_delete_comparer=false;
}
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(new CKeyValuePairComparer<TKey,TValue>(m_comparer));
}
//+------------------------------------------------------------------+
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
//| that contains elements copied from the specified |
//| IMap<TKey,TValue> and uses the default comparer for the key type.|
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
CSortedMap::CSortedMap(IMap<TKey,TValue>*map)
{
//--- use default comaprer
m_comparer=new CDefaultComparer<TKey>();
m_delete_comparer=true;
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(map,new CKeyValuePairComparer<TKey,TValue>(m_comparer));
}
//+------------------------------------------------------------------+
//| Initializes a new instance of the CSortedMap<TKey,TValue> class |
//| that contains elements copied from the specified |
//| IMap<TKey,TValue> and uses the specified IComparer<TKey>. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
CSortedMap::CSortedMap(IMap<TKey,TValue>*map,IComparer<TKey>*comparer)
{
//--- check comaprer
if(CheckPointer(comparer)==POINTER_INVALID)
{
//--- use default comaprer
m_comparer=new CDefaultComparer<TKey>();
m_delete_comparer=true;
}
else
{
//--- use specified comaprer
m_comparer=comparer;
m_delete_comparer=false;
}
m_tree=new CRedBlackTree<CKeyValuePair<TKey,TValue>*>(map,new CKeyValuePairComparer<TKey,TValue>(m_comparer));
}
//+------------------------------------------------------------------+
//| Destructor. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
CSortedMap::~CSortedMap(void)
{
//--- delete comparer
if(m_delete_comparer)
delete m_comparer;
//--- delete tree comparer
delete m_tree.Comparer();
//--- delete nodes values
ClearNodes(m_tree.Root());
//--- delete tree and nodes
delete m_tree;
}
//+------------------------------------------------------------------+
//| Walk all nodes of tree and delete their value. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
static void CSortedMap::ClearNodes(CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node)
{
//--- check node
if(CheckPointer(node)==POINTER_INVALID)
return;
//--- walk of a right subtree
if(!node.Right().IsLeaf())
ClearNodes(node.Right());
//--- delete value
delete node.Value();
//--- walk of a left subtree
if(!node.Left().IsLeaf())
ClearNodes(node.Left());
}
//+------------------------------------------------------------------+
//| Adds the specified key and value to the map. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::Add(TKey key,TValue value)
{
//--- create pair
CKeyValuePair<TKey,TValue>*pair=new CKeyValuePair<TKey,TValue>(key,value);
//--- add pair to tree
bool success=m_tree.Add(pair);
//--- if addition was not successful delte pair
if(!success)
delete pair;
return(success);
}
//+------------------------------------------------------------------+
//| Determines whether the map contains the specified key with value.|
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::Contains(TKey key,TValue value)
{
//--- find node with specified key
CKeyValuePair<TKey,TValue>pair(key,NULL);
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
//--- create value comparer
CDefaultEqualityComparer<TValue>comaprer;
//--- determine whether the finding node contains specified value
if(CheckPointer(node)!=POINTER_INVALID && comaprer.Equals(value,node.Value().Value()))
return(true);
return(false);
}
//+------------------------------------------------------------------+
//| Determines whether the map contains the specified key. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::ContainsKey(TKey key)
{
//--- crete pair
CKeyValuePair<TKey,TValue>pair(key,NULL);
//--- determines whether the tree contains the pair.
return m_tree.Contains(GetPointer(pair));
}
//+------------------------------------------------------------------+
//| Determines whether the map contains the specified value. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::ContainsValue(TValue value)
{
//--- copy all pairs in array
CKeyValuePair<TKey,TValue>*array[];
int count=m_tree.CopyTo(array);
//--- create value comparer
CDefaultEqualityComparer<TValue>comaprer;
//--- determines whether the array contains the specified value
for(int i=0; i<count; i++)
if(comaprer.Equals(value,array[i].Value()))
return(true);
return(false);
}
//+------------------------------------------------------------------+
//| Copies a range of elements from the map to a compatible |
//| one-dimensional array. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
int CSortedMap::CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0)
{
int result=m_tree.CopyTo(dst_array,dst_start);
if(result>0)
{
//--- create clones for each pair
for(int i=0; i<result; i++)
dst_array[dst_start+i]=dst_array[dst_start+i].Clone();
}
return(result);
}
//+------------------------------------------------------------------+
//| Copies a range of elements from the map to a compatible |
//| one-dimensionals keys and values arrays. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
int CSortedMap::CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0)
{
//--- create array and copy all values from tree to there
CKeyValuePair<TKey,TValue>*array[];
int count=m_tree.CopyTo(array);
//--- check real cout
if(count>0)
{
//--- resize keys array
if(dst_start+count>ArraySize(dst_keys))
ArrayResize(dst_keys,dst_start+count);
//--- resize values array
if(dst_start+count>ArraySize(dst_values))
ArrayResize(dst_values,MathMin(ArraySize(dst_keys),dst_start+count));
//--- start copy
int index=0;
while(index<count && dst_start+index<ArraySize(dst_keys) && dst_start+index<ArraySize(dst_values))
{
dst_keys[dst_start+index]=array[index].Key();
dst_values[dst_start+index]=array[index].Value();
index++;
}
return(index);
}
return(0);
}
//+------------------------------------------------------------------+
//| Clear and delete all values from map. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
void CSortedMap::Clear(void)
{
//--- check count
if(m_tree.Count()>0)
{
//--- delete nodes values
ClearNodes(m_tree.Root());
//--- claer th tree
m_tree.Clear();
}
}
//+------------------------------------------------------------------+
//| Removes the value with the specified key from the map. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::Remove(TKey key)
{
//--- create pair with specified key
CKeyValuePair<TKey,TValue>pair(key,NULL);
//--- find node
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
//--- check node
if(CheckPointer(node)!=POINTER_INVALID)
{
CKeyValuePair<TKey,TValue>*real_pair=node.Value();
//--- remove node from tree
if(m_tree.Remove(node))
{
//--- check and delete node value
if(CheckPointer(real_pair)==POINTER_DYNAMIC)
delete real_pair;
return(true);
}
}
return(false);
}
//+------------------------------------------------------------------+
//| Gets the value associated with the specified key. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::TryGetValue(TKey key,TValue &value)
{
//--- create pair with specified key
CKeyValuePair<TKey,TValue>pair(key,NULL);
//--- find node with specified pair in the tree
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
//--- check node
if(CheckPointer(node)==POINTER_INVALID)
return(false);
//--- get value
value=node.Value().Value();
return(true);
}
//+------------------------------------------------------------------+
//| Sets the value associated with the specified key. |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
bool CSortedMap::TrySetValue(TKey key,TValue value)
{
//--- create pair with specified key
CKeyValuePair<TKey,TValue>pair(key,NULL);
//--- find node with specified pair in the tree
CRedBlackTreeNode<CKeyValuePair<TKey,TValue>*>*node=m_tree.Find(GetPointer(pair));
//--- check node
if(CheckPointer(node)==POINTER_INVALID)
return(false);
//--- set value
node.Value().Value(value);
return(true);
}
//+------------------------------------------------------------------+