#ifndef LIB_MQLPLUS_BASE_OBJ_TREE_TEMPLATES_MQH_INCLUDED #define LIB_MQLPLUS_BASE_OBJ_TREE_TEMPLATES_MQH_INCLUDED #property version "1.0"; /********************************************************************************** * Copyright (C) 2010-2022 Dominik Egert * * This file is the objects include file. * * MQLplus, including this file may not be copied and/or distributed * without explecit permit by the author. * Author Dominik Egert / Freie Netze UG. ********************************************************************************** * * Version: 1.0 * State: production * * File information * ================ * * * */ #ifdef DBG_MSG_TRACE_FILE_LOADER DBG_MSG_TRACE_FILE_LOADER; #endif // Incluse element handler #include "lib_base_node_element.mqh" /*********************************************************************************************************************************************************/ /* */ /* MQLplus data structures */ /* */ /*********************************************************************************************************************************************************/ /////////////////////////////////////// // // Tree object // // Base object template struct _tree : public _element_collection { public: // Element access structure class tree_element : public _element<_param_details, NODE_TYPE, USER_DATA> { public: // Constructors tree_element() : _element() { }; tree_element(NODE_TYPE* p_obj, _param_details* p_in) : _element(p_obj, p_in) { }; tree_element(const tree_element& p_in) : _element(p_in) { }; // Functions void remove(const bool _do_not_destroy = false) { p_params.p_last_added = (p_params.p_last_added == p_element_obj) ? NULL : p_params.p_last_added; NODE_TYPE* _root = p_element_obj.remove(p_params.p_root, p_params.do_not_destroy || _do_not_destroy); p_params.p_root = (_root != NULL) ? _root : p_params.p_root; p_params._size--; delete(p_element_obj); }; }; protected: // Constructors / Destructor // Default constructor _tree() : _element_collection() { }; // Copy constructor _tree(const _tree& p_in) : _element_collection(p_in.p_params) { }; // Destructor ~_tree() { reset(); }; // Assignment operator void operator=(_tree& p_in) { // Detach current tree reset(); // Assign new tree _element_collection::operator=(p_in); }; // Comparison operator const bool operator!=(const _tree& p_in) { return(!operator==(p_in)); }; const bool operator==(const _tree& p_in) { // Return return(false); }; public: // Access operator tree_element operator[](USER_DATA& p_in) { return(tree_element(p_params.p_root.operator[](p_in), p_params)); }; // Array functions template const int get_array(ARRAY_TYPE& p_arr[], const bool reverse = false) { USER_DATA tmp; return(_get_array(p_arr, tmp, WHOLE_ARRAY, reverse, true)); }; template const int get_array(ARRAY_TYPE& p_arr[], const USER_DATA& start, const bool reverse = false) { return(_get_array(p_arr, start, WHOLE_ARRAY, reverse, false)); }; template const int get_array(ARRAY_TYPE& p_arr[], const USER_DATA& start, const int count, const bool reverse = false) { return(_get_array(p_arr, start, count, reverse, false)); }; private: // General object functions // Reset tree void reset() { if(::CheckPointer(p_params) == POINTER_INVALID) { return; } if(p_params.instance_cnt == 1) { // Detach object if(p_params.do_not_destroy) { p_params.p_root.detach_obj(); } // Delete subtrees delete_subtree(p_params.p_root); // Delete tree root if(p_params.p_root != NULL) { delete(p_params.p_root); } } p_params.clear(); p_params.instance_cnt += (p_params.instance_cnt == NULL); }; // Tree functions // Objects to array template const int _get_array(ARRAY_TYPE& p_arr[], USER_DATA& _first_obj, const int count, const bool reverse, const bool whole_tree) { // Precheck if(p_params.p_root == NULL) { ArrayFree(p_arr); return(NULL); } // Local init NODE_TYPE* p_this = (whole_tree) || (p_params.p_left.get_obj() == _first_obj) ? p_params.p_left : p_params.p_root.operator[](_first_obj); const int _size = (count != WHOLE_ARRAY) ? MathMin(count, p_params._size) : p_params._size; const int _end = _size - 1; int cnt = NULL; int arr_ptr = (reverse) ? _end : NULL; // Adjust output array ArrayResize(p_arr, _size); // Ascend main tree while( (p_this != NULL) && (cnt <= _end) && (!_StopFlag) ) { // Handle this node cast_obj(p_arr, p_this, arr_ptr); cnt++; arr_ptr += (reverse) ? -1 : 1; // Handle all sub-nodes if(p_this.right_element() != NULL) { traverse_sub_tree(p_arr, p_this.right_element(), cnt, arr_ptr, _end, reverse); } // Loop control p_this = p_this.parent_element(); } // Return return((_StopFlag) ? NULL : ArraySize(p_arr)); }; protected: // Generic cast object function void cast_obj(USER_DATA& p_arr[], NODE_TYPE* p_this, const int arr_ptr) { p_arr[arr_ptr] = p_this.get_obj(); } void cast_obj(tree_element& p_arr[], NODE_TYPE* p_this, const int arr_ptr) { p_arr[arr_ptr].set(p_this, p_params); } void cast_obj(tree_element*& p_arr[], NODE_TYPE* p_this, const int arr_ptr) { // Value assignment if(CheckPointer(p_arr[arr_ptr]) == POINTER_INVALID) { p_arr[arr_ptr] = new tree_element(p_this, p_params); } else { p_arr[arr_ptr].set(p_this, p_params); } }; // Element functions // Insert element const bool insert(USER_DATA& p_in) { // Create new tree node NODE_TYPE* p_new = new NODE_TYPE(p_in); // Insert and return if(insert(p_new)) { return(true); } // Insert failed delete(p_new); return(false); }; const bool insert(NODE_TYPE* p_new) { // Insert node if(p_params.p_root == NULL) { p_params.p_root = p_new; p_params.p_left = p_new; p_params.p_right = p_new; p_params.p_last_added = p_new; p_params._size++; } else { NODE_TYPE* _root = p_new.insert(p_params.p_root); if(_root == NULL) { return(false); } p_params.p_root = _root; p_params.p_left = (p_params.p_left.get_key() > p_new.get_key()) ? p_new : p_params.p_left; p_params.p_right = (p_params.p_right.get_key() < p_new.get_key()) ? p_new : p_params.p_right; p_params.p_last_added = p_new; p_params._size++; } // Return return(true); }; // Remove element const bool remove(USER_DATA& p_in, const bool _do_not_destroy = false) { // Precheck list if( (p_params.p_root == NULL) || (p_in < p_params.p_left.get_key()) || (p_in > p_params.p_right.get_key()) ) { return(false); } // Get access object and return return(remove(p_params.p_root.operator[](p_in), _do_not_destroy)); }; const bool remove(NODE_TYPE* p_remove, const bool _do_not_destroy = false) { // Precheck input if(p_remove == NULL) { return(false); } // Remove node from tree NODE_TYPE* p_node = p_remove.parent_element(); NODE_TYPE* _root = p_remove.remove(p_params.p_root, p_params.do_not_destroy); p_node = (p_node == NULL) ? _root : p_node; // Update control structure p_params._size--; if(p_params._size == NULL) { p_params.p_root = NULL; p_params.p_left = NULL; p_params.p_right = NULL; p_params.p_last_added = NULL; } else { p_params.p_root = (_root != NULL) ? _root : p_params.p_root; p_params.p_left = (p_params.p_left != p_remove) ? p_params.p_left : p_node.smallest_node(); p_params.p_right = (p_params.p_right != p_remove) ? p_params.p_right : p_node.greatest_node(); p_params.p_last_added = (p_params.p_last_added == p_remove) ? NULL : p_params.p_last_added; } // Disconnect and remove element if(p_params.do_not_destroy || _do_not_destroy) { p_remove.detach_obj(); } delete(p_remove); // Return return(true); }; private: // Tree algorithm functions // Traverse subtree value gathering template void traverse_sub_tree(ARRAY_TYPE& p_arr[], NODE_TYPE* ptr, int& cnt, int& arr_ptr, const int _end, const bool reverse) { // End of tree if( (ptr == NULL) || (cnt > _end) ) { return; } // Visit child if( (ptr.left_element() != NULL) && (cnt <= _end) ) { traverse_sub_tree(p_arr, ptr.left_element(), cnt, arr_ptr, _end, reverse); } // Local node if(cnt <= _end) { cnt++; cast_obj(p_arr, ptr, arr_ptr); arr_ptr += (reverse) ? -1 : 1; } // Visit sibling if( (ptr.right_element() != NULL) && (cnt <= _end) ) { traverse_sub_tree(p_arr, ptr.right_element(), cnt, arr_ptr, _end, reverse); } }; // Recursive tree deletion void delete_subtree(NODE_TYPE* p_in) { // Discard empty node if(p_in == NULL) { return; } // Check left tree if(p_in.left_element() != NULL) { if(p_params.do_not_destroy) { p_in.left_element().detach_obj(); } delete_subtree(p_in.left_element()); if(CheckPointer(p_in.left_element()) != POINTER_INVALID) { delete(p_in.left_element()); } } // Check right tree if(p_in.right_element() != NULL) { if(p_params.do_not_destroy) { p_in.right_element().detach_obj(); } delete_subtree(p_in.right_element()); if(CheckPointer(p_in.right_element()) != POINTER_INVALID) { delete(p_in.right_element()); } } }; public: // Debugging helper // Validator helper NODE_TYPE* get_tree_root() { return(p_params.p_root); } // Print tree helper void print_tree_size(const string comment = "") { print_tree(comment, true); }; void print_tree(const string comment = "", const bool size_only = false) { int count = NULL; string out = ""; string out_buffer[]; _print_tree(p_params.p_root, 0, out, count, out_buffer); if(size_only) { printf("Elements counted: %i", count); return; } printf("********* TREE BEGIN (%s) *************", comment); for(int cnt = NULL; cnt < ArraySize(out_buffer); cnt++) { printf("%s", out_buffer[cnt]); } printf("%s\nElements: %i\n********* TREE END *************", out, count); // Return return; } void _print_tree(NODE_TYPE* _root, const int lvl, string& out, int& count, string& out_buffer[]) { if(_root == NULL) { StringSetLength(out, StringLen(out) - 1); out += "------\n"; return; } // This node _print_tabs(out, lvl, out_buffer); string node_out = _root._node_to_string(count); // Check for errors if(node_out == NULL) { out += "\n !!! ERROR IN NODE HIRARCHY !!! \n\n"; return; } // Add output out += StringFormat("%s\n", node_out); // Left node _print_tabs(out, lvl, out_buffer); out += " -> left: \n"; _print_tree(_root.left_element(), lvl + 1, out, count, out_buffer); // Right node _print_tabs(out, lvl, out_buffer); out += " -> right: \n"; _print_tree(_root.right_element(), lvl + 1, out, count, out_buffer); _print_tabs(out, lvl, out_buffer); out += "Done\n"; } void _print_tabs(string& out, const int lvl, string& out_buffer[]) { _print_max_len(out, out_buffer); out += StringFormat("%i: ", lvl); for(int cnt = NULL; (cnt < lvl); cnt++) { out += " "; } }; void _print_max_len(string& out, string& out_buffer[]) { if(StringLen(out) > 4096) { const int ptr = ArrayResize(out_buffer, ArraySize(out_buffer) + 1) - 1; out_buffer[ptr] = out; out = ""; } }; }; // // END MQL data structures */ //*********************************************************************************************************************************************************/ #endif // LIB_MQLPLUS_BASE_OBJ_TREE_TEMPLATES_MQH_INCLUDED