185 lines
8.5 KiB
Plaintext
185 lines
8.5 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| 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;
|
|
}
|