//+------------------------------------------------------------------+ //| 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_NODE_NODEBASE_MQH #define BASESPARSERSLAN_SRC_NODE_NODEBASE_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "..\\DOM\\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; //--- // 1. todo lo que implica devolver un string key si fall retona NULL //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template struct CNodeSFLBase { public: //--- 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 operator[](const string& key); TOut Get(const ulong h); // obtener por hash FNV1A64 __forceinline TOut At(const int index) const; // obtener por hash TOut AtHomegeneo(const int index) const; TOut AtObj(const int index) const; // Obtiene el valor... //--- Pointer (JsonPointer) TOut operator[](BSFLPointerQuery& query); //--- Keys bool HasKey(const string &key) const; int GetKeys(string &out[]) const; int KeyToPosition(const string &key) const; // retorna una posicion en tape int AtObjKey(const int index) const; int AtObjKeyHomogeneo(const int index) const; //--- Arrays template bool ExistInArrayHomogeneo(const T val) const; template int ToArray(T &out_arr[]) const; template bool ExistInArray(const uint flags, const T val) const; //--- __forceinline void RecalcNodePos() { NODEBASEF_RES } //--- Tipo __forceinline TType GetType() const { return TType(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE); } __forceinline uint GetFlag() const { return 1u << int(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(TOut(m_ctx, m_idx, m_end, m_node_pos)); } //--- 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 __forceinline bool ObjectIsJit() const; __forceinline ulong 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; //--- string statico reservado para uso interno... solo para funciones de aqui.. no usar fuera de esto static string __s_node_str; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template string CNodeSFLBase::__s_node_str; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::operator[](const string& key) { //--- 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; //--- ulong h = FNV_OFFSET_BASIS; FNV1A_64_AsM_Str(key, StringLen(key), h, FNV_PRIME) //--- if(m_node_pos != -1) { const int cur = m_ctx.PerfectHashAcces(h, m_ctx.m_tables[m_node_pos]); return cur == -1 ? TOut::EMPTY_NODE : TOut(m_ctx, cur + TSN_SBL_KEYSLOT_SIZE); } //--- Aun es valido if(m_ctx.m_cinta[m_idx] < TSN_SBL_BIT_JIT_ATTEMPS_MASK) // si no tiene el valor invalido de attemps { const ulong v = --m_ctx.m_cinta[m_idx + 1]; // reducimos en 1.. if(v <= 1) // listo para el JIT { const int num_el = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); if(v == 0) // primer valor m_ctx.m_cinta[m_idx + 1] = num_el < TSN_NODEBASEREAD_MIN_JIT_VALUES_TO_HASH ? TSN_SBL_BIT_JIT_INV_VAL : TSN_NODEBASEREAD_MIN_JIT_ATTEMPS_TO_PHASH; else // vale entonces se terminaons los intetenos... probamos.. m_ctx.NodeHashing(m_idx, num_el, m_end, m_node_pos); // si sale false ya pone el try=invalid.. // aparte ya aqui si resulta volveiamos a linear por ultima vez... } } //--- En caso aun estemos porbando o no vale la pena.. entonces lineal.. const int cur = m_ctx.NodeFindByHashFvn1A64(h, m_idx + TSN_SBL_SLOT_OBJ_SIZE, m_end); return cur == -1 ? TOut::EMPTY_NODE : TOut(m_ctx, cur + TSN_SBL_KEYSLOT_SIZE); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template TOut CNodeSFLBase::Get(const ulong h) { //--- 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; //--- if(m_node_pos != -1) { const int cur = m_ctx.PerfectHashAcces(h, m_ctx.m_tables[m_node_pos]); return cur == -1 ? TOut::EMPTY_NODE : TOut(m_ctx, cur + TSN_SBL_KEYSLOT_SIZE); } //--- if(m_ctx.m_cinta[m_idx] < TSN_SBL_BIT_JIT_ATTEMPS_MASK) // si no tiene el valor invalido de attemps { const ulong v = --m_ctx.m_cinta[m_idx + 1]; // reducimos en 1.. if(v <= 1) // listo para el JIT { const int num_el = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); if(v == 0) // primer valor m_ctx.m_cinta[m_idx + 1] = num_el < TSN_NODEBASEREAD_MIN_JIT_VALUES_TO_HASH ? TSN_SBL_BIT_JIT_INV_VAL : TSN_NODEBASEREAD_MIN_JIT_ATTEMPS_TO_PHASH; else // vale entonces se terminaons los intetenos... probamos.. m_ctx.NodeHashing(m_idx, num_el, m_end, m_node_pos); // si sale false ya pone el try=invalid.. // aparte ya aqui si resulta volveiamos a linear por ultima vez... } } //--- En caso aun estemos porbando o no vale la pena.. entonces lineal.. const int cur = m_ctx.NodeFindByHashFvn1A64(h, m_idx + TSN_SBL_SLOT_OBJ_SIZE, m_end); return cur == -1 ? TOut::EMPTY_NODE : TOut(m_ctx, cur + TSN_SBL_KEYSLOT_SIZE); } //+------------------------------------------------------------------+ //| 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 + TSN_SBL_SLOT_ARR_SIZE; const int cur = first + index * m_ctx.GetStep(first); return TOut(m_ctx, cur); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // En caso index>obj size... comportameint indefinido // dado que podra retornba un indice fuera de "rango" del objeto.. asi qeu podira ser basura.. no un valor real por ejemp // [obj][obj][number][number][bool] // ahi si se punta al indice 1... entonces daria como resultao bool... // asi que siempre consultar InRangeSafe (SIEMPRE) 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; //--- // + 1 para aptunar luyego de key const int cur = ((m_node_pos != -1) ? m_ctx.m_tables[m_node_pos].pos_arr[index] : m_ctx.NodeObjAtSlow(m_idx + TSN_SBL_SLOT_OBJ_SIZE, index)) + TSN_SBL_KEYSLOT_SIZE; //--- return TOut(m_ctx, cur); } //+------------------------------------------------------------------+ //| AtObjKey — key string del par en posicion index dentro de OBJ | //+------------------------------------------------------------------+ template int 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 -1; //--- return ((m_node_pos != -1) ? m_ctx.m_tables[m_node_pos].pos_arr[index] : m_ctx.NodeObjAtSlow(m_idx + TSN_SBL_SLOT_OBJ_SIZE, index)); } //+------------------------------------------------------------------+ //| AtObjKeyHomogeneo — igual pero asume step fijo del VAL | //+------------------------------------------------------------------+ template int 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 -1; //--- const int first_val = m_idx + TSN_SBL_SLOT_OBJ_SIZE + 1; const int val_step = m_ctx.GetStep(first_val); const int pair_step = TSN_SBL_KEYSLOT_SIZE + val_step; // key+val const int key_pos = (m_idx + TSN_SBL_SLOT_OBJ_SIZE) + index * pair_step; //--- return key_pos; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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; //--- ulong h = FNV_OFFSET_BASIS; FNV1A_64_AsM_Str(key, StringLen(key), h, FNV_PRIME) //--- if(m_node_pos != -1) // Ya hasheado, m_node_pos ya viene resuelto desde el constructor return m_ctx.PerfectHashComputeHashIndex(h, m_ctx.m_tables[m_node_pos]); else return m_ctx.NodeKeyToPositionSlow(h, m_idx + TSN_SBL_SLOT_OBJ_SIZE, m_end); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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; //--- return m_ctx.NodeGetKeys(m_idx, out, m_end); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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; //--- ulong h = FNV_OFFSET_BASIS; FNV1A_64_AsM_Str(key, StringLen(key), h, FNV_PRIME) //--- return (m_node_pos != -1 ? m_ctx.PerfectHashComputeHashIndex(h, m_ctx.m_tables[m_node_pos]) : m_ctx.NodeFindByHashFvn1A64(h, m_idx + TSN_SBL_SLOT_OBJ_SIZE, m_end)) != -1; } //+------------------------------------------------------------------+ //| At — acceso por indice en ARR | //+------------------------------------------------------------------+ template __forceinline 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; return TOut(m_ctx, m_ctx.NodeAt(m_idx + TSN_SBL_SLOT_ARR_SIZE, index)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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; return m_ctx.SerializeToDom(root, manager, m_idx, m_end); } //+------------------------------------------------------------------+ //| 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 : TSN_SBL_CNG_OBJ_JIT(m_idx) != 0; } //+------------------------------------------------------------------+ template __forceinline ulong 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 : TSN_SBL_CNG_OBJ_JIT_ATTMP(m_idx); } //+------------------------------------------------------------------+ //| 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_UINT: case TSN_SBL_BASE_TYPE_INT: return m_ctx.m_cinta[m_idx + 1] != 0; case TSN_SBL_BASE_TYPE_FLT: { TsnBitInterprete un; un.ulong_value = m_ctx.m_cinta[m_idx + 1]; return un.double_value != 0.0; } case TSN_SBL_BASE_TYPE_BOL: return TSN_SBL_CNG_BOOL(m_idx) != 0; default: 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_UINT: case TSN_SBL_BASE_TYPE_INT: { val = m_ctx.m_cinta[m_idx + 1] != 0; return true; } case TSN_SBL_BASE_TYPE_FLT: { TsnBitInterprete un; un.ulong_value = m_ctx.m_cinta[m_idx + 1]; val = un.double_value != 0.0; return true; } case TSN_SBL_BASE_TYPE_BOL: val = TSN_SBL_CNG_BOOL(m_idx) != 0; return true; default: 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_to_str[uchar(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE)].Length(); } //+------------------------------------------------------------------+ //| 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_tok_pos = m_idx + m_ctx.GetStepPure(m_idx); if(next_tok_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos)) return false; //--- m_idx = next_tok_pos; TOut::OnMute(this); //--- 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; if(next_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos)) return false; //--- m_idx = next_pos; // La idea aqui seria resolver el final.. // En json es facil solo calutar step // En yaml.. tenemos ref\alaises asi que ahi en base a eso avanzamos o saltamos y reciente ahi idx muta // Y se calcula end TOut::OnMute(this); //--- return true; } //+------------------------------------------------------------------+ 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; 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); } //+------------------------------------------------------------------+ //| Arrays | //+------------------------------------------------------------------+ template template __forceinline 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; return m_ctx.ExistInArrayHomogeneo(m_idx + TSN_SBL_SLOT_ARR_SIZE, val, m_end); } //+------------------------------------------------------------------+ template template int CNodeSFLBase::ToArray(T &out_arr[]) 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 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); m_ctx.ToArray(m_idx + TSN_SBL_SLOT_ARR_SIZE, out_arr, m_end); return count; } //+------------------------------------------------------------------+ template template __forceinline bool CNodeSFLBase::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) != TSN_SBL_BASE_TYPE_ARR) return false; //--- return m_ctx.ExistInArray(m_idx + TSN_SBL_SLOT_ARR_SIZE, val, flags, m_end); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // ADVERTENCIA: // 1. El flujo CORRECTO es solo usar una vez este iterador (un solo bucle de consulta) // Ahora dentro de se bucle puede llamar a las funciones que ud desee // Y dentro de esas funciones como Value etc... NO SE VALIDA el is valid.. // dado qeu se COMPRENDE que si se llama de esas funciones ES POR QUE se esta en la parte valida del bucle // Solo las funciones Next tiene el chekeo.. de "es valido" // 2. Aparte KEY siempre debera de tener un slot eso ya esta MENCIONADO en SPEC.md //+------------------------------------------------------------------+ //| 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; } //--- __forceinline void Next() { if(m_cur >= m_end) return; m_cur += m_step; } //--- __forceinline TOut Val() { return TOut(m_ctx, m_cur, m_cur + m_step); } //--- 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; } //--- __forceinline void Next() { if(m_cur >= m_end) return; m_cur += m_ctx.GetStep(m_cur); } //--- __forceinline TOut Val() { return TOut(m_ctx, m_cur, (m_cur + m_ctx.GetStep(m_cur))); } 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; } //--- __forceinline void Next() { if(m_cur >= m_end) return; m_cur += TSN_SBL_KEYSLOT_SIZE; // KEY SIEMPRE UN SLOT m_cur += m_ctx.GetStep(m_cur); } //--- __forceinline int KeyIndex() const { return m_cur; } __forceinline ulong KeyValue() const { return m_ctx.m_cinta[m_cur]; } //--- __forceinline TOut Val() const { const int pos = m_cur + TSN_SBL_KEYSLOT_SIZE; return TOut(m_ctx, pos, (pos + m_ctx.GetStep(pos))); } 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 + TSN_SBL_SLOT_ARR_SIZE, 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 + TSN_SBL_SLOT_ARR_SIZE; 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 + TSN_SBL_SLOT_OBJ_SIZE, m_end); } } //+------------------------------------------------------------------+ #endif // BASESPARSERSLAN_SRC_NODE_NODEBASE_MQH