CryptoByLeo/Src/RSPParser/RSP.mqh
2026-08-25 08:22:06 -05:00

788 行
22 KiB
MQL5

//+------------------------------------------------------------------+
//| RSP.mqh |
//| Copyright 2026, Niquel Mendoza |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza"
#property link "https://www.mql5.com"
#property strict
#ifndef CRYPTOBYLEO_RSPPARSER_RSP_MQH
#define CRYPTOBYLEO_RSPPARSER_RSP_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Def.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CRSPParser : public CBaseLanFormat
{
public:
int m_root_values;
private:
//--- last err
ENUM_RSPPARSER_LAST_ERR m_last_err;
//--- parseo
int m_prev_start_v;
// el ultimo valor esta entre [] osea meta
bool m_last_meta;
// mascara de fin
#ifndef RSPDATA_DESACTIVE_SWAR
ulong m_last_val_mask;
#else
uchar m_last_val_char;
#endif // RSPDATA_DESACTIVE_SWAR
public:
CRSPParser(void);
~CRSPParser(void) {}
//---
__forceinline void CorrectPadding() { CorrectPadingInternal('\n', 8); }
//---
bool AutoParseByFileExt(const int file_ext_type);
int AssingFile(const string& file_name, const bool comon_flag);
//--
// verifica si una clave esta limpia
// En caso no lo este ejeucta la limpiza ahi mismo
void VerifyCleanKey(const int cur, const int start, int& len);
//---
bool KeysEqual(const string &str, const int curr);
bool StrEquals(const string &str, const int curr) const;
//---
__forceinline ENUM_RSPPARSER_LAST_ERR LastErr() const { return m_last_err; }
//---
bool Parse();
//---
void ErrorInfo(bool with_avanze = false) const;
//---
bool SaveCompiled(const string & file_name_out, const bool out_common_flag) const;
bool SaveCompiled(const string & file_name_out, const bool out_common_flag, const string & file_name_data, const bool data_common_flag) const;
//---
void PrintCintaTypes(const int start, const int num) const;
//---
CRSPNode GetRoot();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CRSPParser::CRSPParser()
:
#ifndef RSPDATA_DESACTIVE_SWAR
m_last_val_mask(TSNTABLES_SWAR_MASK_NEW_LINE)
#else // RSPDATA_DESACTIVE_SWAR
m_last_val_char('\n')
#endif // RSPDATA_DESACTIVE_SWAR
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRSPParser::AutoParseByFileExt(const int file_ext_type)
{
switch(file_ext_type)
{
case TSN_SLF_RAW_FILE:
{
CorrectPadding(); // Auto
return Parse();
}
case TSN_SLF_RAW_EMBEBED:
{
return m_cinta_pos > 0 && m_len > 0;
}
default:
{
m_last_err = RSPPARSER_LAST_ERR_INVALID_EXT_FILE;
m_pos = 0;
return false;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRSPParser::StrEquals(const string &str, const int curr) const
{
//---
// m_cinta[m_cinta_pos++] = long(m_pos - 1) | long(start) << TSN_JSON_BIT_STR_START_END;
const int start = int(m_cinta[curr] >> TSN_SBL_BIT_STR_START);
const int len = int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN);
//PrintFormat("Exact = '%s', other = '%s'", CharArrayToString(m_raw, start, len), str);
const int l = StringLen(str);
//---
if(l != len)
return false;
for(int i = 0; i < l; i++)
{
if(str[i] != m_raw[start + i])
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CRSPParser::VerifyCleanKey(const int cur, const int start, int& len)
{
const int k = cur + 1; // kpos+1
if(((m_cinta[k] >> RSPDATA_BITSTART_ISKEY_CLEAN) & RSPDATA_MASK_META_IS) == 0)
{
int j = (start + len) - 1;
while(j >= start && m_raw[j] < 33)
{
j--;
}
len = (j - start) + 1;
m_cinta[cur] = long(RSPDATA_TYPE_PLAIN_KEY)
| long(len) << TSN_SBL_BIT_STR_LEN
| long(start) << TSN_SBL_BIT_STR_START;
m_cinta[k] |= RSPDATA_BITSTART_ISKEY_CLEAN_F;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRSPParser::KeysEqual(const string &str, const int curr)
{
//---
const int start = int(m_cinta[curr] >> TSN_SBL_BIT_STR_START);
int len = int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN);
//---
VerifyCleanKey(curr, start, len);
//---
const int l = StringLen(str);
//---
if(l != len)
return false;
//---
for(int i = 0; i < l; i++)
if(str[i] != m_raw[start + i])
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// luego de un valor buscar key
// el |1 lo hacemos para acitvar el bit 1 cosa uqe aumenta en 1 el valor base del token
// En el enum estan definidos de tal forma qeu si le aumentmos 1 para value=key (ahora es key)
// y los demas tambien
// coment aunenta en uno ahora es comentp
// lo que tambien aumenta es cor que pasa a ser corp
// e invalid pasa a (fuera) de rango (defualt en NEXTT)
// maxima velocidad sin branches
#define TSN_RSPPARSER_NEXTV \
while(true) \
{ \
if(m_pos >= m_len) \
{ \
return true; \
} \
const uchar cfasd = m_raw[m_pos]; \
if(cfasd < 33) \
{ \
m_pos++; \
continue; \
} \
m_next = g_tsn_rsp_t_to_tokesn[cfasd]|1; \
break;\
}
//---
#define RSPDATA_PARSE_FIND_CHAR_UNROLLED_8(CH) \
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break;\
m_pos++;\
if(m_raw[m_pos] == CH)\
break; \
m_pos++;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRSPParser::Parse(void)
{
//---
m_pos = m_offset;
m_cinta_pos = 0;
m_last_meta = false;
m_last_err = RSPPARSER_LAST_ERR_NOT;
m_root_values = 0;
//--- Initial
while(true)
{
const uchar _c = m_raw[m_pos];
if(_c < 33)
{
m_pos++;
continue;
}
m_next = g_tsn_rsp_t_to_tokesn[_c] | 1;
break;
}
//--- Iter
while(true)
{
switch(m_next)
{
//---
case RSPDATA_TOK_TYPE_VALUE:
{
// m_prev_start_v = start del key qeu este ultimo nos definio para este valor
#ifndef RSPDATA_DESACTIVE_SWAR
while(true)
{
const ulong chunk = (ulong)m_raw[m_pos]
| (ulong)m_raw[m_pos + 1] << 8
| (ulong)m_raw[m_pos + 2] << 16
| (ulong)m_raw[m_pos + 3] << 24
| (ulong)m_raw[m_pos + 4] << 32
| (ulong)m_raw[m_pos + 5] << 40
| (ulong)m_raw[m_pos + 6] << 48
| (ulong)m_raw[m_pos + 7] << 56;
//---
const ulong x = chunk ^ m_last_val_mask;
const ulong has_x = TSNTABLES_SWAR_HAS(x);
if(has_x == 0)
{
m_pos += 8;
//---
if((m_pos + 7) >= m_len)
{
m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_V;
return false;
}
//---
continue;
}
//---
// Si hay \n
const ulong flag = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_x);
m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag); // Ahora mismo en \n
break;
}
//---
m_last_val_mask = TSNTABLES_SWAR_MASK_NEW_LINE;
#else // RSPDATA_DESACTIVE_SWAR
while(true)
{
RSPDATA_PARSE_FIND_CHAR_UNROLLED_8(m_last_val_char)
//---
if((m_pos + 7) >= m_len)
{
m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_V;
return false;
}
}
//---
m_last_val_char = '\n';
#endif // RSPDATA_DESACTIVE_SWAR
// Ahora mismo en \n
//---
m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_VALUE) | long(m_pos - m_prev_start_v) << TSN_SBL_BIT_STR_LEN
| long(m_prev_start_v) << TSN_SBL_BIT_STR_START;
//---
m_pos++; // Luiego del \n
m_root_values++;
//---
TSN_RSPPARSER_NEXTV
break;
}
//---
case RSPDATA_TOK_TYPE_KEY:
{
// ahora mismo justo en kstart
const int start = m_pos++;
//---
// Por deqfecto desactivo en priomedio als key no superan los 8 chars ahi
// asi que no hay mucho beneficio
#ifdef RSPDATA_PARSER_KEY_ACTIVE_SWAR
while(true)
{
//Print(CharArrayToString(m_raw, m_pos, 7));
const ulong chunk = (ulong)m_raw[m_pos]
| (ulong)m_raw[m_pos + 1] << 8
| (ulong)m_raw[m_pos + 2] << 16
| (ulong)m_raw[m_pos + 3] << 24
| (ulong)m_raw[m_pos + 4] << 32
| (ulong)m_raw[m_pos + 5] << 40
| (ulong)m_raw[m_pos + 6] << 48
| (ulong)m_raw[m_pos + 7] << 56;
//---
const ulong x = chunk ^ TSNTABLES_SWAR_MASK_IGUAL;
const ulong has_x = TSNTABLES_SWAR_HAS(x);
if(has_x == 0)
{
m_pos += 8;
//---
if((m_pos + 7) >= m_len)
{
m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_EQ;
return false;
}
continue;
}
//---
// Si hay =
const ulong flag = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_x);
m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag);
break;
}
#else // RSPDATA_PARSER_KEY_ACTIVE_SWAR
while(true)
{
RSPDATA_PARSE_FIND_CHAR_UNROLLED_8('=')
//---
if((m_pos + 7) >= m_len)
{
m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_EQ;
return false;
}
}
#endif // RSPDATA_PARSER_KEY_ACTIVE_SWAR
// Ahora mismo justo en =
m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_KEY)
| long(m_pos - start) << TSN_SBL_BIT_STR_LEN
| long(start) << TSN_SBL_BIT_STR_START;
// ahora toca meta
m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_META) | long(m_last_meta) << TSN_SBL_BIT_START_ENDTYPE;
//--- avanzamos
m_pos++; // Ahora toca value
m_prev_start_v = m_pos;
m_last_meta = false;
//--- Ahora buscamos el valor
while(true)
{
const uchar f = m_raw[m_pos];
if(f < 33)
{
if(f == '\n')
{
// No habai nada estamos en\n entonces 0
m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_VALUE) | long(0) << TSN_SBL_BIT_STR_LEN
| long(start) << TSN_SBL_BIT_STR_START;
//---
TSN_RSPPARSER_NEXTV
break;
}
//---
m_pos++;
if(m_pos >= m_len) // o en todo caso fin
{
m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_VALUE) | long(0) << TSN_SBL_BIT_STR_LEN
| long(start) << TSN_SBL_BIT_STR_START;
return true;
}
//---
m_prev_start_v++; // nada avanzamos..
continue;
}
//--- Justo aqui nos detenemos. Vemos que sigue comentario o valor
// Valor raw tal cual (sin 1 asi que el value es vlaue ya no se pasa a key)
m_next = g_tsn_rsp_t_to_tokesn[f];
break;
}
//---
break;
}
//--- [ ]
case RSPDATA_TOK_TYPE_COR:
case RSPDATA_TOK_TYPE_COR_P:
{
m_pos++; // luego del cor
//
m_last_meta = true;
// saltar ws
while(true)
{
if(m_raw[m_pos] < 33)
continue;
break;
}
// camibamos las mcaras para que en vez de \n sea ] fin de valor
#ifndef RSPDATA_DESACTIVE_SWAR
m_last_val_mask = TSNTABLES_SWAR_MASK_COR_END;
#else
m_last_val_char = ']';
#endif
// ahora mismo ene l primer char de key
m_next = RSPDATA_TOK_TYPE_KEY;
break;
}
//---
case RSPDATA_TOK_TYPE_COMMENT:
case RSPDATA_TOK_TYPE_COMMENT_P:
{
m_pos++; // Siguiente..
//---
#ifndef RSPDATA_DESACTIVE_SWAR
while(true)
{
//Print(CharArrayToString(m_raw, m_pos, 7));
const ulong chunk = (ulong)m_raw[m_pos]
| (ulong)m_raw[m_pos + 1] << 8
| (ulong)m_raw[m_pos + 2] << 16
| (ulong)m_raw[m_pos + 3] << 24
| (ulong)m_raw[m_pos + 4] << 32
| (ulong)m_raw[m_pos + 5] << 40
| (ulong)m_raw[m_pos + 6] << 48
| (ulong)m_raw[m_pos + 7] << 56;
//---
const ulong x = chunk ^ TSNTABLES_SWAR_MASK_NEW_LINE;
const ulong has_x = TSNTABLES_SWAR_HAS(x);
if(has_x == 0)
{
m_pos += 8;
//--- Check
if((m_pos + 7) >= m_len)
{
m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_DE_LINEA;
return false;
}
continue;
}
//---
// Si hay \n
const ulong flag = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_x);
m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag); // Ahora mismo en \n+1 \n[aqui]
break;
}
#else // RSPDATA_DESACTIVE_SWAR
while(true)
{
RSPDATA_PARSE_FIND_CHAR_UNROLLED_8('\n')
//---
if((m_pos + 7) >= m_len)
{
m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_DE_LINEA;
return false;
}
}
#endif // RSPDATA_DESACTIVE_SWAR
//---
m_pos++;
// Si o si sigue key
TSN_RSPPARSER_NEXTV
break;
}
//---
case RSPDATA_TOK_INVALID:
{
m_last_err = RSPPARSER_LAST_ERR_INVALID_TOKEN;
return false;
}
//---
default:
m_last_err = RSPPARSER_LAST_ERR_INVALID_NEXTT;
return false;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CRSPParser::AssingFile(const string &file_name, const bool comon_flag)
{
//---
if(FileGetExtension(file_name) == RSPPARSER_TAPECACHE_EXT) // jsontp tape cache
{
::ResetLastError();
const int fh = FileOpen(file_name, FILE_BIN | FILE_ANSI | (comon_flag ? FILE_COMMON : 0) | FILE_READ);
if(fh == INVALID_HANDLE)
{
return -1;
}
// Metadata (cinta\yaml)
m_cinta_pos = FileReadInteger(fh); // Nota que cuadno se guarda se hace con el tamaño exacto
m_cinta_reserve = m_cinta_pos; // Mismo tamaño
const int type = FileReadInteger(fh); // Tipo ()
//---
if(type == TSN_SLF_RAW_EMBEBED)
{
m_len = FileReadInteger(fh);
m_offset = FileReadInteger(fh);
FileReadArray(fh, m_cinta, 0, m_cinta_pos); // Total
// Yaml embebido (aqui no hace falta hacer nada ya todo esta hecho.. osea lo de encoding etc..)
FileReadArray(fh, m_raw, 0, m_len);
}
else // Dir
{
const bool common = bool(FileReadInteger(fh, CHAR_VALUE));
const int file_name_len = FileReadInteger(fh);
if(AssingFile(FileReadString(fh, file_name_len), common) == TSN_SLF_EXT_TYPE_CACHE_FILE)
{
FileClose(fh);
return -1; // fallo
}
FileReadArray(fh, m_cinta, 0, m_cinta_pos);
}
//---
FileClose(fh);
return TSN_SLF_EXT_TYPE_CACHE_FILE;
}
else // Ninguno de los dos... json normal O jsonasm
{
const int l = (int)FileLoad(file_name, m_raw, (comon_flag ? FILE_COMMON : 0));
if(l == -1)
return -1;
//---
m_len = l;
//---
NormalizeUft();
//---
return TSN_SLF_EXT_TYPE_FILE;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//--- Ambos
// 4 bytes: m_cinta_pos
// 4 bytes: type
//---
bool CRSPParser::SaveCompiled(const string & file_name_out, const bool out_common_flag) const
{
::ResetLastError();
const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE | FILE_ANSI);
if(fh == INVALID_HANDLE)
{
return false;
}
//--- Comun
FileWriteInteger(fh, m_cinta_pos);
FileWriteInteger(fh, TSN_SLF_RAW_EMBEBED);
//---
// 4 bytes: len
// 4 bytes: offset
// array: cinta
// array yaml
//---
FileWriteInteger(fh, m_len);
FileWriteInteger(fh, m_offset);
FileWriteArray(fh, m_cinta, 0, m_cinta_pos);
FileWriteArray(fh, m_raw, 0, m_len);
//---
FileClose(fh);
//---
return true;
}
//+------------------------------------------------------------------+
bool CRSPParser::SaveCompiled(const string & file_name_out, const bool out_common_flag,
const string & file_name_data, const bool data_common_flag) const
{
//---
::ResetLastError();
const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE | FILE_ANSI);
if(fh == INVALID_HANDLE)
{
return false;
}
//--- Comun
FileWriteInteger(fh, m_cinta_pos);
FileWriteInteger(fh, TSN_SLF_RAW_FILE);
//---
// 1 bytes: comon
// 4 bytes: len
// string: name_file
// array: cinta
//---
FileWriteInteger(fh, data_common_flag, CHAR_VALUE);
const int len = StringLen(file_name_data);
FileWriteInteger(fh, len);
FileWriteString(fh, file_name_data, len);
FileWriteArray(fh, m_cinta, 0, m_cinta_pos);
//---
FileClose(fh);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CRSPParser::ErrorInfo(bool with_avanze = false) const
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CRSPParser::PrintCintaTypes(const int start, const int num) const
{
//---
int p = fmax(start, 0);
const int end = (num == WHOLE_ARRAY || (p + num) > m_cinta_pos) ? m_cinta_pos : (p + num);
//---
while(p < end)
{
const ENUM_RSPDATA_TYPE tipo = ENUM_RSPDATA_TYPE(m_cinta[p] & TSN_SBL_BIT_MASK_TYPE);
string text = "[" + (string)p + "] " + EnumToString(tipo) + " | ";
//---
switch(tipo)
{
case RSPDATA_TYPE_PLAIN_KEY:
{
const int s = int(m_cinta[p] >> TSN_SBL_BIT_STR_START);
const int slen = int((m_cinta[p] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN);
//---
text += "start=" + (string)s + " len=" + (string)slen + " key=\"" + CharArrayToString(m_raw, s, slen) + "\"";
break;
}
case RSPDATA_TYPE_PLAIN_VALUE:
{
const int s = int(m_cinta[p] >> TSN_SBL_BIT_STR_START);
const int slen = int((m_cinta[p] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN);
//---
text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + CharArrayToString(m_raw, s, slen) + "\"";
break;
}
case RSPDATA_TYPE_META:
{
static BitInterpreter un;
un.long_value = m_cinta[p + 1];
text += StringFormat("is_cor=%s is_val_cleaned=%s is_key_cleaned=%s",
(((m_cinta[p] >> TSN_SBL_BIT_START_ENDTYPE) & RSPDATA_MASK_META_IS) != 0 ? "true" : "false"),
(((m_cinta[p] >> RSPDATA_BITSTART_ISVAL_CLEAN) & RSPDATA_MASK_META_IS) != 0 ? "true" : "false"),
(((m_cinta[p] >> RSPDATA_BITSTART_ISKEY_CLEAN) & RSPDATA_MASK_META_IS) != 0 ? "true" : "false")
);
break;
}
default:
break;
}
Print(text);
p++;
}
}
//---
}
//+------------------------------------------------------------------+
#endif // CRYPTOBYLEO_RSPPARSER_RSP_MQH