//+------------------------------------------------------------------+ //| NodeBase.mqh | //| Copyright 2026, Niquel Mendoza. | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza." #property link "https://www.mql5.com/" #property strict #ifndef BASESPARSERSLAN_SRC_NODEBASE_MQH #define BASESPARSERSLAN_SRC_NODEBASE_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "DomImp.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define NODEBASEF_RES_BASE(_ctx_, _idx_) ((_ctx_ != NULL && int(_ctx_.m_cinta[_idx_] & TSN_SBL_BIT_MASK_TYPE) == TSN_SBL_BASE_TYPE_OBJ) ? _ctx_.FindNodePos(_idx_) : -1) #define NODEBASEF_RES m_node_pos = NODEBASEF_RES_BASE(m_ctx, m_idx); #define NODEBASE_IS_NOT_VALID_F (m_ctx == NULL) #define NODEBASE_IS_VALID (m_ctx != NULL) #define NODEBASE_IS_NOT_VALID_FULL (m_ctx == NULL || m_idx < 1 || m_end < 1) //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template struct CNodeBaseIteradorArray; template struct CNodeBaseIteratorObj; template struct CNodeBaseIteratorArrayFast; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template struct CNodeSFLBase { //--- TCtx* m_ctx; int m_idx; int m_end; int m_node_pos; //--- CNodeSFLBase(TCtx* ctx, const int idx, const int end, const int node_pos) : m_ctx(ctx), m_idx(idx), m_end(end), m_node_pos(node_pos) {} //--- Acceso TOut Get(const ulong hash_fnv1a_64); // obtener por hash TOut At(const int index) const; // obtener por hash TOut AtHomegeneo(const int index) const; TOut AtObj(const int index) const; // Obtiene el valor... TOut Query(const string& path); //--- Keys bool HasKey(const string &key) const; int GetKeys(string &out[]) const; int KeyToPosition(const string &key) const; string AtObjKey(const int index) const; string AtObjKeyHomogeneo(const int index) const; // Array exist template bool ExistInArrayHomogeneo(const T val) const; //--- __forceinline void RecalcNodePos() { NODEBASEF_RES } //--- Tipo __forceinline TType GetType() const { return TType(m_ctx.m_cinta[m_idx] & 0xF); } __forceinline uint GetFlag() const { return 1 << uint(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE); } __forceinline string TypeToMqlStr() const { return TCtx::s_dtype_to_str[int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)]; } //--- Bool bool ToBool(const bool def) const; bool ToBoolSafe(bool& val) const; //--- To template __forceinline TValue GetAs() { return TValue(&this); } //--- Is __forceinline bool IsValid() const; __forceinline bool IsInvalid() const; __forceinline bool IsArray() const; __forceinline bool IsObject() const; __forceinline bool IsValidDataType() const; //--- Size (arr u obj) int Size() const; __forceinline bool InRange(const int index) const; bool InRangeSafe(const int index) const; //--- JIT bool NodeHashing(); __forceinline bool ObjectIsJit() const; __forceinline int ObjectAttempCount() const; //--- Mov raw bool MoveToNextToken(const bool solo_en_el_bloque_actual = true); bool MoveNextPositionsThis(const int posiciones, const bool solo_en_el_bloque_actual = true); TOut MoveNextPositions(const int posiciones, const bool solo_en_el_bloque_actual = true); //--- Dom bool ToDom(CDomNodeBase* root, CDomNodeManager* manager); //--- Iteradores CNodeBaseIteradorArray BeginArr() const; CNodeBaseIteradorArrayFast BeginArrHomogeneo() const; CNodeBaseIteratorObj BeginObj() const; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::Query(const string &path) { //--- 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 TOut::EMPTY_NODE; //--- if(path == "") return TOut(m_ctx, m_idx, m_end, m_node_pos); // clonamos //--- if(path[0] != '/') return TOut::EMPTY_NODE; //--- TOut curr(m_ctx, m_idx, m_end, m_node_pos); const int l = StringLen(path); int p = 1; //--- while(true) { const uchar t = (uchar)curr.GetType(); if(t == TSN_SBL_BASE_TYPE_OBJ) { //--- Calcula y va escapando el key hash...y avanza p const ulong khash = TCtx::EscapePointer(path, p, l); // Ahora mismo en final o / //--- curr = curr.Get(khash); if(curr.IsInvalid()) return TOut::EMPTY_NODE; } else if(t == TSN_SBL_BASE_TYPE_ARR) { //--- uchar ch = (uchar)path[p] ^ '0'; int last_index = -1; //--- if(ch < 10) { last_index = 0; while(true) { //--- last_index = (last_index << 3) + (last_index << 1) + ch; p++; if(p >= l) break; //--- ch = (uchar)path[p]; // p luego del / if(ch == '/') { p++; break; } //-- ch ^= '0'; } } //--- if(!curr.InRangeSafe(last_index)) return TOut::EMPTY_NODE; //-- Accedemos curr = curr.At(last_index); } else { // No se puede return TOut::EMPTY_NODE; } //--- if(p >= l) return curr; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::Get(const ulong hash_fnv1a_64) { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return TOut::EMPTY_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_NODEBASEREAD_MIN_JIT_ATTEMPS_TO_PHASH) // Veriricamos si supero { if(NodeHashing()) { //Print("Hasheado"); //--- Obtenemos posicion int val_pos = m_ctx.PerfectHashAcces(hash_fnv1a_64, m_node_pos); if(val_pos == -1) { return TOut::EMPTY_NODE; } else { val_pos++; // Luego de key return TOut(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 + TCtx::s_slots_size_arrobj; while(cur < m_end) { if(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_KEY) { cur += m_ctx.GetStep(cur); continue; } if(m_ctx.KeysEqual(hash_fnv1a_64, cur)) { const int val_pos = cur + 1; return TOut(m_ctx, val_pos, val_pos + m_ctx.GetStep(val_pos)); } //--- cur++; // salta KEY cur += m_ctx.GetStep(cur); // salta VAL } return TOut::EMPTY_NODE; } //--- m_node_pos ya viene resuelto desde el constructor int val_pos = m_ctx.PerfectHashAcces(hash_fnv1a_64, m_node_pos); if(val_pos == -1) { return TOut::EMPTY_NODE; } else { val_pos++; // Luego de key return TOut(m_ctx, val_pos, val_pos + m_ctx.GetStep(val_pos)); } } //+------------------------------------------------------------------+ //| AtHomegeneo — acceso por indice en ARR con step fijo | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::AtHomegeneo(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_ARR) return TOut::EMPTY_NODE; //--- const int first = m_idx + TCtx::s_slots_size_arrobj; const int step = m_ctx.GetStep(first); const int cur = first + index * step; return TOut(m_ctx, cur, cur + step); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::AtObj(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return TOut::EMPTY_NODE; //--- int cur = 0; if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING)&TSN_SBL_BIT_MASK_IS_HASHSING) != 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 + TCtx::s_slots_size_arrobj; // Ahora mismo apunta a key.. for(int k = 0; k < index; k++) { cur++; // Salta key cur += m_ctx.GetStep(cur); } } //--- return TOut(m_ctx, cur, cur + m_ctx.GetStep(cur)); } //+------------------------------------------------------------------+ //| At — acceso por indice en ARR | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::At(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_ARR) return TOut::EMPTY_NODE; //--- int cur = m_idx + TCtx::s_slots_size_arrobj; for(int k = 0; k < index; k++) cur += m_ctx.GetStep(cur); //--- return TOut(m_ctx, cur, cur + m_ctx.GetStep(cur)); } //+------------------------------------------------------------------+ //| AtObjKey — key string del par en posicion index dentro de OBJ | //+------------------------------------------------------------------+ template string CNodeSFLBase::AtObjKey(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return ""; //--- int cur = 0; if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING)&TSN_SBL_BIT_MASK_IS_HASHSING) != 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 + TCtx::s_slots_size_arrobj; 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 | //+------------------------------------------------------------------+ template string CNodeSFLBase::AtObjKeyHomogeneo(const int index) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return ""; //--- step fijo = 1(KEY) + step(primer VAL) const int first_val = m_idx + TCtx::s_slots_size_arrobj + 1; const int val_step = m_ctx.GetStep(first_val); const int pair_step = 1 + val_step; // key+val const int key_pos = (m_idx + TCtx::s_slots_size_arrobj) + 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); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template int CNodeSFLBase::KeyToPosition(const string &key) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return -1; //--- if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING)&TSN_SBL_BIT_MASK_IS_HASHSING) != 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 + TCtx::s_slots_size_arrobj; int k = 0; while(cur < m_end) { if(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_KEY) { cur += m_ctx.GetStep(cur); continue; } if(m_ctx.KeysEqual(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 | //+------------------------------------------------------------------+ template int CNodeSFLBase::GetKeys(string &out[]) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return 0; //--- if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING)&TSN_SBL_BIT_MASK_IS_HASHSING) != 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 + TCtx::s_slots_size_arrobj; 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; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CNodeSFLBase::HasKey(const string &key) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return false; //--- Iterar pares KEY+VAL if(((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING)&TSN_SBL_BIT_MASK_IS_HASHSING) == 0) { //--- Linear probing.. de siempre... int cur = m_idx + TCtx::s_slots_size_arrobj; while(cur < m_end) { if(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_KEY) { cur += m_ctx.GetStep(cur); continue; } if(m_ctx.KeysEqual(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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CNodeSFLBase::ToDom(CDomNodeBase* root, CDomNodeManager* manager) { //--- 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 false; m_ctx.SerializeToDom(root, manager, m_idx, m_end); return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+} template bool CNodeSFLBase::NodeHashing(void) { //--- if(NODEBASE_IS_NOT_VALID_F || (m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return false; //--- if(m_ctx.NodeHashing(m_idx, int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL), m_end, m_node_pos)) { m_ctx.m_cinta[m_idx] = m_ctx.m_cinta[m_idx] | (long(1) << TSN_SBL_BIT_START_IS_HASING); return true; } else { return false; } } //+------------------------------------------------------------------+ //| Jit instrocpeccion | //+------------------------------------------------------------------+ template __forceinline bool CNodeSFLBase::ObjectIsJit(void) const { return NODEBASE_IS_NOT_VALID_F || ((m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) ? false : ((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_IS_HASING) & TSN_SBL_BIT_MASK_IS_HASHSING) != 0; } //+------------------------------------------------------------------+ template __forceinline int CNodeSFLBase::ObjectAttempCount(void) const { return NODEBASE_IS_NOT_VALID_F || ((m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) ? 0 : int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_C_HASH) & TSN_SBL_BIT_MASK_NUM_C_HASH; } //+------------------------------------------------------------------+ //| Size | //+------------------------------------------------------------------+ template int CNodeSFLBase::Size() 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; //--- return int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); } //+------------------------------------------------------------------+ template __forceinline bool CNodeSFLBase::InRange(const int index) const { const int t = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); return index >= 0 && index < t; } //+------------------------------------------------------------------+ template bool CNodeSFLBase::InRangeSafe(const int index) 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 false; //--- const int t = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); return index >= 0 && index < t; } //+------------------------------------------------------------------+ //| ToBool | //+------------------------------------------------------------------+ template bool CNodeSFLBase::ToBool(const bool 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] != 0; } case TSN_SBL_BASE_TYPE_FLT: { static BitInterpreter un; return un.double_value != 0.0; } case TSN_SBL_BASE_TYPE_BOL: return ((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_BOOL) & 1) != 0; } //--- return def; } //+------------------------------------------------------------------+ template bool CNodeSFLBase::ToBoolSafe(bool & 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] != 0; return true; } case TSN_SBL_BASE_TYPE_FLT: { static BitInterpreter un; val = un.double_value != 0.0; return true; } case TSN_SBL_BASE_TYPE_BOL: val = ((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_BOOL) & 1) != 0; return true; } return false; } //+------------------------------------------------------------------+ //| Is | //+------------------------------------------------------------------+ template __forceinline bool CNodeSFLBase::IsValid() const { return m_ctx != NULL && m_idx >= 0 && m_end >= 0; } template __forceinline bool CNodeSFLBase::IsInvalid() const { return NODEBASE_IS_NOT_VALID_FULL; } //+------------------------------------------------------------------+ template __forceinline bool CNodeSFLBase::IsArray() const { return NODEBASE_IS_VALID && int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) == TSN_SBL_BASE_TYPE_ARR; } //+------------------------------------------------------------------+ template __forceinline bool CNodeSFLBase::IsObject() const { return NODEBASE_IS_VALID && int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) == TSN_SBL_BASE_TYPE_OBJ; } //+------------------------------------------------------------------+ template __forceinline bool CNodeSFLBase::IsValidDataType(void) const { return NODEBASE_IS_VALID && TCtx::s_dtype_is_valid[uchar(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)]; } //+------------------------------------------------------------------+ //| Navegacion raw | //+------------------------------------------------------------------+ template bool CNodeSFLBase::MoveToNextToken(const bool solo_en_el_bloque_actual = true) { //--- if(NODEBASE_IS_NOT_VALID_F) return false; //--- const int next_pos = m_idx + m_ctx.GetStep(m_idx); const int final_pos = next_pos + m_ctx.GetStep(next_pos); //--- if(next_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos)) return false; //--- m_idx = next_pos; m_end = final_pos; //--- NODEBASEF_RES //--- return true; } //+------------------------------------------------------------------+ template bool CNodeSFLBase::MoveNextPositionsThis(const int posiciones, const bool solo_en_el_bloque_actual = true) { //--- if(NODEBASE_IS_NOT_VALID_F) return false; //--- 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 false; //--- m_idx = next_pos; m_end = final_pos; //--- NODEBASEF_RES //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template template bool CNodeSFLBase::ExistInArrayHomogeneo(const T val) const { //--- if(NODEBASE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_ARR) return false; //--- int cur = m_idx + TCtx::s_slots_size_arrobj; //--- switch(int(m_ctx.m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE)) { case TSN_SBL_BASE_TYPE_INT: { while(cur < m_end) { if(val == T(m_ctx.m_cinta[cur + 1])) return true; cur += 2; } return false; } case TSN_SBL_BASE_TYPE_FLT: { 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 TSN_SBL_BASE_TYPE_BOL: { while(cur < m_end) { if(val == T((m_ctx.m_cinta[cur] >> TSN_SBL_BIT_START_ENDTYPE) & 1)) return true; cur++; } return false; } } //--- return false; } //+------------------------------------------------------------------+ //| Navegacion raw | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::MoveNextPositions(const int posiciones, const bool solo_en_el_bloque_actual = true) { //--- if(NODEBASE_IS_NOT_VALID_F) return TOut::EMPTY_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 TOut::EMPTY_NODE; //--- // llamamos a la version con 3 (nodepos se calcula ahi mismo) return TOut(m_ctx, next_pos, final_pos); } //+------------------------------------------------------------------+ //| Iterador de arrays fast | //+------------------------------------------------------------------+ template struct CNodeBaseIteradorArrayFast { TCtx* const m_ctx; int m_cur; const int m_end; const int m_step; //--- CNodeBaseIteradorArrayFast(TCtx* ctx, const int cur, const int end, const int step) : m_ctx(ctx), m_cur(cur), m_end(end), m_step(step) {} //--- CNodeBaseIteradorArrayFast() : m_ctx(NULL), m_cur(0), m_end(0), m_step(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_step; } //--- TOut Val() { if(m_cur >= m_end) return TOut::EMPTY_NODE; const int fin = m_cur + m_step; return TOut(m_ctx, m_cur, fin); } static const CNodeBaseIteradorArrayFast EMPTY_ITERATOR_ARR_FAST; }; template const CNodeBaseIteradorArrayFast CNodeBaseIteradorArrayFast::EMPTY_ITERATOR_ARR_FAST; //+------------------------------------------------------------------+ //| Iterador de arrays | //+------------------------------------------------------------------+ template struct CNodeBaseIteradorArray { TCtx* const m_ctx; int m_cur; const int m_end; //--- CNodeBaseIteradorArray(TCtx* ctx, const int cur, const int end) : m_ctx(ctx), m_cur(cur), m_end(end) {} //--- CNodeBaseIteradorArray() : 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); } //--- TOut Val() { if(m_cur >= m_end) return TOut::EMPTY_NODE; const int fin = m_cur + m_ctx.GetStep(m_cur); return TOut(m_ctx, m_cur, fin); } static const CNodeBaseIteradorArray EMPTY_ITERATOR_ARR; }; template const CNodeBaseIteradorArray CNodeBaseIteradorArray::EMPTY_ITERATOR_ARR; //+------------------------------------------------------------------+ //| Iterador de objetos | //+------------------------------------------------------------------+ template struct CNodeBaseIteratorObj { TCtx* const m_ctx; int m_cur; const int m_end; //--- CNodeBaseIteratorObj(TCtx* ctx, const int cur, const int end) : m_ctx(ctx), m_cur(cur), m_end(end) {} //--- CNodeBaseIteratorObj() : 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) & TSN_SBL_BIT_STR_MASK_LEN); return CharArrayToString(m_ctx.m_raw, s, slen); } //--- TOut Val() { if(m_cur >= m_end) return TOut::EMPTY_NODE; const int pos = m_cur + 1; const int fin = pos + m_ctx.GetStep(pos); return TOut(m_ctx, pos, fin); } static const CNodeBaseIteratorObj EMPTY_ITERATOR_OBJ; }; template const CNodeBaseIteratorObj CNodeBaseIteratorObj::EMPTY_ITERATOR_OBJ; //+------------------------------------------------------------------+ //| BeginArr / BeginObj | //+------------------------------------------------------------------+ template CNodeBaseIteradorArray CNodeSFLBase::BeginArr() const { if(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_ARR) return CNodeBaseIteradorArray::EMPTY_ITERATOR_ARR; return CNodeBaseIteradorArray(m_ctx, m_idx + TCtx::s_slots_size_arrobj, m_end); } //+------------------------------------------------------------------+ template CNodeBaseIteradorArrayFast CNodeSFLBase::BeginArrHomogeneo() const { if(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_ARR) return CNodeBaseIteradorArrayFast::EMPTY_ITERATOR_ARR_FAST; const int s = m_idx + TCtx::s_slots_size_arrobj; return CNodeBaseIteradorArrayFast(m_ctx, s, m_end, m_ctx.GetStep(s)); } //+------------------------------------------------------------------+ template CNodeBaseIteratorObj CNodeSFLBase::BeginObj() const { if(int(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE) != TSN_SBL_BASE_TYPE_OBJ) return CNodeBaseIteratorObj::EMPTY_ITERATOR_OBJ; return CNodeBaseIteratorObj(m_ctx, m_idx + TCtx::s_slots_size_arrobj, m_end); } } //+------------------------------------------------------------------+ #endif // BASESPARSERSLAN_SRC_NODEBASE_MQH