//+------------------------------------------------------------------+ //| PairArray.mqh | //| Copyright © 2019-2020, Marketeer | //| https://www.mql5.com/en/users/marketeer | //+------------------------------------------------------------------+ // aux struct to populate temp array when sorting is enabled struct Pair { double value; string title; Pair(): value(DBL_MAX), title(NULL) {} Pair(const double v, const string s): value(v), title(s) {} Pair(const string s, const double v): value(v), title(s) {} bool operator>(const double v) const { return value > v; } bool operator>(const string s) const { const double d1 = StringToDouble(title); const double d2 = StringToDouble(s); if(d1 != 0 && d2 != 0) return d1 > d2; else if(isNumber(title) && isNumber(s)) { return d1 > d2; } return title > s; } static bool isNumber(const string &s) { ushort a[]; const int n = StringToShortArray(s, a); for(int i = 0; i < n - 1; i++) { if((a[i] < '+' || a[i] > '9') && a[i] != ' ') { return false; } } return true; } }; // this is a common parent, so it can not be templatized class Comparator { public: // templatized method can not be virtual, // so we do artificial dynamic dispatching manually // (see below after declaration of descendant classes) template bool compare(const Pair &v1, const T v2); }; class Greater: public Comparator { public: template bool compare(const Pair &v1, const T v2) { return v1 > v2; } }; class Lesser: public Comparator { public: template bool compare(const Pair &v1, const T v2) { return !(v1 > v2); } }; class PairArray { private: Comparator *comparator; public: // temp array for sorting (if enabled) Pair array[]; PairArray(): comparator(NULL) { } PairArray(const int reserved, Comparator *c = NULL) { comparator = c; ArrayResize(array, reserved); } ~PairArray() { ArrayResize(array, 0); if(CheckPointer(comparator) == POINTER_DYNAMIC) delete comparator; } void allocate(const int reserved) { ArrayResize(array, reserved); } void compareBy(Comparator *c) { if(CheckPointer(comparator) == POINTER_DYNAMIC) delete comparator; comparator = c; } void move(const int index, const int count) { for(int i = count - 1; i >= index; --i) { array[i + 1] = array[i]; } } template void insert(const int count, const T1 v, const T2 s) { Pair p(v, s); for(int i = 0; i < count; i++) { if(comparator != NULL && comparator.compare(array[i], v)) { move(i, count); array[i] = p; return; } } array[count] = p; } void convert(double &x[], string &s[], const bool skipNANs = false) const { int k = 0, n = ArraySize(array); ArrayResize(x, n); ArrayResize(s, n); for(int i = 0; i < n; i++) { if(!skipNANs || MathIsValidNumber(array[i].value)) { x[k] = array[i].value; s[k] = array[i].title; k++; } } ArrayResize(x, k); ArrayResize(s, k); } void convert(double &x[]) const { int n = ArraySize(array); ArrayResize(x, n); for(int i = 0; i < n; i++) { x[i] = array[i].value; } } void convert(string &s[]) const { int n = ArraySize(array); ArrayResize(s, n); for(int i = 0; i < n; i++) { s[i] = array[i].title; } } }; template bool Comparator::compare(const Pair &v1, const T v2) { Greater *g = dynamic_cast(&this); if(g != NULL) return g.compare(v1, v2); Lesser *l = dynamic_cast(&this); if(l != NULL) return l.compare(v1, v2); return false; }