BasesParserSLan/Src/BaseClass/Main.mqh
Nique_372 573509878e
2026-10-08 21:47:12 -05:00

504 lines
15 KiB
MQL5

//+------------------------------------------------------------------+
//| Main.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_BASECLASS_MAIN_MQH
#define BASESPARSERSLAN_SRC_BASECLASS_MAIN_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Def.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| Clase base de formato |
//+------------------------------------------------------------------+
// Como minimo para .ini, .set, .rsp , etc...
class CBaseLanFormat
{
public:
//--- Data del documento
ulong m_cinta[];
uchar m_raw[];
int m_cinta_pos;
int m_len;
int m_offset;
int m_pos;
int m_cinta_reserve;
//--- Perfect hash
//- Pf
CPerfectHashByLeo<ulong, CSBLHasherGenUl, CSBLHasherGenUl1> m_pfh;
ushort m_max_att;
protected:
//--- Del parseo
uchar m_next;
public:
CBaseLanFormat(void);
~CBaseLanFormat(void) {}
//---
__forceinline void CalcLen() { m_len = ArraySize(m_raw); }
__forceinline void Assing(const string& raw, uint cp = CP_ACP);
//---
__forceinline uchar LastToken() { return m_next; }
//---
void NormalizeUft();
//---
void GetLastErrorLocation(int &col, int &line) const;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBaseLanFormat::CBaseLanFormat(void)
: m_cinta_reserve(2048), m_len(0), m_offset(0), m_max_att(5000)
{
ArrayResize(m_cinta, 2048, 512);
}
// [1,2] 4098
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
__forceinline void CBaseLanFormat::Assing(const string& raw, uint cp = CP_ACP)
{
m_len = StringToCharArray(raw, m_raw, 0, WHOLE_ARRAY, cp);
m_offset = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBaseLanFormat::GetLastErrorLocation(int &col, int &line) const
{
//---
col = 1;
line = 1;
//--- len podira ser negtvo en casos raros pero pos nunca
for(int i = 0; i < (int)m_pos && i < m_len; i++)
{
if(m_raw[i] == '\n')
{
line++;
col = 1;
}
else
col++;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBaseLanFormat::NormalizeUft()
{
m_offset = 0;
//---
if(m_len >= 2)
{
// UTF16 BE
if(m_raw[0] == 0xFF && m_raw[1] == 0xFE)
{
const int n = (m_len - 2) >> 1;
for(int i = 0; i < n; i++)
m_raw[i] = m_raw[2 + (i * 2)]; // byte bajo (el char real)
m_len = ArrayResize(m_raw, n);
}
// UTF16 LE
else
if(m_raw[0] == 0xFE && m_raw[1] == 0xFF)
{
const int n = (m_len - 2) >> 1;
for(int i = 0; i < n; i++)
m_raw[i] = m_raw[3 + (i * 2)]; // byte alto (invertido)
m_len = ArrayResize(m_raw, n);
}
}
else
if(m_len >= 3 && m_raw[0] == 0xEF && m_raw[1] == 0xBB && m_raw[2] == 0xBF)
{
// UTF-8 BOM
m_offset = 3; // simplemente saltear
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Esto en especiifco es para lengaujes qeu soprotes como minimo objetos,tipsode datos, arrays
// y anidacion
// layout: [bucket_l][final_l<<32]
#define BSFL_T_GET_FINALTABLE_L(V) ((V)>>32)
#define BSFL_T_GET_BUCKET_L(V) ((V)&0xffffffff)
#define BSFL_T_PACK(B, F) (ulong(B) | ulong(F) << 32)
//---
#define BSFL_OPT_F_ENABLE_JIT (1)
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CBaseStructuredLan : public CBaseLanFormat
{
public:
//- Structs
struct ObjNode
{
ushort seeds[]; // Seeds..
ulong key_hash[]; // Key hash
int pos_index[]; // [h] (hash) = devuevle indice del objeto
int pos_arr[]; // [i] (index de objeto) = devuelve indice en la cinta
ulong sizes; // Tamaños
int start; // Start en cinta
int table_size; // Tamaño de tabla
};
ObjNode m_tables[];
int m_tables_size;
int m_tables_reserve;
//- valor de hash
ulong m_jit_enabled;
protected:
//---
virtual int CalcRegType(const string& file_name) = 0;
public:
CBaseStructuredLan(void);
~CBaseStructuredLan(void) {}
//---
int AssingFile(const string& file_name, const bool comon_flag);
//---
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 SaveTables(const int fh) const;
void LoadTables(const int fh);
//---
int PerfectHashAcces(const ulong key_hash, const ObjNode& node) const;
int PerfectHashComputeHashIndex(const ulong key_hash, const ObjNode& node) const;
//---
__forceinline int FindNodePos(const int start) const;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBaseStructuredLan::CBaseStructuredLan()
: m_tables_size(0), m_tables_reserve(4), m_jit_enabled(TSN_SBL_BIT_JIT_INITIAL_V)
{
ArrayResize(m_tables, 4, 2);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CBaseStructuredLan::AssingFile(const string& file_name, const bool comon_flag)
{
//---
const int reg_type = CalcRegType(file_name);
//---
if(reg_type == TSN_SLF_EXT_TYPE_CACHE_FILE) // 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);
LoadTables(fh); // Perfect hash tables
}
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);
LoadTables(fh); // Perfect hash tables
}
//---
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 reg_type;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CBaseStructuredLan::PerfectHashAcces(const ulong key_hash, const ObjNode& node) const
{
//---
const ulong v = node.sizes;
const int seed_index = int(key_hash & BSFL_T_GET_BUCKET_L(v));
//--- Alg
SBL_HASH_ALG(key_hash, node.seeds[seed_index])
//--- Pos
const int fi = int(h & BSFL_T_GET_FINALTABLE_L(v));
return node.key_hash[fi] == key_hash ? node.pos_arr[node.pos_index[fi]] : -1;
}
//+------------------------------------------------------------------+
int CBaseStructuredLan::PerfectHashComputeHashIndex(const ulong key_hash, const ObjNode& node) const
{
//---
const ulong v = node.sizes;
const int seed_index = int(key_hash & BSFL_T_GET_BUCKET_L(v));
//--- Alg
SBL_HASH_ALG(key_hash, node.seeds[seed_index])
//--- Pos
const int fi = int(h & BSFL_T_GET_FINALTABLE_L(v));
return node.key_hash[fi] == key_hash ? node.pos_index[fi] : -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//--- Ambos
// 4 bytes: m_cinta_pos
// 4 bytes: type
//---
bool CBaseStructuredLan::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);
//--- Perfect hash tables (m_tables)
SaveTables(fh);
//---
FileClose(fh);
//---
return true;
}
//+------------------------------------------------------------------+
bool CBaseStructuredLan::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);
//--- Perfect hash tables (m_tables)
SaveTables(fh);
//---
FileClose(fh);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBaseStructuredLan::SaveTables(const int fh) const
{
//---
FileWriteInteger(fh, m_tables_size);
//---
for(int i = 0; i < m_tables_size; i++)
{
const int table_size = m_tables[i].table_size;
const ulong v = m_tables[i].sizes;
const int bucket_size = (int)BSFL_T_GET_BUCKET_L(v) + 1;
const int final_size = (int)BSFL_T_GET_FINALTABLE_L(v) + 1;
//---
FileWriteInteger(fh, m_tables[i].start);
FileWriteInteger(fh, table_size);
FileWriteInteger(fh, bucket_size);
FileWriteInteger(fh, final_size);
//---
FileWriteArray(fh, m_tables[i].seeds, 0, bucket_size);
FileWriteArray(fh, m_tables[i].pos_index, 0, final_size);
FileWriteArray(fh, m_tables[i].key_hash, 0, final_size);
FileWriteArray(fh, m_tables[i].pos_arr, 0, table_size);
}
}
//+------------------------------------------------------------------+
void CBaseStructuredLan::LoadTables(const int fh)
{
//---
m_tables_size = FileReadInteger(fh);
m_tables_reserve = m_tables_size;
ArrayResize(m_tables, m_tables_size, m_tables_size);
//---
for(int i = 0; i < m_tables_size; i++)
{
//---
m_tables[i].start = FileReadInteger(fh);
const int table_size = FileReadInteger(fh);
m_tables[i].table_size = table_size;
//---
const int bucket_size = FileReadInteger(fh);
const int final_size = FileReadInteger(fh);
//---
m_tables[i].sizes = BSFL_T_PACK(bucket_size - 1, final_size - 1);
//---
FileReadArray(fh, m_tables[i].seeds, 0, bucket_size);
FileReadArray(fh, m_tables[i].pos_index, 0, final_size);
FileReadArray(fh, m_tables[i].key_hash, 0, final_size);
FileReadArray(fh, m_tables[i].pos_arr, 0, table_size);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
__forceinline int CBaseStructuredLan::FindNodePos(const int start) const
{
for(short i = 0; i < m_tables_size; i++)
if(m_tables[i].start == start)
return i;
return -1;
}
//---
#define BASESPARSERSLAN_START_NODE_HASH(TABLE_POS, START) \
for(short i = 0; i < m_tables_size; i++) \
{ \
if(m_tables[i].start == START) \
{ \
TABLE_POS = i; \
return; \
} \
} \
if(m_tables_size >= m_tables_reserve) \
{ \
m_tables_reserve += 8; \
ArrayResize(m_tables, m_tables_reserve, m_tables_reserve); \
} \
TABLE_POS = m_tables_size; \
m_tables[m_tables_size++].start = START;
//---
}
//+------------------------------------------------------------------+
#endif // BASESPARSERSLAN_SRC_BASECLASS_MAIN_MQH