972 lines
35 KiB
MQL5
972 lines
35 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| HashSet.mqh |
| |||
//| Copyright 2000-2025, 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);
| |||
}
| |||
//+------------------------------------------------------------------+
|