//+------------------------------------------------------------------+ //| JsonNode.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_JSONNODE_MQH #define JSONPARSERBYLEO_SRC_JSONNODE_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "JsonAsm.mqh" #include "JsonBuilder.mqh" #include "JsonStrBuilder.mqh" #include //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { // Layour de los demas en repo base // Layout cinta: // NULL 1 pos [tipo(4)] //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //--- struct CJsonIteratorArray; struct CJsonIteratorObj; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct CJsonNode : CNodeSFLBase { public: //--- CJsonNode() : CNodeSFLBase(NULL, -1, -1, -1) {} //--- Resuelve m_node_pos una unica vez aqui (igual que YML_NODE_RPOS en YAML) CJsonNode(CJsonParser* _ctx, const int _idx, const int _end) : CNodeSFLBase(_ctx, _idx, _end, NODEBASEF_RES_BASE(_ctx, _idx)) {} CJsonNode(CJsonParser* _ctx, const int _idx) : CNodeSFLBase(_ctx, _idx, _idx + _ctx.GetStep(_idx), NODEBASEF_RES_BASE(_ctx, _idx)) {} //--- Acceso CJsonNode operator[](const string& key); CJsonNode At(const int index) const; CJsonNode AtHomegeneo(const int index) const; CJsonNode AtObj(const int index) const; // Obtiene el valor... //--- Keys string AtObjKey(const int index) const; string AtObjKeyHomogeneo(const int index) const; int KeyToPosition(const string& key) const; int GetKeys(string& out[]) const; bool HasKey(const string& key) const; //--- Array template int ToArray(T& out_arr[]) const; // Exist? template bool ExistInArrayHomogeneo(const T val) const; template bool ExistInArray(const uint flags, const T val) const; bool ExistInArrayStr(const string& val) const; //--- String string ToString(const string def = "") const; int ToStringUArray(uchar& data[]) const; string ToStringNoEscape(const string def = "") const; int ToStringUArrayNoEscape(uchar& data[]) const; int StrLenRaw() const; __forceinline bool CompareStrWith(const string& str) const; // Compara sin pagar el costo de copias.. directo al buffer. // Interpolacion template string Interpolate(const TInterpolate& cs, const string def) const; //--- string ComplexToString(bool clean) const; int ComplexToData(uchar& data[], bool clean, int dst_start = 0, bool ajustar_arr = true) const; //--- Int long ToInt(const long def) const; bool ToIntSafe(long& val) const; //--- Double double ToDouble(const double def) const; bool ToDoubleSafe(double& val) const; //--- __forceinline ENUM_JSON_VTYPE GetType() const { return ENUM_JSON_VTYPE(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE);} //--- Is __forceinline bool IsNull() const; //--- Iteradores CJsonIteratorArray BeginArr() const; CJsonIteratorObj BeginObj() const; //--- Navegacion raw CJsonNode MoveNextPositions(const int posiciones, const bool solo_en_el_bloque_actual = true); }; //--- const CJsonNode EMPTY_JSON_NODE; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CJsonNode::ComplexToString(bool clean) const { if(NODEBASE_IS_NOT_VALID_F || ((1 << int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) & (TSN_SBL_BASE_F_OBJ | TSN_SBL_BASE_F_ARR)) == 0) return ""; //--- const int start = int(m_ctx.m_cinta[m_idx + 1] & 0xFFFFFFFF); const int end = int(m_ctx.m_cinta[m_idx + 1] >> TSN_JSON_BIT_END_T); return clean ? m_ctx.CleanNode(start, end) : CharArrayToString(m_ctx.m_raw, start, (end - start) + 1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CJsonNode::ComplexToData(uchar &data[], bool clean, int dst_start = 0, bool ajustar_arr = true) const { if(NODEBASE_IS_NOT_VALID_F || ((1 << int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) & (TSN_SBL_BASE_F_OBJ | TSN_SBL_BASE_F_ARR)) == 0) return 0; //--- const int start = int(m_ctx.m_cinta[m_idx + 1] & 0xFFFFFFFF); const int end = int(m_ctx.m_cinta[m_idx + 1] >> TSN_JSON_BIT_END_T); return clean ? m_ctx.CleanNode(start, end, data, dst_start, ajustar_arr) : ArrayCopy(data, m_ctx.m_raw, dst_start, start, (end - start) + 1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonNode CJsonNode::operator[](const string& key) { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return EMPTY_JSON_NODE; //--- Iterar pares KEY+VAL // Print("Call"); if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING) & TSN_SBL_BIT_MASK_IS_HASHSING) == 0) { //Print("No esta hasheado buscando o(n)"); //--- int c = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_C_HASH) & TSN_SBL_BIT_MASK_NUM_C_HASH; //Print("Contador actual: ", c); if(c >= TSN_JSON_JIT_MIN_REF_TO_HASING) // Veriricamos si supero { if(NodeHashing()) { //Print("Hasheado"); //--- Obtenemos posicion int val_pos = m_ctx.PerfectHashComputeHash(key, m_node_pos); if(val_pos == -1) { return EMPTY_JSON_NODE; } else { val_pos++; // Luego de key return CJsonNode(m_ctx, val_pos, val_pos + m_ctx.GetStep(val_pos)); } } //Print("No se pudo hashear"); // Si llega aqui es por que fallo.. en ese caso reiniciamos los intetnos.. //--- c = 0; const long mask = long(TSN_SBL_BIT_MASK_NUM_C_HASH) << TSN_SBL_BIT_START_NUM_C_HASH; // máscara de 3 bits en pos 5 m_ctx.m_cinta[m_idx] = (m_ctx.m_cinta[m_idx] & ~mask) | (c << TSN_SBL_BIT_START_NUM_C_HASH); } else { // Aun no.. solo aumentamos y modificamos.. c++; const long mask = long(TSN_SBL_BIT_MASK_NUM_C_HASH) << TSN_SBL_BIT_START_NUM_C_HASH; // máscara de 3 bits en pos 5 m_ctx.m_cinta[m_idx] = (m_ctx.m_cinta[m_idx] & ~mask) | (c << TSN_SBL_BIT_START_NUM_C_HASH); } //--- Linear probing.. de siempre... int cur = m_idx + 2; while(cur < m_end) { if(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_KEY) { cur += m_ctx.GetStep(cur); continue; } if(m_ctx.StrEquals(key, cur)) { const int val_pos = cur + 1; return CJsonNode(m_ctx, val_pos, val_pos + m_ctx.GetStep(val_pos)); } //--- cur++; // salta KEY cur += m_ctx.GetStep(cur); // salta VAL } return EMPTY_JSON_NODE; } //--- m_node_pos ya viene resuelto desde el constructor int val_pos = m_ctx.PerfectHashComputeHash(key, m_node_pos); if(val_pos == -1) { return EMPTY_JSON_NODE; } else { val_pos++; // Luego de key return CJsonNode(m_ctx, val_pos, val_pos + m_ctx.GetStep(val_pos)); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonNode::HasKey(const string &key) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return false; //--- Iterar pares KEY+VAL if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING)&B'1')==0) { //--- Linear probing.. de siempre... int cur = m_idx + 2; while(cur < m_end) { if(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_KEY) { cur += m_ctx.GetStep(cur); continue; } if(m_ctx.StrEquals(key, cur)) { return true; } //--- cur++; // salta KEY cur += m_ctx.GetStep(cur); // salta VAL } return false; } //--- return m_ctx.PerfectHashComputeHash(key, m_node_pos) != -1; } //+------------------------------------------------------------------+ //| At — acceso por indice en ARR | //+------------------------------------------------------------------+ CJsonNode CJsonNode::At(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return EMPTY_JSON_NODE; //--- int cur = m_idx + 2; for(int k = 0; k < index; k++) cur += m_ctx.GetStep(cur); return CJsonNode(m_ctx, cur, cur + m_ctx.GetStep(cur)); } //+------------------------------------------------------------------+ //| AtHomegeneo — acceso por indice en ARR con step fijo | //+------------------------------------------------------------------+ CJsonNode CJsonNode::AtHomegeneo(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return EMPTY_JSON_NODE; //--- const int first = m_idx + 2; const int step = m_ctx.GetStep(first); const int cur = first + index * step; return CJsonNode(m_ctx, cur, cur + step); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonNode CJsonNode::AtObj(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return EMPTY_JSON_NODE; //--- int cur = 0; if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING) & 1) != 0) { cur = m_ctx.m_tables[m_node_pos].pos_arr[index] + 1;// Ahora mismo apunta a key saltos al valor.. } else { cur = m_idx + 2; // Ahora mismo apunta a key.. for(int k = 0; k < index; k++) { cur++; // Salta key cur += m_ctx.GetStep(cur); } } //--- return CJsonNode(m_ctx, cur, cur + m_ctx.GetStep(cur)); } //+------------------------------------------------------------------+ //| AtObjKey — key string del par en posicion index dentro de OBJ | //+------------------------------------------------------------------+ string CJsonNode::AtObjKey(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return ""; //--- int cur = 0; if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING) & 1) != 0) { //--- Objeto ya hasheado, m_node_pos ya viene resuelto desde el constructor. // Usamos pos_arr en vez de recorrer linealmente (esta funcion no fuerza el JIT, solo lo aprovecha). cur = m_ctx.m_tables[m_node_pos].pos_arr[index]; } else { cur = m_idx + 2; for(int k = 0; k < index; k++) { cur++; // salta KEY (1 pos) cur += m_ctx.GetStep(cur); // salta VAL } } //--- TSN_SBL_BIT_STR_MASK_LEN // KEY ocupa 1 pos: [tipo(4)|len(28low)|start(32high)] (igual que STRING) const int start = int(m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return CharArrayToString(m_ctx.m_raw, start, slen); } //+------------------------------------------------------------------+ //| AtObjKeyHomogeneo — igual pero asume step fijo del VAL | //+------------------------------------------------------------------+ string CJsonNode::AtObjKeyHomogeneo(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return ""; //--- step fijo = 1(KEY) + step(primer VAL) const int first_val = m_idx + 3; const int val_step = m_ctx.GetStep(first_val); const int pair_step = 1 + val_step; // key+val const int key_pos = (m_idx + 2) + index * pair_step; //--- KEY ocupa 1 pos: [tipo(4)|len(28low)|start(32high)] (igual que STRING) const int start = int(m_ctx.m_cinta[key_pos] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[key_pos] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return CharArrayToString(m_ctx.m_raw, start, slen); } //+------------------------------------------------------------------+ //| KeyToPosition — indice posicional de una key dentro del objeto | //+------------------------------------------------------------------+ int CJsonNode::KeyToPosition(const string &key) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return -1; //--- if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING) & 1) != 0) { //--- Ya hasheado, m_node_pos ya viene resuelto desde el constructor return m_ctx.PerfectHashComputeHashIndex(key, m_node_pos); } else { int cur = m_idx + 2; int k = 0; while(cur < m_end) { if(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_KEY) { cur += m_ctx.GetStep(cur); continue; } if(m_ctx.StrEquals(key, cur)) return k; //--- cur++; // salta KEY cur += m_ctx.GetStep(cur); // salta VAL k++; } return -1; } } //+------------------------------------------------------------------+ //| GetKeys — vacia todas las keys del objeto a un array de strings | //+------------------------------------------------------------------+ int CJsonNode::GetKeys(string &out[]) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return 0; //--- if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING) & 1) != 0) { //--- Ya hasheado, m_node_pos ya viene resuelto desde el constructor const int count = m_ctx.m_tables[m_node_pos].table_size; ArrayResize(out, count); for(int i = 0; i < count; i++) { const int cur = m_ctx.m_tables[m_node_pos].pos_arr[i]; const int start = int(m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); out[i] = CharArrayToString(m_ctx.m_raw, start, slen); } return count; } else { //--- const int count = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); ArrayResize(out, count); //--- int i = 0; int cur = m_idx + 2; while(cur < m_end) { const int start = int(m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); out[i++] = CharArrayToString(m_ctx.m_raw, start, slen); //--- cur++; // salta KEY cur += m_ctx.GetStep(cur); // salta VAL } //--- return count; } } //+------------------------------------------------------------------+ //| String | //+------------------------------------------------------------------+ string CJsonNode::ToString(const string def = "") const { //--- if(NODEBASE_IS_NOT_VALID_F) return def; //--- switch(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_INTEGER: return string(m_ctx.m_cinta[m_idx + 1]); case JSON_VTYPE_REAL: { static BitInterpreter un; un.long_value = m_ctx.m_cinta[m_idx + 1]; return string(un.double_value); } case JSON_VTYPE_BOOLEAN: return ((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & 1) != 0 ? "true" : "false"; case JSON_VTYPE_STRING: { const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return m_ctx.Unescape(start, start + slen - 1); } } return def; } //+------------------------------------------------------------------+ template string CJsonNode::Interpolate(const TInterpolate& cs, const string def) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_STRING) return def; //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return cs.Interpolate(m_ctx.m_raw, start, start + slen - 1, def); } //+------------------------------------------------------------------+ string CJsonNode::ToStringNoEscape(const string def = "") const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_STRING) return def; //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return CharArrayToString(m_ctx.m_raw, start, slen); //--- return def; } //+------------------------------------------------------------------+ int CJsonNode::ToStringUArray(uchar & data[]) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_STRING) return 0; //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return m_ctx.Unescape(start, start + slen - 1, data); } //+------------------------------------------------------------------+ int CJsonNode::ToStringUArrayNoEscape(uchar &data[]) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_STRING) return 0; //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return ArrayCopy(data, m_ctx.m_raw, 0, start, slen); } //+------------------------------------------------------------------+ int CJsonNode::StrLenRaw(void) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_STRING) return 0; //--- return int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); } //+------------------------------------------------------------------+ __forceinline bool CJsonNode::CompareStrWith(const string &str) const { if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_STRING) return false; return m_ctx.StrEquals(str, m_idx); } //+------------------------------------------------------------------+ //| Arrays | //+------------------------------------------------------------------+ template int CJsonNode::ToArray(T &out_arr[]) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return 0; //--- const int count = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); ArrayResize(out_arr, count); //--- int cur = m_idx + 2; int k = 0; //--- switch(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_INTEGER: { while(cur < m_end) { out_arr[k++] = T(m_ctx.m_cinta[cur + 1]); cur += 2; } return count; } case JSON_VTYPE_REAL: { while(cur < m_end) { static BitInterpreter bit; bit.long_value = m_ctx.m_cinta[cur + 1]; out_arr[k++] = T(bit.double_value); cur += 2; } return count; } case JSON_VTYPE_BOOLEAN: { while(cur < m_end) { out_arr[k++] = T((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_START_ENDTYPE) & 1); cur++; } return count; } case JSON_VTYPE_STRING: { while(cur < m_end) { const int start = int(m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); out_arr[k++] = T(m_ctx.Unescape(start, start + slen - 1)); cur++; } return count; } } //--- return 0; } //+------------------------------------------------------------------+ template bool CJsonNode::ExistInArray(const uint flags, const T val) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return false; //--- int cur = m_idx + 2; while(cur < m_end) { //--- const uint ct = 1U << uint(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE); if((ct & flags) == 0) { cur += m_ctx.GetStep(cur); continue; } //--- switch(ct) { case JSON_VTYPE_INTEGER: { if(m_ctx.m_cinta[cur + 1] == T(val)) return true; break; } case JSON_VTYPE_REAL: { bit.long_value = m_ctx.m_cinta[cur + 1]; if(bit.double_value == T(val)) return true; break; } case JSON_VTYPE_BOOLEAN: { if(val == T((m_ctx.m_cinta[cur] >> TSN_JSON_BIT_START_ENDTYPE) & 1)) return true; break; } case JSON_VTYPE_STRING: { const int start = int(m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); if(val == T(m_ctx.Unescape(start, start + slen - 1))) return true; break; } case JSON_VTYPE_NULL: { return true; } } //--- cur += m_ctx.GetStep(cur); } //--- return false; } //+------------------------------------------------------------------+ bool CJsonNode::ExistInArrayStr(const string& val) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return false; //--- int cur = m_idx + 2; while(cur < m_end) { //--- const int ct = int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE); if(ct != JSON_VTYPE_STRING) { cur += m_ctx.GetStep(cur); continue; } //--- const int start = int(m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); if(val == m_ctx.Unescape(start, start + slen - 1)) return true; //--- cur += m_ctx.GetStep(cur); } //--- return false; } //+------------------------------------------------------------------+ template bool CJsonNode::ExistInArrayHomogeneo(const T val) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return false; //--- int cur = m_idx + 2; //--- switch(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_INTEGER: { while(cur < m_end) { if(val == T(m_ctx.m_cinta[cur + 1])) return true; cur += 2; } return false; } case JSON_VTYPE_REAL: { while(cur < m_end) { static BitInterpreter bit; bit.long_value = m_ctx.m_cinta[cur + 1]; if(val == T(bit.double_value)) return true; //--- cur += 2; } return false; } case JSON_VTYPE_BOOLEAN: { while(cur < m_end) { if(val == T((m_ctx.m_cinta[cur] >> TSN_JSON_BIT_START_ENDTYPE) & 1)) return true; cur++; } return false; } } //--- return false; } //+------------------------------------------------------------------+ //| ToInt | //+------------------------------------------------------------------+ long CJsonNode::ToInt(const long def) const { //--- if(NODEBASE_IS_NOT_VALID_F) return def; //--- switch(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) { case TSN_SBL_BASE_TYPE_INT: return m_ctx.m_cinta[m_idx + 1]; case TSN_SBL_BASE_TYPE_FLT: { static BitInterpreter un; un.long_value = m_ctx.m_cinta[m_idx + 1]; return long(un.double_value); } case TSN_SBL_BASE_TYPE_BOL: return long((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & 1); case TSN_SBL_BASE_TYPE_STR: { const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return long(CharArrayToString(m_ctx.m_raw, start, slen)); } } return def; } //+------------------------------------------------------------------+ bool CJsonNode::ToIntSafe(long & val) const { //--- if(NODEBASE_IS_NOT_VALID_F) return false; //--- switch(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) { case TSN_SBL_BASE_TYPE_INT: val = m_ctx.m_cinta[m_idx + 1]; return true; case TSN_SBL_BASE_TYPE_FLT: { static BitInterpreter un; un.long_value = m_ctx.m_cinta[m_idx + 1]; val = long(un.double_value); return true; } case TSN_SBL_BASE_TYPE_BOL: val = long((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & 1); return true; case TSN_SBL_BASE_TYPE_STR: { const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); val = long(CharArrayToString(m_ctx.m_raw, start, slen)); return true; } } return false; } //+------------------------------------------------------------------+ //| ToDouble | //+------------------------------------------------------------------+ double CJsonNode::ToDouble(const double def) const { //--- if(NODEBASE_IS_NOT_VALID_F) return def; //--- switch(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) { case TSN_SBL_BASE_TYPE_INT: return double(m_ctx.m_cinta[m_idx + 1]); case TSN_SBL_BASE_TYPE_FLT: { static BitInterpreter un; un.long_value = m_ctx.m_cinta[m_idx + 1]; return un.double_value; } case TSN_SBL_BASE_TYPE_BOL: return double((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & 1); case TSN_SBL_BASE_TYPE_STR: { const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); return double(CharArrayToString(m_ctx.m_raw, start, slen)); } } return def; } //+------------------------------------------------------------------+ bool CJsonNode::ToDoubleSafe(double & val) const { //--- if(NODEBASE_IS_NOT_VALID_F) return false; //--- switch(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)) { case TSN_SBL_BASE_TYPE_INT: val = double(m_ctx.m_cinta[m_idx + 1]); return true; case TSN_SBL_BASE_TYPE_FLT: { static BitInterpreter un; un.long_value = m_ctx.m_cinta[m_idx + 1]; val = un.double_value; return true; } case TSN_SBL_BASE_TYPE_BOL: val = double((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & 1); return true; case TSN_SBL_BASE_TYPE_STR: { const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); val = double(CharArrayToString(m_ctx.m_raw, start, slen)); return true; } } return false; } //+------------------------------------------------------------------+ //| Is | //+------------------------------------------------------------------+ __forceinline bool CJsonNode::IsNull() const { return NODEBASE_IS_VALID && int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) == JSON_VTYPE_NULL; } //+------------------------------------------------------------------+ //| Navegacion raw | //+------------------------------------------------------------------+ CJsonNode CJsonNode::MoveNextPositions(const int posiciones, const bool solo_en_el_bloque_actual = true) { //--- if(NODEBASE_IS_NOT_VALID_F) return EMPTY_JSON_NODE; //--- const int next_pos = m_idx + posiciones; const int final_pos = solo_en_el_bloque_actual ? m_end : next_pos + m_ctx.GetStep(next_pos); //--- if(next_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos)) return EMPTY_JSON_NODE; //--- return CJsonNode(m_ctx, next_pos, final_pos); } //+------------------------------------------------------------------+ //| Iterador de arrays | //+------------------------------------------------------------------+ struct CJsonIteratorArray { CJsonParser* const m_ctx; int m_cur; const int m_end; //--- CJsonIteratorArray(CJsonParser* ctx, const int cur, const int end) : m_ctx(ctx), m_cur(cur), m_end(end) {} //--- CJsonIteratorArray() : m_ctx(NULL), m_cur(0), m_end(0) {} //--- __forceinline bool IsValid() { return m_cur < m_end; } __forceinline void Kill() { m_cur = m_end; } //--- void Next() { if(m_cur >= m_end) return; m_cur += m_ctx.GetStep(m_cur); } //--- CJsonNode Val() { if(m_cur >= m_end) return EMPTY_JSON_NODE; const int fin = m_cur + m_ctx.GetStep(m_cur); return CJsonNode(m_ctx, m_cur, fin); } }; const CJsonIteratorArray EMPTY_JSON_ITERATOR_ARR; //+------------------------------------------------------------------+ //| Iterador de objetos | //+------------------------------------------------------------------+ struct CJsonIteratorObj { CJsonParser* const m_ctx; int m_cur; const int m_end; //--- CJsonIteratorObj(CJsonParser* ctx, const int cur, const int end) : m_ctx(ctx), m_cur(cur), m_end(end) {} //--- CJsonIteratorObj() : m_ctx(NULL), m_cur(0), m_end(0) {} //--- __forceinline bool IsValid() { return m_cur < m_end; } __forceinline void Kill() { m_cur = m_end; } //--- void Next() { if(m_cur >= m_end) return; m_cur++; // salta KEY (2 pos) m_cur += m_ctx.GetStep(m_cur); // salta VAL } //--- string Key() { if(m_cur >= m_end) return ""; //--- KEY ocupa 1 pos: [tipo(4)|len(28low)|start(32high)] (igual que STRING) const int s = int(m_ctx.m_cinta[m_cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_ctx.m_cinta[m_cur] >> TSN_SBL_BIT_STR_LEN) & 0xFFFFFFF); return CharArrayToString(m_ctx.m_raw, s, slen); } //--- CJsonNode Val() { if(m_cur >= m_end) return EMPTY_JSON_NODE; const int pos = m_cur + 1; const int fin = pos + m_ctx.GetStep(pos); return CJsonNode(m_ctx, pos, fin); } }; //--- const CJsonIteratorObj EMPTY_JSON_ITERATOR_OBJ; //+------------------------------------------------------------------+ //| BeginArr / BeginObj | //+------------------------------------------------------------------+ CJsonIteratorArray CJsonNode::BeginArr() const { if(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_ARR) return EMPTY_JSON_ITERATOR_ARR; return CJsonIteratorArray(m_ctx, m_idx + 2, m_end); } //+------------------------------------------------------------------+ CJsonIteratorObj CJsonNode::BeginObj() const { if(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_OBJ) return EMPTY_JSON_ITERATOR_OBJ; return CJsonIteratorObj(m_ctx, m_idx + 2, m_end); } //--- } //+------------------------------------------------------------------+ #endif // JSONPARSERBYLEO_SRC_JSONNODE_MQH