| //+------------------------------------------------------------------+
|
| //| 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 "JsonEscape.mqh"
|
| #include <TSN\\MQLArticles\\Utils\\FA\\Str\\Conv.mqh>
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| #define JSONBUILDER_EXPAND_E(need) if(m_pos + (need) >= m_cap) { m_cap += (need) + 32; ArrayResize(m_buf, m_cap, m_cap); }
|
| #define JSONBUILDER_EXPAND(need) JSONBUILDER_EXPAND_E(need)
|
|
|
| //---
|
| #ifndef JSONBUILDER_MAX_STACK
|
| #define JSONBUILDER_MAX_STACK (16)
|
| #endif // JSONBUILDER_MAX_STACK
|
|
|
|
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| namespace TSN
|
| {
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| #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;
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| struct pack(sizeof(int)) JsonBuilderSnapshot
|
| {
|
| int pos;
|
| uchar sp;
|
| bool stack_first;
|
| };
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| class CJsonBuilderBase
|
| {
|
| public:
|
| uchar m_buf[];
|
| int m_pos;
|
| int m_cap;
|
|
|
| protected:
|
| bool m_stack_first[JSONBUILDER_MAX_STACK];
|
| uchar m_sp;
|
|
|
| public:
|
| CJsonBuilderBase(int initial_cap = 1024);
|
| ~CJsonBuilderBase() {}
|
|
|
| //---
|
| // limpieza
|
| void Clear();
|
| // truncar tamaño del arra
|
| __forceinline void Truncate() { m_cap = ArrayResize(m_buf, m_pos); }
|
|
|
| //---
|
| // Chekear si se peude soporta cap.. si no se revera de golope (esto no incluye la reserva extra..)
|
| __forceinline void CheckReserve(int cap) { if(m_pos + cap >= m_cap) { m_cap += cap; ArrayResize(m_buf, m_cap); } }
|
|
|
| //--- contruir
|
| __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); }
|
|
|
|
|
| //--- Structure
|
| CJsonBuilderBase* Obj();
|
| CJsonBuilderBase* EndObj();
|
| CJsonBuilderBase* Arr();
|
| CJsonBuilderBase* EndArr();
|
|
|
| //--- Valores
|
| //- Integer
|
| CJsonBuilderBase* Val(int v);
|
| CJsonBuilderBase* Val(long v);
|
| CJsonBuilderBase* Val(uint v);
|
| CJsonBuilderBase* Val(ulong v);
|
|
|
| //- Double
|
| CJsonBuilderBase* Val(double v, uchar digits = 8);
|
|
|
| //- Bool
|
| 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);
|
|
|
| //---
|
| __forceinline void GetSnapshot(JsonBuilderSnapshot& snap);
|
| __forceinline void ApplySnapshot(const JsonBuilderSnapshot& snap);
|
| };
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| 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;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| __forceinline void CJsonBuilderBase::GetSnapshot(JsonBuilderSnapshot &snap)
|
| {
|
| snap.sp = m_sp;
|
| snap.pos = m_pos;
|
| snap.stack_first = m_stack_first[m_sp];
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| __forceinline void CJsonBuilderBase::ApplySnapshot(const JsonBuilderSnapshot &snap)
|
| {
|
| m_sp = snap.sp;
|
| m_pos = snap.pos;
|
| m_stack_first[m_sp] = snap.stack_first;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| 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 + 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 << 2) + 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 << 2) + 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++] = '{';
|
|
|
| //---
|
| m_sp++;
|
| m_stack_first[m_sp] = true;
|
| return &this;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::EndObj()
|
| {
|
| //---
|
| if(m_sp)
|
| 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++] = '[';
|
|
|
| //---
|
| m_sp++;
|
| m_stack_first[m_sp] = true;
|
| return &this;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::EndArr()
|
| {
|
| //---
|
| if(m_sp)
|
| m_sp--;
|
|
|
| //---
|
| JSON_BUILDER_PUT(']')
|
| m_stack_first[m_sp] = false;
|
| return &this;
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::Val(int v)
|
| {
|
| //---
|
| JSONBUILDER_EXPAND_E((MQLARTICLES_CONV_MAXDIG_I + 1))
|
| JSON_BUILDER_COMMA_F
|
| STRCONV_VALTOBUFFER_SIGNED(v, m_buf, m_pos, uint, uvalue)
|
| return &this;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::Val(long v)
|
| {
|
| //---
|
| JSONBUILDER_EXPAND_E((MQLARTICLES_CONV_MAXDIG_L + 1))
|
| JSON_BUILDER_COMMA_F
|
| STRCONV_VALTOBUFFER_SIGNED(v, m_buf, m_pos, ulong, uvalue)
|
| return &this;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::Val(uint v)
|
| {
|
| //---
|
| JSONBUILDER_EXPAND_E((MQLARTICLES_CONV_MAXDIG_I + 1))
|
| JSON_BUILDER_COMMA_F
|
| STRCONV_VALTOBUFFER_USIGNED(v, m_buf, m_pos)
|
| return &this;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::Val(ulong v)
|
| {
|
| //---
|
| JSONBUILDER_EXPAND_E((MQLARTICLES_CONV_MAXDIG_UL + 1))
|
| JSON_BUILDER_COMMA_F
|
| STRCONV_VALTOBUFFER_USIGNED(v, m_buf, m_pos);
|
| return &this;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| CJsonBuilderBase* CJsonBuilderBase::Val(double v, uchar digits = 8)
|
| {
|
| //---
|
| JSONBUILDER_EXPAND_E(MQLARTICLES_CONV_MAXDIG_DBL(digits))
|
| JSON_BUILDER_COMMA_F
|
|
|
| //---
|
| 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;
|
| }
|
|
|
| //---
|
| CValueToBuffer::ToValue(v, m_buf, m_pos, digits);
|
| 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
|