MQL5Book/Include/OutputStream.mqh

157 lines
4.2 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:09:41 +02:00
//+------------------------------------------------------------------+
//| OutputStream.mqh |
//| Copyright 2021, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Print a sequence of data via overloaded operator<< |
//+------------------------------------------------------------------+
class OutputStream
{
protected:
int digits;
ushort delimiter;
int timemode;
string line;
// remove trailing delimiter
string trimDelimiter() const
{
if(delimiter != 0)
{
int n = StringLen(line);
if(n > 0)
{
if(StringGetCharacter(line, n - 1) == delimiter)
{
return StringSubstr(line, 0, n - 1);
}
}
}
return line;
}
// add new component into the string using delimiter as a glue
void appendWithDelimiter(const string v, const bool skipDelimiter = false)
{
line += v;
if(delimiter != 0 && !skipDelimiter)
{
line += ShortToString(delimiter);
}
}
// detach the string from this and hand over it to caller
string move()
{
string result = trimDelimiter();
line = NULL;
return result;
}
public:
OutputStream(int p = 0, ushort d = 0, int t = TIME_DATE|TIME_MINUTES):
digits(p ? p : _Digits), delimiter(d), timemode(t) { }
OutputStream(string d, int p = 0, int t = TIME_DATE|TIME_MINUTES):
digits(p ? p : _Digits),
delimiter(d[0]),
timemode(t) { }
// flush content into Print or add more from other stream
OutputStream *operator<<(OutputStream &self)
{
// passing itself into << means flush
if(&this == &self)
{
Print(trimDelimiter());
line = NULL;
}
else // append other stream data to this
{
this << self.move();
}
return &this;
}
OutputStream *operator<<(const double v)
{
appendWithDelimiter(v == EMPTY_VALUE ? "<EMPTY_VALUE>" : StringFormat("%.*f", digits, v));
return &this;
}
OutputStream *operator<<(const datetime v)
{
appendWithDelimiter(TimeToString((datetime)v, timemode));
return &this;
}
OutputStream *operator<<(const ushort v)
{
appendWithDelimiter(ShortToString(v));
return &this;
}
OutputStream *operator<<(const color v)
{
string result = (string)v;
// non-embedded colors print in hex
if(StringFind(result, "clr") != 0)
{
result = "clr" + StringFormat("%02X%02X%02X",
((int)v & 0xFF), (((int)v >> 8) & 0xFF), (((int)v >> 16) & 0xFF));
}
appendWithDelimiter(result);
return &this;
}
template<typename T>
OutputStream *operator<<(const T v)
{
appendWithDelimiter((string)v);
return &this;
}
template<typename T>
OutputStream *operator<<(T &a[])
{
int n = ArraySize(a);
this << this;
appendWithDelimiter("[", true);
// we could use ArrayPrint (need to respect datetime settings in flags)
// ArrayPrint(a, digits, ShortToString(delimiter), 0, WHOLE_ARRAY, flags);
for(int i = 0; i < n; i++)
{
this << a[i];
}
line = trimDelimiter();
appendWithDelimiter("]", true);
this << this;
return &this;
}
template<typename T>
OutputStream *operator<<(const T *v)
{
appendWithDelimiter(typename(v) + StringFormat("%lld", v));
return &this;
}
};
//+------------------------------------------------------------------+
/*
// USAGE
OutputStream out(5, ',', TIME_DATE|TIME_MINUTES|TIME_SECONDS);
void OnStart()
{
bool b = true;
datetime dt = TimeCurrent();
color clr = Red;
out << M_PI << "text" << b << dt << clr << out;
}
*/
//+------------------------------------------------------------------+