Add files via upload
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,622 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HashMap.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IMap.mqh>
|
||||
#include <Generic\Interfaces\IEqualityComparer.mqh>
|
||||
#include <Generic\Internal\DefaultEqualityComparer.mqh>
|
||||
#include <Generic\Interfaces\IComparable.mqh>
|
||||
#include <Generic\Internal\CompareFunction.mqh>
|
||||
#include "HashSet.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Struct Entry<TKey, TValue>. |
|
||||
//| Usage: Internal structure for organization CHashMap<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
struct Entry: public Slot<TValue>
|
||||
{
|
||||
public:
|
||||
TKey key;
|
||||
Entry(void): key((TKey)NULL) {}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CKeyValuePair<TKey, TValue>. |
|
||||
//| Usage: Defines a key/value pair that can be set or retrieved. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CKeyValuePair: public IComparable<CKeyValuePair<TKey,TValue>*>
|
||||
{
|
||||
protected:
|
||||
TKey m_key;
|
||||
TValue m_value;
|
||||
|
||||
public:
|
||||
CKeyValuePair(void) { }
|
||||
CKeyValuePair(TKey key,TValue value): m_key(key), m_value(value) { }
|
||||
~CKeyValuePair(void) { }
|
||||
//--- methods to access protected data
|
||||
TKey Key(void) { return(m_key); }
|
||||
void Key(TKey key) { m_key=key; }
|
||||
TValue Value(void) { return(m_value); }
|
||||
void Value(TValue value) { m_value=value; }
|
||||
//--- method to create clone of current instance
|
||||
CKeyValuePair<TKey,TValue>*Clone(void) { return new CKeyValuePair<TKey,TValue>(m_key,m_value); }
|
||||
//--- method to compare keys
|
||||
int Compare(CKeyValuePair<TKey,TValue>*pair) { return ::Compare(m_key,pair.m_key); }
|
||||
//--- method for determining equality
|
||||
bool Equals(CKeyValuePair<TKey,TValue>*pair) { return ::Equals(m_key,pair.m_key); }
|
||||
//--- method to calculate hash code
|
||||
int HashCode(void) { return ::GetHashCode(m_key); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CKeyValuePairComparer<TKey, TValue>. |
|
||||
//| Usage: Provides a comparer class for convertation IComparer<TKey>|
|
||||
//| to the IComparer<CKeyValuePair<TKey, TValue>*> interface. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CKeyValuePairComparer: public IComparer<CKeyValuePair<TKey,TValue>*>
|
||||
{
|
||||
private:
|
||||
IComparer<TKey>*m_comparer;
|
||||
|
||||
public:
|
||||
CKeyValuePairComparer(IComparer<TKey>*comaprer) { m_comparer=comaprer; }
|
||||
int Compare(CKeyValuePair<TKey,TValue>* x,CKeyValuePair<TKey,TValue>* y) { return(m_comparer.Compare(x.Key(), y.Key())); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHashMap<TKey, TValue>. |
|
||||
//| Usage: Represents a collection of keys and values. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
class CHashMap: public IMap<TKey,TValue>
|
||||
{
|
||||
protected:
|
||||
int m_buckets[];
|
||||
Entry<TKey,TValue>m_entries[];
|
||||
int m_count;
|
||||
int m_capacity;
|
||||
int m_free_list;
|
||||
int m_free_count;
|
||||
IEqualityComparer<TKey>*m_comparer;
|
||||
bool m_delete_comparer;
|
||||
|
||||
public:
|
||||
CHashMap(void);
|
||||
CHashMap(const int capacity);
|
||||
CHashMap(IEqualityComparer<TKey>*comparer);
|
||||
CHashMap(const int capacity,IEqualityComparer<TKey>*comparer);
|
||||
CHashMap(IMap<TKey,TValue>*map);
|
||||
CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer);
|
||||
~CHashMap(void);
|
||||
//--- methods of filling data
|
||||
bool Add(CKeyValuePair<TKey,TValue>*pair);
|
||||
bool Add(TKey key,TValue value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return(m_count-m_free_count); }
|
||||
IEqualityComparer<TKey>*Comparer(void) const { return(m_comparer); }
|
||||
bool Contains(CKeyValuePair<TKey,TValue>*item);
|
||||
bool Contains(TKey key,TValue value);
|
||||
bool ContainsKey(TKey key);
|
||||
bool ContainsValue(TValue value);
|
||||
//--- 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);
|
||||
bool Remove(TKey key);
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(TKey key,TValue &value);
|
||||
bool TrySetValue(TKey key,TValue value);
|
||||
|
||||
private:
|
||||
void Initialize(const int capacity);
|
||||
bool Resize(int new_size);
|
||||
int FindEntry(TKey key);
|
||||
bool Insert(TKey key,TValue value,const bool add);
|
||||
static int m_collision_threshold;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the default initial capacity, and uses the |
|
||||
//| default equality comparer for the key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(void): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the specified initial capacity, and uses the |
|
||||
//| default equality comparer for the key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(const int capacity): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- set capacity
|
||||
if(capacity>0)
|
||||
Initialize(capacity);
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the default initial capacity, and uses the |
|
||||
//| specified IEqualityComparer<TKey>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that is empty, has the specified initial capacity, and uses the |
|
||||
//| specified IEqualityComparer<TKey>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(const int capacity,IEqualityComparer<TKey>*comparer): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
if(capacity>0)
|
||||
Initialize(capacity);
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that contains elements copied from the specified |
|
||||
//| IMap<TKey,TValue> and uses the default equality comparer for the |
|
||||
//| key type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(IMap<TKey,TValue>*map): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
//--- check map
|
||||
if(CheckPointer(map)!=POINTER_INVALID && map.Count()>0)
|
||||
{
|
||||
//--- set capacity
|
||||
Initialize(map.Count());
|
||||
TKey keys[];
|
||||
TValue values[];
|
||||
map.CopyTo(keys,values);
|
||||
//--- copy all keys and values from specified map to current map
|
||||
for(int i=0; i<map.Count(); i++)
|
||||
Add(keys[i],values[i]);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashMap<TKey,TValue> class |
|
||||
//| that contains elements copied from the specified |
|
||||
//| IMap<TKey,TValue> and uses the specified IEqualityComparer<TKey>.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::CHashMap(IMap<TKey,TValue>*map,IEqualityComparer<TKey>*comparer): m_count(0),
|
||||
m_free_list(0),
|
||||
m_free_count(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<TKey>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
//--- check map
|
||||
if(CheckPointer(map)!=POINTER_INVALID && map.Count()>0)
|
||||
{
|
||||
//--- set capacity
|
||||
Initialize(map.Count());
|
||||
TKey keys[];
|
||||
TValue values[];
|
||||
map.CopyTo(keys,values);
|
||||
//--- copy all keys and values from specified map to current map
|
||||
for(int i=0; i<map.Count(); i++)
|
||||
Add(keys[i],values[i]);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
CHashMap::~CHashMap(void)
|
||||
{
|
||||
if(m_delete_comparer)
|
||||
delete m_comparer;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified key-value pair to the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Add(CKeyValuePair<TKey,TValue>*pair)
|
||||
{
|
||||
//--- check pair
|
||||
if(CheckPointer(pair)==POINTER_INVALID)
|
||||
return(false);
|
||||
return(Add(pair.Key(),pair.Value()));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified key and value to the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Add(TKey key,TValue value)
|
||||
{
|
||||
return(Insert(key,value,true));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key-value pair.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Contains(CKeyValuePair<TKey,TValue>*item)
|
||||
{
|
||||
//--- check pair
|
||||
if(CheckPointer(item)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(item.Key());
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer;
|
||||
//--- check value is equal value from the found pair
|
||||
if(i>=0 && comparer.Equals(m_entries[i].value,item.Value()))
|
||||
return(true);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key with value.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Contains(TKey key,TValue value)
|
||||
{
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(key);
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer;
|
||||
//--- check value is equal value from the found pair
|
||||
if(i>=0 && comparer.Equals(m_entries[i].value,value))
|
||||
return(true);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::ContainsKey(TKey key)
|
||||
{
|
||||
return(FindEntry(key)>=0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the map contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::ContainsValue(TValue value)
|
||||
{
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer_value();
|
||||
//--- try to find pair contains specified value
|
||||
for(int i=0; i<m_count; i++)
|
||||
if(m_entries[i].hash_code>=0 && comparer_value.Equals(m_entries[i].value,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 CHashMap::CopyTo(CKeyValuePair<TKey,TValue>*&dst_array[],const int dst_start=0)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_count>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_count);
|
||||
//--- start copy
|
||||
int index=0;
|
||||
for(int i=0; i<ArraySize(m_entries); i++)
|
||||
if(m_entries[i].hash_code>=0)
|
||||
{
|
||||
//--- check indexes
|
||||
if(dst_start+index>=ArraySize(dst_array) || index>=m_count)
|
||||
return(index);
|
||||
dst_array[dst_start+index++]=new CKeyValuePair<TKey,TValue>(m_entries[i].key,m_entries[i].value);
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the map to a compatible |
|
||||
//| one-dimensionals keys and values arrays. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CHashMap::CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0)
|
||||
{
|
||||
int count=m_count-m_free_count;
|
||||
//--- 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;
|
||||
for(int i=0; i<ArraySize(m_entries); i++)
|
||||
if(m_entries[i].hash_code>=0)
|
||||
{
|
||||
//--- check indexes
|
||||
if(dst_start+index>=ArraySize(dst_keys) || dst_start+index>=ArraySize(dst_values) || index>=count)
|
||||
return(index);
|
||||
dst_keys[dst_start+index]=m_entries[i].key;
|
||||
dst_values[dst_start+index]=m_entries[i].value;
|
||||
index++;
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all keys and values from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
void CHashMap::Clear(void)
|
||||
{
|
||||
//--- check count
|
||||
if(m_count>0)
|
||||
{
|
||||
ArrayFill(m_buckets,0,m_capacity,-1);
|
||||
ArrayFree(m_entries);
|
||||
m_count=0;
|
||||
m_free_list=-1;
|
||||
m_free_count=0;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the specified key-value pair from map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Remove(CKeyValuePair<TKey,TValue>*item)
|
||||
{
|
||||
//--- check pair
|
||||
if(CheckPointer(item)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(item.Key());
|
||||
//--- create default equality value comparer
|
||||
CDefaultEqualityComparer<TValue>comparer_value();
|
||||
//--- remove pair
|
||||
if(i>=0 && comparer_value.Equals(m_entries[i].value,item.Value()))
|
||||
return Remove(item.Key());
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the value with the specified key from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Remove(TKey key)
|
||||
{
|
||||
if(m_capacity!=0)
|
||||
{
|
||||
int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
|
||||
int bucket=hash_code%m_capacity;
|
||||
int last=-1;
|
||||
//--- search pair with specified key
|
||||
for(int i=m_buckets[bucket]; i>=0; last=i,i=m_entries[i].next)
|
||||
{
|
||||
if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key))
|
||||
{
|
||||
if(last<0)
|
||||
m_buckets[bucket]=m_entries[i].next;
|
||||
else
|
||||
m_entries[last].next=m_entries[i].next;
|
||||
//--- remove pair
|
||||
m_entries[i].hash_code=-1;
|
||||
m_entries[i].next=m_free_list;
|
||||
m_entries[i].key=(TKey)NULL;
|
||||
m_entries[i].value=(TValue)NULL;
|
||||
//--- incremet free count
|
||||
m_free_list=i;
|
||||
m_free_count++;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the value associated with the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::TryGetValue(TKey key,TValue &value)
|
||||
{
|
||||
//--- find pair with specified key
|
||||
int i=FindEntry(key);
|
||||
//--- check index
|
||||
if(i>=0)
|
||||
{
|
||||
//--- get value
|
||||
value=m_entries[i].value;
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the value associated with the specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::TrySetValue(TKey key,TValue value)
|
||||
{
|
||||
return(Insert(key, value, false));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize map with specified capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
void CHashMap::Initialize(const int capacity)
|
||||
{
|
||||
m_capacity=CPrimeGenerator::GetPrime(capacity);
|
||||
ArrayResize(m_buckets,m_capacity);
|
||||
ArrayFill(m_buckets,0,m_capacity,-1);
|
||||
ArrayResize(m_entries,m_capacity);
|
||||
m_free_list=-1;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Resize map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Resize(const int new_size)
|
||||
{
|
||||
//--- resize buckets
|
||||
if(ArrayResize(m_buckets,new_size)!=new_size)
|
||||
return(false);
|
||||
ArrayFill(m_buckets,0,new_size,-1);
|
||||
//--- resize entries
|
||||
if(ArrayResize(m_entries,new_size)!=new_size)
|
||||
return(false);
|
||||
//--- restore buckets
|
||||
for(int i=0; i<m_count; i++)
|
||||
if(m_entries[i].hash_code>=0)
|
||||
{
|
||||
int bucket=m_entries[i].hash_code%new_size;
|
||||
m_entries[i].next = m_buckets[bucket];
|
||||
m_buckets[bucket] = i;
|
||||
}
|
||||
//--- restore capacity
|
||||
m_capacity=new_size;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Find index of entry with specified key. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
int CHashMap::FindEntry(TKey key)
|
||||
{
|
||||
if(m_capacity!=NULL)
|
||||
{
|
||||
//--- get hash code from key
|
||||
int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
|
||||
//--- search pair with specified key
|
||||
for(int i=m_buckets[hash_code%m_capacity]; i>=0; i=m_entries[i].next)
|
||||
if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key))
|
||||
return(i);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert the value with the specified key from the map. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
bool CHashMap::Insert(TKey key,TValue value,const bool add)
|
||||
{
|
||||
if(m_capacity==0)
|
||||
Initialize(0);
|
||||
//--- get hash code from key
|
||||
int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
|
||||
int target_bucket=hash_code%m_capacity;
|
||||
//--- collisions count in one bucket with different hashes
|
||||
int collision_count=0;
|
||||
//--- search pair with specified key
|
||||
for(int i=m_buckets[target_bucket]; i>=0; i=m_entries[i].next)
|
||||
{
|
||||
//--- hash compare
|
||||
if(m_entries[i].hash_code!=hash_code)
|
||||
{
|
||||
collision_count++;
|
||||
continue;
|
||||
}
|
||||
//--- value compare
|
||||
if(m_comparer.Equals(m_entries[i].key,key))
|
||||
{
|
||||
//--- adding duplicate
|
||||
if(add)
|
||||
return(false);
|
||||
m_entries[i].value=value;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
//--- check collision
|
||||
if(collision_count>=m_collision_threshold)
|
||||
{
|
||||
int new_size=CPrimeGenerator::ExpandPrime(m_count);
|
||||
if(!Resize(new_size))
|
||||
return(false);
|
||||
target_bucket=hash_code%new_size;
|
||||
}
|
||||
//--- calculate index
|
||||
int index;
|
||||
if(m_free_count>0)
|
||||
{
|
||||
index=m_free_list;
|
||||
m_free_list=m_entries[index].next;
|
||||
m_free_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_count==ArraySize(m_entries))
|
||||
{
|
||||
int new_size=CPrimeGenerator::ExpandPrime(m_count);
|
||||
if(!Resize(new_size))
|
||||
return(false);
|
||||
target_bucket=hash_code%new_size;
|
||||
}
|
||||
index=m_count;
|
||||
m_count++;
|
||||
}
|
||||
//--- set pair
|
||||
m_entries[index].hash_code=hash_code;
|
||||
m_entries[index].next=m_buckets[target_bucket];
|
||||
m_entries[index].key=key;
|
||||
m_entries[index].value=value;
|
||||
m_buckets[target_bucket]=index;
|
||||
return(true);
|
||||
}
|
||||
template<typename TKey,typename TValue>
|
||||
static int CHashMap::m_collision_threshold=8;
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,972 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HashSet.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include<Generic\Interfaces\ISet.mqh>
|
||||
#include <Generic\Internal\PrimeGenerator.mqh>
|
||||
#include <Generic\Interfaces\IEqualityComparer.mqh>
|
||||
#include <Generic\Internal\DefaultEqualityComparer.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Struct Slot<T>. |
|
||||
//| Usage: Internal structure for organization CHashSet<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
struct Slot
|
||||
{
|
||||
public:
|
||||
int hash_code;
|
||||
T value;
|
||||
int next;
|
||||
Slot(void): hash_code(0),value((T)NULL),next(0) {}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHashSet<T>. |
|
||||
//| Usage: Represents a set of unique values. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CHashSet: public ISet<T>
|
||||
{
|
||||
protected:
|
||||
int m_buckets[];
|
||||
Slot<T> m_slots[];
|
||||
int m_count;
|
||||
int m_last_index;
|
||||
int m_free_list;
|
||||
IEqualityComparer<T>*m_comparer;
|
||||
bool m_delete_comparer;
|
||||
|
||||
public:
|
||||
CHashSet(void);
|
||||
CHashSet(IEqualityComparer<T>*comparer);
|
||||
CHashSet(ICollection<T>*collection);
|
||||
CHashSet(ICollection<T>*collection,IEqualityComparer<T>*comparer);
|
||||
CHashSet(T &array[]);
|
||||
CHashSet(T &array[],IEqualityComparer<T>*comparer);
|
||||
~CHashSet(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return(m_count); }
|
||||
IEqualityComparer<T>* Comparer(void) const { return(m_comparer); }
|
||||
bool Contains(T item);
|
||||
void TrimExcess(void);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &ds_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
//--- methods of changing sets
|
||||
void ExceptWith(ICollection<T>*collection);
|
||||
void ExceptWith(T &array[]);
|
||||
void IntersectWith(ICollection<T>*collection);
|
||||
void IntersectWith(T &array[]);
|
||||
void SymmetricExceptWith(ICollection<T>*collection);
|
||||
void SymmetricExceptWith(T &array[]);
|
||||
void UnionWith(ICollection<T>*collection);
|
||||
void UnionWith(T &array[]);
|
||||
//--- methods for determining the relationship between sets
|
||||
bool IsProperSubsetOf(ICollection<T>*collection);
|
||||
bool IsProperSubsetOf(T &array[]);
|
||||
bool IsProperSupersetOf(ICollection<T>*collection);
|
||||
bool IsProperSupersetOf(T &array[]);
|
||||
bool IsSubsetOf(ICollection<T>*collection);
|
||||
bool IsSubsetOf(T &array[]);
|
||||
bool IsSupersetOf(ICollection<T>*collection);
|
||||
bool IsSupersetOf(T &array[]);
|
||||
bool Overlaps(ICollection<T>*collection);
|
||||
bool Overlaps(T &array[]);
|
||||
bool SetEquals(ICollection<T>*collection);
|
||||
bool SetEquals(T &array[]);
|
||||
|
||||
private:
|
||||
void SetCapacity(const int new_size,bool new_hash_codes);
|
||||
bool AddIfNotPresent(T value);
|
||||
void Initialize(const int capacity);
|
||||
void InternalSymmetricExceptWith(CHashSet<T>*set);
|
||||
bool InternalIsSubsetOf(CHashSet<T>*set);
|
||||
bool InternalIsSupersetOf(CHashSet<T>*set);
|
||||
bool InternalIsProperSubsetOf(CHashSet<T>*set);
|
||||
bool InternalIsProperSupersetOf(CHashSet<T>*set);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that is empty|
|
||||
//| and uses the default equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(void): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that is empty|
|
||||
//| and uses the specified equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(IEqualityComparer<T>*comparer): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified equality comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| default equality comparer for the set type, contains elements |
|
||||
//| copied from the specified collection, and has sufficient capacity|
|
||||
//| to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(ICollection<T>*collection): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- set capacity for elements of the collection
|
||||
int count=collection.Count();
|
||||
Initialize(count);
|
||||
//--- add element from collection to the set
|
||||
this.UnionWith(collection);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| specified equality comparer for the set type, contains elements |
|
||||
//| copied from the specified collection, and has sufficient capacity|
|
||||
//| to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(ICollection<T>*collection,IEqualityComparer<T>*comparer): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- set capacity for elements of the collection
|
||||
int count=collection.Count();
|
||||
Initialize(count);
|
||||
//--- add element from collection to the set
|
||||
this.UnionWith(collection);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| default equality comparer for the set type, contains elements |
|
||||
//| copied from the specified array, and has sufficient capacity to |
|
||||
//| accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(T &array[]): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
//--- set capacity for elements of the array
|
||||
int count=ArraySize(array);
|
||||
Initialize(count);
|
||||
//--- add element from array to the set
|
||||
this.UnionWith(array);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CHashSet<T> class that uses the|
|
||||
//| specified equality comparer for the set type, contains elements |
|
||||
//| copied from the specified array, and has sufficient capacity to |
|
||||
//| accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CHashSet::CHashSet(T &array[],IEqualityComparer<T>*comparer): m_count(0),
|
||||
m_last_index(0),
|
||||
m_free_list(-1)
|
||||
{
|
||||
//--- check equality comaprer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
{
|
||||
//--- use default equality comaprer
|
||||
m_comparer=new CDefaultEqualityComparer<T>();
|
||||
m_delete_comparer=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use specified comaprer
|
||||
m_comparer=comparer;
|
||||
m_delete_comparer=false;
|
||||
}
|
||||
//--- set capacity for elements of the array
|
||||
int count=ArraySize(array);
|
||||
Initialize(count);
|
||||
//--- add element from array to the set
|
||||
this.UnionWith(array);
|
||||
if((m_count==0 && ArraySize(m_slots)>3) ||
|
||||
(m_count>0 && ArraySize(m_slots)/m_count>3))
|
||||
TrimExcess();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T> CHashSet::~CHashSet(void)
|
||||
{
|
||||
if(m_delete_comparer)
|
||||
delete m_comparer;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified element to a set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Add(T value)
|
||||
{
|
||||
return AddIfNotPresent(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set contains the specified element. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Contains(T item)
|
||||
{
|
||||
//--- check buckets
|
||||
if(ArraySize(m_buckets)!=0)
|
||||
{
|
||||
//--- get hash code for item
|
||||
int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF;
|
||||
//--- search item in the slots
|
||||
for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next)
|
||||
if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item))
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the capacity of a set to the actual number of elements it |
|
||||
//| contains, rounded up to a nearby, implementation-specific value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::TrimExcess(void)
|
||||
{
|
||||
if(m_count==0)
|
||||
{
|
||||
ArrayFree(m_buckets);
|
||||
ArrayFree(m_slots);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- calculate min prime size for current count
|
||||
int new_size=CPrimeGenerator::GetPrime(m_count);
|
||||
//--- resize buckets and slots
|
||||
ArrayResize(m_slots,new_size);
|
||||
ArrayResize(m_buckets,new_size);
|
||||
//--- restore buckets and slots
|
||||
int new_index=0;
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
m_slots[new_index]=m_slots[i];
|
||||
//--- rehash
|
||||
int bucket=m_slots[new_index].hash_code%new_size;
|
||||
m_slots[new_index].next=m_buckets[bucket]-1;
|
||||
m_buckets[bucket]=new_index+1;
|
||||
//--- increment index
|
||||
new_index++;
|
||||
}
|
||||
}
|
||||
m_last_index=new_index;
|
||||
m_free_list=-1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the set to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CHashSet::CopyTo(T &dst_array[],const int dst_start)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_count>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_count);
|
||||
//--- start copy
|
||||
int index=0;
|
||||
for(int i=0; i<ArraySize(m_slots); i++)
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
if(dst_start+index>=ArraySize(dst_array) || index>=m_count)
|
||||
return(index);
|
||||
dst_array[dst_start+index++]=m_slots[i].value;
|
||||
}
|
||||
return(index);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements from a set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::Clear(void)
|
||||
{
|
||||
if(m_last_index>0)
|
||||
{
|
||||
ArrayFree(m_slots);
|
||||
ArrayFree(m_buckets);
|
||||
m_last_index=0;
|
||||
m_count=0;
|
||||
m_free_list=-1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the specified element from a set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Remove(T item)
|
||||
{
|
||||
if(ArraySize(m_buckets)!=0)
|
||||
{
|
||||
//--- get hash code for item
|
||||
int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF;
|
||||
int bucket=hash_code%ArraySize(m_buckets);
|
||||
int last=-1;
|
||||
//--- search item
|
||||
for(int i=m_buckets[bucket]-1; i>=0; last=i,i=m_slots[i].next)
|
||||
{
|
||||
if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item))
|
||||
{
|
||||
if(last<0)
|
||||
m_buckets[bucket]=m_slots[i].next+1;
|
||||
else
|
||||
m_slots[last].next=m_slots[i].next;
|
||||
//--- remove item
|
||||
m_slots[i].hash_code=-1;
|
||||
m_slots[i].value=(T)NULL;
|
||||
m_slots[i].next =m_free_list;
|
||||
//--- decrement count
|
||||
m_count--;
|
||||
if(m_count==0)
|
||||
{
|
||||
m_last_index= 0;
|
||||
m_free_list = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_free_list=i;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified collection from the current|
|
||||
//| set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::ExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- this is already the enpty set
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- special case if collecion is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- copy collection to array
|
||||
T array[];
|
||||
collection.CopyTo(array,0);
|
||||
//--- remove every element in collection from this
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
Remove(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified array from the current set.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::ExceptWith(T &array[])
|
||||
{
|
||||
//--- this is already the enpty set
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- remove every element in collection from this
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
Remove(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::IntersectWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- intersection of anything with empty set is empty set, so return if count is 0
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- if collection is empty, intersection is empty set
|
||||
if(collection.Count()==0)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- intersect
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!collection.Contains(item))
|
||||
Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::IntersectWith(T &array[])
|
||||
{
|
||||
//--- intersection of anything with empty set is empty set, so return if count is 0
|
||||
if(m_count==0)
|
||||
return;
|
||||
//--- if collection is empty, intersection is empty set
|
||||
if(ArraySize(array)==0)
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- intersect
|
||||
CHashSet<T>set(array);
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
if(m_slots[i].hash_code>=0)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!set.Contains(item))
|
||||
Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified collection, but |
|
||||
//| not both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::SymmetricExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- if set is empty, then symmetric difference is other
|
||||
if(m_count==0)
|
||||
{
|
||||
UnionWith(collection);
|
||||
return;
|
||||
}
|
||||
//--- special case this; the symmetric difference of a set with itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
InternalSymmetricExceptWith(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
InternalSymmetricExceptWith(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified array, but not |
|
||||
//| both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::SymmetricExceptWith(T &array[])
|
||||
{
|
||||
//--- if set is empty, then symmetric difference is other
|
||||
if(m_count==0)
|
||||
{
|
||||
UnionWith(array);
|
||||
return;
|
||||
}
|
||||
//--- symmetric except
|
||||
CHashSet<T>set(array);
|
||||
InternalSymmetricExceptWith(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified collection, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::UnionWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- union array with the current set
|
||||
UnionWith(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified array, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::UnionWith(T &array[])
|
||||
{
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
AddIfNotPresent(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(collection.Count()>0);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsProperSubsetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsProperSubsetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSubsetOf(T &array[])
|
||||
{
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(ArraySize(array)>0);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsProperSubsetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_count>0);
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsProperSupersetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsProperSupersetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsProperSupersetOf(T &array[])
|
||||
{
|
||||
//--- the empty set is a proper subset of anything but the empty set
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsProperSupersetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified collection.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_count==0);
|
||||
//--- The empty set is a subset of any set
|
||||
if(m_count==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsSubsetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsSubsetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSubsetOf(T &array[])
|
||||
{
|
||||
//--- The empty set is a subset of any set
|
||||
if(m_count==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsSubsetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_count>=0);
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return InternalIsSupersetOf(ptr_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return InternalIsSupersetOf(GetPointer(set));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::IsSupersetOf(T &array[])
|
||||
{
|
||||
//--- if other is the empty set then this is a superset
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return InternalIsSupersetOf(GetPointer(set));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified collection |
|
||||
//| share common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Overlaps(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check current count
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- check overlaps between current set and array
|
||||
return Overlaps(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified array share |
|
||||
//| common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::Overlaps(T &array[])
|
||||
{
|
||||
//--- check current count
|
||||
if(m_count==0)
|
||||
return(false);
|
||||
//--- try to find any elements from specified array in current set
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
if(Contains(array[i]))
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified collection contain the|
|
||||
//| same elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::SetEquals(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check current set is equal specified collection
|
||||
if(collection==GetPointer(this))
|
||||
return(true);
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- check current set is equal specified array
|
||||
return SetEquals(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified array contain the same|
|
||||
//| elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::SetEquals(T &array[])
|
||||
{
|
||||
//--- check size
|
||||
if(ArraySize(array)!=m_count)
|
||||
return(false);
|
||||
//--- check current set is equal specified array
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
if(!Contains(array[i]))
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Set the underlying buckets array to size new_size and rehash. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::SetCapacity(const int new_size,bool new_hash_codes)
|
||||
{
|
||||
//--- resize slots
|
||||
ArrayResize(m_slots,new_size);
|
||||
//--- restore slots
|
||||
if(new_hash_codes)
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
if(m_slots[i].hash_code!=-1)
|
||||
m_slots[i].hash_code=m_comparer.HashCode(m_slots[i].value)&0x7FFFFFFF;
|
||||
//--- resize buckets
|
||||
ArrayResize(m_buckets,new_size);
|
||||
ArrayFill(m_buckets,0,new_size,0);
|
||||
//--- restore buckets
|
||||
for(int i=0; i<m_last_index; i++)
|
||||
{
|
||||
int bucket=m_slots[i].hash_code%new_size;
|
||||
m_slots[i].next=m_buckets[bucket]-1;
|
||||
m_buckets[bucket]=i+1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds value to set if not contained already. Returns true if added|
|
||||
//| and false if already present. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::AddIfNotPresent(T value)
|
||||
{
|
||||
//--- set minimum capacity
|
||||
if(ArraySize(m_buckets)==0)
|
||||
Initialize(0);
|
||||
//--- get hash code and bucket for value
|
||||
int hash_code=m_comparer.HashCode(value)&0x7FFFFFFF;
|
||||
int bucket=hash_code%ArraySize(m_buckets);
|
||||
//--- check value already in the set
|
||||
for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next)
|
||||
if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,value))
|
||||
return(false);
|
||||
//--- calculate index for value
|
||||
int index=0;
|
||||
if(m_free_list>=0)
|
||||
{
|
||||
index=m_free_list;
|
||||
m_free_list=m_slots[index].next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_last_index==ArraySize(m_slots))
|
||||
{
|
||||
int new_size=CPrimeGenerator::ExpandPrime(m_count);
|
||||
SetCapacity(new_size,false);
|
||||
bucket=hash_code%ArraySize(m_buckets);
|
||||
}
|
||||
index=m_last_index;
|
||||
m_last_index++;
|
||||
}
|
||||
//--- set value
|
||||
m_slots[index].hash_code=hash_code;
|
||||
m_slots[index].value=value;
|
||||
m_slots[index].next=m_buckets[bucket]-1;
|
||||
m_buckets[bucket]=index+1;
|
||||
//--- increase count
|
||||
m_count++;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initialize set with specified capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::Initialize(const int capacity)
|
||||
{
|
||||
int size=CPrimeGenerator::GetPrime(capacity);
|
||||
ArrayResize(m_buckets,size);
|
||||
ArrayResize(m_slots,size);
|
||||
ZeroMemory(m_buckets);
|
||||
ZeroMemory(m_slots);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified set, but not both.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CHashSet::InternalSymmetricExceptWith(CHashSet<T>*set)
|
||||
{
|
||||
for(int i=0; i<ArraySize(set.m_slots); i++)
|
||||
{
|
||||
T item=set.m_slots[i].value;
|
||||
if(!Remove(item))
|
||||
AddIfNotPresent(item);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsSubsetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has more elements then it can't be a subset
|
||||
if(m_count>set.m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from current set in specified set
|
||||
for(int i=0; i<m_count; i++)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!set.Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsSupersetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has less elements then it can't be a superset
|
||||
if(set.m_count>m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from specified set in current set
|
||||
for(int i=0; i<set.m_count; i++)
|
||||
{
|
||||
T item=set.m_slots[i].value;
|
||||
if(!Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified set.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsProperSubsetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has more or equal elements then it can't be a proper subset
|
||||
if(m_count>=set.m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from current set in specified set
|
||||
for(int i=0; i<m_count; i++)
|
||||
{
|
||||
T item=m_slots[i].value;
|
||||
if(!set.Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CHashSet::InternalIsProperSupersetOf(CHashSet<T>*set)
|
||||
{
|
||||
//--- if this has less or equal elements then it can't be a proper superset
|
||||
if(m_count<=set.m_count)
|
||||
return(false);
|
||||
//--- try to find any elements from specified set in current set
|
||||
for(int i=0; i<set.m_count; i++)
|
||||
{
|
||||
T item=set.m_slots[i].value;
|
||||
if(!Contains(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,24 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ICollection.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface ICollection<T>. |
|
||||
//| Usage: Defines methods to manipulate generic collections. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface ICollection
|
||||
{
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void);
|
||||
bool Contains(T item);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and removing
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,19 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IComparable.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "IEqualityComparable.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IComparable<T>. |
|
||||
//| Usage: Defines a generalized comparison method to create a |
|
||||
//| type-specific comparison method for ordering or sorting |
|
||||
//| instances. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IComparable: public IEqualityComparable<T>
|
||||
{
|
||||
//--- method for determining compare
|
||||
int Compare(T value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,17 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IComparer<T>. |
|
||||
//| Usage: Defines a method that a type implements to compare two |
|
||||
//| values. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IComparer
|
||||
{
|
||||
//--- compares two values and returns a value indicating whether one is less than, equal to, or greater than the other
|
||||
int Compare(T x,T y);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,19 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IEqualityComparable.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IEqualityComparable<T>. |
|
||||
//| Usage: Defines a generalized method to create a type-specific |
|
||||
//| method for determining equality of instances. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IEqualityComparable
|
||||
{
|
||||
//--- method for determining equality
|
||||
bool Equals(T value);
|
||||
//--- method to calculate hash code
|
||||
int HashCode(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,19 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IEqualityComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IEqualityComparer<T>. |
|
||||
//| Usage: Defines methods to support the comparison of values for |
|
||||
//| equality. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IEqualityComparer
|
||||
{
|
||||
//--- determines whether the specified values are equal
|
||||
bool Equals(T x,T y);
|
||||
//--- returns a hash code for the specified object
|
||||
int HashCode(T value);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,26 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IList.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ICollection.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IList<T>. |
|
||||
//| Usage: Represents a collection of objects that can be |
|
||||
//| individually accessed by index. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface IList: public ICollection<T>
|
||||
{
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(const int index,T &value);
|
||||
bool TrySetValue(const int index,T value);
|
||||
//--- methods of filling the array
|
||||
bool Insert(const int index,T item);
|
||||
//--- methods for searching index
|
||||
int IndexOf(T item);
|
||||
int LastIndexOf(T item);
|
||||
//--- methods of cleaning and deleting
|
||||
bool RemoveAt(const int index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,27 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| IMap.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ICollection.mqh"
|
||||
template<typename TKey,typename TValue>
|
||||
class CKeyValuePair;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface IMap<TKey,TValue>. |
|
||||
//| Usage: Represents a generic collection of key/value pairs. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TValue>
|
||||
interface IMap: public ICollection<CKeyValuePair<TKey,TValue>*>
|
||||
{
|
||||
//--- methods of filling data
|
||||
bool Add(TKey key,TValue value);
|
||||
//--- methods of access to protected data
|
||||
bool Contains(TKey key,TValue value);
|
||||
bool Remove(TKey key);
|
||||
//--- method of access to the data
|
||||
bool TryGetValue(TKey key,TValue &value);
|
||||
bool TrySetValue(TKey key,TValue value);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,37 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ISet.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ICollection.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Interface ISet<T>. |
|
||||
//| Usage: Provides the base interface for the abstraction of sets. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
interface ISet: public ICollection<T>
|
||||
{
|
||||
//--- methods of changing sets
|
||||
void ExceptWith(ICollection<T>*collection);
|
||||
void ExceptWith(T &array[]);
|
||||
void IntersectWith(ICollection<T>*collection);
|
||||
void IntersectWith(T &array[]);
|
||||
void SymmetricExceptWith(ICollection<T>*collection);
|
||||
void SymmetricExceptWith(T &array[]);
|
||||
void UnionWith(ICollection<T>*collection);
|
||||
void UnionWith(T &array[]);
|
||||
//--- methods for determining the relationship between sets
|
||||
bool IsProperSubsetOf(ICollection<T>*collection);
|
||||
bool IsProperSubsetOf(T &array[]);
|
||||
bool IsProperSupersetOf(ICollection<T>*collection);
|
||||
bool IsProperSupersetOf(T &array[]);
|
||||
bool IsSubsetOf(ICollection<T>*collection);
|
||||
bool IsSubsetOf(T &array[]);
|
||||
bool IsSupersetOf(ICollection<T>*collection);
|
||||
bool IsSupersetOf(T &array[]);
|
||||
bool Overlaps(ICollection<T>*collection);
|
||||
bool Overlaps(T &array[]);
|
||||
bool SetEquals(ICollection<T>*collection);
|
||||
bool SetEquals(T &array[]);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,135 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ArrayFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "CompareFunction.mqh"
|
||||
#include <Generic\Interfaces\IComparer.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Searches an entire one-dimensional sorted array for a specific |
|
||||
//| element, using the IComparable<T> generic interface implemented |
|
||||
//| by each element of the array and by the specified object. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int ArrayBinarySearch(T &array[],const int start_index,const int count, T value,IComparer<T>*comparer)
|
||||
{
|
||||
int lo=start_index;
|
||||
int hi=start_index+count-1;
|
||||
int size=ArraySize(array);
|
||||
//--- check array size
|
||||
if(size==0)
|
||||
return(-1);
|
||||
//--- check comaparer
|
||||
if(CheckPointer(comparer)==POINTER_INVALID)
|
||||
return(-1);
|
||||
//--- check index
|
||||
if(start_index<0 || count<0 || size-start_index<count)
|
||||
return(-1);
|
||||
//--- bianry search value
|
||||
while(lo<=hi)
|
||||
{
|
||||
int i=lo+((hi-lo)>>1);
|
||||
int order=comparer.Compare(array[i],value);
|
||||
if(order==0)
|
||||
{
|
||||
return(i);
|
||||
}
|
||||
if(order<0)
|
||||
{
|
||||
lo=i+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi=i-1;
|
||||
}
|
||||
}
|
||||
//--- returns the index of an element nearest in value
|
||||
if(lo>0)
|
||||
return(lo-1);
|
||||
return(lo);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Searches for the specified object and returns the index of its |
|
||||
//| first occurrence in a one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int ArrayIndexOf(T &array[],T value,const int start_index,const int count)
|
||||
{
|
||||
int size=ArraySize(array);
|
||||
//--- check array size
|
||||
if(size==0)
|
||||
return(-1);
|
||||
//--- check start index and count
|
||||
if(start_index<0 || start_index>size ||
|
||||
count<0 || count>size-start_index)
|
||||
return(-1);
|
||||
//--- search value
|
||||
int end_index=start_index+count;
|
||||
for(int i=start_index; i<end_index; i++)
|
||||
{
|
||||
//--- check the value in array is eqaul to specified value
|
||||
if(::Equals(array[i],value))
|
||||
{
|
||||
//--- return fist index
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
//--- return -1 if value not in array
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns the index of the last occurrence of a value in a |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int ArrayLastIndexOf(T &array[],T value,const int start_index,const int count)
|
||||
{
|
||||
int size=ArraySize(array);
|
||||
//--- check array size
|
||||
if(size==0)
|
||||
return(-1);
|
||||
//--- check start index and count
|
||||
if(start_index<0 || start_index>=size ||
|
||||
count<0 || count>start_index+1)
|
||||
return(-1);
|
||||
//--- search value
|
||||
int end_index=start_index-count+1;
|
||||
for(int i=start_index; i>=end_index; i--)
|
||||
{
|
||||
//--- check the value in array is eqaul to specified value
|
||||
if(::Equals(array[i],value))
|
||||
{
|
||||
//--- return fist index from the end
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
//--- return -1 if value not in array
|
||||
return(-1);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Reverses the elements in a range of this array. Following a call |
|
||||
//| to this method, an element in the range given by index and count |
|
||||
//| which was previously located at index i will now be located at |
|
||||
//| index index + (index + count - i - 1). |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool ArrayReverse(T &array[],const int start_index,const int count)
|
||||
{
|
||||
int size=ArraySize(array);
|
||||
//--- check start index and count
|
||||
if(count<0 || size-start_index<count)
|
||||
return(false);
|
||||
//--- reverse elements
|
||||
int i = start_index;
|
||||
int j = start_index + count - 1;
|
||||
while(i<j)
|
||||
{
|
||||
T temp=array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,209 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| CompareFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IComparable.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const bool x,const bool y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const char x,const char y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const uchar x,const uchar y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const short x,const short y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const ushort x,const ushort y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const color x,const color y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const int x,const int y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const uint x,const uint y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const datetime x,const datetime y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const long x,const long y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const ulong x,const ulong y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const float x,const float y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const double x,const double y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
int Compare(const string x,const string y)
|
||||
{
|
||||
if(x>y)
|
||||
return(1);
|
||||
else if(x<y)
|
||||
return(-1);
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Compares two objects and returns a value indicating whether one |
|
||||
//| is less than, equal to, or greater than the other. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int Compare(T x,T y)
|
||||
{
|
||||
//--- try to convert to comparable object
|
||||
IComparable<T>*comparable=dynamic_cast<IComparable<T>*>(x);
|
||||
if(comparable)
|
||||
{
|
||||
//--- use specied compare method
|
||||
return comparable.Compare(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- unknown compare function
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,22 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DefaultComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IComparer.mqh>
|
||||
#include "CompareFunction.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDefaultComparer<T>. |
|
||||
//| Usage: Provides a default class for implementations of the |
|
||||
//| IComparer<T> generic interface. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CDefaultComparer: public IComparer<T>
|
||||
{
|
||||
public:
|
||||
CDefaultComparer(void) { }
|
||||
~CDefaultComparer(void) { }
|
||||
//--- compares two values and returns a value describing relationship between them
|
||||
int Compare(T x,T y) { return ::Compare(x,y); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,25 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| DefaultEqualityComparer.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IEqualityComparer.mqh>
|
||||
#include "EqualFunction.mqh"
|
||||
#include "HashFunction.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CDefaultEqualityComparer<T>. |
|
||||
//| Usage: Provides a default class for implementations of the |
|
||||
//| IEqualityComparer<T> generic interface. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CDefaultEqualityComparer: public IEqualityComparer<T>
|
||||
{
|
||||
public:
|
||||
CDefaultEqualityComparer(void) { }
|
||||
~CDefaultEqualityComparer(void) { }
|
||||
//--- determines whether the specified values are equal
|
||||
bool Equals(T x,T y) { return ::Equals(x,y); }
|
||||
//--- returns a hash code for the specified object
|
||||
int HashCode(T value) { return ::GetHashCode(value); }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,26 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| EqualFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\IEqualityComparable.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Indicates whether x object is equal y object of the same type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool Equals(T x,T y)
|
||||
{
|
||||
//--- try to convert to equality comparable object
|
||||
IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(x);
|
||||
if(equtable)
|
||||
{
|
||||
//--- use specied equality compare method
|
||||
return equtable.Equals(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- use default equality comparer operator
|
||||
return(x==y);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,176 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HashFunction.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Unioun BitInterpreter. |
|
||||
//| Usage: Provides the ability to interpret the same bit sequence in|
|
||||
//| different types. |
|
||||
//+------------------------------------------------------------------+
|
||||
union BitInterpreter
|
||||
{
|
||||
bool bool_value;
|
||||
char char_value;
|
||||
uchar uchar_value;
|
||||
short short_value;
|
||||
ushort ushort_value;
|
||||
color color_value;
|
||||
int int_value;
|
||||
uint uint_value;
|
||||
datetime datetime_value;
|
||||
long long_value;
|
||||
ulong ulong_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for boolean. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const bool value)
|
||||
{
|
||||
return((value)?true:false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for character. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const char value)
|
||||
{
|
||||
return((int)value | ((int)value << 16));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned character. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const uchar value)
|
||||
{
|
||||
return((int)value | ((int)value << 16));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for short. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const short value)
|
||||
{
|
||||
return(((int)((ushort)value) | (((int)value) << 16)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned short. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const ushort value)
|
||||
{
|
||||
return((int)value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for color. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const color value)
|
||||
{
|
||||
return((int)value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for integer. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const int value)
|
||||
{
|
||||
return(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned integer. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const uint value)
|
||||
{
|
||||
return((int)value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for datetime. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const datetime value)
|
||||
{
|
||||
long ticks=(long)value;
|
||||
return(((int)ticks) ^ (int)(ticks >> 32));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for long. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const long value)
|
||||
{
|
||||
return(((int)((long)value)) ^ (int)(value >> 32));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for unsigned long. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const ulong value)
|
||||
{
|
||||
return(((int)value) ^ (int)(value >> 32));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for float. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const float value)
|
||||
{
|
||||
if(value==0)
|
||||
{
|
||||
//--- ensure that 0 and -0 have the same hash code
|
||||
return(0);
|
||||
}
|
||||
BitInterpreter convert;
|
||||
convert.float_value=value;
|
||||
return(convert.int_value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for string. |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const double value)
|
||||
{
|
||||
if(value==0)
|
||||
{
|
||||
//--- ensure that 0 and -0 have the same hash code
|
||||
return(0);
|
||||
}
|
||||
BitInterpreter convert;
|
||||
convert.double_value=value;
|
||||
long lvalue=convert.long_value;
|
||||
return(((int)lvalue) ^ ((int)(lvalue >> 32)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for string. |
|
||||
//| The hashcode for a string is computed as: |
|
||||
//| |
|
||||
//| s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] |
|
||||
//| |
|
||||
//| using int arithmetic, where s[i] is the ith character of the |
|
||||
//| string, n is the length of the string, and ^ indicates |
|
||||
//| exponentiation. (The hash value of the empty string is zero.) |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetHashCode(const string value)
|
||||
{
|
||||
int len=StringLen(value);
|
||||
int hash=0;
|
||||
//--- check length of string
|
||||
if(len>0)
|
||||
{
|
||||
//--- calculate a hash as a fucntion of each char
|
||||
for(int i=0; i<len; i++)
|
||||
hash=31*hash+value[i];
|
||||
}
|
||||
return(hash);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns a hashcode for custom object. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int GetHashCode(T value)
|
||||
{
|
||||
//--- try to convert to equality comparable object
|
||||
IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(value);
|
||||
if(equtable)
|
||||
{
|
||||
//--- calculate hash by specied method
|
||||
return equtable.HashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- calculate hash from name of object
|
||||
return GetHashCode(typename(value));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,244 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Introsort.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Struct Introsort<TKey,TItem>. |
|
||||
//| Usage: Used by the sort methods for instances of array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
struct Introsort
|
||||
{
|
||||
public:
|
||||
IComparer<TKey>* comparer;
|
||||
TKey keys[];
|
||||
TItem items[];
|
||||
|
||||
Introsort(void) {}
|
||||
~Introsort(void) {}
|
||||
//--- method for sort array
|
||||
void Sort(const int index,const int length);
|
||||
private:
|
||||
//--- methods for introspective sorting
|
||||
void IntroSort(const int lo,const int hi,int depthLimit);
|
||||
int PickPivotAndPartition(const int lo,const int hi);
|
||||
void InsertionSort(const int lo,const int hi);
|
||||
//--- methods for heap sorting
|
||||
void Heapsort(const int lo,const int hi);
|
||||
void DownHeap(const int i,const int n,const int lo);
|
||||
//--- swap methods
|
||||
void SwapIfGreaterWithItems(const int a,const int b);
|
||||
void Swap(const int i,const int j);
|
||||
//--- service methods
|
||||
int FloorLog2(int n) const;
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| IntrospectiveSort is a hybrid sorting algorithm that provides |
|
||||
//| both fast average performance and (asymptotically) optimal |
|
||||
//| worst-case performance. It begins with quicksort and switches to |
|
||||
//| heapsort when the recursion depth exceeds a level based on the |
|
||||
//| number of elements being sorted. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::Sort(const int index,const int length)
|
||||
{
|
||||
if(length<2)
|
||||
return;
|
||||
IntroSort(index,length+index-1,2*FloorLog2(ArraySize(keys)));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Exchanges the values of a and b, if a greater b. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::SwapIfGreaterWithItems(const int a,const int b)
|
||||
{
|
||||
if(a!=b)
|
||||
{
|
||||
if(comparer.Compare(keys[a],keys[b])>0)
|
||||
{
|
||||
TKey key=keys[a];
|
||||
keys[a]=keys[b];
|
||||
keys[b]=key;
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
TItem item=items[a];
|
||||
items[a]=items[b];
|
||||
items[b]=item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Exchanges the values of a and b. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::Swap(const int i,const int j)
|
||||
{
|
||||
TKey key=keys[i];
|
||||
keys[i]=keys[j];
|
||||
keys[j]=key;
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
TItem item=items[i];
|
||||
items[i]=items[j];
|
||||
items[j]=item;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns the closest integer value less than or equal to the base |
|
||||
//| 2 log of the input value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
int Introsort::FloorLog2(int n) const
|
||||
{
|
||||
int result=0;
|
||||
while(n>=1)
|
||||
{
|
||||
result++;
|
||||
n=n/2;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Introspective sort. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::IntroSort(const int lo,int hi,int depthLimit)
|
||||
{
|
||||
const int IntrosortSizeThreshold=16;
|
||||
while(hi>lo)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if(partitionSize <= IntrosortSizeThreshold)
|
||||
{
|
||||
if(partitionSize==1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(partitionSize==2)
|
||||
{
|
||||
SwapIfGreaterWithItems(lo,hi);
|
||||
return;
|
||||
}
|
||||
if(partitionSize==3)
|
||||
{
|
||||
SwapIfGreaterWithItems(lo,hi-1);
|
||||
SwapIfGreaterWithItems(lo,hi);
|
||||
SwapIfGreaterWithItems(hi-1,hi);
|
||||
return;
|
||||
}
|
||||
InsertionSort(lo,hi);
|
||||
return;
|
||||
}
|
||||
if(depthLimit==0)
|
||||
{
|
||||
Heapsort(lo,hi);
|
||||
return;
|
||||
}
|
||||
depthLimit--;
|
||||
int p=PickPivotAndPartition(lo,hi);
|
||||
IntroSort(p+1,hi,depthLimit);
|
||||
hi=p-1;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insertion sort. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::InsertionSort(const int lo,const int hi)
|
||||
{
|
||||
int i,j;
|
||||
TKey t;
|
||||
TItem dt;
|
||||
for(i=lo; i<hi; i++)
|
||||
{
|
||||
j = i;
|
||||
t = keys[i + 1];
|
||||
dt=(ArraySize(items)!=NULL) ? (TItem)items[i+1] : (TItem)NULL;
|
||||
while(j>=lo && comparer.Compare(t,keys[j])<0)
|
||||
{
|
||||
keys[j+1]=keys[j];
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
items[j+1]=items[j];
|
||||
}
|
||||
j--;
|
||||
}
|
||||
keys[j+1]=t;
|
||||
if(ArraySize(items)!=NULL)
|
||||
{
|
||||
items[j+1]=dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Array partitioning by a quick sort algorithm. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
int Introsort::PickPivotAndPartition(const int lo,const int hi)
|
||||
{
|
||||
//--- Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int mid=lo+(hi-lo)/2;
|
||||
SwapIfGreaterWithItems(lo,mid);
|
||||
SwapIfGreaterWithItems(lo,hi);
|
||||
SwapIfGreaterWithItems(mid,hi);
|
||||
TKey pivot=keys[mid];
|
||||
Swap(mid,hi-1);
|
||||
int left=lo,right=hi-1;
|
||||
while(left<right)
|
||||
{
|
||||
while(comparer.Compare(keys[++left], pivot) < 0);
|
||||
while(comparer.Compare(pivot, keys[--right]) < 0);
|
||||
if(left>=right)
|
||||
break;
|
||||
Swap(left,right);
|
||||
}
|
||||
//--- Put pivot in the right location.
|
||||
Swap(left,(hi-1));
|
||||
return (left);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Heap sorting algorithm. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::Heapsort(const int lo,const int hi)
|
||||
{
|
||||
int n=hi-lo+1;
|
||||
for(int i=n/2; i>=1; i=i-1)
|
||||
{
|
||||
DownHeap(i,n,lo);
|
||||
}
|
||||
for(int i=n; i>1; i=i-1)
|
||||
{
|
||||
Swap(lo,lo+i-1);
|
||||
DownHeap(1,i-1,lo);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Downheap function for heapsort. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename TKey,typename TItem>
|
||||
void Introsort::DownHeap(int i,const int n,const int lo)
|
||||
{
|
||||
bool f=ArraySize(items)!=0;
|
||||
TKey d=keys[lo+i-1];
|
||||
TItem dt=f ? (TItem)items[lo+i-1] : (TItem)NULL;
|
||||
|
||||
while(i<=n/2)
|
||||
{
|
||||
int child=2*i;
|
||||
if(child<n && comparer.Compare(keys[lo+child-1],keys[lo+child])<0)
|
||||
child++;
|
||||
if(!(comparer.Compare(d,keys[lo+child-1])<0))
|
||||
break;
|
||||
keys[lo+i-1]=keys[lo+child-1];
|
||||
if(f)
|
||||
items[lo+i-1]=items[lo+child-1];
|
||||
i=child;
|
||||
}
|
||||
keys[lo+i-1]=d;
|
||||
if(f)
|
||||
items[lo+i-1]=dt;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,81 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PrimeGenerator.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPrimeGenrator. |
|
||||
//| Usage: Used to generate prime numbers. |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPrimeGenerator
|
||||
{
|
||||
private:
|
||||
const static int s_primes[]; // table of prime numbers
|
||||
const static int s_hash_prime;
|
||||
|
||||
public:
|
||||
static bool IsPrime(const int candidate);
|
||||
static int GetPrime(const int min);
|
||||
static int ExpandPrime(const int old_size);
|
||||
};
|
||||
const static int CPrimeGenerator::s_primes[]=
|
||||
{
|
||||
3,7,11,17,23,29,37,47,59,71,89,107,131,163,197,239,293,353,431,521,631,761,919,
|
||||
1103,1327,1597,1931,2333,2801,3371,4049,4861,5839,7013,8419,10103,12143,14591,
|
||||
17519,21023,25229,30293,36353,43627,52361,62851,75431,90523,108631,130363,156437,
|
||||
187751,225307,270371,324449,389357,467237,560689,672827,807403,968897,1162687,1395263,
|
||||
1674319,2009191,2411033,2893249,3471899,4166287,4999559,5999471,7199369,8332579,
|
||||
9999161,11998949,14398753,16665163,19998337,23997907,28797523,33330329,39996683,
|
||||
47995853,57595063,66660701,79993367,95991737,115190149,133321403,159986773,191983481,
|
||||
230380307,266642809,319973567,383966977,460760623,533285671,639947149,767933981,
|
||||
921521257,1066571383,1279894313,1535867969,1843042529,2133142771
|
||||
};
|
||||
const static int CPrimeGenerator::s_hash_prime=101;
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a value is prime. |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPrimeGenerator::IsPrime(const int candidate)
|
||||
{
|
||||
if((candidate&1)!=0)
|
||||
{
|
||||
int limit=(int)MathSqrt(candidate);
|
||||
//--- check value is prime
|
||||
for(int divisor=3; divisor<=limit; divisor+=2)
|
||||
if((candidate%divisor)==0)
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
return(candidate==2);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Fast generator of prime value. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CPrimeGenerator::GetPrime(const int min)
|
||||
{
|
||||
//--- a typical resize algorithm would pick the smallest prime number in this array
|
||||
//--- that is larger than twice the previous capacity.
|
||||
//--- get next prime value from table
|
||||
for(int i=0; i<ArraySize(s_primes); i++)
|
||||
{
|
||||
int prime=s_primes[i];
|
||||
if(prime>=min)
|
||||
return(prime);
|
||||
}
|
||||
//--- outside of our predefined table
|
||||
for(int i=(min|1); i<=INT_MAX;i+=2)
|
||||
{
|
||||
if(IsPrime(i) && ((i-1)%s_hash_prime!=0))
|
||||
return(i);
|
||||
}
|
||||
return(min);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Generate a new prime value greater than old_size. |
|
||||
//+------------------------------------------------------------------+
|
||||
int CPrimeGenerator::ExpandPrime(const int old_size)
|
||||
{
|
||||
if(old_size>=INT_MAX/2)
|
||||
return(INT_MAX);
|
||||
return(GetPrime(old_size*2));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,563 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| LinkedList.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\ICollection.mqh>
|
||||
#include <Generic\Internal\EqualFunction.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLinkedListNode<T>. |
|
||||
//| Usage: Represents a node of linked list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CLinkedListNode
|
||||
{
|
||||
protected:
|
||||
CLinkedList<T>*m_list;
|
||||
CLinkedListNode<T>*m_next;
|
||||
CLinkedListNode<T>*m_prev;
|
||||
T m_item;
|
||||
|
||||
public:
|
||||
CLinkedListNode(T value): m_item(value) { }
|
||||
CLinkedListNode(CLinkedList<T>*list,T value): m_list(list),m_item(value) { }
|
||||
~CLinkedListNode(void) { }
|
||||
//--- methods of access to protected data
|
||||
CLinkedList<T>* List(void) { return(m_list); }
|
||||
void List(CLinkedList<T>*value) { m_list=value; }
|
||||
CLinkedListNode<T>*Next(void) { return(m_next); }
|
||||
void Next(CLinkedListNode<T>*value) { m_next=value; }
|
||||
CLinkedListNode<T>*Previous(void) { return(m_prev); }
|
||||
void Previous(CLinkedListNode<T>*value) { m_prev=value; }
|
||||
T Value(void) { return(m_item); }
|
||||
void Value(T value) { m_item=value; }
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLinkedList<T>. |
|
||||
//| Usage: Represents a doubly linked list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CLinkedList: public ICollection<T>
|
||||
{
|
||||
protected:
|
||||
CLinkedListNode<T>*m_head;
|
||||
int m_count;
|
||||
|
||||
public:
|
||||
CLinkedList(void);
|
||||
CLinkedList(ICollection<T>*collection);
|
||||
CLinkedList(T &array[]);
|
||||
~CLinkedList(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
CLinkedListNode<T>*AddAfter(CLinkedListNode<T>*node,T value);
|
||||
bool AddAfter(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node);
|
||||
CLinkedListNode<T>*AddBefore(CLinkedListNode<T>*node,T value);
|
||||
bool AddBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node);
|
||||
CLinkedListNode<T>*AddFirst(T value);
|
||||
bool AddFirst(CLinkedListNode<T>*node);
|
||||
CLinkedListNode<T>*AddLast(T value);
|
||||
bool AddLast(CLinkedListNode<T>*node);
|
||||
//--- methods of access to protected data
|
||||
int Count(void);
|
||||
CLinkedListNode<T>*Head(void) {return(m_head);}
|
||||
CLinkedListNode<T>*First(void);
|
||||
CLinkedListNode<T>*Last(void);
|
||||
bool Contains(T item);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
bool Remove(CLinkedListNode<T>*node);
|
||||
bool RemoveFirst(void);
|
||||
bool RemoveLast(void);
|
||||
//--- method for searching
|
||||
CLinkedListNode<T>*Find(T value);
|
||||
CLinkedListNode<T>*FindLast(T value);
|
||||
|
||||
private:
|
||||
bool ValidateNode(CLinkedListNode<T>*node);
|
||||
bool ValidateNewNode(CLinkedListNode<T>*node);
|
||||
void InternalInsertNodeBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node);
|
||||
void InternalInsertNodeToEmptyList(CLinkedListNode<T>*new_node);
|
||||
void InternalRemoveNode(CLinkedListNode<T>*node);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CLinkedList<T> class that is |
|
||||
//| empty. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::CLinkedList(void): m_count(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CLinkedList<T> class that |
|
||||
//| contains elements copied from the specified array and has |
|
||||
//| sufficient capacity to accommodate the number of elements copied.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::CLinkedList(T &array[]): m_count(0)
|
||||
{
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
AddLast(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CLinkedList<T> class that |
|
||||
//| contains elements copied from the specified collection and has |
|
||||
//| sufficient capacity to accommodate the number of elements copied.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::CLinkedList(ICollection<T>*collection): m_count(0)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)!=POINTER_INVALID)
|
||||
{
|
||||
T array[];
|
||||
int size=collection.CopyTo(array,0);
|
||||
for(int i=0; i<size; i++)
|
||||
AddLast(array[i]);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedList::~CLinkedList(void)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds an value to the end of the list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Add(T value)
|
||||
{
|
||||
return(CheckPointer(AddLast(value))!=POINTER_INVALID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value after the |
|
||||
//| specified existing node in the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddAfter(CLinkedListNode<T>*node,T value)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(NULL);
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*result=new CLinkedListNode<T>(node.List(),value);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node.Next(),result);
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node after the specified existing node in |
|
||||
//| the LinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddAfter(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(false);
|
||||
//--- check new node
|
||||
if(!ValidateNewNode(new_node))
|
||||
return(false);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node.Next(),new_node);
|
||||
//--- set the current list as list for new node
|
||||
new_node.List(GetPointer(this));
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value before the |
|
||||
//| specified existing node in the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddBefore(CLinkedListNode<T>*node,T value)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(NULL);
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*result=new CLinkedListNode<T>(node.List(),value);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node,result);
|
||||
if(node==m_head)
|
||||
m_head=result;
|
||||
return(result);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node before the specified existing node in|
|
||||
//| the LinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNode(node))
|
||||
return(false);
|
||||
//--- check new node
|
||||
if(!ValidateNewNode(new_node))
|
||||
return(false);
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(node,new_node);
|
||||
//--- set the current list as list for new node
|
||||
new_node.List(GetPointer(this));
|
||||
if(node==m_head)
|
||||
m_head=new_node;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value at the start of |
|
||||
//| the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddFirst(T value)
|
||||
{
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*node=new CLinkedListNode<T>(GetPointer(this),value);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
m_head=node;
|
||||
}
|
||||
return(node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node at the start of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddFirst(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNewNode(node))
|
||||
return(false);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
m_head=node;
|
||||
}
|
||||
//--- set the current list as list for node
|
||||
node.List(GetPointer(this));
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds a new node containing the specified value at the end of the |
|
||||
//| CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::AddLast(T value)
|
||||
{
|
||||
//--- create new node
|
||||
CLinkedListNode<T>*node=new CLinkedListNode<T>(GetPointer(this),value);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
}
|
||||
return(node);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds the specified new node at the end of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::AddLast(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(!ValidateNewNode(node))
|
||||
return(false);
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
{
|
||||
//--- insert node to the empty list
|
||||
InternalInsertNodeToEmptyList(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- insert node to the list
|
||||
InternalInsertNodeBefore(m_head,node);
|
||||
}
|
||||
//--- set the current list as list for node
|
||||
node.List(GetPointer(this));
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether an element is in the linked list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CLinkedList::Count(void)
|
||||
{
|
||||
return(m_count);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the first node of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::First(void)
|
||||
{
|
||||
return(m_head);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the last node of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::Last(void)
|
||||
{
|
||||
return(CheckPointer(m_head)!=POINTER_INVALID ? m_head.Previous() : NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a value is in the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Contains(T item)
|
||||
{
|
||||
return(CheckPointer(Find(item))!=POINTER_INVALID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the linkedlist to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CLinkedList::CopyTo(T &dst_array[],const int dst_start=0)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_count>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_count);
|
||||
//--- check start index
|
||||
if(dst_start>ArraySize(dst_array))
|
||||
return(0);
|
||||
//--- start copy
|
||||
CLinkedListNode<T>*node=m_head;
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
int dst_index=dst_start;
|
||||
do
|
||||
{
|
||||
dst_array[dst_index++]=node.Value();
|
||||
node=node.Next();
|
||||
}
|
||||
while(dst_index<ArraySize(dst_array) && node!=m_head);
|
||||
return(dst_index-dst_start);
|
||||
}
|
||||
//--- list is empty
|
||||
return(0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all nodes from the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::Clear(void)
|
||||
{
|
||||
//--- check count
|
||||
if(m_count>0)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)!=POINTER_INVALID)
|
||||
{
|
||||
while(m_head.Next()!=m_head)
|
||||
{
|
||||
CLinkedListNode<T>*node=m_head.Next();
|
||||
m_head.Next(node.Next());
|
||||
delete node;
|
||||
}
|
||||
delete m_head;
|
||||
}
|
||||
//--- reset count
|
||||
m_count=0;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the first occurrence of the specified value from the |
|
||||
//| CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Remove(T item)
|
||||
{
|
||||
//--- find node with specified value
|
||||
CLinkedListNode<T>*node=Find(item);
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
//--- remove node
|
||||
InternalRemoveNode(node);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the specified node from the LinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::Remove(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(ValidateNode(node))
|
||||
{
|
||||
//--- remove node
|
||||
InternalRemoveNode(node);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the node at the start of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::RemoveFirst(void)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- remove head node
|
||||
InternalRemoveNode(m_head);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the node at the end of the CLinkedList<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::RemoveLast(void)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- remove last node
|
||||
InternalRemoveNode(m_head.Previous());
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Finds the first node that contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::Find(T value)
|
||||
{
|
||||
CLinkedListNode<T>*node=m_head;
|
||||
//--- start search specified value in the list
|
||||
if(CheckPointer(node)!=POINTER_INVALID)
|
||||
{
|
||||
do
|
||||
{
|
||||
//--- use default equals function
|
||||
if(::Equals(node.Value(),value))
|
||||
return(node);
|
||||
node=node.Next();
|
||||
}
|
||||
while(node!=m_head);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Finds the last node that contains the specified value. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CLinkedListNode<T>*CLinkedList::FindLast(T value)
|
||||
{
|
||||
//--- check head node
|
||||
if(CheckPointer(m_head)==POINTER_INVALID)
|
||||
return(NULL);
|
||||
//--- get last node
|
||||
CLinkedListNode<T> *last = m_head.Previous();
|
||||
CLinkedListNode<T> *node = last;
|
||||
//--- start search from the end of the list
|
||||
if(node!=NULL)
|
||||
{
|
||||
do
|
||||
{
|
||||
//--- use default equals function
|
||||
if(::Equals(node.Value(),value))
|
||||
return(node);
|
||||
node=node.Previous();
|
||||
}
|
||||
while(node!=last);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation of node on not null and belongs in the current list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::ValidateNode(CLinkedListNode<T>*node)
|
||||
{
|
||||
return(CheckPointer(node)!=POINTER_INVALID && node.List()==GetPointer(this));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Validation of new node on not null. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CLinkedList::ValidateNewNode(CLinkedListNode<T>*node)
|
||||
{
|
||||
return(CheckPointer(node)!=POINTER_INVALID && node.List()==NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Insert node before the specified node. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::InternalInsertNodeBefore(CLinkedListNode<T>*node,CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- set node befor the specified node
|
||||
new_node.Next(node);
|
||||
new_node.Previous(node.Previous());
|
||||
node.Previous().Next(new_node);
|
||||
node.Previous(new_node);
|
||||
//--- increment count
|
||||
m_count++;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add first node to the list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::InternalInsertNodeToEmptyList(CLinkedListNode<T>*new_node)
|
||||
{
|
||||
//--- set node as head of the list
|
||||
new_node.Next(new_node);
|
||||
new_node.Previous(new_node);
|
||||
m_head=new_node;
|
||||
//--- increment count
|
||||
m_count++;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Remove specified node from the list. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CLinkedList::InternalRemoveNode(CLinkedListNode<T>*node)
|
||||
{
|
||||
//--- check node
|
||||
if(node.Next()==node)
|
||||
{
|
||||
//--- resets the head of the list
|
||||
m_head=NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- detach node from the list
|
||||
node.Next().Previous(node.Previous());
|
||||
node.Previous().Next(node.Next());
|
||||
if(m_head==node)
|
||||
m_head=node.Next();
|
||||
}
|
||||
//--- decrement count and delete node
|
||||
m_count--;
|
||||
delete node;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,341 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SortedMap.mqh |
|
||||
//| Copyright 2000-2024, 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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,673 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SortedList.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\ISet.mqh>
|
||||
#include <Generic\Internal\Introsort.mqh>
|
||||
#include "RedBlackTree.mqh"
|
||||
#include "HashSet.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CSortedSet<T>. |
|
||||
//| Usage: Represents a collection of objects that is maintained in |
|
||||
//| sorted order. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CSortedSet: public ISet<T>
|
||||
{
|
||||
protected:
|
||||
CRedBlackTree<T>*m_tree;
|
||||
|
||||
public:
|
||||
CSortedSet(void);
|
||||
CSortedSet(IComparer<T>*comparer);
|
||||
CSortedSet(ICollection<T>*collection);
|
||||
CSortedSet(ICollection<T>*collection,IComparer<T>*comparer);
|
||||
CSortedSet(T &array[]);
|
||||
CSortedSet(T &array[],IComparer<T>*comparer);
|
||||
~CSortedSet(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value) { return(m_tree.Add(value)); }
|
||||
//--- methods of access to protected data
|
||||
int Count(void) { return(m_tree.Count()); }
|
||||
bool Contains(T item) { return(m_tree.Contains(item)); }
|
||||
IComparer<T> *Comparer(void) const { return(m_tree.Comparer()); }
|
||||
bool TryGetMin(T &min) { return(m_tree.TryGetMin(min)); }
|
||||
bool TryGetMax(T &max) { return(m_tree.TryGetMax(max)); }
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and deleting
|
||||
void Clear(void) { m_tree.Clear(); }
|
||||
bool Remove(T item) { return(m_tree.Remove(item)); }
|
||||
//--- methods of changing sets
|
||||
void ExceptWith(ICollection<T>*collection);
|
||||
void ExceptWith(T &array[]);
|
||||
void IntersectWith(ICollection<T>*collection);
|
||||
void IntersectWith(T &array[]);
|
||||
void SymmetricExceptWith(ICollection<T>*collection);
|
||||
void SymmetricExceptWith(T &array[]);
|
||||
void UnionWith(ICollection<T>*collection);
|
||||
void UnionWith(T &array[]);
|
||||
//--- methods for determining the relationship between sets
|
||||
bool IsProperSubsetOf(ICollection<T>*collection);
|
||||
bool IsProperSubsetOf(T &array[]);
|
||||
bool IsProperSupersetOf(ICollection<T>*collection);
|
||||
bool IsProperSupersetOf(T &array[]);
|
||||
bool IsSubsetOf(ICollection<T>*collection);
|
||||
bool IsSubsetOf(T &array[]);
|
||||
bool IsSupersetOf(ICollection<T>*collection);
|
||||
bool IsSupersetOf(T &array[]);
|
||||
bool Overlaps(ICollection<T>*collection);
|
||||
bool Overlaps(T &array[]);
|
||||
bool SetEquals(ICollection<T>*collection);
|
||||
bool SetEquals(T &array[]);
|
||||
//--- methods for working with an ordered set
|
||||
bool GetViewBetween(T &array[],T lower_value,T upper_value);
|
||||
bool GetReverse(T &array[]);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that is |
|
||||
//| empty and uses the default equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(void)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that is |
|
||||
//| empty and uses the specified equality comparer for the set type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(IComparer<T>*comparer)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(comparer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the default equality comparer for the set type, contains elements|
|
||||
//| copied from the specified collection, and has sufficient capacity|
|
||||
//| to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(ICollection<T>*collection)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(collection);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the specified equality comparer for the set type, contains |
|
||||
//| elements copied from the specified collection, and has sufficient|
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(ICollection<T>*collection,IComparer<T>*comparer)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(collection,comparer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the default equality comparer for the set type, contains |
|
||||
//| elements copied from the specified array, and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(T &array[])
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CSortedSet<T> class that uses |
|
||||
//| the specified equality comparer for the set type, contains |
|
||||
//| elements copied from the specified array, and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::CSortedSet(T &array[],IComparer<T>*comparer)
|
||||
{
|
||||
m_tree=new CRedBlackTree<T>(array,comparer);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CSortedSet::~CSortedSet(void)
|
||||
{
|
||||
delete m_tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the set to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CSortedSet::CopyTo(T &dst_array[],const int dst_start=0)
|
||||
{
|
||||
return(m_tree.CopyTo(dst_array, dst_start));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified collection from the current|
|
||||
//| set. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::ExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- special case if collection is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- copy collection to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- find max and min value
|
||||
T max;
|
||||
T min;
|
||||
//--- get comaprer
|
||||
IComparer<T>*comparer=Comparer();
|
||||
if(!m_tree.TryGetMax(max))
|
||||
return;
|
||||
if(!m_tree.TryGetMin(min))
|
||||
return;
|
||||
//--- remove elements
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
T item=array[i];
|
||||
if(!(comparer.Compare(item,min)<0 || comparer.Compare(item,max)>0) && Contains(item))
|
||||
m_tree.Remove(item);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all elements in the specified array from the current set.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::ExceptWith(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- get array size
|
||||
int size=ArraySize(array);
|
||||
//--- find max and min value
|
||||
T max;
|
||||
T min;
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=Comparer();
|
||||
if(!m_tree.TryGetMax(max))
|
||||
return;
|
||||
if(!m_tree.TryGetMin(min))
|
||||
return;
|
||||
//--- remove elements
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
T item=array[i];
|
||||
if(!(comparer.Compare(item,min)<0 || comparer.Compare(item,max)>0) && Contains(item))
|
||||
m_tree.Remove(item);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::IntersectWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- special case if collection is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
return;
|
||||
//--- copy collection to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- create emty tree
|
||||
CRedBlackTree<T>*tree=new CRedBlackTree<T>();
|
||||
//--- store values conatin in tree and array
|
||||
for(int i=0; i<size; i++)
|
||||
if(m_tree.Contains(array[i]))
|
||||
tree.Add(array[i]);
|
||||
//--- overwrite tree
|
||||
delete m_tree;
|
||||
m_tree=tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present in that object and in the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::IntersectWith(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return;
|
||||
//--- get array size
|
||||
int size=ArraySize(array);
|
||||
//--- create emty tree
|
||||
CRedBlackTree<T>*tree=new CRedBlackTree<T>();
|
||||
//--- store values conatin in tree and array
|
||||
for(int i=0; i<size; i++)
|
||||
if(m_tree.Contains(array[i]))
|
||||
tree.Add(array[i]);
|
||||
//--- overwrite tree
|
||||
delete m_tree;
|
||||
m_tree=tree;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified collection, but |
|
||||
//| not both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::SymmetricExceptWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
{
|
||||
UnionWith(collection);
|
||||
return;
|
||||
}
|
||||
//--- special case if collection is this
|
||||
//--- a set minus itself is the empty set
|
||||
if(collection==GetPointer(this))
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
//--- copy colleaction to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=m_tree.Comparer();
|
||||
//--- sort array
|
||||
Introsort<T,T>sort;
|
||||
ArrayCopy(sort.keys,array);
|
||||
sort.comparer=comparer;
|
||||
sort.Sort(0, size);
|
||||
ArrayCopy(array,sort.keys);
|
||||
//--- modify tree
|
||||
T last=array[0];
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
while(i<size && i!=0 && comparer.Compare(array[i],last)==0)
|
||||
i++;
|
||||
if(i>=size)
|
||||
break;
|
||||
|
||||
if(m_tree.Contains(array[i]))
|
||||
m_tree.Remove(array[i]);
|
||||
else
|
||||
m_tree.Add(array[i]);
|
||||
|
||||
last=array[i];
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain only elements that are |
|
||||
//| present either in that set or in the specified array, but not |
|
||||
//| both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::SymmetricExceptWith(T &array[])
|
||||
{
|
||||
//--- check array size
|
||||
if(ArraySize(array)==0)
|
||||
return;
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
{
|
||||
UnionWith(array);
|
||||
return;
|
||||
}
|
||||
//--- get size
|
||||
int size=ArraySize(array);
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=m_tree.Comparer();
|
||||
//--- sort array
|
||||
Introsort<T,T>sort;
|
||||
ArrayCopy(sort.keys,array);
|
||||
sort.comparer=comparer;
|
||||
sort.Sort(0, size);
|
||||
ArrayReverse(sort.keys,0,ArraySize(sort.keys));
|
||||
//--- modify tree
|
||||
T last=sort.keys[0];
|
||||
for(int i=0; i<size; i++)
|
||||
{
|
||||
while(i<size && i!=0 && comparer.Compare(sort.keys[i],last)==0)
|
||||
i++;
|
||||
if(i>=size)
|
||||
break;
|
||||
|
||||
if(m_tree.Contains(sort.keys[i]))
|
||||
m_tree.Remove(sort.keys[i]);
|
||||
else
|
||||
m_tree.Add(sort.keys[i]);
|
||||
|
||||
last=sort.keys[i];
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified collection, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::UnionWith(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return;
|
||||
//--- copy all elements from collecton to array
|
||||
T array[];
|
||||
int size=collection.CopyTo(array);
|
||||
//--- add all elemets from array to set
|
||||
for(int i=0; i<size; i++)
|
||||
m_tree.Add(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Modifies the current set to contain all elements that are present|
|
||||
//| in itself, the specified array, or both. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CSortedSet::UnionWith(T &array[])
|
||||
{
|
||||
//--- get array size
|
||||
int size=ArraySize(array);
|
||||
//--- add all elemets from array to set
|
||||
for(int i=0; i<size; i++)
|
||||
m_tree.Add(array[i]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(collection.Count() > 0);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper subset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSubsetOf(T &array[])
|
||||
{
|
||||
if(m_tree.Count()==0)
|
||||
return(ArraySize(array) > 0);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
if(m_tree.Count()>=set.Count())
|
||||
return(false);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_tree.Count()>0);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.IsProperSubsetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsProperSubsetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a proper superset of the specified |
|
||||
//| array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsProperSupersetOf(T &array[])
|
||||
{
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return(set.IsProperSubsetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified collection.|
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSubsetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- cehck collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_tree.Count()==0);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)==POINTER_DYNAMIC)
|
||||
{
|
||||
return(ptr_set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a subset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSubsetOf(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
if(m_tree.Count()>set.Count())
|
||||
return(false);
|
||||
return(set.IsProperSupersetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified |
|
||||
//| collection. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSupersetOf(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(m_tree.Count()>=0);
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return(true);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.IsSupersetOf(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.IsSupersetOf(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set is a superset of the specified array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::IsSupersetOf(T &array[])
|
||||
{
|
||||
//--- check array size
|
||||
if(ArraySize(array)==0)
|
||||
return(true);
|
||||
//--- create a set based on a specified array
|
||||
CHashSet<T>set(array);
|
||||
return(set.IsSupersetOf(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified collection |
|
||||
//| share common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::Overlaps(ICollection<T>*collection)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
//--- check collection count
|
||||
if(collection.Count()==0)
|
||||
return(false);
|
||||
//--- check collection is set
|
||||
CHashSet<T>*ptr_set=dynamic_cast<CHashSet<T>*>(collection);
|
||||
if(CheckPointer(ptr_set)!=POINTER_INVALID)
|
||||
{
|
||||
return(ptr_set.Overlaps(m_tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- create a set based on a specified collection
|
||||
CHashSet<T>set(collection);
|
||||
return(set.Overlaps(m_tree));
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether the current set and a specified array share |
|
||||
//| common elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::Overlaps(T &array[])
|
||||
{
|
||||
//--- check tree count
|
||||
if(m_tree.Count()==0)
|
||||
return(false);
|
||||
//--- check array size
|
||||
if(ArraySize(array)==0)
|
||||
return(false);
|
||||
//--- convert array to set
|
||||
CHashSet<T>set(array);
|
||||
return(set.Overlaps(m_tree));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified collection contain the|
|
||||
//| same elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::SetEquals(ICollection<T>*collection)
|
||||
{
|
||||
if(CheckPointer(collection)==POINTER_INVALID)
|
||||
return(false);
|
||||
//--- get array from collection
|
||||
T array[];
|
||||
collection.CopyTo(array);
|
||||
//--- check current set is equal specified array
|
||||
return SetEquals(array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Determines whether a set and the specified array contain the same|
|
||||
//| elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::SetEquals(T &array[])
|
||||
{
|
||||
//--- try find all elements in the tree
|
||||
for(int i=0; i<ArraySize(array); i++)
|
||||
if(!m_tree.Contains(array[i]))
|
||||
return(false);
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copy a view of a subset in a CSortedSet<T> to array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::GetViewBetween(T &array[],T lower_value,T upper_value)
|
||||
{
|
||||
//--- get comparer
|
||||
IComparer<T>*comparer=m_tree.Comparer();
|
||||
if(comparer.Compare(lower_value,upper_value)>0)
|
||||
return(false);
|
||||
//--- copy all element from tree to array
|
||||
T buff[];
|
||||
int size=m_tree.CopyTo(buff);
|
||||
//--- check range
|
||||
if(size==0 || comparer.Compare(buff[0],upper_value)>0 || comparer.Compare(buff[size-1],lower_value)<0)
|
||||
return(false);
|
||||
//--- find first element greater than lower_value
|
||||
int index_lower=0;
|
||||
while(index_lower<size && comparer.Compare(buff[index_lower],lower_value)<0)
|
||||
index_lower++;
|
||||
//--- find first element less than upper_value
|
||||
int index_upper=size-1;
|
||||
while(index_upper>0 && comparer.Compare(buff[index_upper],upper_value)>0)
|
||||
index_upper--;
|
||||
//--- check indices
|
||||
if(index_lower>index_upper)
|
||||
return(false);
|
||||
//--- copy view between lower_value and upper_value to array
|
||||
return(ArrayCopy(array,buff,0,index_lower,index_upper-index_lower+1)>=0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copy the CSortedSet<T> in reverse order to array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CSortedSet::GetReverse(T &array[])
|
||||
{
|
||||
int size=m_tree.CopyTo(array);
|
||||
return ArrayReverse(array,0,size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,227 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stack.mqh |
|
||||
//| Copyright 2000-2024, MetaQuotes Ltd. |
|
||||
//| https://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include <Generic\Interfaces\ICollection.mqh>
|
||||
#include <Generic\Internal\ArrayFunction.mqh>
|
||||
#include <Generic\Internal\EqualFunction.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CStack<T>. |
|
||||
//| Usage: Represents a variable size last-in-first-out (LIFO) |
|
||||
//| collection of instances of the same specified type. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
class CStack: public ICollection<T>
|
||||
{
|
||||
protected:
|
||||
T m_array[];
|
||||
int m_size;
|
||||
const int m_default_capacity;
|
||||
|
||||
public:
|
||||
CStack(void);
|
||||
CStack(const int capacity);
|
||||
CStack(ICollection<T>&collection[]);
|
||||
CStack(T &array[]);
|
||||
~CStack(void);
|
||||
//--- methods of filling data
|
||||
bool Add(T value);
|
||||
bool Push(T value);
|
||||
//--- methods of access to protected data
|
||||
int Count(void);
|
||||
bool Contains(T item);
|
||||
void TrimExcess(void);
|
||||
//--- methods of copy data from collection
|
||||
int CopyTo(T &dst_array[],const int dst_start=0);
|
||||
//--- methods of cleaning and removing
|
||||
void Clear(void);
|
||||
bool Remove(T item);
|
||||
//--- methods of access to protected data
|
||||
T Peek(void);
|
||||
T Pop(void);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that is empty |
|
||||
//| and has the default initial capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(void): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that is empty |
|
||||
//| and has the specified initial capacity or the default initial |
|
||||
//| capacity, whichever is greater. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(const int capacity): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
ArrayResize(m_array,capacity);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that contains |
|
||||
//| elements copied from the specified array and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(T &array[]): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
m_size=ArrayCopy(m_array,array);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Initializes a new instance of the CStack<T> class that contains |
|
||||
//| elements copied from the specified collection and has sufficient |
|
||||
//| capacity to accommodate the number of elements copied. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::CStack(ICollection<T>*collection): m_default_capacity(4),
|
||||
m_size(0)
|
||||
{
|
||||
//--- check collection
|
||||
if(CheckPointer(collection)!=POINTER_INVALID)
|
||||
m_size=collection.CopyTo(m_array,0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
CStack::~CStack(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts an value at the top of the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Add(T value)
|
||||
{
|
||||
return Push(value);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Gets the number of elements. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CStack::Count(void)
|
||||
{
|
||||
return(m_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all values from the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Contains(T item)
|
||||
{
|
||||
int count=m_size;
|
||||
//--- try to find item in array
|
||||
while(count-->0)
|
||||
{
|
||||
//--- use default equality function
|
||||
if(::Equals(m_array[count],item))
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Copies a range of elements from the stack to a compatible |
|
||||
//| one-dimensional array. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
int CStack::CopyTo(T &dst_array[],const int dst_start=0)
|
||||
{
|
||||
//--- resize array
|
||||
if(dst_start+m_size>ArraySize(dst_array))
|
||||
ArrayResize(dst_array,dst_start+m_size);
|
||||
//--- start copy
|
||||
int src_index = m_size-1;
|
||||
int dst_index = dst_start;
|
||||
while(src_index>=0 && dst_index<ArraySize(dst_array))
|
||||
dst_array[dst_index++]=m_array[src_index--];
|
||||
return(dst_index-dst_start);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes all values from the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CStack::Clear(void)
|
||||
{
|
||||
//--- check current size
|
||||
if(m_size>0)
|
||||
{
|
||||
ZeroMemory(m_array);
|
||||
m_size=0;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes the first occurrence of a specific value from the stack. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Remove(T item)
|
||||
{
|
||||
//--- find index of item
|
||||
int index=ArrayIndexOf(m_array,item,0,m_size);
|
||||
//--- check index
|
||||
if(index==-1)
|
||||
return(false);
|
||||
//--- shift the values to the left
|
||||
ArrayCopy(m_array,m_array,index,index+1);
|
||||
//--- decrement size
|
||||
m_size--;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts an values at the top of the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
bool CStack::Push(T value)
|
||||
{
|
||||
int size=ArraySize(m_array);
|
||||
//--- check array size
|
||||
if(m_size==size)
|
||||
{
|
||||
//--- increase capacity
|
||||
if(size==0)
|
||||
ArrayResize(m_array,m_default_capacity);
|
||||
else
|
||||
ArrayResize(m_array,2*size);
|
||||
}
|
||||
//--- add value to the end
|
||||
m_array[m_size++]=value;
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Returns the value at the top of the CStack<T> without removing. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
T CStack::Peek(void)
|
||||
{
|
||||
//--- return last value
|
||||
return(m_array[m_size-1]);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Removes and returns the value at the top of the CStack<T>. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
T CStack::Pop(void)
|
||||
{
|
||||
//--- return last value and decrement size
|
||||
T item=m_array[--m_size];
|
||||
return(item);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets the capacity to the actual number of elements in the |
|
||||
//| CStack<T>, if that number is less than 90 percent of current |
|
||||
//| capacity. |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename T>
|
||||
void CStack::TrimExcess(void)
|
||||
{
|
||||
//--- calculate threshold value
|
||||
int threshold=(int)(((double)ArraySize(m_array)*0.9));
|
||||
//--- calculate resize array
|
||||
if(m_size<threshold)
|
||||
ArrayResize(m_array,m_size);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user