864 lines
27 KiB
MQL5
864 lines
27 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Node.mqh |
|
|
//| Copyright 2026, Niquel Mendoza. |
|
|
//| https://www.mql5.com/ |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2026, Niquel Mendoza."
|
|
#property link "https://www.mql5.com/"
|
|
#property strict
|
|
|
|
#ifndef SETFILEBYLEO_SRC_NODE_MQH
|
|
#define SETFILEBYLEO_SRC_NODE_MQH
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "Parser.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
namespace TSN
|
|
{
|
|
|
|
// Layout cinta:
|
|
// ROOT 1 pos [tipo(4)|count(resto)<<END_TYPE][jittry<<36]
|
|
// KEY 1 pos [tipo(4)|len(28)<<LEN_PLAIN|start(32)<<START_STR] (igual que STRING)
|
|
// META 1 pos [tipo(4)|op_type(VAL/Y/N)<<END_TYPE] -- no es valor, precede al/los valor(es)
|
|
// INTEGER 2 pos [tipo(4)] [valor_long]
|
|
// REAL 2 pos [tipo(4)] [valor_long (bits double)]
|
|
// BOOLEAN 1 pos [tipo(4)|val<<END_TYPE]
|
|
// STRING 1 pos [tipo(4)|len(28)<<LEN_PLAIN|start(32)<<START_STR]
|
|
//
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#define SETFILE_NODE_IS_NOT_VALID_F (m_ctx == NULL)
|
|
#define SETFILE_NODE_IS_VALID (m_ctx != NULL)
|
|
|
|
//--- Avanza lo que ocupa una entrada completa (KEY+META+valor(es)) partiendo de la
|
|
// posicion del KEY. Asume estructura correcta (sin validar tipos).
|
|
#define SETFILE_ENTRY_STEP(idx) \
|
|
(2 + m_ctx.GetStep((idx) + 2) * (int(m_ctx.m_cinta[(idx) + 1] >> TSN_SETFILE_BIT_END_TYPE) != SETFILE_TOK_OP_TYPE_VAL ? 4 : 1))
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
struct CSetIteratorObj;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
struct CSetNode
|
|
{
|
|
CSetFileParser* const m_ctx;
|
|
int m_idx;
|
|
int m_end;
|
|
|
|
//---
|
|
CSetNode(void)
|
|
: m_ctx(NULL), m_idx(-1), m_end(-1) {}
|
|
CSetNode(CSetFileParser* _ctx, const int _idx, const int _end)
|
|
: m_ctx(_ctx), m_idx(_idx), m_end(_end) {}
|
|
|
|
//---
|
|
__forceinline bool IsJit() const;
|
|
__forceinline int AttempCount() const;
|
|
bool NodeHashing();
|
|
|
|
//---
|
|
CSetNode operator[](const string& key);
|
|
CSetNode AtObj(const int index) const; // acceso posicional a la entrada index del root
|
|
|
|
//--- Keys
|
|
string AtObjKey(const int index) const;
|
|
bool HasKey(const string& key) const;
|
|
int KeyToPosition(const string& key) const;
|
|
int GetKeys(string& out[]) const;
|
|
|
|
//--- Root
|
|
__forceinline int RootSize() const;
|
|
CSetIteratorObj BeginObj() const;
|
|
__forceinline bool InRange(const int index) const;
|
|
bool InRangeSafe(const int index) const;
|
|
|
|
//---
|
|
__forceinline ENUM_SETFILE_TOK_OP_TYPE OpType() const;
|
|
__forceinline bool IsOptimizable() const;
|
|
__forceinline bool IsEnabled() const;
|
|
bool SetEnabled(const bool val);
|
|
|
|
//--- Valor
|
|
CSetNode Value() const;
|
|
__forceinline ENUM_SETFILE_TOKENS GetType() const;
|
|
__forceinline uint GetFlag() const;
|
|
|
|
//-- To
|
|
long ToInt(const long def = 0) const;
|
|
double ToDouble(const double def = 0.0) const;
|
|
bool ToBool(const bool def = false) const;
|
|
string ToString(const string def = "") const;
|
|
|
|
//-- To safe
|
|
bool ToIntSafe(long& val) const;
|
|
bool ToDoubleSafe(double& val) const;
|
|
bool ToBoolSafe(bool& val) const;
|
|
|
|
//--- Rango (idx = META de la entrada, solo valido si IsOptimizable())
|
|
CSetNode Start() const;
|
|
CSetNode Step() const;
|
|
CSetNode Stop() const;
|
|
|
|
//--- Mutacion (in-place, solo mismo tipo)
|
|
bool SetInt(const long val);
|
|
bool SetDbl(const double val);
|
|
bool SetBool(const bool val);
|
|
|
|
//--- Validez
|
|
__forceinline bool IsValid() const;
|
|
__forceinline bool IsInvalid() const;
|
|
|
|
//---
|
|
bool MoveToNextToken();
|
|
CSetNode MoveNextPositions(const int posiciones);
|
|
bool MoveNextPositionsThis(const int posiciones);
|
|
};
|
|
|
|
//---
|
|
const CSetNode EMPTY_SET_NODE;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
struct CSetIteratorObj
|
|
{
|
|
CSetFileParser* const m_ctx;
|
|
int m_cur;
|
|
const int m_end;
|
|
|
|
//---
|
|
CSetIteratorObj(CSetFileParser* ctx, const int cur, const int end)
|
|
: m_ctx(ctx), m_cur(cur), m_end(end) {}
|
|
CSetIteratorObj(void)
|
|
: 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 += SETFILE_ENTRY_STEP(m_cur);
|
|
}
|
|
|
|
//---
|
|
string Key()
|
|
{
|
|
if(m_cur >= m_end)
|
|
return "";
|
|
const int start = int(m_ctx.m_cinta[m_cur] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[m_cur] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
return CharArrayToString(m_ctx.m_data, start, slen);
|
|
}
|
|
|
|
//---
|
|
CSetNode Val()
|
|
{
|
|
if(m_cur >= m_end)
|
|
return EMPTY_SET_NODE;
|
|
return CSetNode(m_ctx, m_cur + 1, m_end); // deja el nodo en META, igual que operator[]/AtObj
|
|
}
|
|
};
|
|
|
|
//---
|
|
const CSetIteratorObj EMPTY_SET_ITERATOR_OBJ;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| IsJit / AttempCount / NodeHashing |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline bool CSetNode::IsJit() const
|
|
{
|
|
return SETFILE_NODE_IS_VALID && m_ctx.m_table_ready;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline int CSetNode::AttempCount() const
|
|
{
|
|
return SETFILE_NODE_IS_NOT_VALID_F ? 0 : int(m_ctx.m_cinta[0] >> TSN_SETFILE_BIT_START_JIT_TRY);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::NodeHashing(void)
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || m_idx != 0)
|
|
return false;
|
|
|
|
//---
|
|
const int count = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & TSN_SETFILE_MASK_COUNT);
|
|
return m_ctx.NodeHashing(m_idx, count, m_end);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::operator[](const string &key)
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
if(!m_ctx.m_table_ready)
|
|
{
|
|
//--- No esta hasheado, verificamos si ya toca intentar
|
|
int c = int(m_ctx.m_cinta[0] >> TSN_SETFILE_BIT_START_JIT_TRY);
|
|
if(c >= TSN_SETFILE_JIT_MIN_REF_TO_HASING)
|
|
{
|
|
if(NodeHashing())
|
|
{
|
|
//--- Ya hasheado, obtenemos posicion (del KEY) via hash perfecto
|
|
const int key_pos = m_ctx.PerfectHashComputeHash(key);
|
|
if(key_pos == -1)
|
|
return EMPTY_SET_NODE;
|
|
return CSetNode(m_ctx, key_pos + 1, m_end); // +1: de KEY a META
|
|
}
|
|
//--- Fallo el hasheo, reiniciamos el contador
|
|
c = 0;
|
|
}
|
|
else
|
|
{
|
|
c++;
|
|
}
|
|
const long mask = long(TSN_SETFILE_MASK_JIT_TRY) << TSN_SETFILE_BIT_START_JIT_TRY;
|
|
m_ctx.m_cinta[m_idx] = (m_ctx.m_cinta[m_idx] & ~mask) | (long(c) << TSN_SETFILE_BIT_START_JIT_TRY);
|
|
|
|
//--- Lineal (siempre, este intento no se hasheo o fallo)
|
|
int cur = 1;
|
|
while(cur < m_end)
|
|
{
|
|
const int step = SETFILE_ENTRY_STEP(cur);
|
|
if(m_ctx.StrEquals(key, cur))
|
|
return CSetNode(m_ctx, cur + 1, m_end);
|
|
cur += step;
|
|
}
|
|
return EMPTY_SET_NODE;
|
|
}
|
|
|
|
//--- ya hasheado
|
|
const int key_pos = m_ctx.PerfectHashComputeHash(key);
|
|
if(key_pos == -1)
|
|
return EMPTY_SET_NODE;
|
|
return CSetNode(m_ctx, key_pos + 1, m_end);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| AtObj — acceso posicional a la entrada index del root |
|
|
//| (JIT: pos_arr[index] ya da la posicion del KEY directo) |
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::AtObj(const int index) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
if(m_ctx.m_table_ready)
|
|
{
|
|
const int cur = m_ctx.m_table_pos_arr[index];
|
|
return CSetNode(m_ctx, cur + 1, m_end); // deja el nodo en META
|
|
}
|
|
|
|
//---
|
|
int cur = 1;
|
|
for(int k = 0; k < index; k++)
|
|
cur += SETFILE_ENTRY_STEP(cur);
|
|
|
|
return CSetNode(m_ctx, cur + 1, m_end); // deja el nodo en META, igual que operator[]
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| AtObjKey — key de la entrada index del root |
|
|
//+------------------------------------------------------------------+
|
|
string CSetNode::AtObjKey(const int index) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return "";
|
|
|
|
//---
|
|
int cur = 0;
|
|
if(m_ctx.m_table_ready)
|
|
{
|
|
cur = m_ctx.m_table_pos_arr[index];
|
|
}
|
|
else
|
|
{
|
|
cur = 1;
|
|
for(int k = 0; k < index; k++)
|
|
cur += SETFILE_ENTRY_STEP(cur);
|
|
}
|
|
|
|
//---
|
|
const int start = int(m_ctx.m_cinta[cur] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[cur] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
return CharArrayToString(m_ctx.m_data, start, slen);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::HasKey(const string &key) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return false;
|
|
|
|
//---
|
|
if(m_ctx.m_table_ready)
|
|
return m_ctx.PerfectHashComputeHash(key) != -1;
|
|
|
|
//---
|
|
int cur = 1;
|
|
while(cur < m_ctx.m_cinta_pos)
|
|
{
|
|
if(m_ctx.StrEquals(key, cur))
|
|
return true;
|
|
cur += SETFILE_ENTRY_STEP(cur);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| KeyToPosition |
|
|
//+------------------------------------------------------------------+
|
|
int CSetNode::KeyToPosition(const string &key) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return -1;
|
|
|
|
//---
|
|
if(m_ctx.m_table_ready)
|
|
return m_ctx.PerfectHashComputeHashIndex(key);
|
|
|
|
//---
|
|
int cur = 1;
|
|
int k = 0;
|
|
while(cur < m_ctx.m_cinta_pos)
|
|
{
|
|
if(m_ctx.StrEquals(key, cur))
|
|
return k;
|
|
cur += SETFILE_ENTRY_STEP(cur);
|
|
k++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GetKeys — con JIT usamos pos_arr (ya resuelto), sin recorrer |
|
|
//| calculando steps entrada por entrada. |
|
|
//+------------------------------------------------------------------+
|
|
int CSetNode::GetKeys(string &out[]) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return 0;
|
|
|
|
//---
|
|
if(m_ctx.m_table_ready)
|
|
{
|
|
const int count = m_ctx.m_table_size;
|
|
ArrayResize(out, count);
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
const int cur = m_ctx.m_table_pos_arr[i];
|
|
const int start = int(m_ctx.m_cinta[cur] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[cur] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
out[i] = CharArrayToString(m_ctx.m_data, start, slen);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//---
|
|
const int count = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & TSN_SETFILE_MASK_COUNT);
|
|
ArrayResize(out, count);
|
|
|
|
//---
|
|
int i = 0;
|
|
int cur = 1; // en key
|
|
while(cur < m_ctx.m_cinta_pos)
|
|
{
|
|
const int start = int(m_ctx.m_cinta[cur] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[cur] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
out[i++] = CharArrayToString(m_ctx.m_data, start, slen);
|
|
cur += SETFILE_ENTRY_STEP(cur);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline int CSetNode::RootSize() const
|
|
{
|
|
return SETFILE_NODE_IS_NOT_VALID_F || m_idx != 0 ? 0 : int((m_ctx.m_cinta[0] >> TSN_SETFILE_BIT_END_TYPE) & TSN_SETFILE_MASK_COUNT);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline bool CSetNode::InRange(const int index) const
|
|
{
|
|
const int t = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & TSN_SETFILE_MASK_COUNT);
|
|
return index >= 0 && index < t;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::InRangeSafe(const int index) const
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || m_idx != 0)
|
|
return false;
|
|
const int t = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & TSN_SETFILE_MASK_COUNT);
|
|
return index >= 0 && index < t;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| BeginObj |
|
|
//+------------------------------------------------------------------+
|
|
CSetIteratorObj CSetNode::BeginObj() const
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || m_idx != 0)
|
|
return EMPTY_SET_ITERATOR_OBJ;
|
|
return CSetIteratorObj(m_ctx, 1, m_end);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OpType / IsOptimizable / IsEnabled — leen el META |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline ENUM_SETFILE_TOK_OP_TYPE CSetNode::OpType() const
|
|
{
|
|
return ENUM_SETFILE_TOK_OP_TYPE(int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline bool CSetNode::IsOptimizable() const
|
|
{
|
|
return int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) != SETFILE_TOK_OP_TYPE_VAL;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline bool CSetNode::IsEnabled() const
|
|
{
|
|
return int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) == SETFILE_TOK_OP_TYPE_Y;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| SetEnabled — togglea Y/N en los bits altos del META |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::SetEnabled(const bool val)
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || (m_ctx.m_cinta[m_idx] & 0xf) != SETFILE_TOK_META)
|
|
return false;
|
|
|
|
//---
|
|
const long mask = long(0x3) << TSN_SETFILE_BIT_END_TYPE;
|
|
m_ctx.m_cinta[m_idx] = (m_ctx.m_cinta[m_idx] & ~mask) |
|
|
(long(val ? SETFILE_TOK_OP_TYPE_Y : SETFILE_TOK_OP_TYPE_N) << TSN_SETFILE_BIT_END_TYPE);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Value — nodo del primer valor (idx+2 respecto al KEY) |
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::Value() const
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || (m_ctx.m_cinta[m_idx] & 0xf) != SETFILE_TOK_META)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
const int pos = m_idx + 1;
|
|
return CSetNode(m_ctx, pos, pos + m_ctx.GetStep(pos));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline ENUM_SETFILE_TOKENS CSetNode::GetType() const
|
|
{
|
|
return ENUM_SETFILE_TOKENS(m_ctx.m_cinta[m_idx] & 0xF);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
__forceinline uint CSetNode::GetFlag() const
|
|
{
|
|
return 1 << uint(m_ctx.m_cinta[m_idx] & 0xF);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Start / Step / Stop — mismo step que Value(), offsets +1/+2/+3 |
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::Start() const
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || (m_ctx.m_cinta[m_idx] & 0xf) != SETFILE_TOK_META)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
const int val_pos = m_idx + 1;
|
|
const int step = m_ctx.GetStep(val_pos);
|
|
const int pos = val_pos + step;
|
|
return CSetNode(m_ctx, pos, pos + step);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::Step() const
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || (m_ctx.m_cinta[m_idx] & 0xf) != SETFILE_TOK_META)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
const int val_pos = m_idx + 1;
|
|
const int step = m_ctx.GetStep(val_pos);
|
|
const int pos = val_pos + step * 2;
|
|
return CSetNode(m_ctx, pos, pos + step);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::Stop() const
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || (m_ctx.m_cinta[m_idx] & 0xf) != SETFILE_TOK_META)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
const int val_pos = m_idx + 1;
|
|
const int step = m_ctx.GetStep(val_pos);
|
|
const int pos = val_pos + step * 3;
|
|
return CSetNode(m_ctx, pos, pos + step);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ToInt |
|
|
//+------------------------------------------------------------------+
|
|
long CSetNode::ToInt(const long def = 0) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return def;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
return m_ctx.m_cinta[m_idx + 1];
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
return long(un.double_value);
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
return long((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1);
|
|
case SETFILE_TOK_STRING:
|
|
{
|
|
const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
return long(CharArrayToString(m_ctx.m_data, start, slen));
|
|
}
|
|
}
|
|
return def;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::ToIntSafe(long &val) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return false;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
val = m_ctx.m_cinta[m_idx + 1];
|
|
return true;
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
val = long(un.double_value);
|
|
return true;
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
val = long((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1);
|
|
return true;
|
|
case SETFILE_TOK_STRING:
|
|
{
|
|
const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
val = long(CharArrayToString(m_ctx.m_data, start, slen));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ToDouble |
|
|
//+------------------------------------------------------------------+
|
|
double CSetNode::ToDouble(const double def = 0.0) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return def;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
return double(m_ctx.m_cinta[m_idx + 1]);
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
return un.double_value;
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
return double((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1);
|
|
case SETFILE_TOK_STRING:
|
|
{
|
|
const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
return double(CharArrayToString(m_ctx.m_data, start, slen));
|
|
}
|
|
}
|
|
return def;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::ToDoubleSafe(double &val) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return false;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
val = double(m_ctx.m_cinta[m_idx + 1]);
|
|
return true;
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
val = un.double_value;
|
|
return true;
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
val = double((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1);
|
|
return true;
|
|
case SETFILE_TOK_STRING:
|
|
{
|
|
const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
val = double(CharArrayToString(m_ctx.m_data, start, slen));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ToBool |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::ToBool(const bool def = false) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return def;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
return m_ctx.m_cinta[m_idx + 1] != 0;
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
return un.double_value != 0.0;
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
return ((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1) != 0;
|
|
}
|
|
return def;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::ToBoolSafe(bool &val) const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return false;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
val = m_ctx.m_cinta[m_idx + 1] != 0;
|
|
return true;
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
val = un.double_value != 0.0;
|
|
return true;
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
val = ((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1) != 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ToString — sin unescape, los valores de .set no llevan escapes |
|
|
//+------------------------------------------------------------------+
|
|
string CSetNode::ToString(const string def = "") const
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return def;
|
|
|
|
//---
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xF))
|
|
{
|
|
case SETFILE_TOK_INTEGER:
|
|
return string(m_ctx.m_cinta[m_idx + 1]);
|
|
case SETFILE_TOK_REAL:
|
|
{
|
|
static BitInterpreter un;
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
return string(un.double_value);
|
|
}
|
|
case SETFILE_TOK_BOOLEAN:
|
|
return ((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_END_TYPE) & 1) != 0 ? "true" : "false";
|
|
case SETFILE_TOK_STRING:
|
|
{
|
|
const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_STR);
|
|
const int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
|
|
return CharArrayToString(m_ctx.m_data, start, slen);
|
|
}
|
|
}
|
|
return def;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| SetInt |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::SetInt(const long val)
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & 0xF) != SETFILE_TOK_INTEGER)
|
|
return false;
|
|
//---
|
|
m_ctx.m_cinta[m_idx + 1] = val;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| SetDbl |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::SetDbl(const double val)
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & 0xF) != SETFILE_TOK_REAL)
|
|
return false;
|
|
|
|
//---
|
|
static BitInterpreter un;
|
|
un.double_value = val;
|
|
m_ctx.m_cinta[m_idx + 1] = un.long_value;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| SetBool |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::SetBool(const bool val)
|
|
{
|
|
if(SETFILE_NODE_IS_NOT_VALID_F || int(m_ctx.m_cinta[m_idx] & 0xF) != SETFILE_TOK_BOOLEAN)
|
|
return false;
|
|
|
|
//---
|
|
m_ctx.m_cinta[m_idx] = SETFILE_TOK_BOOLEAN | long(val) << TSN_SETFILE_BIT_END_TYPE;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Is |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline bool CSetNode::IsValid() const { return m_ctx != NULL && m_idx >= 0 && m_end >= 0; }
|
|
__forceinline bool CSetNode::IsInvalid() const { return m_ctx == NULL || m_idx < 0 || m_end < 0; }
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::MoveToNextToken()
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return false;
|
|
|
|
//---
|
|
const int next_end = m_idx + m_ctx.GetStep(m_idx);
|
|
if(next_end >= m_end)
|
|
return false;
|
|
|
|
//---
|
|
m_idx = next_end;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetNode::MoveNextPositions(const int posiciones)
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
const int next_pos = m_idx + posiciones;
|
|
if(next_pos >= m_end)
|
|
return EMPTY_SET_NODE;
|
|
|
|
//---
|
|
return CSetNode(m_ctx, next_pos, m_end);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetNode::MoveNextPositionsThis(const int posiciones)
|
|
{
|
|
//---
|
|
if(SETFILE_NODE_IS_NOT_VALID_F)
|
|
return false;
|
|
|
|
//---
|
|
const int next_pos = m_idx + posiciones;
|
|
if(next_pos >= m_end)
|
|
return false;
|
|
|
|
//---
|
|
m_idx = next_pos;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
CSetNode CSetFileParser::GetRoot()
|
|
{
|
|
if(m_cinta_pos == 0)
|
|
return EMPTY_SET_NODE;
|
|
return CSetNode(&this, 0, m_cinta_pos);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
#endif // SETFILEBYLEO_SRC_NODE_MQH
|