Files

185 lines
8.5 KiB
Plaintext
Raw Permalink Normal View History

2025-02-07 19:13:59 +03:30
//+------------------------------------------------------------------+
//| 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<typename T>
bool compare(const Pair &v1, const T v2);
};
class Greater: public Comparator
{
public:
template<typename T>
bool compare(const Pair &v1, const T v2)
{
return v1 > v2;
}
};
class Lesser: public Comparator
{
public:
template<typename T>
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<typename T1, typename T2>
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<typename T>
bool Comparator::compare(const Pair &v1, const T v2)
{
Greater *g = dynamic_cast<Greater *>(&this);
if(g != NULL) return g.compare(v1, v2);
Lesser *l = dynamic_cast<Lesser *>(&this);
if(l != NULL) return l.compare(v1, v2);
return false;
}