//+------------------------------------------------------------------+ //| DomImp.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_DOM_DOM_IMP_MQH #define BASESPARSERSLAN_SRC_DOM_DOM_IMP_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "DomDef.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| Keys | //+------------------------------------------------------------------+ __forceinline int CDomNodeBase::GetKeys(string &out[]) const { return m_type == TSN_SBL_BASE_TYPE_OBJ ? m_ctx.m_objs[m_v.ix].GetKeys(out) : 0; } //+------------------------------------------------------------------+ __forceinline bool CDomNodeBase::HasKey(const string &key) const { return m_type == TSN_SBL_BASE_TYPE_OBJ ? m_ctx.m_objs[m_v.ix].ContainsKey(key) : false; } //+------------------------------------------------------------------+ bool CDomNodeBase::Remove(const string &key) { if(m_type != TSN_SBL_BASE_TYPE_OBJ) return false; //--- CHashMapFast(string, CDomNodeBase*)* ptr = m_ctx.m_objs[m_v.ix]; //--- if(!ptr.ContainsKey(key)) return false; //--- // #1: truco de bajo nivel hashmap guarda la ultima posicion ahi.. CDomNodeBase* f = ptr.m_table[ptr.m_last_pos_tbl].value; // En caso el contexto del objeto... a eliminar es el mismo (proviene de la misma pila) // ENtonces eliminamos.. if(f.m_ctx == m_ctx && CheckPointer(f) == POINTER_DYNAMIC) delete f; ptr.RemoveLastFindCall(); // eliminamos el ultimo caller return true; } //+------------------------------------------------------------------+ void CDomNodeBase::NewObj(int inital_hash_map_size) { //--- Revisamos previa.. (en caso de ser compejo liberamos) BASESPARSERSLAN_DOMNODE_FREE //--- m_type = TSN_SBL_BASE_TYPE_OBJ; m_v.ix = m_ctx.ReserveObj(inital_hash_map_size); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ __forceinline int CDomNodeBase::Size(void) const { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: return m_ctx.m_node[m_v.ix].values_size; case TSN_SBL_BASE_TYPE_OBJ: return m_ctx.m_objs[m_v.ix].Count(); default: return 0; } } //+------------------------------------------------------------------+ __forceinline bool CDomNodeBase::InRange(const int index) const { const int t = Size(); return index >= 0 && index < t; } //+------------------------------------------------------------------+ __forceinline bool CDomNodeBase::RemoveItem(const int index) { return m_type == TSN_SBL_BASE_TYPE_ARR ? m_ctx.DeleteElementArr(m_v.ix, index) : false; } //+------------------------------------------------------------------+ __forceinline bool CDomNodeBase::AddItem(CDomNodeBase* node) { return m_type == TSN_SBL_BASE_TYPE_ARR ? m_ctx.AddElementArr(m_v.ix, node) : false; } //+------------------------------------------------------------------+ void CDomNodeBase::NewArr(int inital_reserve) { //--- Revisamos previa.. (en caso de ser compejo liberamos) BASESPARSERSLAN_DOMNODE_FREE //--- m_type = TSN_SBL_BASE_TYPE_ARR; m_v.ix = m_ctx.ReserveArr(inital_reserve); } //+------------------------------------------------------------------+ template __forceinline int CDomNodeBase::ToArray(T &array[]) const { if(m_type != TSN_SBL_BASE_TYPE_ARR) return -1; // Error return m_ctx.ToArray(m_v.ix, array); } //+------------------------------------------------------------------+ __forceinline int CDomNodeBase::CopyTo(CDomNodeBase *&out[], int dst_start) const { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: return m_ctx.ArrCopyTo(m_v.ix, out, dst_start); case TSN_SBL_BASE_TYPE_OBJ: return m_ctx.m_objs[m_v.ix].GetValues(out, dst_start); default: return -1; } } //+------------------------------------------------------------------+ __forceinline int CDomNodeBase::PySlicing(CDomNodeBase *&out[], int dst_start = 0, int start = -1, int end = -1, int step = 1) const { if(m_type != TSN_SBL_BASE_TYPE_ARR) return -1; // Error return m_ctx.SlicingArr(m_v.ix, out, dst_start, start, end, step); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CDomNodeBase::Clear() { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.ClearArray(m_v.ix); break; } case TSN_SBL_BASE_TYPE_OBJ: { //--- CHashMapFast(string, CDomNodeBase*)* ptr = m_ctx.m_objs[m_v.ix]; CHashMapFastIterator(string, CDomNodeBase*) it = ptr.BeginIteration(); //--- while(it.IsValid()) { CDomNodeBase* f = it.Val(); // En caso el contexto del objeto... a eliminar es el mismo (proviene de la misma pila) // ENtonces eliminamos.. if(CheckPointer(f) == POINTER_DYNAMIC && f.m_ctx == m_ctx) delete f; //--- it.Next(); } //--- ptr.Clear(); break; } default: break; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CDomNodeBase::Type(const uchar tt, int default_els_in_arrojb) { //--- BASESPARSERSLAN_DOMNODE_FREE //--- m_type = tt; // reasignamos el nuevo tipo switch(tt) { case TSN_SBL_BASE_TYPE_ARR: { NewArr(default_els_in_arrojb); break; } case TSN_SBL_BASE_TYPE_OBJ: { NewObj(default_els_in_arrojb); break; } case TSN_SBL_BASE_TYPE_UINT: case TSN_SBL_BASE_TYPE_INT: case TSN_SBL_BASE_TYPE_FLT: case TSN_SBL_BASE_TYPE_BOL: break; case TSN_SBL_BASE_TYPE_STR: { m_v.ix = m_ctx.ReserveString(); break; } case TSN_SBL_BASE_DOM_NULL: break; default: break; } } //+------------------------------------------------------------------+ //| Asignaciones | //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(CDomNodeBase* ptr) { if(ptr.m_ctx != m_ctx) return false; //--- m_ctx = ptr.m_ctx; m_v = ptr.m_v; m_type = ptr.m_type; return true; } //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(CDomNodeBase& ref) { if(ref.m_ctx != m_ctx) return false; //--- m_ctx = ref.m_ctx; m_v = ref.m_v; m_type = ref.m_type; return true; } //+------------------------------------------------------------------+ //| String | //+------------------------------------------------------------------+ bool CDomNodeBase::As(const string v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_STR; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_STR; break; } case TSN_SBL_BASE_TYPE_UINT: case TSN_SBL_BASE_TYPE_INT: case TSN_SBL_BASE_TYPE_FLT: case TSN_SBL_BASE_TYPE_BOL: m_type = TSN_SBL_BASE_TYPE_STR; break; case TSN_SBL_BASE_TYPE_STR: { m_ctx.m_string_stack[m_v.ix] = v; return true; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_STR; break; } default: return false; } //--- m_v.ix = m_ctx.ReserveString(); m_ctx.m_string_stack[m_v.ix] = v; return true; } //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(const string& v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_STR; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_STR; break; } case TSN_SBL_BASE_TYPE_UINT: case TSN_SBL_BASE_TYPE_INT: case TSN_SBL_BASE_TYPE_FLT: case TSN_SBL_BASE_TYPE_BOL: m_type = TSN_SBL_BASE_TYPE_STR; break; case TSN_SBL_BASE_TYPE_STR: { m_ctx.m_string_stack[m_v.ix] = v; return true; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_STR; break; } default: return false; } //--- m_v.ix = m_ctx.ReserveString(); m_ctx.m_string_stack[m_v.ix] = v; return true; } //+------------------------------------------------------------------+ //| Bool | //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(const bool v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_BOL; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_BOL; break; } case TSN_SBL_BASE_TYPE_UINT: case TSN_SBL_BASE_TYPE_INT: case TSN_SBL_BASE_TYPE_FLT: { m_type = TSN_SBL_BASE_TYPE_BOL; break; } case TSN_SBL_BASE_TYPE_BOL: break; case TSN_SBL_BASE_TYPE_STR: { m_ctx.FreeString(m_v.ix); m_type = TSN_SBL_BASE_TYPE_BOL; break; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_BOL; break; } default: return false; } //--- m_v.bv = v; return true; } //+------------------------------------------------------------------+ //| Reales | //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(const double v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_FLT; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_FLT; break; } case TSN_SBL_BASE_TYPE_UINT: case TSN_SBL_BASE_TYPE_INT: { m_type = TSN_SBL_BASE_TYPE_FLT; break; } case TSN_SBL_BASE_TYPE_FLT: break; case TSN_SBL_BASE_TYPE_BOL: { m_type = TSN_SBL_BASE_TYPE_FLT; break; } case TSN_SBL_BASE_TYPE_STR: { m_ctx.FreeString(m_v.ix); m_type = TSN_SBL_BASE_TYPE_FLT; break; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_FLT; break; } default: return false; } //--- m_v.dv = v; return true; } //+------------------------------------------------------------------+ //| Enteros | //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(const ulong v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_UINT; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_UINT; break; } case TSN_SBL_BASE_TYPE_UINT: break; // NADA sale case TSN_SBL_BASE_TYPE_INT: case TSN_SBL_BASE_TYPE_FLT: case TSN_SBL_BASE_TYPE_BOL: { m_type = TSN_SBL_BASE_TYPE_UINT; break; } case TSN_SBL_BASE_TYPE_STR: { m_ctx.FreeString(m_v.ix); m_type = TSN_SBL_BASE_TYPE_UINT; break; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_UINT; break; } default: return false; } //--- m_v.uv = v; return true; } //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(const long v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_UINT: { m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_INT: break; // Nada sale case TSN_SBL_BASE_TYPE_FLT: case TSN_SBL_BASE_TYPE_BOL: { m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_STR: { m_ctx.FreeString(m_v.ix); m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_INT; break; } default: return false; } //--- m_v.iv = v; return true; } //+------------------------------------------------------------------+ bool CDomNodeBase::operator=(const int v) { switch(m_type) { case TSN_SBL_BASE_TYPE_ARR: { m_ctx.FreeArr(m_v.ix); m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_OBJ: { m_ctx.FreeObj(m_v.ix); m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_UINT: { m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_INT: break; // Nada sale case TSN_SBL_BASE_TYPE_FLT: case TSN_SBL_BASE_TYPE_BOL: { m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_TYPE_STR: { m_ctx.FreeString(m_v.ix); m_type = TSN_SBL_BASE_TYPE_INT; break; } case TSN_SBL_BASE_DOM_NULL: { m_type = TSN_SBL_BASE_TYPE_INT; break; } default: return false; } //--- m_v.iv = v; return true; } //+------------------------------------------------------------------+ //| At | //+------------------------------------------------------------------+ CDomNodeBase* const CDomNodeBase::At(const int idx) const { if(m_type != TSN_SBL_BASE_TYPE_ARR) return NULL; return m_ctx.m_node[m_v.ix].values[idx]; } //+------------------------------------------------------------------+ CDomNodeBase* const CDomNodeBase::AtSafe(const int idx) const { if(m_type != TSN_SBL_BASE_TYPE_ARR) return NULL; const int t = m_ctx.m_node[m_v.ix].values_size; if(idx < 0 || idx >= t) return NULL; return m_ctx.m_node[m_v.ix].values[idx]; } //+------------------------------------------------------------------+ bool CDomNodeBase::Ats(const int idx, CDomNodeBase *val) { if(m_type != TSN_SBL_BASE_TYPE_ARR) return false; const int t = m_ctx.m_node[m_v.ix].values_size; if(idx < 0 || idx >= t) return false; // Ya existe... siempre.. CDomNodeBase* old = m_ctx.m_node[m_v.ix].values[idx]; if(CheckPointer(old) == POINTER_DYNAMIC && old.m_ctx == m_ctx) delete old; m_ctx.m_node[m_v.ix].values[idx] = val; return true; } //+------------------------------------------------------------------+ //| Key-Resolved | //+------------------------------------------------------------------+ CDomNodeBase* const CDomNodeBase::Get(const string &key) const { if(m_type != TSN_SBL_BASE_TYPE_OBJ) return NULL; //---- CHashMapFast(string, CDomNodeBase*)* ptr = m_ctx.m_objs[m_v.ix]; return ptr.ContainsKey(key) ? ptr.m_table[ptr.m_last_pos_tbl].value : NULL; } // En caso no existe da error //+------------------------------------------------------------------+ CDomNodeBase* const CDomNodeBase::Get(const ulong fnv164_hash) const { if(m_type != TSN_SBL_BASE_TYPE_OBJ) return NULL; //---- CHashMapFast(string, CDomNodeBase*)* ptr = m_ctx.m_objs[m_v.ix]; return ptr.ContainsKeyByHash(fnv164_hash) ? ptr.m_table[ptr.m_last_pos_tbl].value : NULL; } // En caso no existe da error //+------------------------------------------------------------------+ bool CDomNodeBase::Set(const string &key, CDomNodeBase *val) { if(m_type != TSN_SBL_BASE_TYPE_OBJ) return false; //--- // JUSTO el caso de uso de bajo nivel que requerismo para evitar dos finds.. CHashMapFast(string, CDomNodeBase*)* ptr = m_ctx.m_objs[m_v.ix]; //--- Esta funcion se comporta como un find, si retonra false es que ya exciste if(!ptr.ReserveSlot(key)) { // existe const uint p = ptr.m_last_pos_tbl; CDomNodeBase* old = ptr.m_table[p].value; if(CheckPointer(old) == POINTER_DYNAMIC && old.m_ctx == m_ctx) delete old; ptr.m_table[p].value = val; // replace return true; } //--- no existe, entonces ya no reservaron un slot // Solo hay que llenarlo (key, value, hash ya lo hace la lib en si) const uint p = ptr.m_last_pos_tbl; ptr.m_table[p].key = key; ptr.m_table[p].value = val; //--- return true; } //+------------------------------------------------------------------+ CDomNodeBase* const CDomNodeBase::operator[](const string& key) { if(m_type != TSN_SBL_BASE_TYPE_OBJ) return NULL; //--- CHashMapFast(string, CDomNodeBase*)* ptr = m_ctx.m_objs[m_v.ix]; if(!ptr.ReserveSlot(key)) // existe return ptr.m_table[ptr.m_last_pos_tbl].value; //--- No existe entonces ya nos reservaron un slot lo podemos poner ahi const uint p = ptr.m_last_pos_tbl; ptr.m_table[p].key = key; // llenamos key //--- ahora retornamos una vez que llenamos value return (ptr.m_table[p].value = new CDomNodeBase(m_ctx)); } // En caso no existe lo crea. //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ulong CDomNodeBase::ToUint(const ulong def) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: return m_v.uv; case TSN_SBL_BASE_TYPE_INT: return (ulong)m_v.iv; case TSN_SBL_BASE_TYPE_FLT: return (ulong)m_v.dv; case TSN_SBL_BASE_TYPE_BOL: return m_v.bv; case TSN_SBL_BASE_TYPE_STR: return (ulong)m_ctx.m_string_stack[m_v.ix]; default: return def; } } //+------------------------------------------------------------------+ bool CDomNodeBase::ToUintSafe(ulong &val) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: val = m_v.uv; return true; case TSN_SBL_BASE_TYPE_INT: val = (ulong)m_v.iv; return true; case TSN_SBL_BASE_TYPE_FLT: val = (ulong)m_v.dv; return true; case TSN_SBL_BASE_TYPE_BOL: val = m_v.bv; return true; case TSN_SBL_BASE_TYPE_STR: val = (ulong)m_ctx.m_string_stack[m_v.ix]; return true; default: return false; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ long CDomNodeBase::ToInt(const long def) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: return (long)m_v.uv; case TSN_SBL_BASE_TYPE_INT: return m_v.iv; case TSN_SBL_BASE_TYPE_FLT: return (long)m_v.dv; case TSN_SBL_BASE_TYPE_BOL: return m_v.bv; case TSN_SBL_BASE_TYPE_STR: return (long)m_ctx.m_string_stack[m_v.ix]; default: return def; } } //+------------------------------------------------------------------+ bool CDomNodeBase::ToIntSafe(long &val) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: val = (long)m_v.uv; return true; case TSN_SBL_BASE_TYPE_INT: val = m_v.iv; return true; case TSN_SBL_BASE_TYPE_FLT: val = (long)m_v.dv; return true; case TSN_SBL_BASE_TYPE_BOL: val = m_v.bv; return true; case TSN_SBL_BASE_TYPE_STR: val = (long)m_ctx.m_string_stack[m_v.ix]; return true; default: return false; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double CDomNodeBase::ToDouble(const double def) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: return (double)m_v.uv; case TSN_SBL_BASE_TYPE_INT: return (double)m_v.iv; case TSN_SBL_BASE_TYPE_FLT: return m_v.dv; case TSN_SBL_BASE_TYPE_BOL: return m_v.bv; case TSN_SBL_BASE_TYPE_STR: return (double)m_ctx.m_string_stack[m_v.ix]; default: return def; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CDomNodeBase::ToBool(const bool def) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: return m_v.uv != 0; case TSN_SBL_BASE_TYPE_INT: return m_v.iv != 0; case TSN_SBL_BASE_TYPE_FLT: return m_v.dv != 0.0; case TSN_SBL_BASE_TYPE_BOL: return m_v.bv; default: return def; } } //+------------------------------------------------------------------+ bool CDomNodeBase::ToBoolSafe(bool &val) const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: val = m_v.uv != 0; return true; case TSN_SBL_BASE_TYPE_INT: val = m_v.iv != 0; return true; case TSN_SBL_BASE_TYPE_FLT: val = m_v.dv != 0.0; return true; case TSN_SBL_BASE_TYPE_BOL: val = m_v.bv; return true; default: return false; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CDomNodeBase::ToString(const string def = "") const { switch(m_type) { case TSN_SBL_BASE_TYPE_UINT: return (string)m_v.uv; case TSN_SBL_BASE_TYPE_INT: return (string)m_v.iv; case TSN_SBL_BASE_TYPE_FLT: return (string)m_v.dv; case TSN_SBL_BASE_TYPE_BOL: return (string)m_v.bv; case TSN_SBL_BASE_TYPE_STR: return m_ctx.m_string_stack[m_v.ix]; default: return def; } } //+------------------------------------------------------------------+ int CDomNodeBase::StrLenRaw(void) const { return m_type == TSN_SBL_BASE_TYPE_STR ? StringLen(m_ctx.m_string_stack[m_v.ix]) : 0; } } //+------------------------------------------------------------------+ #endif // BASESPARSERSLAN_SRC_DOM_DOM_IMP_MQH