//+------------------------------------------------------------------+
//|                                                      HashMap.mqh |
//|                             Copyright 2000-2026, MetaQuotes Ltd. |
//|                                                     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;
//+------------------------------------------------------------------+