diff --git a/Dict.enum.h b/Dict.enum.h index 99618ba5b..c746f87e3 100644 --- a/Dict.enum.h +++ b/Dict.enum.h @@ -30,7 +30,7 @@ #pragma once #endif -#define DICT_GROW_UP_PERCENT_DEFAULT 50 +#define DICT_GROW_UP_PERCENT_DEFAULT 100 #define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 20 /** diff --git a/Dict.mqh b/Dict.mqh index 5d30563ce..f123cf539 100644 --- a/Dict.mqh +++ b/Dict.mqh @@ -90,6 +90,8 @@ class Dict : public DictBase { } void Clear() { + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { if (THIS_ATTR _DictSlots_ref.DictSlots[i].IsUsed()) THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -210,7 +212,7 @@ class Dict : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -315,7 +317,7 @@ class Dict : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { @@ -353,6 +355,18 @@ class Dict : public DictBase { MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -362,7 +376,7 @@ class Dict : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false; @@ -389,6 +403,8 @@ class Dict : public DictBase { // Freeing old DictSlots array. ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); + delete THIS_ATTR _DictSlots_ref; + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; diff --git a/DictBase.mqh b/DictBase.mqh index 234c09d92..187191f2d 100644 --- a/DictBase.mqh +++ b/DictBase.mqh @@ -62,12 +62,13 @@ class DictBase { _mode = DictModeUnknown; _flags = 0; overflow_listener = nullptr; + _DictSlots_ref = new DictSlotsRef(); } /** * Destructor. */ - ~DictBase() {} + ~DictBase() { delete _DictSlots_ref; } DictIteratorBase Begin() { // Searching for first item index. @@ -106,7 +107,7 @@ class DictBase { /** * Returns slot by key. */ - DictSlot* GetSlotByKey(DictSlotsRef& dictSlotsRef, const K _key, unsigned int& position) { + DictSlot* GetSlotByKey(DictSlotsRef*& dictSlotsRef, const K _key, unsigned int& position) { unsigned int numSlots = ArraySize(dictSlotsRef.DictSlots); if (numSlots == 0) return NULL; @@ -137,7 +138,7 @@ class DictBase { /** * Returns slot by position. */ - DictSlot* GetSlotByPos(DictSlotsRef& dictSlotsRef, const unsigned int position) { + DictSlot* GetSlotByPos(DictSlotsRef*& dictSlotsRef, const unsigned int position) { return dictSlotsRef.DictSlots[position].IsUsed() ? &dictSlotsRef.DictSlots[position] : NULL; } @@ -335,9 +336,9 @@ class DictBase { protected: /** - * Array of DictSlots. + * Pointer to array of DictSlots. */ - DictSlotsRef _DictSlots_ref; + DictSlotsRef* _DictSlots_ref; DictOverflowListener overflow_listener; unsigned int overflow_listener_max_conflicts; diff --git a/DictObject.mqh b/DictObject.mqh index 4a851cb31..63db36d87 100644 --- a/DictObject.mqh +++ b/DictObject.mqh @@ -21,8 +21,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "Convert.basic.h" @@ -105,6 +105,8 @@ class DictObject : public DictBase { } void Clear() { + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots); ++i) { this PTR_DEREF _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -210,7 +212,7 @@ class DictObject : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V& value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -315,7 +317,7 @@ class DictObject : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V& value) { if (this PTR_DEREF _mode == DictModeUnknown) this PTR_DEREF _mode = DictModeList; else if (this PTR_DEREF _mode != DictModeList) { @@ -354,6 +356,18 @@ class DictObject : public DictBase { 10, (int)((float)ArraySize(this PTR_DEREF _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -364,7 +378,7 @@ class DictObject : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); int i; @@ -389,7 +403,9 @@ class DictObject : public DictBase { // Freeing old DictSlots array. ArrayFree(this PTR_DEREF _DictSlots_ref.DictSlots); - this PTR_DEREF _DictSlots_ref = new_DictSlots; + delete THIS_ATTR _DictSlots_ref; + + THIS_ATTR _DictSlots_ref = new_DictSlots; return true; } diff --git a/DictSlotsRef.h b/DictSlotsRef.h index ff90c8b17..32da49a6e 100644 --- a/DictSlotsRef.h +++ b/DictSlotsRef.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -42,7 +42,8 @@ template class DictSlot; template -struct DictSlotsRef { +class DictSlotsRef { + public: ARRAY(DictSlot, DictSlots); // Incremental index for dict operating in list mode. @@ -61,14 +62,13 @@ struct DictSlotsRef { _avg_conflicts = 0; } - void operator=(DictSlotsRef& r) { - Util::ArrayCopy(DictSlots, r.DictSlots); - _list_index = r._list_index; - _num_used = r._num_used; - _num_conflicts = r._num_conflicts; - _avg_conflicts = r._avg_conflicts; - } + private: + /** + * Private assignment operator to avoid invalid copying. + */ + void operator=(DictSlotsRef& r) {} + public: /** * Adds given number of conflicts for an insert action, so we can store average number of conflicts. */ diff --git a/DictStruct.mqh b/DictStruct.mqh index 5f7ff54b3..5b5c6e1c9 100644 --- a/DictStruct.mqh +++ b/DictStruct.mqh @@ -90,6 +90,9 @@ class DictStruct : public DictBase { } void Clear() { + delete _DictSlots_ref; + _DictSlots_ref = new DictSlotsRef(); + for (unsigned int i = 0; i < (unsigned int)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots); ++i) { THIS_ATTR _DictSlots_ref.DictSlots[i].SetFlags(0); } @@ -256,7 +259,7 @@ class DictStruct : public DictBase { /** * Inserts value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, const K key, V& value, bool allow_resize) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, const K key, V& value, bool allow_resize) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeDict; else if (THIS_ATTR _mode != DictModeDict) { @@ -361,7 +364,7 @@ class DictStruct : public DictBase { /** * Inserts hashless value into given array of DictSlots. */ - bool InsertInto(DictSlotsRef& dictSlotsRef, V& value) { + bool InsertInto(DictSlotsRef*& dictSlotsRef, V& value) { if (THIS_ATTR _mode == DictModeUnknown) THIS_ATTR _mode = DictModeList; else if (THIS_ATTR _mode != DictModeList) { @@ -398,6 +401,18 @@ class DictStruct : public DictBase { MathMax(10, (int)((float)ArraySize(THIS_ATTR _DictSlots_ref.DictSlots) * ((float)(percent + 100) / 100.0f)))); } + public: + /** + * Ensures that there is at least given number of slots in dict. + */ + bool Reserve(int _size) { + if (_size <= ArraySize(THIS_ATTR _DictSlots_ref.DictSlots)) { + return true; + } + return Resize(_size); + } + + protected: /** * Shrinks or expands array of DictSlots. */ @@ -407,7 +422,7 @@ class DictStruct : public DictBase { return true; } - DictSlotsRef new_DictSlots; + DictSlotsRef* new_DictSlots = new DictSlotsRef(); if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) { return false; @@ -432,7 +447,9 @@ class DictStruct : public DictBase { } } // Freeing old DictSlots array. - ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots); + ArrayFree(THIS_ATTR _DictSlots_ref PTR_DEREF DictSlots); + + delete THIS_ATTR _DictSlots_ref; THIS_ATTR _DictSlots_ref = new_DictSlots; diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index 8a75ed9b4..7b8ad1c86 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -96,11 +96,11 @@ class IndicatorCandle : public Indicator { */ IndicatorCandle(const TS& _icparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_icparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR, INDI_CANDLE_HISTORY_SIZE) { Init(); } IndicatorCandle(ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name), history(INDI_CANDLE_HISTORY_SIZE) { + : Indicator(_itype, _shift, _name), history(THIS_PTR, INDI_CANDLE_HISTORY_SIZE) { Init(); } @@ -361,7 +361,11 @@ class IndicatorCandle : public Indicator { * because otherwise, we could end up with OnCalculate() working on partial * history candles. */ - void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) override {} + void OnDataSourceWillEmitEntries(ENUM_INDI_EMITTED_ENTRY_TYPE _type, int _num_entries) override { + if (_type == INDI_EMITTED_ENTRY_TYPE_CANDLE) { + idata.Reserve(_num_entries); + } + } /** * Returns value storage of given kind. diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 4cbccc76c..1b45a6cac 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -34,7 +34,7 @@ #include "../Storage/ItemsHistory.h" /** - * Regenerates candles and updates exising candles from new ticks. Subclasses by IndicatorTf, IndicatorRenko. + * Regenerates candles and updates exising candles from new ticks. Subclassed by IndicatorTf, IndicatorRenko. */ template class ItemsHistoryCandleProvider : public ItemsHistoryItemProvider> { diff --git a/Indicator/IndicatorTick.h b/Indicator/IndicatorTick.h index 29c298696..f9bbfbb9e 100644 --- a/Indicator/IndicatorTick.h +++ b/Indicator/IndicatorTick.h @@ -25,8 +25,8 @@ #define INDICATOR_TICK_H #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -83,7 +83,7 @@ class IndicatorTick : public Indicator { */ IndicatorTick(string _symbol, const TS& _itparams, const IndicatorDataParams& _idparams, IndicatorData* _indi_src = NULL, int _indi_mode = 0) - : Indicator(_itparams, _idparams, _indi_src, _indi_mode) { + : Indicator(_itparams, _idparams, _indi_src, _indi_mode), history(THIS_PTR) { itparams = _itparams; if (_indi_src != NULL) { THIS_ATTR SetDataSource(_indi_src, _indi_mode); @@ -92,7 +92,7 @@ class IndicatorTick : public Indicator { Init(); } IndicatorTick(string _symbol, ENUM_INDICATOR_TYPE _itype = INDI_CANDLE, int _shift = 0, string _name = "") - : Indicator(_itype, _shift, _name) { + : Indicator(_itype, _shift, _name), history(THIS_PTR) { symbol = _symbol; Init(); } diff --git a/Indicators/Tf/Indi_TfMt.provider.h b/Indicators/Tf/Indi_TfMt.provider.h index 4af7095de..55e9cf0e3 100644 --- a/Indicators/Tf/Indi_TfMt.provider.h +++ b/Indicators/Tf/Indi_TfMt.provider.h @@ -153,6 +153,10 @@ class ItemsHistoryTfMtCandleProvider : public ItemsHistoryCandleProvider { int _num_copied = CopyRates(indi PTR_DEREF GetSymbol(), indi PTR_DEREF GetTf(), _end_shift, _count, _rates); ArrayResize(_out_arr, _num_copied); + // Acknowledging indicator that we will emit _num_copied number of candles. + _history PTR_DEREF GetIndicator() + PTR_DEREF OnDataSourceWillEmitEntries(INDI_EMITTED_ENTRY_TYPE_CANDLE, _num_copied); + for (int i = 0; i < _num_copied; ++i) { MqlRates _rate = _rates[i]; int _start_secs = (int)(long)_rate.time; diff --git a/Storage/ItemsHistory.h b/Storage/ItemsHistory.h index 5560e8ffc..1420a5076 100644 --- a/Storage/ItemsHistory.h +++ b/Storage/ItemsHistory.h @@ -100,6 +100,9 @@ class ItemsHistoryItemProvider : public Dynamic { */ template class ItemsHistory { + // Indicator the history is provided for. + IndicatorData* indi; + // Provides items from bound provider. Ref item_provider; @@ -136,13 +139,16 @@ class ItemsHistory { /** * Constructor */ - ItemsHistory(unsigned int _history_max_size = 0) - : history_max_size(_history_max_size), + ItemsHistory(IndicatorData* _indi, unsigned int _history_max_size = 0) + : indi(_indi), + history_max_size(_history_max_size), current_index(0), first_valid_index(0), first_valid_index_ever(0), last_valid_index(0), - peak_size(0) {} + peak_size(0) { + history.SetMaxConflicts(25); + } /** * Returns item provider. @@ -163,6 +169,11 @@ class ItemsHistory { } */ + /** + * Returns indicator the history is provided for. + */ + IndicatorData* GetIndicator() { return indi; } + /** * Returns maximum number of items that occupied the history. Could be used e.g., to determine how many bars could be * retrieved from history and past the history.