//+------------------------------------------------------------------+
//|                                              PersistentCache.mqh |
//|                 Lightweight Persistent Key-Value Storage Engine  |
//+------------------------------------------------------------------+
#ifndef PERSISTENT_CACHE_MQH
#define PERSISTENT_CACHE_MQH

//--- Includes
#include <Generic\HashMap.mqh>

//+------------------------------------------------------------------+
//| CPersistentCache                                                 |
//| Wraps CHashMap<string,string> to provide an in-memory key-value  |
//| store with O(1) average-case Get, Set, Delete, and Exists        |
//| operations. All persistence is delegated to CPersistentStore.    |
//+------------------------------------------------------------------+
class CPersistentCache
  {
private:
   CHashMap<string,string> m_map;    // Backing hash map
   int               m_count;        // Number of entries currently held

public:
                     CPersistentCache(void);
                    ~CPersistentCache(void);

   bool              Set(const string key, const string value);
   bool              Get(const string key, string &out_value);
   bool              Delete(const string key);
   bool              Exists(const string key);
   int               Count(void) const;
   void              Clear(void);

   bool              GetAllPairs(string &out_keys[],
                                 string &out_values[]);
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPersistentCache::CPersistentCache(void)
  {
   m_count = 0;
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPersistentCache::~CPersistentCache(void)
  {
   m_map.Clear();
  }

//+------------------------------------------------------------------+
//| Insert or overwrite a key-value pair in the cache                |
//+------------------------------------------------------------------+
bool CPersistentCache::Set(const string key, const string value)
  {
   if(StringLen(key) == 0)
      return(false);

//--- Probe for existing entry to distinguish insert from update
   string existing;
   bool   already_present = m_map.TryGetValue(key, existing);

   if(!m_map.TrySetValue(key, value))
      return(false);

//--- Increment count only for new insertions
   if(!already_present)
      m_count++;

   return(true);
  }

//+------------------------------------------------------------------+
//| Retrieve a value by key; returns false if key is absent          |
//+------------------------------------------------------------------+
bool CPersistentCache::Get(const string key, string &out_value)
  {
   return(m_map.TryGetValue(key, out_value));
  }

//+------------------------------------------------------------------+
//| Remove a key-value pair from the cache                           |
//+------------------------------------------------------------------+
bool CPersistentCache::Delete(const string key)
  {
   if(!m_map.Remove(key))
      return(false);

   m_count--;
   return(true);
  }

//+------------------------------------------------------------------+
//| Return true if the key exists in the cache                       |
//+------------------------------------------------------------------+
bool CPersistentCache::Exists(const string key)
  {
   string dummy;
   return(m_map.TryGetValue(key, dummy));
  }

//+------------------------------------------------------------------+
//| Return the number of entries currently held in the cache         |
//+------------------------------------------------------------------+
int CPersistentCache::Count(void) const
  {
   return(m_count);
  }

//+------------------------------------------------------------------+
//| Remove all entries from the cache                                |
//+------------------------------------------------------------------+
void CPersistentCache::Clear(void)
  {
   m_map.Clear();
   m_count = 0;
  }

//+------------------------------------------------------------------+
//| Export all keys and values to parallel arrays for serialization  |
//+------------------------------------------------------------------+
bool CPersistentCache::GetAllPairs(string &out_keys[],
                                   string &out_values[])
  {
   if(m_count == 0)
     {
      ArrayResize(out_keys,   0);
      ArrayResize(out_values, 0);
      return(false);
     }

//--- Resize both arrays to the current entry count
   ArrayResize(out_keys,   m_count);
   ArrayResize(out_values, m_count);

//--- Copy all keys and values in a single call starting at index 0
   m_map.CopyTo(out_keys, out_values, 0);

   return(true);
  }

#endif // PERSISTENT_CACHE_MQH
//+------------------------------------------------------------------+