Add files via upload

This commit is contained in:
amirghadiri1987
2025-02-07 19:08:31 +03:30
committed by GitHub
parent c33ac55f2f
commit a9340e5d4e
85 changed files with 15214 additions and 0 deletions
Binary file not shown.
+622
View File
@@ -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;
//+------------------------------------------------------------------+
+972
View File
@@ -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);
}
//+------------------------------------------------------------------+
+24
View File
@@ -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);
};
//+------------------------------------------------------------------+
+19
View File
@@ -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);
};
//+------------------------------------------------------------------+
+17
View File
@@ -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);
};
//+------------------------------------------------------------------+
+19
View File
@@ -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);
};
//+------------------------------------------------------------------+
+26
View File
@@ -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);
};
//+------------------------------------------------------------------+
+27
View File
@@ -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);
};
//+------------------------------------------------------------------+
+37
View File
@@ -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[]);
};
//+------------------------------------------------------------------+
+135
View File
@@ -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);
}
//+------------------------------------------------------------------+
+209
View File
@@ -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);
}
}
//+------------------------------------------------------------------+
+22
View File
@@ -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); }
};
//+------------------------------------------------------------------+
+26
View File
@@ -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);
}
}
//+------------------------------------------------------------------+
+176
View File
@@ -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));
}
}
//+------------------------------------------------------------------+
+244
View File
@@ -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;
}
//+------------------------------------------------------------------+
+81
View File
@@ -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));
}
//+------------------------------------------------------------------+
+563
View File
@@ -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;
}
//+------------------------------------------------------------------+
BIN
View File
Binary file not shown.
Binary file not shown.
+341
View File
@@ -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);
}
//+------------------------------------------------------------------+
+673
View File
@@ -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);
}
//+------------------------------------------------------------------+
+227
View File
@@ -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);
}
//+------------------------------------------------------------------+