//+------------------------------------------------------------------+ //| 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 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 CManagerBasesSimple::CManagerBasesSimple() : total(0) { ArrayResize(items, 0); this.clean_in_destructor = true; } //+------------------------------------------------------------------+ template 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 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 void CManagerBasesSimple::RemoveInternal(int index) { //--- for(int i = index; i < total - 1; i++) items[i] = items[i + 1]; //--- total--; ArrayResize(items, total); } //+------------------------------------------------------------------+ template inline void CManagerBasesSimple::AddItemInternal(T* item) { ArrayResize(items, total + 1); items[total] = item; total++; } //+------------------------------------------------------------------+ template inline void CManagerBasesSimple::ReplaceInternal(int index, T* new_item) { items[index] = new_item; } //+------------------------------------------------------------------+ template 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 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 bool CManagerBasesSimple::AddItem(T& item, bool check_duplicate) { return AddItem(GetPointer(item), check_duplicate); } //+------------------------------------------------------------------+ template inline void CManagerBasesSimple::AddItemFast(T* item) { ArrayResize(items, total + 1); items[total] = item; total++; OnNewElement((total - 1), MANAGER_BASE_ACTION_CHANGE_SIZE); } //+------------------------------------------------------------------+ template 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 bool CManagerBasesSimple::Insert(T& item, int index) { return Insert(::GetPointer(item), index); } //+------------------------------------------------------------------+ template 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 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 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 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 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 bool CManagerBasesSimple::RemoveFirst() { return Remove(0); } //+------------------------------------------------------------------+ template bool CManagerBasesSimple::RemoveLast() { return Remove(total - 1); } //+------------------------------------------------------------------+ template 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 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 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 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 int CManagerBasesSimple::GetActiveCount() { int count = 0; for(int i = 0; i < total; i++) if(CheckPointer(items[i]) != POINTER_INVALID) count++; //--- return count; } //+------------------------------------------------------------------+ template 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 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 void CManagerBasesSimple::Reverse() { ArrayReverse(items); } //+------------------------------------------------------------------+ template 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 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 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 class CManagerBase : public CManagerBasesSimple { 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::AddItem; // reference bool AddItem(T* item, bool check_duplicate) override; // Add item to end of array (pointer) // Insert using CManagerBasesSimple::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 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 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 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 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 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 void CManagerBase::AddLogFlags(const uint8_t flags) { CLoggerBase::AddLogFlags(flags); if(funcionar_solo_como_container) return; PropagateFlags(flags, true); } //+------------------------------------------------------------------+ template void CManagerBase::RemoveLogFlags(const uint8_t flags) { CLoggerBase::RemoveLogFlags(flags); if(funcionar_solo_como_container) return; PropagateFlags(flags, false); } //+------------------------------------------------------------------+ template void CManagerBase::EnableAllLogs() { CLoggerBase::EnableAllLogs(); if(funcionar_solo_como_container) return; for(int i = 0; i < total; i++) { items[i].EnableAllLogs(); } } //+------------------------------------------------------------------+ template 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 //+------------------------------------------------------------------+