533 lines
13 KiB
MQL5
533 lines
13 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| BuilderDefs.mqh |
| |
//| Copyright 2026, Niquel Mendoza. |
| |
//| https://www.mql5.com/ |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2026, Niquel Mendoza."
| |
#property link "https://www.mql5.com/"
| |
#property strict
| |
| |
#ifndef JSONPARSERBYLEO_SRC_BUILDERSDEFS_MQH
| |
#define JSONPARSERBYLEO_SRC_BUILDERSDEFS_MQH
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#include "JsonDefines.mqh"
| |
#include <TSN\\Tables\\DPairs.mqh>
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#define JSONBUILDER_EXPAND(need) if(m_pos + (need) >= m_cap) { m_cap += (need) + 4096; ArrayResize(m_buf, m_cap, m_cap); }
| |
#define JSONBUILDER_EXPAND_E(need) if(m_pos + (need) >= m_cap) { m_cap += (need); ArrayResize(m_buf, m_cap, m_cap); }
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#define JSON_BUILDER_PUT(c) \
| |
JSONBUILDER_EXPAND(1) \
| |
m_buf[m_pos++] = c; \
| |
| |
//---
| |
#define JSON_BUILDER_COMMA \
| |
if(!m_stack_first[m_sp]) \
| |
{ \
| |
JSON_BUILDER_PUT(',') \
| |
} \
| |
m_stack_first[m_sp] = false;
| |
| |
//---
| |
#define JSON_BUILDER_COMMA_F \
| |
if(!m_stack_first[m_sp]) \
| |
{ \
| |
m_buf[m_pos++] = ','; \
| |
} \
| |
m_stack_first[m_sp] = false;
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
namespace TSN
| |
{
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class CJsonBuilderBase
| |
{
| |
public:
| |
uchar m_buf[];
| |
int m_pos;
| |
int m_cap;
| |
| |
protected:
| |
bool m_stack_first[64];
| |
int m_sp;
| |
| |
public:
| |
CJsonBuilderBase(int initial_cap = 1024);
| |
~CJsonBuilderBase() {}
| |
| |
//---
| |
void Clear();
| |
| |
//---
| |
__forceinline string Build() const { return CharArrayToString(m_buf, 0, m_pos, CP_UTF8); }
| |
__forceinline int Build(uchar& out[], int dst_start = 0) const { return ArrayCopy(out, m_buf, dst_start, 0, m_pos); }
| |
__forceinline void Truncate() { m_cap = ArrayResize(m_buf, m_pos, m_cap); }
| |
| |
| |
//--- Structure
| |
CJsonBuilderBase* Obj();
| |
CJsonBuilderBase* EndObj();
| |
CJsonBuilderBase* Arr();
| |
CJsonBuilderBase* EndArr();
| |
| |
// Valor basico
| |
CJsonBuilderBase* Val(int v);
| |
CJsonBuilderBase* Val(long value);
| |
CJsonBuilderBase* Val(double v, int digits = 8);
| |
CJsonBuilderBase* Val(bool v);
| |
| |
// Null
| |
CJsonBuilderBase* Null();
| |
| |
//---
| |
void CheckCap();
| |
void CheckComma();
| |
| |
//--- Put raw
| |
void PutChar(const uchar c);
| |
void PutRawNoRef(const string s);
| |
void PutRaw(const string& s);
| |
void PutRaw(const uchar& s[], int count = WHOLE_ARRAY);
| |
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase::CJsonBuilderBase(int initial_cap)
| |
{
| |
m_cap = initial_cap;
| |
ArrayResize(m_buf, m_cap);
| |
m_pos = 0;
| |
m_sp = 0;
| |
m_stack_first[0] = true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::CheckCap(void)
| |
{
| |
if(m_pos >= m_cap)
| |
{
| |
m_cap = m_pos + 4096;
| |
ArrayResize(m_buf, m_cap, m_cap);
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::CheckComma(void)
| |
{
| |
JSON_BUILDER_COMMA
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::Clear()
| |
{
| |
m_pos = 0;
| |
m_sp = 0;
| |
m_stack_first[0] = true;
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::PutChar(const uchar c)
| |
{
| |
JSON_BUILDER_PUT(c)
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::PutRaw(const uchar& s[], int count = WHOLE_ARRAY)
| |
{
| |
//---
| |
const int l = (count == WHOLE_ARRAY) ? ArraySize(s) : fmin(ArraySize(s), count);
| |
const int max_bytes = l * 4 + 1;
| |
JSONBUILDER_EXPAND(max_bytes)
| |
| |
//---
| |
m_pos += ArrayCopy(m_buf, s, m_pos, 0, l);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::PutRaw(const string& s)
| |
{
| |
//---
| |
const int l = StringLen(s);
| |
const int max_bytes = l * 4 + 1;
| |
JSONBUILDER_EXPAND(max_bytes)
| |
| |
//---
| |
int written = StringToCharArray(s, m_buf, m_pos, WHOLE_ARRAY, CP_UTF8);
| |
if(written > 0 && m_buf[m_pos + written - 1] == 0)
| |
written--;
| |
m_pos += written;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
void CJsonBuilderBase::PutRawNoRef(const string s)
| |
{
| |
//---
| |
const int l = StringLen(s);
| |
const int max_bytes = l * 4 + 1;
| |
JSONBUILDER_EXPAND(max_bytes)
| |
| |
//---
| |
int written = StringToCharArray(s, m_buf, m_pos, WHOLE_ARRAY, CP_UTF8);
| |
if(written > 0 && m_buf[m_pos + written - 1] == 0)
| |
written--;
| |
m_pos += written;
| |
}
| |
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Obj()
| |
{
| |
JSONBUILDER_EXPAND_E(3)
| |
JSON_BUILDER_COMMA_F
| |
m_buf[m_pos++] = '{';
| |
| |
//---
| |
if(m_sp < 63)
| |
{
| |
m_sp++;
| |
m_stack_first[m_sp] = true;
| |
}
| |
return &this;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::EndObj()
| |
{
| |
if(m_sp > 0)
| |
m_sp--;
| |
| |
//---
| |
JSON_BUILDER_PUT('}')
| |
m_stack_first[m_sp] = false;
| |
return &this;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Arr()
| |
{
| |
//---
| |
JSONBUILDER_EXPAND_E(3)
| |
JSON_BUILDER_COMMA_F
| |
m_buf[m_pos++] = '[';
| |
| |
//---
| |
if(m_sp < 63)
| |
{
| |
m_sp++;
| |
m_stack_first[m_sp] = true;
| |
}
| |
return &this;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::EndArr()
| |
{
| |
if(m_sp > 0)
| |
m_sp--;
| |
JSON_BUILDER_PUT(']')
| |
m_stack_first[m_sp] = false;
| |
return &this;
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Val(int v)
| |
{
| |
//---
| |
// 11 slots para int (10 digitos + signo) + 1 comma + 1 extra
| |
JSONBUILDER_EXPAND_E(13)
| |
JSON_BUILDER_COMMA_F
| |
| |
//---
| |
if(v == 0)
| |
{
| |
m_buf[m_pos++] = '0';
| |
return &this;
| |
}
| |
| |
//---
| |
bool negativo = (v < 0);
| |
uint uvalue;
| |
if(negativo)
| |
{
| |
m_buf[m_pos++] = '-';
| |
uvalue = (uint)(-(v + 1)) + 1; // evita overflow con INT_MIN
| |
}
| |
else
| |
{
| |
uvalue = (uint)v;
| |
}
| |
| |
//---
| |
static uchar digits[12];
| |
int n = 0;
| |
| |
//---
| |
while(uvalue >= 100)
| |
{
| |
const uint idx = (uvalue % 100U) << 1U;
| |
digits[n++] = g_tsn_digit_pairs[idx + 1];
| |
digits[n++] = g_tsn_digit_pairs[idx];
| |
uvalue /= 100U;
| |
}
| |
//---
| |
if(uvalue >= 10)
| |
{
| |
const uint idx = uvalue << 1U;
| |
digits[n++] = g_tsn_digit_pairs[idx + 1];
| |
digits[n++] = g_tsn_digit_pairs[idx];
| |
}
| |
else
| |
{
| |
digits[n++] = (uchar)('0' + uvalue);
| |
}
| |
| |
//---
| |
for(int j = n - 1; j >= 0; j--)
| |
m_buf[m_pos++] = digits[j];
| |
| |
//---
| |
return &this;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Val(long value)
| |
{
| |
//---
| |
// 25 slots para long + 1 comma+ 1 extra
| |
JSONBUILDER_EXPAND_E(27)
| |
JSON_BUILDER_COMMA_F
| |
| |
//---
| |
if(value == 0)
| |
{
| |
m_buf[m_pos++] = '0';
| |
return &this;
| |
}
| |
| |
//--
| |
int pos = 0;
| |
ulong uvalue;
| |
if(value < 0)
| |
{
| |
m_buf[m_pos++] = '-';
| |
uvalue = ulong(-(value + 1)) + 1;
| |
}
| |
else
| |
{
| |
uvalue = ulong(value);
| |
}
| |
| |
//---
| |
static uchar digits[24];
| |
int n = 0;
| |
| |
//---
| |
while(uvalue >= 100)
| |
{
| |
const ulong idx = (uvalue % 100ULL) << 1ULL;
| |
digits[n++] = g_tsn_digit_pairs[idx + 1];
| |
digits[n++] = g_tsn_digit_pairs[idx];
| |
uvalue /= 100ULL;
| |
}
| |
| |
//---
| |
if(uvalue >= 10)
| |
{
| |
const ulong idx = (uvalue << 1);
| |
digits[n++] = g_tsn_digit_pairs[idx + 1];
| |
digits[n++] = g_tsn_digit_pairs[idx];
| |
}
| |
else
| |
{
| |
digits[n++] = uchar('0' + uvalue);
| |
}
| |
| |
//---
| |
for(int j = n - 1; j >= 0; j--)
| |
m_buf[m_pos++] = digits[j];
| |
| |
//---
| |
return &this;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Val(double v, int digits = 8)
| |
{
| |
//---
| |
JSONBUILDER_EXPAND_E(32)
| |
JSON_BUILDER_COMMA_F
| |
| |
//---
| |
// JSON no soporta NaN/Infinity
| |
if(!MathIsValidNumber(v))
| |
{
| |
m_buf[m_pos++] = 'n';
| |
m_buf[m_pos++] = 'u';
| |
m_buf[m_pos++] = 'l';
| |
m_buf[m_pos++] = 'l';
| |
return &this;
| |
}
| |
//---
| |
if(v < 0)
| |
{
| |
m_buf[m_pos++] = '-';
| |
v = -v;
| |
}
| |
| |
//---
| |
const double factor = g_Pow10[digits];
| |
const ulong escalado = (ulong)MathRound(v * factor);
| |
ulong ent = escalado / (ulong)factor;
| |
ulong dec = escalado % (ulong)factor;
| |
| |
| |
// --- parte entera, mismo algoritmo de 2-en-2 que ya usas ---
| |
if(ent == 0)
| |
{
| |
m_buf[m_pos++] = '0';
| |
}
| |
else
| |
{
| |
static uchar dig_buff[24];
| |
int n = 0;
| |
| |
//---
| |
while(ent >= 100)
| |
{
| |
const ulong idx = (ent % 100ULL) << 1ULL;
| |
dig_buff[n++] = g_tsn_digit_pairs[idx + 1];
| |
dig_buff[n++] = g_tsn_digit_pairs[idx];
| |
ent /= 100ULL;
| |
}
| |
if(ent >= 10)
| |
{
| |
const ulong idx = ent << 1ULL;
| |
dig_buff[n++] = g_tsn_digit_pairs[idx + 1];
| |
dig_buff[n++] = g_tsn_digit_pairs[idx];
| |
}
| |
else
| |
{
| |
dig_buff[n++] = (uchar)('0' + ent);
| |
}
| |
for(int j = n - 1; j >= 0; j--)
| |
m_buf[m_pos++] = dig_buff[j];
| |
}
| |
| |
//--- punto decimal ---
| |
m_buf[m_pos++] = '.';
| |
| |
//--- parte decimal, con ceros a la izquierda (padding fijo a 'digits') ---
| |
static uchar dec_buff[24];
| |
int dn = 0;
| |
| |
//---
| |
if(dec == 0)
| |
{
| |
dec_buff[dn++] = '0';
| |
}
| |
else
| |
{
| |
while(dec >= 100)
| |
{
| |
const ulong idx = (dec % 100ULL) << 1ULL;
| |
dec_buff[dn++] = g_tsn_digit_pairs[idx + 1];
| |
dec_buff[dn++] = g_tsn_digit_pairs[idx];
| |
dec /= 100ULL;
| |
}
| |
if(dec >= 10)
| |
{
| |
const ulong idx = dec << 1ULL;
| |
dec_buff[dn++] = g_tsn_digit_pairs[idx + 1];
| |
dec_buff[dn++] = g_tsn_digit_pairs[idx];
| |
}
| |
else
| |
{
| |
dec_buff[dn++] = (uchar)('0' + dec);
| |
}
| |
}
| |
//---
| |
// padding de ceros a la izquierda para completar 'digits' posiciones
| |
const int padding = digits - dn;
| |
for(int p = 0; p < padding; p++)
| |
m_buf[m_pos++] = '0';
| |
for(int j = dn - 1; j >= 0; j--)
| |
m_buf[m_pos++] = dec_buff[j];
| |
| |
//---
| |
return &this;
| |
}
| |
| |
| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Val(bool v)
| |
{
| |
JSONBUILDER_EXPAND_E(7)
| |
JSON_BUILDER_COMMA_F
| |
if(v)
| |
{
| |
m_buf[m_pos++] = 't';
| |
m_buf[m_pos++] = 'r';
| |
m_buf[m_pos++] = 'u';
| |
m_buf[m_pos++] = 'e';
| |
}
| |
else
| |
{
| |
m_buf[m_pos++] = 'f';
| |
m_buf[m_pos++] = 'a';
| |
m_buf[m_pos++] = 'l';
| |
m_buf[m_pos++] = 's';
| |
m_buf[m_pos++] = 'e';
| |
}
| |
return &this;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CJsonBuilderBase* CJsonBuilderBase::Null()
| |
{
| |
JSONBUILDER_EXPAND_E(6)
| |
JSON_BUILDER_COMMA_F
| |
m_buf[m_pos++] = 'n';
| |
m_buf[m_pos++] = 'u';
| |
m_buf[m_pos++] = 'l';
| |
m_buf[m_pos++] = 'l';
| |
return &this;
| |
}
| |
| |
//--- end namespace
| |
}
| |
| |
#endif // JSONPARSERBYLEO_SRC_BUILDERSDEFS_MQH
|