Skip to content

Commit

Permalink
Merge pull request #757 from nseam/v3.008-dev-new--dict-uses-class-ge…
Browse files Browse the repository at this point in the history
…t-entry-problem

WIP. Dict now uses class instead of struct in order to prevent copying slots two times.
  • Loading branch information
kenorb committed Jul 7, 2024
2 parents 28205be + e7ba4d5 commit 80672f1
Show file tree
Hide file tree
Showing 31 changed files with 1,465 additions and 788 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
Language: Cpp
BasedOnStyle: Google
ColumnLimit: 120
IndentPPDirectives: BeforeHash
21 changes: 17 additions & 4 deletions Candle.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

// Forward class declaration.
Expand Down Expand Up @@ -262,9 +262,12 @@ struct CandleOCTOHLC : CandleOHLC<T> {
#endif

/**
* Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price.
* Initializes candle with a given start time, length in seconds, first tick's timestamp and its price.
*/
void Init(int _start_time, int _length, long _timestamp_ms = -1, T _price = 0) {
if (_start_time < 0) {
Print("Error!");
}
is_complete = false;
start_time = _start_time;
length = _length;
Expand All @@ -279,7 +282,16 @@ struct CandleOCTOHLC : CandleOHLC<T> {
*/
void Update(long _timestamp_ms, T _price) {
if (!ContainsTimeMs(_timestamp_ms)) {
Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame!");
Print("Error: Cannot update candle. Given time doesn't fit in candle's time-frame! Given time ", _timestamp_ms,
", but candle range is ", (long)start_time * 1000, " - ", (long)(start_time + length) * 1000, ".");
long _ms;
if (_timestamp_ms < (long)start_time * 1000) {
_ms = (long)start_time * 1000 - _timestamp_ms;
Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, " s) before the candle starts.");
} else {
_ms = _timestamp_ms - (long)(start_time + length) * 1000;
Print("Looks like given time is ", _ms, " ms (", (double)_ms / 1000, "s) after the candle ends.");
}
DebugBreak();
}

Expand All @@ -288,6 +300,7 @@ struct CandleOCTOHLC : CandleOHLC<T> {
if (_is_init || _timestamp_ms < open_timestamp_ms) {
open_timestamp_ms = _timestamp_ms;
THIS_ATTR open = _price;
start_time = int(_timestamp_ms / 1000);
}
if (_is_init || _timestamp_ms > close_timestamp_ms) {
close_timestamp_ms = _timestamp_ms;
Expand Down
8 changes: 4 additions & 4 deletions Dict.enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
*/

#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

#define DICT_GROW_UP_PERCENT_DEFAULT 25
#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 10
#define DICT_GROW_UP_PERCENT_DEFAULT 100
#define DICT_PERFORMANCE_PROBLEM_AVG_CONFLICTS 20

/**
* Whether Dict operates in yet uknown mode, as dict or as list.
Expand Down
22 changes: 19 additions & 3 deletions Dict.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class Dict : public DictBase<K, V> {
}

void Clear() {
_DictSlots_ref = new DictSlotsRef<K, V>();

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);
}
Expand Down Expand Up @@ -210,7 +212,7 @@ class Dict : public DictBase<K, V> {
/**
* Inserts value into given array of DictSlots.
*/
bool InsertInto(DictSlotsRef<K, V>& dictSlotsRef, const K key, V value, bool allow_resize) {
bool InsertInto(DictSlotsRef<K, V>*& dictSlotsRef, const K key, V value, bool allow_resize) {
if (THIS_ATTR _mode == DictModeUnknown)
THIS_ATTR _mode = DictModeDict;
else if (THIS_ATTR _mode != DictModeDict) {
Expand Down Expand Up @@ -315,7 +317,7 @@ class Dict : public DictBase<K, V> {
/**
* Inserts hashless value into given array of DictSlots.
*/
bool InsertInto(DictSlotsRef<K, V>& dictSlotsRef, V value) {
bool InsertInto(DictSlotsRef<K, V>*& dictSlotsRef, V value) {
if (THIS_ATTR _mode == DictModeUnknown)
THIS_ATTR _mode = DictModeList;
else if (THIS_ATTR _mode != DictModeList) {
Expand Down Expand Up @@ -353,6 +355,18 @@ class Dict : public DictBase<K, V> {
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.
*/
Expand All @@ -362,7 +376,7 @@ class Dict : public DictBase<K, V> {
return true;
}

DictSlotsRef<K, V> new_DictSlots;
DictSlotsRef<K, V>* new_DictSlots = new DictSlotsRef<K, V>();

if (ArrayResize(new_DictSlots.DictSlots, new_size) == -1) return false;

Expand All @@ -389,6 +403,8 @@ class Dict : public DictBase<K, V> {
// Freeing old DictSlots array.
ArrayFree(THIS_ATTR _DictSlots_ref.DictSlots);

delete THIS_ATTR _DictSlots_ref;

THIS_ATTR _DictSlots_ref = new_DictSlots;

return true;
Expand Down
50 changes: 42 additions & 8 deletions DictBase.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ class DictBase {
_mode = DictModeUnknown;
_flags = 0;
overflow_listener = nullptr;
_DictSlots_ref = new DictSlotsRef<K, V>();
}

/**
* Destructor.
*/
~DictBase() {}
~DictBase() { delete _DictSlots_ref; }

DictIteratorBase<K, V> Begin() {
// Searching for first item index.
Expand Down Expand Up @@ -106,7 +107,7 @@ class DictBase {
/**
* Returns slot by key.
*/
DictSlot<K, V>* GetSlotByKey(DictSlotsRef<K, V>& dictSlotsRef, const K _key, unsigned int& position) {
DictSlot<K, V>* GetSlotByKey(DictSlotsRef<K, V>*& dictSlotsRef, const K _key, unsigned int& position) {
unsigned int numSlots = ArraySize(dictSlotsRef.DictSlots);

if (numSlots == 0) return NULL;
Expand Down Expand Up @@ -137,7 +138,7 @@ class DictBase {
/**
* Returns slot by position.
*/
DictSlot<K, V>* GetSlotByPos(DictSlotsRef<K, V>& dictSlotsRef, const unsigned int position) {
DictSlot<K, V>* GetSlotByPos(DictSlotsRef<K, V>*& dictSlotsRef, const unsigned int position) {
return dictSlotsRef.DictSlots[position].IsUsed() ? &dictSlotsRef.DictSlots[position] : NULL;
}

Expand Down Expand Up @@ -335,9 +336,9 @@ class DictBase {

protected:
/**
* Array of DictSlots.
* Pointer to array of DictSlots.
*/
DictSlotsRef<K, V> _DictSlots_ref;
DictSlotsRef<K, V>* _DictSlots_ref;

DictOverflowListener overflow_listener;
unsigned int overflow_listener_max_conflicts;
Expand Down Expand Up @@ -378,17 +379,50 @@ class DictBase {
/**
* Specialization of hashing function.
*/
unsigned int Hash(unsigned int x) { return x; }
unsigned int Hash(float x) { return (unsigned int)((unsigned long)x * 10000 % 10000); }

/**
* Specialization of hashing function.
*/
unsigned int Hash(int x) { return (unsigned int)x; }
unsigned int Hash(int value) {
value ^= (value >> 8);
value ^= (value << 3);
value ^= (value >> 9);
value ^= (value >> 4);
value ^= (value << 6);
value ^= (value >> 14);
return value;
}

/**
* Specialization of hashing function.
*/
unsigned int Hash(float x) { return (unsigned int)((unsigned long)x * 10000 % 10000); }
unsigned int Hash(unsigned int value) { return Hash((int)value); }

/**
* Specialization of hashing function.
*/
unsigned int Hash(long value) {
value ^= (value >> 33);
value ^= (value << 21);
value ^= (value >> 17);

// Step 2: Combine upper and lower 32 bits to form a 32-bit hash
long hash = (int)(value ^ (value >> 32));

// Step 3: Further bit manipulation to spread the bits
hash ^= (hash >> 16);
hash *= 0x85ebca6b; // A large prime number
hash ^= (hash >> 13);
hash *= 0xc2b2ae35; // Another large prime number
hash ^= (hash >> 16);
return int(value >> 32);
}

/**
* Specialization of hashing function.
*/
unsigned int Hash(unsigned long value) { return Hash((unsigned long)value); }
};

#endif
28 changes: 22 additions & 6 deletions DictObject.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -105,6 +105,8 @@ class DictObject : public DictBase<K, V> {
}

void Clear() {
_DictSlots_ref = new DictSlotsRef<K, V>();

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);
}
Expand Down Expand Up @@ -210,7 +212,7 @@ class DictObject : public DictBase<K, V> {
/**
* Inserts value into given array of DictSlots.
*/
bool InsertInto(DictSlotsRef<K, V>& dictSlotsRef, const K key, V& value, bool allow_resize) {
bool InsertInto(DictSlotsRef<K, V>*& dictSlotsRef, const K key, V& value, bool allow_resize) {
if (THIS_ATTR _mode == DictModeUnknown)
THIS_ATTR _mode = DictModeDict;
else if (THIS_ATTR _mode != DictModeDict) {
Expand Down Expand Up @@ -315,7 +317,7 @@ class DictObject : public DictBase<K, V> {
/**
* Inserts hashless value into given array of DictSlots.
*/
bool InsertInto(DictSlotsRef<K, V>& dictSlotsRef, V& value) {
bool InsertInto(DictSlotsRef<K, V>*& dictSlotsRef, V& value) {
if (this PTR_DEREF _mode == DictModeUnknown)
this PTR_DEREF _mode = DictModeList;
else if (this PTR_DEREF _mode != DictModeList) {
Expand Down Expand Up @@ -354,6 +356,18 @@ class DictObject : public DictBase<K, V> {
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.
*/
Expand All @@ -364,7 +378,7 @@ class DictObject : public DictBase<K, V> {
return true;
}

DictSlotsRef<K, V> new_DictSlots;
DictSlotsRef<K, V>* new_DictSlots = new DictSlotsRef<K, V>();

int i;

Expand All @@ -389,7 +403,9 @@ class DictObject : public DictBase<K, V> {
// 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;
}
Expand Down
20 changes: 10 additions & 10 deletions DictSlotsRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -42,7 +42,8 @@ template <typename K, typename V>
class DictSlot;

template <typename K, typename V>
struct DictSlotsRef {
class DictSlotsRef {
public:
ARRAY(DictSlot<K _COMMA V>, DictSlots);

// Incremental index for dict operating in list mode.
Expand All @@ -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.
*/
Expand Down
Loading

0 comments on commit 80672f1

Please sign in to comment.