MQLArticles/Utils/FA/Managers.mqh

845 lines
50 KiB
MQL5
Raw Permalink Normal View History

2025-10-01 12:22:08 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Managers.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Niquel Mendoza."
#property link "https://www.mql5.com/es/users/nique_372/news"
#property strict
#ifndef UTILS_FA_SIMPLE_MANAGER_MQH
#define UTILS_FA_SIMPLE_MANAGER_MQH
//+------------------------------------------------------------------+
//| Includes |
//+------------------------------------------------------------------+
//--- CLoggerBase
#include "SimpleLogger.mqh"
//---
#include "FuncionesBases.mqh"
//+------------------------------------------------------------------+
//| Base class for object managers |
//+------------------------------------------------------------------+
/*
ADVERTENCIA: ESTA CLASE SI ELIMINA LOS ITEMS POR DEFECTO, TAMBIEN PROPAGA LOS FLAGS, ES COMO UNA EVOLUCION DE CSPECILZIAEDMANAGER, DADO QUE
NO SOLO PROPAGA LOS FLAGS SI NO QUE SE PEUDEN HACER MAS COSAS CON LOS ITEMS.
WARNING: IF THIS CLASS REMOVES THE DEFAULT ITEMS, IT ALSO PROPAGATES THE FLAGS. IT IS LIKE AN EVOLUTION OF CSPECILZIAEDMANAGER,
SINCE IT NOT ONLY PROPAGATES THE FLAGS BUT MORE THINGS CAN BE DONE WITH THE ITEMS.
*/
/*
Spanish:
Antes de incluir mqhs se podria poner CMANAGERBASE_DEBUG, este define unicamente quitara verificacion de fuera de rango... para CheckPoitner
este siempre se debera de hacer, esto lo hago para optimizar, por que si se que un codigo no dara errores entonces, creo que hacer esos check, estan
por demas.. cuando lo programo, ahi creo qeu si es muy necesario..
English:
Before including mqhs, you could set CMANAGERBASE_DEBUG. This defines that it will only remove the out-of-range check... for CheckPointer,
this should always be done. I do this for optimization purposes, because if I know a code won't produce errors, then I think doing those checks is unnecessary...
when I program it, I think it's very necessary.
*/
//---
//#define CMANAGERBASE_DEBUG
//---
template<typename T>
class CManagerBase : public CLoggerBase
{
protected:
T* items[]; // Pointers Array
int total; // Total number of items
bool clean_in_destructor; // Flag indicating whether items will be deleted in the destructor
bool funcionar_solo_como_container; // Flag indicating whether the class only functions as a manager (No flags are propagated)
//--- Function to propagate logging flags
void PropagateFlags(const uint8_t flags, bool enable);
//--- Internal methods (without calling virtual functions, class-specific use)
void RemoveInternal(int index);
inline void AddItemInternal(T* item);
inline void ReplaceInternal(int index, T* new_item);
void InsertInternal(T* item, int index);
//--- Virtual functions
virtual void OnAntesClear() {}
virtual void OnNewElement(int new_pos) {} // Function executed each time a new element is added at index new_pos
virtual void OnDeleteElement(int delete_pos, T* item) {} // Function executed each time an element is deleted at delete_pos
public:
CManagerBase(bool funcionar_solo_como_container_);
~CManagerBase();
//--- General
void SetCleanInDestructor(bool new_val) { clean_in_destructor = new_val; }
inline int Size() const { return total; }
void CleanItems(bool delete_ptrs); // Clean the class and remove items
//--- Basic operations
// Add
virtual void AddItem(T* item, bool check_duplicate); // Add item to end of array (pointer)
void AddItem(T& item, bool check_duplicate); // Add item to end of array (reference - usage: instance)
inline void AddItemFast(T* item); // Add item to end of array (pointer), without checks
// Insert
bool Insert(T* item, int index); // Insert at position
bool Insert(T& item, int index); // Insert at position
// Remove
bool Remove(int index); // Remove by index (The function does not delete the pointer)
bool Remove(T* item); // Remove by object (The function does not delete the pointer)
bool RemoveFirst(); // Remove first (The function does not delete the pointer)
bool RemoveLast(); // Remove last (The function does not delete the pointer)
T* Pop(); // Remove last and return (The function does not delete the pointer)
// Replace
bool Replace(int index, T* new_item); // Replace item
// Check index
inline bool InRange(const int index, const string& function_name) const; // Check index
//--- Search
int Find(T* item); // Find index
int Exist(T* item); // Check if item exists (unique), returns its index if exists
T* GetFirst(); // First item
T* GetLast(); // Last item
int GetActiveCount(); // Non-invalid items
//--- Utilities
void Compact(); // Remove invalid items
bool Swap(int index1, int index2); // Swap items
void Reverse(); // Reverse order
virtual void PrintInfo(); // Debug info
//--- Operators
#ifdef CMANAGERBASE_DEBUG
T* operator[](const int index) { return InRange(index, FUNCION_ACTUAL) ? items[index] : NULL; }
#else
T* operator[](const int index) { return items[index]; }
#endif
//--- Logs
void AddLogFlags(const uint8_t flags) override;
void RemoveLogFlags(const uint8_t flags) override;
void EnableAllLogs() override;
void DisableAllLogs() override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
template<typename T> CManagerBase::CManagerBase(bool funcionar_solo_como_container_) : total(0)
{
ArrayResize(items, 0);
this.funcionar_solo_como_container = funcionar_solo_como_container_;
this.clean_in_destructor = true;
}
//+------------------------------------------------------------------+
template<typename T> CManagerBase::~CManagerBase()
{
if(clean_in_destructor)
CleanItems(true);
else
{
ArrayResize(items, 0);
}
}
//+------------------------------------------------------------------+
//| Function to check if an index is in the range [0 - (total-1)] |
//+------------------------------------------------------------------+
template<typename T>
inline bool CManagerBase::InRange(const int index, const string& function_name) const
{
if(index < total && index >= 0)
return true;
else
{
LogError(StringFormat("(%s) Index %d is invalid, array range [ %d - %d ]", function_name, index, total), function_name);
return false;
}
}
//+------------------------------------------------------------------+
//| Functions for (add - insert - replace) elements |
//| (without calling virtual functions, class-specific use) |
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::RemoveInternal(int index)
{
//---
for(int i = index; i < total - 1; i++)
items[i] = items[i + 1];
//---
total--;
ArrayResize(items, total);
}
//+------------------------------------------------------------------+
template<typename T>
inline void CManagerBase::AddItemInternal(T* item)
{
ArrayResize(items, total + 1);
items[total] = item;
total++;
}
//+------------------------------------------------------------------+
template<typename T>
inline void CManagerBase::ReplaceInternal(int index, T* new_item)
{
items[index] = new_item;
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::InsertInternal(T* item, int index)
{
//---
ArrayResize(items, total + 1);
//---
for(int i = total; i > index; i--)
items[i] = items[i - 1];
//---
items[index] = item;
total++;
}
//+------------------------------------------------------------------+
//| Functions to (add - insert - replace) items |
//| (public with calls to virtual functions) |
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::AddItem(T* item, bool check_duplicate)
{
//---
if(!CheckPointer(item))
{
LogError("Cannot add NULL item", FUNCION_ACTUAL);
return;
}
//--- Only check if exists if requested
if(check_duplicate)
{
if(Exist(item) != -1)
{
LogWarning("Item not added, it's duplicated", FUNCION_ACTUAL);
return;
}
}
//--- Resize
ArrayResize(items, total + 1);
items[total] = item;
//--- Add log_flags
if(!funcionar_solo_como_container)
items[total].AddLogFlags(LogFlags());
//---
OnNewElement(total);
//---
total++;
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::AddItem(T& item, bool check_duplicate)
{
AddItem(GetPointer(item), check_duplicate);
}
//+------------------------------------------------------------------+
template<typename T>
inline void CManagerBase::AddItemFast(T* item)
{
ArrayResize(items, total + 1);
items[total] = item;
OnNewElement(total);
total++;
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::Insert(T* item, int index)
{
//---
if(CheckPointer(item) == POINTER_INVALID)
{
LogError("Cannot insert NULL item", FUNCION_ACTUAL);
return false;
}
//---
if(!InRange(index, FUNCION_ACTUAL))
return false;
//---
ArrayResize(items, total + 1);
//--- Move elements to the right
for(int i = total; i > index; i--)
items[i] = items[i - 1];
//---
items[index] = item;
total++;
//---
OnNewElement(index);
//--- Log
LogInfo(StringFormat("Item inserted at index %d. Total: %d", index, total), FUNCION_ACTUAL);
return true;
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::Insert(T& item, int index)
{
return Insert(::GetPointer(item), index);
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::Remove(int index)
{
//---
#ifdef CMANAGERBASE_DEBUG
if(!InRange(index, FUNCION_ACTUAL))
return false;
#endif
//---
OnDeleteElement(index, items[index]);
//---
for(int i = index; i < total - 1; i++)
items[i] = items[i + 1];
//---
total--;
ArrayResize(items, total);
//--- Log
LogInfo(StringFormat("Item removed from index %d. Total: %d", index, total), FUNCION_ACTUAL);
return true;
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::Remove(T* item)
{
// Find already checks if the item is invalid, and if it returns -1, Remove handles it (if CMANAGERBASE_DEBUG is enabled)
return Remove(Find(item));
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::Replace(int index, T* new_item)
{
#ifdef CMANAGERBASE_DEBUG
if(!InRange(index, FUNCION_ACTUAL))
return false;
#endif
//---
if(CheckPointer(new_item) == POINTER_INVALID)
{
LogError("Cannot replace with NULL item", FUNCION_ACTUAL);
return false;
}
//---
OnDeleteElement(index, items[index]);
items[index] = new_item;
OnNewElement(index);
//---
LogInfo(StringFormat("Item replaced at index %d", index), FUNCION_ACTUAL);
return true;
}
//+------------------------------------------------------------------+
template<typename T>
T* CManagerBase::Pop()
{
//---
if(total == 0)
{
LogWarning("No items to Pop", FUNCION_ACTUAL);
return NULL;
}
//---
const int last_index = total - 1;
T* last_item = items[last_index];
OnDeleteElement(last_index, last_item);
//---
total--;
ArrayResize(items, total);
//---
LogInfo(StringFormat("Pop executed. Total: %d", total), FUNCION_ACTUAL);
return last_item;
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::RemoveFirst()
{
return Remove(0);
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::RemoveLast()
{
return Remove(total - 1);
}
//+------------------------------------------------------------------+
template<typename T>
int CManagerBase::Find(T* item)
{
//---
if(CheckPointer(item) == POINTER_INVALID)
{
LogError("Cannot find index of item*, its pointer is invalid", FUNCION_ACTUAL);
return -1;
}
//---
for(int i = 0; i < total; i++)
if(items[i] == item)
return i;
//---
LogWarning("Index not found for item pointer", FUNCION_ACTUAL);
return -1;
}
//+------------------------------------------------------------------+
template <typename T>
int CManagerBase::Exist(T* item)
{
//---
if(CheckPointer(item) == POINTER_INVALID)
{
LogError("Pointer is invalid", FUNCION_ACTUAL);
return -1;
}
//---
const void* ptr1 = item;
for(int i = 0; i < total; i++)
{
const void* ptr2 = items[i];
if(ptr2 == ptr1)
return i;
}
//---
return -1;
}
//+------------------------------------------------------------------+
template<typename T>
T* CManagerBase::GetFirst()
{
if(total > 0)
return items[0];
LogWarning("Total size of items is less than 1, there is no first item, will return NULL", FUNCION_ACTUAL);
return NULL;
}
//+------------------------------------------------------------------+
template<typename T>
T* CManagerBase::GetLast()
{
if(total > 0)
return items[total - 1];
LogWarning("Total size of items is less than 1, there is no last item, will return NULL", FUNCION_ACTUAL);
return NULL;
}
//+------------------------------------------------------------------+
template<typename T>
int CManagerBase::GetActiveCount()
{
int count = 0;
for(int i = 0; i < total; i++)
if(CheckPointer(items[i]) != POINTER_INVALID)
count++;
//---
return count;
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::Compact()
{
//---
int write_pos = 0;
//---
for(int i = 0; i < total; i++)
{
if(CheckPointer(items[i]) != POINTER_INVALID)
{
if(write_pos != i)
items[write_pos] = items[i];
write_pos++;
}
}
//---
int old_total = total;
total = write_pos;
ArrayResize(items, total);
//--- Log
LogInfo(StringFormat("Compaction completed: %d -> %d items", old_total, total), FUNCION_ACTUAL);
}
//+------------------------------------------------------------------+
template<typename T>
bool CManagerBase::Swap(int index1, int index2)
{
#ifdef CMANAGERBASE_DEBUG
if(!InRange(index1, FUNCION_ACTUAL) || !InRange(index2, FUNCION_ACTUAL))
return false;
#endif
//---
T* temp = items[index1];
items[index1] = items[index2];
items[index2] = temp;
//--- Log
LogCaution(StringFormat("Items swapped: indices %d and %d", index1, index2), FUNCION_ACTUAL);
return true;
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::Reverse()
{
ArrayReverse(items);
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::CleanItems(bool delete_ptrs)
{
//---
if(total < 1)
return;
//---
const int t = total;
OnAntesClear();
//---
for(int i = 0; i < total; i++)
{
OnDeleteElement(i, items[i]);
if(delete_ptrs && CheckPointer(items[i]) == POINTER_DYNAMIC)
{
delete items[i];
items[i] = NULL;
}
}
//---
ArrayResize(items, 0);
total = 0;
//--- Log
LogWarning(StringFormat("Manager cleaned, objects before = %d, now = 0", t), FUNCION_ACTUAL);
}
//+------------------------------------------------------------------+
//| Function to print manager information |
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::PrintInfo()
{
LogInfo(StringFormat("Manager Info - Total: %d, Active: %d, ArraySize: %d", total, GetActiveCount(), ArraySize(items)), FUNCION_ACTUAL);
}
//+------------------------------------------------------------------+
//| Functions for propagating logging flags |
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::PropagateFlags(const uint8_t flags, bool enable)
{
for(int i = 0; i < total; i++)
{
if(enable)
items[i].AddLogFlags(flags);
else
items[i].RemoveLogFlags(flags);
}
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::AddLogFlags(const uint8_t flags)
{
CLoggerBase::AddLogFlags(flags);
if(funcionar_solo_como_container)
return;
PropagateFlags(flags, true);
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::RemoveLogFlags(const uint8_t flags)
{
CLoggerBase::RemoveLogFlags(flags);
if(funcionar_solo_como_container)
return;
PropagateFlags(flags, false);
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::EnableAllLogs()
{
CLoggerBase::EnableAllLogs();
if(funcionar_solo_como_container)
return;
for(int i = 0; i < total; i++)
{
items[i].EnableAllLogs();
}
}
//+------------------------------------------------------------------+
template<typename T>
void CManagerBase::DisableAllLogs()
{
CLoggerBase::DisableAllLogs();
if(funcionar_solo_como_container)
return;
for(int i = 0; i < total; i++)
{
items[i].DisableAllLogs();
}
}
//+------------------------------------------------------------------------------+
//| Base class for flag propagation |
//| Utils: When you have a class with several objects separate from CLoggerBase, |
//| so propagating logs to instances or pointers is necessary |
//+------------------------------------------------------------------------------+
/*
Spanish:
ADVERTENCIA NO SE ELIMINAN LOS ITEMS, PERO SI HAY UNA FUNCION INTEGRADA PARA HCERLO PERO ESTA SOLO ESTA COMO FUNCIONALDAD, IDEALMENTE SOLO SUAR PARA PROPAGAR FLAGS
English:
WARNING ITEMS ARE NOT REMOVED, BUT THERE IS A BUILT-IN FUNCTION TO DO SO, BUT THIS IS ONLY FOR FUNCTIONALITY, IDEALLY ONLY USED TO PROPAGATE FLAGS
*/
//--- Implementation
class CSpecializedManager : public CLoggerBase
{
protected:
int total;
CLoggerBase* items[];
void PropagateFlags(const uint8_t flags, bool enable);
void RemoveLogger(int index);
bool RemoveLogger(CLoggerBase * _logger);
void AddLogger(CLoggerBase * _logger);
void AddLogger(CLoggerBase & _logger);
virtual void CleanItems(const string &den_name) final;
public:
CSpecializedManager();
void AddLogFlags(const uint8_t flags) override;
void RemoveLogFlags(const uint8_t flags) override;
void EnableAllLogs() override;
void DisableAllLogs() override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSpecializedManager::CSpecializedManager() : total(0)
{
ArrayResize(items, 0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSpecializedManager::CleanItems(const string &den_name)
{
#ifdef CSM_DEBUG_ELIMIACIONES
const string f = StringFormat("CSpecializedManger[%s]::CleanItems", den_name);
FastLog(f, "WARNING", "Se esta limpiando los items");
#endif
//---
for(int i = 0; i < total; i++)
if(CheckPointer(items[i]) == POINTER_DYNAMIC)
delete items[i];
//---
total = 0;
ArrayResize(items, 0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSpecializedManager::AddLogger(CLoggerBase* _logger)
{
if(CheckPointer(_logger) == POINTER_INVALID)
{
LogFatalError("El puntero *_logger es inv<00>lido", FUNCION_ACTUAL);
return;
}
//---
AddArrayNoVerification1(this.items, _logger, total, 0);
//---
total = ArraySize(items);
//---
_logger.AddLogFlags(LogFlags());
}
//+------------------------------------------------------------------+
void CSpecializedManager::AddLogger(CLoggerBase &_logger)
{
AddLogger(GetPointer(_logger));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSpecializedManager::PropagateFlags(const uint8_t flags, bool enable)
{
for(int i = 0; i < total; i++)
{
if(enable)
items[i].AddLogFlags(flags);
else
items[i].RemoveLogFlags(flags);
}
}
//+------------------------------------------------------------------+
void CSpecializedManager::AddLogFlags(const uint8_t flags)
{
CLoggerBase::AddLogFlags(flags);
PropagateFlags(flags, true);
}
//+------------------------------------------------------------------+
void CSpecializedManager::RemoveLogFlags(const uint8_t flags)
{
CLoggerBase::RemoveLogFlags(flags);
PropagateFlags(flags, false);
}
//+------------------------------------------------------------------+
void CSpecializedManager::EnableAllLogs()
{
CLoggerBase::EnableAllLogs();
for(int i = 0; i < total; i++)
{
items[i].EnableAllLogs();
}
}
//+------------------------------------------------------------------+
void CSpecializedManager::DisableAllLogs()
{
CLoggerBase::DisableAllLogs();
for(int i = 0; i < total; i++)
{
items[i].DisableAllLogs();
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSpecializedManager::RemoveLogger(int index)
{
if(index < 0 || index >= total)
{
LogError(StringFormat("<00>ndice inv<00>lido: %d. Rango v<00>lido: 0-%d", index, total - 1), FUNCION_ACTUAL);
return;
}
if(total == 0)
{
LogWarning("No hay loggers para remover", FUNCION_ACTUAL);
return;
}
for(int i = index; i < total - 1; i++)
{
items[i] = items[i + 1];
}
total--;
ArrayResize(items, total);
LogInfo(StringFormat("Logger en <00>ndice %d removido. Total restante: %d", index, total), FUNCION_ACTUAL);
}
//+------------------------------------------------------------------+
bool CSpecializedManager::RemoveLogger(CLoggerBase* _logger)
{
if(CheckPointer(_logger) == POINTER_INVALID)
{
LogError("No se puede remover logger nulo", FUNCION_ACTUAL);
return false;
}
for(int i = 0; i < total; i++)
{
if(items[i] == _logger)
{
RemoveLogger(i);
return true;
}
}
LogWarning("Logger no encontrado para remover", FUNCION_ACTUAL);
return false;
}
#endif
//+------------------------------------------------------------------+