//+------------------------------------------------------------------+ //| 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_DOM_BUILDERSDEFS_MQH #define JSONPARSERBYLEO_SRC_DOM_BUILDERSDEFS_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "..\\JsonNode\\JsonNode.mqh" #include "..\\Ser\\JsonEscape.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; }; //+------------------------------------------------------------------+ struct JsonBuilderFSnapshot : JsonBuilderSnapshot { uchar buf[]; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); //--- __forceinline void GetSnapshotF(JsonBuilderFSnapshot& snap); __forceinline void ApplySnapshotF(JsonBuilderFSnapshot& 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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ __forceinline void CJsonBuilderBase::GetSnapshotF(JsonBuilderFSnapshot &snap) { snap.sp = m_sp; snap.pos = m_pos; snap.stack_first = m_stack_first[m_sp]; ArraySwap(snap.buf, m_buf); // snap buff ahora es m_buf m_cap = ArraySize(m_buf); // Actulizamos } //+------------------------------------------------------------------+ __forceinline void CJsonBuilderBase::ApplySnapshotF(JsonBuilderFSnapshot &snap) { m_sp = snap.sp; m_pos = snap.pos; m_stack_first[m_sp] = snap.stack_first; ArraySwap(m_buf, snap.buf); // ahora somso snap buff m_cap = ArraySize(m_buf); // Actulizamos } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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_DOM_BUILDERSDEFS_MQH