forked from nique_372/MQLArticles
1061 lines
64 KiB
MQL5
1061 lines
64 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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 MQLARTICLES_UTILS_FA_MANAGERS_MQH
|
|
#define MQLARTICLES_UTILS_FA_MANAGERS_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Includes |
|
|
//+------------------------------------------------------------------+
|
|
//--- CLoggerBase
|
|
#include "SimpleLogger.mqh"
|
|
|
|
//--- Basic Functions
|
|
#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_STRICT_MODE, 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_STRICT_MODE. 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_STRICT_MODE
|
|
|
|
#define MANAGER_BASE_ACTION_NO_CHANGE_SIZE 0
|
|
#define MANAGER_BASE_ACTION_CHANGE_SIZE 1
|
|
#define MANAGER_BASE_ACTION_CLEAR_ITEMS 2
|
|
|
|
// Notas para CManagerBasesSimple:
|
|
// P no debe tener constructor con parametros o tener uno default, si la clase es pura entonces se tendra que crear una clase hija.
|
|
// P should not have a constructor with parameters or should have a default one; if the class is pure, then a child class will have to be created.
|
|
// P debe de heredar de CLoggerBase
|
|
// T es libre puede o no ser heredero de CLoggerBase
|
|
//+------------------------------------------------------------------+
|
|
//| CManagerBasesSimple class |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
class CManagerBasesSimple : public P
|
|
{
|
|
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
|
|
|
|
//--- 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() {}
|
|
|
|
// Function executed each time a new element is added at index new_pos
|
|
virtual void OnNewElement(int new_pos, int8_t action) {}
|
|
|
|
// Function executed each time an element is deleted at delete_pos
|
|
virtual void OnDeleteElement(int delete_pos, T* item, int8_t action) {}
|
|
|
|
public:
|
|
CManagerBasesSimple();
|
|
~CManagerBasesSimple();
|
|
|
|
//--- 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 bool AddItem(T* item, bool check_duplicate); // Add item to end of array (pointer)
|
|
bool 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
|
|
virtual 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* RemoveLastAndReturn(); // Remove last and return (The function does not delete the pointer)
|
|
|
|
// Delete
|
|
bool Delete(int index); // Delete pointer
|
|
|
|
// Replace
|
|
virtual bool Replace(int index, T* new_item); // Replace item (The function does not delete the pointer)
|
|
|
|
// 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
|
|
|
|
// Get
|
|
bool GetData(T* &dst_array[], int start = 0, int count = WHOLE_ARRAY) const;
|
|
|
|
//--- Utilities
|
|
void Compact(); // Remove invalid items
|
|
bool Swap(int index1, int index2); // Swap items
|
|
void Reverse(); // Reverse order
|
|
virtual void Summary(); // Info
|
|
|
|
//--- Operators
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
T* operator[](const int index) { return InRange(index, FUNCION_ACTUAL) ? items[index] : NULL; }
|
|
#else
|
|
T* operator[](const int index) { return items[index]; }
|
|
#endif
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor and Destructor |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P> CManagerBasesSimple::CManagerBasesSimple() : total(0)
|
|
{
|
|
ArrayResize(items, 0);
|
|
this.clean_in_destructor = true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P> CManagerBasesSimple::~CManagerBasesSimple()
|
|
{
|
|
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, typename P>
|
|
inline bool CManagerBasesSimple::InRange(const int index, const string& function_name) const
|
|
{
|
|
if(index < total && index >= 0)
|
|
return true;
|
|
else
|
|
{
|
|
LogError(StringFormat("Index %d is invalid, array range [ %d - %d ]", index, total - 1), function_name);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Functions for (add - insert - replace) elements |
|
|
//| (without calling virtual functions, class-specific use) |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
void CManagerBasesSimple::RemoveInternal(int index)
|
|
{
|
|
//---
|
|
for(int i = index; i < total - 1; i++)
|
|
items[i] = items[i + 1];
|
|
|
|
//---
|
|
total--;
|
|
ArrayResize(items, total);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
inline void CManagerBasesSimple::AddItemInternal(T* item)
|
|
{
|
|
ArrayResize(items, total + 1);
|
|
items[total] = item;
|
|
total++;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
inline void CManagerBasesSimple::ReplaceInternal(int index, T* new_item)
|
|
{
|
|
items[index] = new_item;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
void CManagerBasesSimple::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, typename P>
|
|
bool CManagerBasesSimple::AddItem(T* item, bool check_duplicate)
|
|
{
|
|
//---
|
|
if(!CheckPointer(item))
|
|
{
|
|
LogError("Cannot add NULL item", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//--- Only check if exists if requested
|
|
if(check_duplicate)
|
|
{
|
|
if(Exist(item) != -1)
|
|
{
|
|
LogWarning("Item not added, it's duplicated", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//--- Resize
|
|
ArrayResize(items, total + 1);
|
|
items[total] = item;
|
|
|
|
//---
|
|
total++;
|
|
|
|
//---
|
|
OnNewElement((total - 1), MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::AddItem(T& item, bool check_duplicate)
|
|
{
|
|
return AddItem(GetPointer(item), check_duplicate);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
inline void CManagerBasesSimple::AddItemFast(T* item)
|
|
{
|
|
ArrayResize(items, total + 1);
|
|
items[total] = item;
|
|
total++;
|
|
OnNewElement((total - 1), MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::Insert(T* item, int index)
|
|
{
|
|
//---
|
|
if(!CheckPointer(item))
|
|
{
|
|
LogError("Cannot insert NULL item", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
if(!InRange(index, FUNCION_ACTUAL))
|
|
return false;
|
|
#endif
|
|
|
|
//---
|
|
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, MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
|
|
//--- Log
|
|
LogInfo(StringFormat("Item inserted at index %d. Total: %d", index, total), FUNCION_ACTUAL);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::Insert(T& item, int index)
|
|
{
|
|
return Insert(::GetPointer(item), index);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::Delete(int index)
|
|
{
|
|
//---
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
if(!InRange(index, FUNCION_ACTUAL))
|
|
return false;
|
|
#endif
|
|
//---
|
|
if(CheckPointer(items[index]) == POINTER_DYNAMIC)
|
|
{
|
|
delete items[index];
|
|
items[index] = NULL;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError("The pointer was not removed because it is not dynamic or is invalid", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::Remove(int index)
|
|
{
|
|
//---
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
if(!InRange(index, FUNCION_ACTUAL))
|
|
return false;
|
|
#endif
|
|
|
|
//---
|
|
OnDeleteElement(index, items[index], MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
|
|
//---
|
|
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, typename P>
|
|
bool CManagerBasesSimple::Remove(T* item)
|
|
{
|
|
// Find already checks if the item is invalid, and if it returns -1, Remove handles it (if CMANAGERBASE_STRICT_MODE is enabled)
|
|
return Remove(Find(item));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::Replace(int index, T* new_item)
|
|
{
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
if(!InRange(index, FUNCION_ACTUAL))
|
|
return false;
|
|
#endif
|
|
|
|
//---
|
|
if(!CheckPointer(new_item))
|
|
{
|
|
LogError("Cannot replace with NULL item", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
OnDeleteElement(index, items[index], MANAGER_BASE_ACTION_NO_CHANGE_SIZE);
|
|
items[index] = new_item;
|
|
OnNewElement(index, MANAGER_BASE_ACTION_NO_CHANGE_SIZE);
|
|
|
|
//---
|
|
LogInfo(StringFormat("Item replaced at index %d", index), FUNCION_ACTUAL);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
T* CManagerBasesSimple::RemoveLastAndReturn()
|
|
{
|
|
//---
|
|
if(total == 0)
|
|
{
|
|
LogWarning("No items to RemoveLastAndReturn", FUNCION_ACTUAL);
|
|
return NULL;
|
|
}
|
|
|
|
//---
|
|
const int last_index = total - 1;
|
|
T* last_item = items[last_index];
|
|
OnDeleteElement(last_index, last_item, MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
|
|
//---
|
|
total--;
|
|
ArrayResize(items, total);
|
|
|
|
//---
|
|
LogInfo(StringFormat("RemoveLastAndReturn executed. Total: %d", total), FUNCION_ACTUAL);
|
|
return last_item;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::RemoveFirst()
|
|
{
|
|
return Remove(0);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::RemoveLast()
|
|
{
|
|
return Remove(total - 1);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
int CManagerBasesSimple::Find(T* item)
|
|
{
|
|
//---
|
|
if(!CheckPointer(item))
|
|
{
|
|
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, typename P>
|
|
int CManagerBasesSimple::Exist(T* item)
|
|
{
|
|
//---
|
|
if(!CheckPointer(item))
|
|
{
|
|
LogError("Pointer is invalid", FUNCION_ACTUAL);
|
|
return -1;
|
|
}
|
|
|
|
//---
|
|
const void* const ptr1 = item;
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
const void* const ptr2 = items[i];
|
|
if(ptr2 == ptr1)
|
|
return i;
|
|
}
|
|
|
|
//---
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
T* CManagerBasesSimple::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, typename P>
|
|
T* CManagerBasesSimple::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, typename P>
|
|
int CManagerBasesSimple::GetActiveCount()
|
|
{
|
|
int count = 0;
|
|
for(int i = 0; i < total; i++)
|
|
if(CheckPointer(items[i]) != POINTER_INVALID)
|
|
count++;
|
|
|
|
//---
|
|
return count;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
void CManagerBasesSimple::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, typename P>
|
|
bool CManagerBasesSimple::Swap(int index1, int index2)
|
|
{
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
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, typename P>
|
|
void CManagerBasesSimple::Reverse()
|
|
{
|
|
ArrayReverse(items);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
void CManagerBasesSimple::CleanItems(bool delete_ptrs)
|
|
{
|
|
//---
|
|
if(total < 1)
|
|
return;
|
|
|
|
//---
|
|
const int t = total;
|
|
OnAntesClear();
|
|
|
|
//---
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
OnDeleteElement(i, items[i], MANAGER_BASE_ACTION_CLEAR_ITEMS);
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
bool CManagerBasesSimple::GetData(T* &dst_array[], int start = 0, int count = WHOLE_ARRAY) const
|
|
{
|
|
//---
|
|
count = (count == WHOLE_ARRAY) ? (total - start) : count; // Count real
|
|
const int end = (start + (count - 1)); // Indice final
|
|
if(start < 0 || end >= total) // Strat menor a 0 | final mayor o igual a total
|
|
return false;
|
|
|
|
//---
|
|
ArrayResize(dst_array, count);
|
|
|
|
//---
|
|
for(int id = 0, is = start; is <= end; id++, is++)
|
|
{
|
|
dst_array[id] = items[is];
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Function to print manager information |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T, typename P>
|
|
void CManagerBasesSimple::Summary()
|
|
{
|
|
LogInfo(StringFormat("<< ManagerInfo >> Total: %d | Active: %d | ArraySize: %d", total, GetActiveCount(), ArraySize(items)), FUNCION_ACTUAL);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CManagerBase class |
|
|
//+------------------------------------------------------------------+
|
|
// Nota: T debe de ser herededo de CLoggerBase si o si
|
|
|
|
template<typename T>
|
|
class CManagerBase : public CManagerBasesSimple<T, CLoggerBase>
|
|
{
|
|
protected:
|
|
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);
|
|
|
|
public:
|
|
CManagerBase(bool funcionar_solo_como_container_);
|
|
~CManagerBase() {}
|
|
|
|
//--- Basic operations
|
|
// Add
|
|
using CManagerBasesSimple<T, CLoggerBase>::AddItem; // reference
|
|
bool AddItem(T* item, bool check_duplicate) override; // Add item to end of array (pointer)
|
|
|
|
// Insert
|
|
using CManagerBasesSimple<T, CLoggerBase>::Insert; // reference
|
|
bool Insert(T* item, int index) override; // Insert at position
|
|
|
|
// Replace
|
|
bool Replace(int index, T* new_item) override; // Replace item (The function does not delete the pointer)
|
|
|
|
//--- Logs
|
|
void AddLogFlags(const uint8_t flags) override;
|
|
void RemoveLogFlags(const uint8_t flags) override;
|
|
void EnableAllLogs() override;
|
|
void DisableAllLogs() override;
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Constructor and Destructor |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T> CManagerBase::CManagerBase(bool funcionar_solo_como_container_)
|
|
{
|
|
this.funcionar_solo_como_container = funcionar_solo_como_container_;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Functions to (add - insert - replace) items |
|
|
//| (public with calls to virtual functions) |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T>
|
|
bool CManagerBase::AddItem(T* item, bool check_duplicate)
|
|
{
|
|
//---
|
|
if(!CheckPointer(item))
|
|
{
|
|
LogError("Cannot add NULL item", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//--- Only check if exists if requested
|
|
if(check_duplicate)
|
|
{
|
|
if(Exist(item) != -1)
|
|
{
|
|
LogWarning("Item not added, it's duplicated", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//--- Resize
|
|
ArrayResize(items, total + 1);
|
|
items[total] = item;
|
|
|
|
//--- Add log_flags
|
|
if(!funcionar_solo_como_container)
|
|
items[total].AddLogFlags(LogFlags());
|
|
|
|
//---
|
|
total++;
|
|
|
|
//---
|
|
OnNewElement((total - 1), MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T>
|
|
bool CManagerBase::Insert(T* item, int index)
|
|
{
|
|
//---
|
|
if(!CheckPointer(item))
|
|
{
|
|
LogError("Cannot insert NULL item", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
if(!InRange(index, FUNCION_ACTUAL))
|
|
return false;
|
|
#endif
|
|
|
|
//---
|
|
ArrayResize(items, total + 1);
|
|
|
|
//--- Move elements to the right
|
|
for(int i = total; i > index; i--)
|
|
items[i] = items[i - 1];
|
|
|
|
//---
|
|
items[index] = item;
|
|
|
|
//--- Add log_flags
|
|
if(!funcionar_solo_como_container)
|
|
items[index].AddLogFlags(LogFlags());
|
|
|
|
//---
|
|
total++;
|
|
|
|
//---
|
|
OnNewElement(index, MANAGER_BASE_ACTION_CHANGE_SIZE);
|
|
|
|
//--- Log
|
|
LogInfo(StringFormat("Item inserted at index %d. Total: %d", index, total), FUNCION_ACTUAL);
|
|
return true;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
template<typename T>
|
|
bool CManagerBase::Replace(int index, T* new_item)
|
|
{
|
|
#ifdef CMANAGERBASE_STRICT_MODE
|
|
if(!InRange(index, FUNCION_ACTUAL))
|
|
return false;
|
|
#endif
|
|
|
|
//---
|
|
if(!CheckPointer(new_item))
|
|
{
|
|
LogError("Cannot replace with NULL item", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
OnDeleteElement(index, items[index], MANAGER_BASE_ACTION_NO_CHANGE_SIZE);
|
|
items[index] = new_item;
|
|
OnNewElement(index, MANAGER_BASE_ACTION_NO_CHANGE_SIZE);
|
|
|
|
//--- Add log_flags
|
|
if(!funcionar_solo_como_container)
|
|
items[index].AddLogFlags(LogFlags());
|
|
|
|
//---
|
|
LogInfo(StringFormat("Item replaced at index %d", index), FUNCION_ACTUAL);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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á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("Índice inválido: %d. Rango vá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 í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
|
|
//+------------------------------------------------------------------+
|