SetFileByLeo/Src/Parser.mqh
2026-07-07 18:35:33 -05:00

1435 lines
42 KiB
MQL5

//+------------------------------------------------------------------+
//| Parser.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_PARSER_MQH
#define SETFILEBYLEO_SRC_PARSER_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Def.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CSetFileParser
{
public:
uchar m_data[];
long m_cinta[];
int m_cinta_pos;
int m_cinta_reserve;
int m_offset;
int m_pos;
int m_len;
//---
CPerfectHashByLeo<ulong> m_pfh;
//---
ulong m_table_seeds[]; // Seeds..
ulong m_table_key_hash[]; // Key hash
int m_table_pos_index[]; // [h] (hash) = devuelve indice del objeto
int m_table_pos_arr[]; // [i] (index de objeto) = devuelve indice en la cinta (posicion del KEY)
ulong m_table_bucket_size; // Buckets
ulong m_table_final_table_size; // Tamaño de pos_index (tabla final)
int m_table_size; // Cantidad de keys en la tabla
bool m_table_ready; // true una vez construida con exito
ulong m_max_att;
private:
uchar m_next;
int m_prev_start;
ENUM_SETFILE_PARSER_ERROR m_last_err;
long m_mask;
int m_pares;
int m_last_lock;
int m_root_c;
//---
bool ProccesDecimal(double val);
public:
CSetFileParser(void);
~CSetFileParser(void) {}
//--- Utils.
bool StrEquals(const string &str, const int curr) const;
bool StrEquals(const int other, const int curr) const;
__forceinline int GetStep(const int idx) const;
//--- Load..
inline void Assing(const string& set);
int AssingFile(const string& file_name, const bool comon_flag);
bool AutoParseByFileExt(const int file_ext_type);
//--- Save\Load
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_set, const bool json_common_flag) const;
void SaveTables(const int fh) const;
void LoadTables(const int fh);
//--- Extra
__forceinline void CalcLen() { m_len = ArraySize(m_data); }
void CorrectPading();
//--- Last err
__forceinline ENUM_SETFILE_PARSER_ERROR LastErr() const { return m_last_err; }
//--- Info
void PrintCintaTypes(const int start, const int num) const;
//--- Base
bool Parse();
CSetNode GetRoot();
//--- Perfect hash
int PerfectHashComputeHash(const string& word) const;
int PerfectHashComputeHashIndex(const string& word) const;
bool NodeHashing(int curr, const int obj_count, const int bend);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CSetFileParser::CSetFileParser(void)
: m_table_size(0), m_table_ready(false), m_max_att(1000)
{
//---
m_cinta_reserve = ArrayResize(m_cinta, 4096, 4096);
//---
m_pfh.DeleteHashers(true);
m_pfh.Hasher0(new CSetFHasherGenUl());
m_pfh.Hasher1(new CSetFHasherGenUl1());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
inline void CSetFileParser::Assing(const string& set)
{
m_len = StringToCharArray(set, m_data);
m_offset = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
__forceinline int CSetFileParser::GetStep(const int idx) const
{
const int tipo = int(m_cinta[idx] & 0xF);
switch(tipo)
{
case SETFILE_TOK_ROOT:
return 1;
case SETFILE_TOK_INTEGER:
case SETFILE_TOK_REAL:
return 2;
case SETFILE_TOK_BOOLEAN:
return 1;
case SETFILE_TOK_STRING:
return 1;
case SETFILE_TOK_KEY:
return 1;
case SETFILE_TOK_META:
return 1;
}
return 1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSetFileParser::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_SETFILE_BIT_START_STR);
const int len = int((m_cinta[curr] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
//PrintFormat("Exact = '%s', other = '%s'", CharArrayToString(m_data, start, len), str);
const int l = StringLen(str);
//---
if(l != len)
return false;
for(int i = 0; i < l; i++)
{
if(str[i] != m_data[start + i])
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSetFileParser::StrEquals(const int other, 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_SETFILE_BIT_START_STR);
const int len = int((m_cinta[curr] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
//PrintFormat("Exact = '%s', other = '%s'", CharArrayToString(m_data, start, len), str);
const int s = int(m_cinta[other] >> TSN_SETFILE_BIT_START_STR);
const int l = int((m_cinta[other] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
//---
if(l != len)
return false;
for(int i = 0; i < l; i++)
{
if(m_data[s + i] != m_data[start + i])
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// luego de un valor buscar key
#define TSN_SETFILE_NEXT_V \
while(true) \
{ \
if(m_pos >= m_len) \
{ \
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;\
return true; \
} \
const uchar cfasd = m_data[m_pos]; \
if(cfasd < 33) \
{ \
m_pos++; \
continue; \
} \
if(cfasd == ';') \
{ \
m_next = SETFILE_TOKENS_INT_COMENTARIO; \
} \
else \
{ \
m_next = SETFILE_TOKENS_INT_KEY; \
} \
break; \
} \
//----
#define TSN_SETFILE_CHECKNUMBER \
while(true) \
{ \
const uchar f = m_data[m_pos]; \
if(f < 33) \
{ \
if(f == '\n') \
{ \
if(m_pares>0) \
{ \
m_cinta_pos = m_last_lock + 1; \
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(m_pos - m_prev_start) << TSN_SETFILE_BIT_START_LEN_PLAIN \
| long(m_prev_start) << TSN_SETFILE_BIT_START_STR; \
m_pos++; \
TSN_SETFILE_NEXT_V \
} \
else \
{ \
m_cinta[m_last_lock] |= long(SETFILE_TOK_OP_TYPE_VAL) << TSN_SETFILE_BIT_END_TYPE; \
m_pos++;\
TSN_SETFILE_NEXT_V\
} \
break; \
} \
m_pos++; \
if(m_pos >= m_len) \
{ \
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;\
return true; \
} \
continue; \
} \
if(f == '|') \
{ \
if(m_data[m_pos+1] == '|') \
{ \
m_pos+=2; \
while(true) \
{ \
const uchar fca = m_data[m_pos]; \
if(fca < 33) \
{ \
m_pos++; \
if(m_pos >= m_len) \
{ \
m_cinta_pos = m_last_lock + 1; \
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(m_pos - m_prev_start) << TSN_SETFILE_BIT_START_LEN_PLAIN \
| long(m_prev_start) << TSN_SETFILE_BIT_START_STR; \
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;\
return true; \
} \
continue; \
} \
if(m_pares >= 3) \
{ \
m_cinta[m_last_lock] |= long((fca == 'Y') ? SETFILE_TOK_OP_TYPE_Y : SETFILE_TOK_OP_TYPE_N) << TSN_SETFILE_BIT_END_TYPE; \
m_pos++;\
TSN_SETFILE_NEXT_V \
} \
else \
{ \
if((fca ^ '0') < 10 || fca == '-') \
{ \
m_next = SETFILE_TOKENS_INT_NUMBER; \
m_pares++; \
} \
else \
{ \
m_pos++;\
m_cinta_pos = m_last_lock + 1; \
m_next = SETFILE_TOKENS_INT_STRING; \
} \
}\
break;\
}\
break;\
} \
}\
m_pos++;\
m_cinta_pos = m_last_lock + 1; \
m_next = SETFILE_TOKENS_INT_STRING; \
break; \
} \
// 0-1 | 1-2 | 2-3 |
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSetFileParser::ProccesDecimal(double val)
{
//---
m_pos++;
//---
long frac_int = 0;
int fract_digits = 0;
//---
while(true)
{
const uchar c = m_data[m_pos] ^ '0';
if(c > 9)
{
if(c == 76 || c == 58) // es | o \n
break;
else
return false; // plain
}
frac_int = (frac_int << 3) + (frac_int << 1) + c;
fract_digits++;
m_pos++;
}
//---
val += frac_int * g_Exp10[fract_digits];
//---
static BitInterpreter bit;
bit.double_value = val;
bit.long_value ^= (m_mask & (1LL << 63));
m_cinta[m_cinta_pos++] = SETFILE_TOK_REAL;
m_cinta[m_cinta_pos++] = bit.long_value;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSetFileParser::CorrectPading(void)
{
//---
const int extra = 1 + (m_len % 8); // Resto
const int prev = m_len;
ArrayResize(m_data, (m_len += extra));
//---
for(int i = prev; i < m_len; i++)
{
m_data[i] = '\n';
}
// ArrayPrint(m_data);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSetFileParser::Parse()
{
//---
m_pos = m_offset;
m_cinta_pos = 0;
m_root_c = 0;
if(m_len > m_cinta_reserve)
{
m_cinta_reserve = m_len;
ArrayResize(m_cinta, m_len, m_len);
}
//---
m_cinta[m_cinta_pos++] = SETFILE_TOK_ROOT;
while(true)
{
const uchar f = m_data[m_pos];
if(f < 33)
{
m_pos++;
continue;
}
if(f == ';')
{
m_next = SETFILE_TOKENS_INT_COMENTARIO;
}
else
{
m_next = SETFILE_TOKENS_INT_KEY;
}
break;
}
//---
while(true)
{
switch(m_next)
{
case SETFILE_TOKENS_INT_NUMBER:
{
//---
long v = 0;
//--- Validamos signo
m_mask = 0;
uchar ch = m_data[m_pos];
if(ch == '-')
{
m_mask = -1;
m_pos++; // Ahora en numero
ch = m_data[m_pos];
}
//---
ch ^= '0';
//---
while(true)
{
//---
v = (v << 3) + (v << 1) + ch;
//--- *
m_pos++;
//---
ch = m_data[m_pos] ^ '0';
//---
if(ch < 10)
{
continue;
}
else
if(ch == 30)
{
if(!ProccesDecimal(double(v)))
{
m_next = SETFILE_TOKENS_INT_STRING;
}
else
{
TSN_SETFILE_CHECKNUMBER
}
break;
}
else
{
m_cinta[m_cinta_pos++] = SETFILE_TOK_INTEGER;
m_cinta[m_cinta_pos++] = (v ^ m_mask) - m_mask;
// Print("c: " , CharToString(m_data[m_pos]), " pos: " , m_pos, " len: " , m_len);
TSN_SETFILE_CHECKNUMBER
// Print(EnumToString((ENUM_SETFILE_TOKENS_INT)m_next));
break; // Fin
}
}
//---
break;
}
//--- string
case SETFILE_TOKENS_INT_STRING:
{
const int start = m_prev_start == -1 ? m_pos++ : m_prev_start;
#ifndef SETFILEBYLEO_DESACTIVE_SWAR
int curr_end = m_pos + 8;
if(curr_end <= m_len)
{
while(true)
{
const ulong chunk = (ulong)m_data[m_pos]
| (ulong)m_data[m_pos + 1] << 8
| (ulong)m_data[m_pos + 2] << 16
| (ulong)m_data[m_pos + 3] << 24
| (ulong)m_data[m_pos + 4] << 32
| (ulong)m_data[m_pos + 5] << 40
| (ulong)m_data[m_pos + 6] << 48
| (ulong)m_data[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 = curr_end;
curr_end += 8;
//---
if(curr_end > m_len)
{
do
{
if(m_data[m_pos] == '\n')
break;
m_pos++;
}
while(m_pos < m_len);
break; // Salimos..
}
//---
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;
}
}
else
{
#endif // SETFILEBYLEO_DESACTIVE_SWAR
do
{
if(m_data[m_pos] == '\n')
break;
m_pos++;
}
while(m_pos < m_len);
#ifndef SETFILEBYLEO_DESACTIVE_SWAR
}
#endif // SETFILEBYLEO_DESACTIVE_SWAR
//---
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(m_pos - start) << TSN_SETFILE_BIT_START_LEN_PLAIN
| long(start) << TSN_SETFILE_BIT_START_STR;
//---
m_pos++; // Luiego del \n
//---
//m_prev_start = -1;
//---
TSN_SETFILE_NEXT_V
break;
}
//---
case SETFILE_TOKENS_INT_TRUE:
{
m_prev_start = m_pos++;
if(m_pos + 2 < m_len)
{
if(m_data[m_pos++] != 'r' || m_data[m_pos++] != 'u' || m_data[m_pos++] != 'e')
{
m_next = SETFILE_TOKENS_INT_STRING;
break;
}
if(m_pos <= m_len)
{
m_cinta[m_cinta_pos++] = SETFILE_TOK_BOOLEAN | (long)1 << TSN_SETFILE_BIT_END_TYPE;
m_next = SETFILE_TOKENS_INT_AFTER_TRUE_FASE_OPT;
}
else
{
m_pos++;
m_next = SETFILE_TOKENS_INT_STRING;
}
}
else
{
m_next = SETFILE_TOKENS_INT_STRING;
}
break;
}
//---
case SETFILE_TOKENS_INT_FALSE:
{
m_prev_start = m_pos++;
if(m_pos + 3 < m_len)
{
if(m_data[m_pos++] != 'a' || m_data[m_pos++] != 'l' || m_data[m_pos++] != 's' || m_data[m_pos++] != 'e')
{
m_next = SETFILE_TOKENS_INT_STRING;
break;
}
if(m_pos <= m_len)
{
m_cinta[m_cinta_pos++] = SETFILE_TOK_BOOLEAN;
m_next = SETFILE_TOKENS_INT_AFTER_TRUE_FASE_OPT; // check
}
else
{
m_pos++;
m_next = SETFILE_TOKENS_INT_STRING;
}
}
else
{
m_next = SETFILE_TOKENS_INT_STRING;
}
break;
}
//---
case SETFILE_TOKENS_INT_AFTER_TRUE_FASE_OPT: // =x||false||0||true||N\Y
{
while(true)
{
const uchar f = m_data[m_pos];
if(f < 33)
{
if(f == '\n') // termino.
{
TSN_SETFILE_NEXT_V
break;
}
//---
m_pos++;
if(m_pos >= m_len)
{
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;
return true;
}
continue;
}
if(f == '|')
{
if(m_data[m_pos + 1] == '|')
{
m_pos += 2; // luego del |
// Skip ws
int state = 0;
// 0 = false
// 1 = 0
// 2 = true
do
{
const uchar fc = m_data[m_pos];
// ws
if(fc < 33)
{
m_pos++;
if(m_pos >= m_len)
{
m_cinta_pos = m_last_lock + 1;
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(m_pos - m_prev_start) << TSN_SETFILE_BIT_START_LEN_PLAIN
| long(m_prev_start) << TSN_SETFILE_BIT_START_STR;
//m_pos++;
// m_prev_start = -1;
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;
return true; // terminamos...
}
continue;
}
// state
switch(state)
{
case 0: // false
{
if(m_pos + 4 < m_len)
{
if(m_data[m_pos++] != 'f' || m_data[m_pos++] != 'a' || m_data[m_pos++] != 'l' || m_data[m_pos++] != 's' || m_data[m_pos++] != 'e')
{
state = -1;
break;
}
if(m_pos < m_len) // || YAMLPARSER_IS_PARAR_CHARCTX(m_data[m_pos])
{
m_cinta[m_cinta_pos++] = SETFILE_TOK_BOOLEAN; // bool\bool
state++;
}
else
{
m_pos++;
state = -1;
}
}
else //
{
state = -1;
}
break;
}
case 1: // 0
{
if(m_data[m_pos] != '0')
{
state = -1;
}
else
{
m_cinta[m_cinta_pos++] = SETFILE_TOK_BOOLEAN; // false=
state++;
}
break;
}
case 2: // true
{
if(m_pos + 3 < m_len)
{
if(m_data[m_pos++] != 't' || m_data[m_pos++] != 'r' || m_data[m_pos++] != 'u' || m_data[m_pos++] != 'e')
{
state = -1;
break;
}
if(m_pos < m_len) // || YAMLPARSER_IS_PARAR_CHARCTX(m_data[m_pos])
{
m_cinta[m_cinta_pos++] = SETFILE_TOK_BOOLEAN | long(1) << TSN_SETFILE_BIT_END_TYPE; // bool\bool
state++;
}
else
{
m_pos++;
state = -1;
}
}
else //
{
state = -1;
}
break;
}
case 3: // Y\N
{
state = -2; // salida limpia
m_cinta[m_last_lock] |= long((fc == 'Y') ? SETFILE_TOK_OP_TYPE_Y : SETFILE_TOK_OP_TYPE_N) << TSN_SETFILE_BIT_END_TYPE;
m_pos++; // luego
//m_prev_start = -1; // Salida limpia
TSN_SETFILE_NEXT_V
break;
}
}
// Buscar ||
while(state >= 0)
{
if(m_data[m_pos] == '|')
{
if(m_data[m_pos + 1] == '|')
{
m_pos += 2;
break; // Bien continuamos
}
else
{
state = -1; // Fallo
break;
}
}
//---
m_pos++;
if(m_pos >= m_len)
{
// salimos de una vez..
m_cinta_pos = m_last_lock + 1;
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(m_pos - m_prev_start) << TSN_SETFILE_BIT_START_LEN_PLAIN
| long(m_prev_start) << TSN_SETFILE_BIT_START_STR;
//m_pos++;
//m_prev_start = -1;
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;
return true;
}
}
}
while(state >= 0);
//---
if(state == -1)
{
//Print("gf");
m_next = SETFILE_TOKENS_INT_STRING;
m_cinta_pos = m_last_lock + 1;
}
}
else
{
m_cinta_pos = m_last_lock + 1; // para que sobreescibra
m_next = SETFILE_TOKENS_INT_STRING;
}
}
else
{
// Ahotra mismo en f que es invalido no es |
m_pos++; // luego del |
m_cinta_pos = m_last_lock + 1; // para que sobreescibra
m_next = SETFILE_TOKENS_INT_STRING;
}
break;
}
//---
break;
}
//---
case SETFILE_TOKENS_INT_KEY:
{
const int start = m_pos++; // Luego del a=
//Print(CharToString(m_data[m_pos]));
//---
int curr_end = m_pos + 8;
if(curr_end <= m_len)
{
while(true)
{
//Print(CharArrayToString(m_data, m_pos, 7));
const ulong chunk = (ulong)m_data[m_pos]
| (ulong)m_data[m_pos + 1] << 8
| (ulong)m_data[m_pos + 2] << 16
| (ulong)m_data[m_pos + 3] << 24
| (ulong)m_data[m_pos + 4] << 32
| (ulong)m_data[m_pos + 5] << 40
| (ulong)m_data[m_pos + 6] << 48
| (ulong)m_data[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 = curr_end;
curr_end += 8;
//---
if(curr_end > m_len)
{
do
{
if(m_data[m_pos] == '=')
break;
m_pos++;
}
while(m_pos < m_len);
break;
}
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
{
do
{
if(m_data[m_pos] == '=')
break;
m_pos++;
}
while(m_pos < m_len);
}
// Justo m_pos='='
//-- Agregamos
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_KEY) | long(m_pos - start) << TSN_SETFILE_BIT_START_LEN_PLAIN
| long(start) << TSN_SETFILE_BIT_START_STR;
//---
m_root_c++; // Nuevo elemento
m_prev_start = ++m_pos; // luego del =
m_last_lock = m_cinta_pos++; // lock aqui
m_cinta[m_last_lock] = SETFILE_TOK_META; // meta type
m_pares = 0;
//---
while(true)
{
const uchar f = m_data[m_pos];
if(f < 33)
{
if(f == '\n')
{
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(0) << TSN_SETFILE_BIT_START_LEN_PLAIN
| long(start) << TSN_SETFILE_BIT_START_STR;
m_cinta[m_last_lock] |= long(SETFILE_TOK_OP_TYPE_VAL) << TSN_SETFILE_BIT_END_TYPE;
//---
TSN_SETFILE_NEXT_V
break;
}
m_pos++;
if(m_pos >= m_len)
{
m_cinta[m_cinta_pos++] = long(SETFILE_TOK_STRING) | long(0) << TSN_SETFILE_BIT_START_LEN_PLAIN
| long(start) << TSN_SETFILE_BIT_START_STR;
m_cinta[m_last_lock] |= long(SETFILE_TOK_OP_TYPE_VAL) << TSN_SETFILE_BIT_END_TYPE;
m_cinta[0] |= long(m_root_c) << TSN_SETFILE_BIT_END_TYPE;
return true;
}
continue;
}
m_next = g_tsn_setfile_tokens[f];
break;
}
break;
}
//---
case SETFILE_TOKENS_INT_COMENTARIO:
{
m_pos++; // Siguiente..
//---
int curr_end = m_pos + 8;
if(curr_end <= m_len)
{
while(true)
{
//Print(CharArrayToString(m_data, m_pos, 7));
const ulong chunk = (ulong)m_data[m_pos]
| (ulong)m_data[m_pos + 1] << 8
| (ulong)m_data[m_pos + 2] << 16
| (ulong)m_data[m_pos + 3] << 24
| (ulong)m_data[m_pos + 4] << 32
| (ulong)m_data[m_pos + 5] << 40
| (ulong)m_data[m_pos + 6] << 48
| (ulong)m_data[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 = curr_end;
curr_end += 8;
//--- Check
if(curr_end > m_len)
{
do
{
if(m_data[m_pos] == '\n')
break;
m_pos++;
}
while(m_pos < m_len);
break;
}
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
{
do
{
if(m_data[m_pos] == '\n')
break;
m_pos++;
}
while(m_pos < m_len);
}
//---
m_pos++;
// Si o si sigue key
TSN_SETFILE_NEXT_V
break;
}
//---
default:
m_last_err = SETFILE_PARSER_ERROR_INVALID_TOKEN;
return false;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CSetFileParser::PerfectHashComputeHash(const string& word) const
{
//--- Hash 64
ulong key_hash = FNV_OFFSET_BASIS;
const int len = StringLen(word);
for(int i = 0; i < len; i++)
{
key_hash ^= (uchar)word[i];
key_hash *= FNV_PRIME;
}
//----
const int seed_index = int(key_hash % m_table_bucket_size);
//--- Alg
ulong h = key_hash + m_table_seeds[seed_index] * 0x9e3779b97f4a7c15;
h = (h ^ (h >> 30)) * 0xbf58476d1ce4e5b9;
h = (h ^ (h >> 27)) * 0x94d049bb133111eb;
h ^= (h >> 31);
//--- Pos (devuelve la posicion del KEY en la cinta)
const int fi = int(h % m_table_final_table_size);
return m_table_key_hash[fi] == key_hash ? m_table_pos_arr[m_table_pos_index[fi]] : -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CSetFileParser::PerfectHashComputeHashIndex(const string& word) const
{
//--- Hash 64
ulong key_hash = FNV_OFFSET_BASIS;
const int len = StringLen(word);
for(int i = 0; i < len; i++)
{
key_hash ^= (uchar)word[i];
key_hash *= FNV_PRIME;
}
//----
const int seed_index = int(key_hash % m_table_bucket_size);
//--- Alg
ulong h = key_hash + m_table_seeds[seed_index] * 0x9e3779b97f4a7c15;
h = (h ^ (h >> 30)) * 0xbf58476d1ce4e5b9;
h = (h ^ (h >> 27)) * 0x94d049bb133111eb;
h ^= (h >> 31);
//--- Pos
const int fi = int(h % m_table_final_table_size);
return m_table_key_hash[fi] == key_hash ? m_table_pos_index[fi] : -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSetFileParser::NodeHashing(int curr, const int obj_count, const int bend)
{
//---
m_pfh.MaxValSeed(m_max_att++);
m_pfh.InitAlg(obj_count, 0.75, fmin(obj_count, 4));
//---
m_table_size = obj_count;
ArrayResize(m_table_pos_arr, obj_count);
//---
ulong keys_h[];
int posiciones[];
ArrayResize(keys_h, obj_count);
ArrayResize(posiciones, obj_count);
int pos_c = 0;
curr++;
//---
while(curr < bend)
{
//---
m_table_pos_arr[pos_c] = curr; // Assing (posicion del KEY)
//---
ulong key_hash = FNV_OFFSET_BASIS;
int i = int(m_cinta[curr] >> TSN_SETFILE_BIT_START_STR); // start
const int len = i + int((m_cinta[curr] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF); // start+len
//--- Hash 64
for(; i < len; i++)
{
key_hash ^= m_data[i];
key_hash *= FNV_PRIME;
}
//---
keys_h[pos_c] = key_hash;
posiciones[pos_c] = pos_c;
pos_c++;
//---
const int meta = curr + 1;
const int val_pos = meta + 1;
const int val_step = GetStep(val_pos);
const bool optimizable = int(m_cinta[meta] >> TSN_SETFILE_BIT_END_TYPE) != SETFILE_TOK_OP_TYPE_VAL;
//---
curr += 2 + val_step * (optimizable ? 4 : 1);
}
//---
m_table_bucket_size = m_pfh.m_buckets_size;
const int fn = m_pfh.m_final_table_size;
m_table_final_table_size = fn;
//--- Iniciamos..
ArrayResize(m_table_pos_index, fn);
ArrayResize(m_table_key_hash, fn);
ArrayInitialize(m_table_pos_index, -1);
ArrayInitialize(m_table_key_hash, 0ULL);
//---
return (m_table_ready = m_pfh.RunWValue(keys_h, posiciones, m_table_seeds, m_table_pos_index, m_table_key_hash));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CSetFileParser::AssingFile(const string& file_name, const bool comon_flag)
{
//---
const int reg_type = FileGetExtension(file_name) == "settc" ? TSNSETF_RI_SETTC_FILE : TSNSETF_RI_SET_FILE;
//---
if(reg_type == TSNSETF_RI_SETTC_FILE) // settc 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)
m_cinta_pos = FileReadInteger(fh); // Nota que cuando 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_SETFPARSER_SETTC_TYPE_EMBEBED)
{
m_len = FileReadInteger(fh);
m_offset = FileReadInteger(fh);
FileReadArray(fh, m_cinta, 0, m_cinta_pos); // Total
FileReadArray(fh, m_data, 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);
AssingFile(FileReadString(fh, file_name_len), common); // Carga
FileReadArray(fh, m_cinta, 0, m_cinta_pos);
LoadTables(fh); // Perfect hash tables
}
//---
FileClose(fh);
return TSNSETF_RI_SETTC_FILE;
}
else // set normal
{
m_len = (int)FileLoad(file_name, m_data, (comon_flag ? FILE_COMMON : 0));
m_offset = 0;
//---
if(m_len >= 2)
{
// UTF16 BE
if(m_data[0] == 0xFF && m_data[1] == 0xFE)
{
const int n = (m_len - 2) >> 1;
for(int i = 0; i < n; i++)
m_data[i] = m_data[2 + (i * 2)]; // byte bajo (el char real)
m_len = ArrayResize(m_data, n);
}
// UTF16 LE
else
if(m_data[0] == 0xFE && m_data[1] == 0xFF)
{
const int n = (m_len - 2) >> 1;
for(int i = 0; i < n; i++)
m_data[i] = m_data[3 + (i * 2)]; // byte alto (invertido)
m_len = ArrayResize(m_data, n);
}
}
else
if(m_len >= 3 && m_data[0] == 0xEF && m_data[1] == 0xBB && m_data[2] == 0xBF)
{
// UTF-8 BOM
m_offset = 3; // simplemente saltear
}
//---
return reg_type;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSetFileParser::AutoParseByFileExt(const int file_ext_type)
{
switch(file_ext_type)
{
case TSNSETF_RI_SET_FILE:
{
return Parse();
}
case TSNSETF_RI_SETTC_FILE:
{
return m_cinta_pos > 0 && m_len > 0;
}
default:
{
m_last_err = SETFILE_PARSER_ERROR_INVALID_EXT_FILE;
m_pos = 0;
return false;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//--- Ambos
// 4 bytes: m_cinta_pos
// 4 bytes: type
//---
bool CSetFileParser::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);
if(fh == INVALID_HANDLE)
{
return false;
}
//--- Comun
FileWriteInteger(fh, m_cinta_pos);
FileWriteInteger(fh, TSN_SETFPARSER_SETTC_TYPE_EMBEBED);
//---
// 4 bytes: len
// 4 bytes: offset
// array: cinta
// array: data
//---
FileWriteInteger(fh, m_len);
FileWriteInteger(fh, m_offset);
FileWriteArray(fh, m_cinta, 0, m_cinta_pos);
FileWriteArray(fh, m_data, 0, m_len);
//--- Perfect hash tables (m_tables)
SaveTables(fh);
//---
FileClose(fh);
//---
return true;
}
//+------------------------------------------------------------------+
bool CSetFileParser::SaveCompiled(const string & file_name_out, const bool out_common_flag, const string & file_name_set, const bool json_common_flag) const
{
//---
::ResetLastError();
const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE);
if(fh == INVALID_HANDLE)
{
return false;
}
//--- Comun
FileWriteInteger(fh, m_cinta_pos);
FileWriteInteger(fh, TSN_SETFPARSER_SETTC_TYPE_FILE);
//---
// 1 bytes: comon
// 4 bytes: len
// string: name_file
// array: cinta
//---
FileWriteInteger(fh, json_common_flag, CHAR_VALUE);
const int len = StringLen(file_name_set);
FileWriteInteger(fh, len);
FileWriteString(fh, file_name_set, len);
FileWriteArray(fh, m_cinta, 0, m_cinta_pos);
//--- Perfect hash tables (m_tables)
SaveTables(fh);
//---
FileClose(fh);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSetFileParser::SaveTables(const int fh) const
{
//---
FileWriteInteger(fh, m_table_ready ? 1 : 0);
if(!m_table_ready)
return;
//---
const int bucket_size = (int)m_table_bucket_size;
const int final_size = (int)m_table_final_table_size;
FileWriteInteger(fh, m_table_size);
FileWriteInteger(fh, bucket_size);
FileWriteInteger(fh, final_size);
//---
FileWriteArray(fh, m_table_seeds, 0, bucket_size);
FileWriteArray(fh, m_table_pos_index, 0, final_size);
FileWriteArray(fh, m_table_key_hash, 0, final_size);
FileWriteArray(fh, m_table_pos_arr, 0, m_table_size);
}
//+------------------------------------------------------------------+
void CSetFileParser::LoadTables(const int fh)
{
//---
m_table_ready = FileReadInteger(fh) != 0;
if(!m_table_ready)
{
m_table_size = 0;
return;
}
//---
m_table_size = FileReadInteger(fh);
const int bucket_size = FileReadInteger(fh);
m_table_bucket_size = ulong(bucket_size);
const int final_size = FileReadInteger(fh);
m_table_final_table_size = ulong(final_size);
//---
FileReadArray(fh, m_table_seeds, 0, bucket_size);
FileReadArray(fh, m_table_pos_index, 0, final_size);
FileReadArray(fh, m_table_key_hash, 0, final_size);
FileReadArray(fh, m_table_pos_arr, 0, m_table_size);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CSetFileParser::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_SETFILE_TOKENS tipo = ENUM_SETFILE_TOKENS(m_cinta[p] & 0xF);
string text = "[" + (string)p + "] " + EnumToString(tipo) + " | ";
//---
switch(tipo)
{
case SETFILE_TOK_ROOT:
{
const int count = int((m_cinta[p] >> TSN_SETFILE_BIT_END_TYPE) & TSN_SETFILE_MASK_COUNT);
const int jit_try = int(m_cinta[p] >> TSN_SETFILE_BIT_START_JIT_TRY);
text += "count=" + (string)count + " jit_try=" + (string)jit_try;
break;
}
case SETFILE_TOK_INTEGER:
text += "val=" + (string)m_cinta[p + 1];
break;
case SETFILE_TOK_REAL:
{
static BitInterpreter un;
un.long_value = m_cinta[p + 1];
text += "val=" + (string)un.double_value;
break;
}
case SETFILE_TOK_BOOLEAN:
text += "val=" + (string)(bool)((m_cinta[p] >> TSN_SETFILE_BIT_END_TYPE) & 1);
break;
case SETFILE_TOK_STRING:
{
const int s = int(m_cinta[p] >> TSN_SETFILE_BIT_START_STR);
const int slen = int((m_cinta[p] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + CharArrayToString(m_data, s, slen) + "\"";
break;
}
case SETFILE_TOK_KEY:
{
const int s = int(m_cinta[p] >> TSN_SETFILE_BIT_START_STR);
const int slen = int((m_cinta[p] >> TSN_SETFILE_BIT_START_LEN_PLAIN) & 0xFFFFFFF);
text += "start=" + (string)s + " len=" + (string)slen + " key=\"" + CharArrayToString(m_data, s, slen) + "\"";
break;
}
case SETFILE_TOK_META:
{
const int op = int(m_cinta[p] >> TSN_SETFILE_BIT_END_TYPE);
text += "op_type=" + EnumToString(ENUM_SETFILE_TOK_OP_TYPE(op));
break;
}
}
Print(text);
p += GetStep(p);
}
}
//---
}
//+------------------------------------------------------------------+
#endif // SETFILEBYLEO_SRC_PARSER_MQH