2026-07-27 15:07:46 -05:00 | | | //+------------------------------------------------------------------+
|
2026-06-26 12:44:41 -05:00 | | | //| PerfectHash.mqh |
|
| | | //| Copyright 2026, Niquel Mendoza. |
|
| | | //| https://www.mql5.com/ |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2026, Niquel Mendoza."
|
| | | #property link "https://www.mql5.com/"
|
| | | #property strict
|
| | |
|
| | | #ifndef SIMPHASH_SRC_PERFECTHASH_MQH
|
| | | #define SIMPHASH_SRC_PERFECTHASH_MQH
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include "Def.mqh"
|
| | | #include "Hash\\All.mqh"
|
2026-09-06 09:01:53 -05:00 | | |
|
| | | //---
|
| | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 11:10:24 -05:00 | | | #include <TSN\\ExtraCodes\\WinApiExt.mqh>
|
2026-09-06 20:08:32 -05:00 | | | #include <WinAPI\\errhandlingapi.mqh>
|
| | | #include <WinAPI\\handleapi.mqh>
|
| | | #include <WinAPI\\fileapi.mqh>
|
| | |
|
2026-09-06 09:01:53 -05:00 | | | #endif // SIMPHASH_ENABLE_DLL
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | class CPerfectHashGenerator : public CLoggerBase
|
| | | {
|
| | | private:
|
| | | //--- Parser config
|
2026-07-27 15:07:46 -05:00 | | | CYamlParser m_yml; // Yaml parser
|
| | | CPerfectHashByLeo<ulong, CHashGeneratorBasis, CSimPHashHaserUl1> m_perfect_hash; // Pefect hash class
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //---
|
2026-07-27 15:07:46 -05:00 | | | ulong m_i_max_attemps; // Maximos intentos para hashear
|
| | | string m_i_nampespace; // namespace usado en include final
|
| | | string m_table_prefix; // Prefijo de la tabla
|
| | | IHashGenerator* m_hash; // Hasher (convierete incilamte los string a ulong)
|
| | | IHashGeneratorWSeed* m_hash_pf_1; // Hasher 1 (Wrraper incilla) este es con seed
|
| | | string m_copyright; // Copyrifth del archvo final
|
| | | string m_link; // Link del proiperty archivo final
|
| | | string m_func_name; // Nombre del afuncion de hashing
|
| | | string m_file_name_out; // Ruta del archivo mqh de salida
|
| | | string m_bucket_size_def_name; // Nombre del define del tamñao de los buckets
|
| | | string m_final_table_size_def_name; // Nombre del define del taaño final
|
| | | string m_guard; // Guard name
|
| | | string m_invalid_value; // Valor invalido
|
| | | bool m_comment_func; // Comentar la funcion?¿ que se genera auto?
|
| | | bool m_use_map_value; // Usar los valores del map? o array? (por indice.. ya implicito)
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-09-06 09:01:53 -05:00 | | | //---
|
| | | #ifndef SIMPHASH_ENABLE_DLL
|
| | | bool m_comon_flag;
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //--- In
|
2026-07-27 15:07:46 -05:00 | | | string m_keys[]; // Clave
|
| | | int m_pos[]; // Index
|
| | | ulong m_hashes[]; // Hashes
|
| | | int m_table_size; // Tamaño de la tabla
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-06-27 21:28:54 -05:00 | | | //---
|
2026-07-27 15:07:46 -05:00 | | | ulong m_prev_hashes[]; // Hashes prev
|
2026-06-27 21:28:54 -05:00 | | |
|
2026-06-26 12:44:41 -05:00 | | | //--- Out
|
2026-06-27 21:28:54 -05:00 | | | ulong m_out_seeds[]; // Semillas
|
2026-07-27 15:07:46 -05:00 | | | int m_out_slots[]; // Slots finales..
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //---
|
| | | bool BuildInternal();
|
| | | bool Save();
|
2026-06-27 11:10:24 -05:00 | | | bool SaveBin(CYmlNode& bin);
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //--- Alg
|
| | | bool TryBuildWithSeed(const ulong seed);
|
| | |
|
| | | //--- Construccion
|
| | | void CodeAddFuncBlock(string& data);
|
| | |
|
| | |
|
| | | public:
|
| | | CPerfectHashGenerator(void);
|
| | | ~CPerfectHashGenerator(void);
|
| | |
|
| | | //---
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-28 16:04:15 -05:00 | | | bool Init(const string& file_name_yaml);
|
2026-09-06 09:01:53 -05:00 | | | #else
|
| | | bool Init(const string& file_name_yaml, bool comon);
|
| | | #endif //SIMPHASH_ENABLE_DLL
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //---
|
| | | bool RunAlg();
|
| | | };
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CPerfectHashGenerator::CPerfectHashGenerator()
|
2026-07-27 15:07:46 -05:00 | | | : m_hash(NULL), m_hash_pf_1(NULL)
|
2026-06-26 12:44:41 -05:00 | | | {
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CPerfectHashGenerator::~CPerfectHashGenerator()
|
| | | {
|
| | | if(m_hash != NULL)
|
| | | delete m_hash;
|
2026-07-27 15:07:46 -05:00 | | | if(m_hash_pf_1 != NULL)
|
| | | delete m_hash_pf_1;
|
2026-06-26 12:44:41 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
| | | bool CPerfectHashGenerator::Init(const string& file_name_yaml)
|
| | | #else
|
| | | bool CPerfectHashGenerator::Init(const string& file_name_yaml, bool comon)
|
| | | #endif //SIMPHASH_ENABLE_DLL
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-06-28 16:04:15 -05:00 | | | //---
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-28 16:04:15 -05:00 | | | HANDLE handle = kernel32::CreateFileW(file_name_yaml, GENERIC_READ, SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError(StringFormat("Failed to open file = %s, last err = %d",
|
2026-06-28 16:04:15 -05:00 | | | file_name_yaml, kernel32::GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | |
|
| | | // Prev
|
| | | long Size;
|
| | | kernel32::GetFileSizeEx(handle, Size);
|
| | | uint Read;
|
| | |
|
| | | // Read
|
| | | m_yml.m_len = (int)Size;
|
2026-07-27 15:07:46 -05:00 | | | ArrayResize(m_yml.m_raw, m_yml.m_len);
|
| | | kernel32::ReadFile(handle, m_yml.m_raw, (uint)Size, Read, 0);
|
2026-06-28 16:04:15 -05:00 | | | kernel32::CloseHandle(handle);
|
| | |
|
2026-09-06 09:01:53 -05:00 | | |
|
| | | // Check
|
2026-06-28 16:04:15 -05:00 | | | if(Read < 5)
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError("Empty YAML", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00 | | | return false;
|
| | | }
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | |
|
| | | m_comon_flag = comon;
|
| | |
|
| | | ::ResetLastError();
|
| | | if(m_yml.AssingFile(file_name_yaml, comon) == -1)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError(StringFormat("Failed to load file = %s, last err = %d", file_name_yaml, ::GetLastError()), FUNCION_ACTUAL);
|
2026-09-06 09:01:53 -05:00 | | | return false;
|
| | | }
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-09-06 09:01:53 -05:00 | | | //---
|
2026-06-29 09:02:53 -05:00 | | | // Correcion del padding auto..
|
| | | m_yml.CorrectPadding();
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //---
|
2026-07-27 15:07:46 -05:00 | | | const ulong a = GetMicrosecondCount();
|
| | | const bool r = m_yml.Parse();
|
| | | const ulong b = GetMicrosecondCount();
|
| | |
|
| | | //---
|
| | | if(!r)
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError("Failed to parse YAML, parser message: ", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00 | | | m_yml.ErrorInfo();
|
| | | return false;
|
| | | }
|
| | |
|
2026-07-27 15:07:46 -05:00 | | | //---
|
2026-09-06 15:54:03 -05:00 | | | LogInfo(StringFormat("YAML parsed in %I64u micro", ulong(b - a)), FUNCION_ACTUAL);
|
2026-07-27 15:07:46 -05:00 | | |
|
2026-06-26 12:44:41 -05:00 | | | //---
|
| | | return BuildInternal();
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CPerfectHashGenerator::BuildInternal(void)
|
| | | {
|
2026-06-27 12:37:19 -05:00 | | | //---
|
2026-07-28 11:19:10 -05:00 | | | //m_yml.PrintCintaTypes();
|
2026-06-27 12:37:19 -05:00 | | |
|
| | | //---
|
2026-06-26 12:44:41 -05:00 | | | CYmlNode root = m_yml.GetRoot();
|
| | |
|
2026-06-27 21:28:54 -05:00 | | | //--- Variables generales..
|
2026-06-26 12:44:41 -05:00 | | | m_i_max_attemps = int(root["max_attepms"].ToInt(1000));
|
| | | m_i_nampespace = root["namespace"].ToString("");
|
| | | m_file_name_out = root["file_name_out"].ToString("C:\\Test.mqh");
|
| | | m_table_prefix = root["table_prefix"].ToString("g_table");
|
| | | m_copyright = root["copyright"].ToString("MyName");
|
| | | m_link = root["link"].ToString("my_org.com");
|
| | | m_func_name = root["func_name"].ToString("Hash");
|
2026-06-28 16:04:15 -05:00 | | | m_bucket_size_def_name = root["def_bucket_size_name"].ToString("TABLE_SIZE_BUCKETS");
|
2026-06-27 21:28:54 -05:00 | | | m_use_map_value = root["map_use_value"].ToBool(false);
|
2026-06-28 17:05:25 -05:00 | | | m_final_table_size_def_name = root["def_name_table_size"].ToString("TABLE_SIZE_FINAL");
|
2026-06-27 21:28:54 -05:00 | | | m_invalid_value = root["invalid_value"].ToString("NULL");
|
2026-06-28 17:05:25 -05:00 | | | m_comment_func = root["comment_funct"].ToBool(false);
|
2026-06-29 07:41:51 -05:00 | | | m_guard = root["guard_name"].ToString("");
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //--- Hash
|
| | | CYmlNode hash = root["hash"];
|
2026-06-26 22:13:05 -05:00 | | | if(!hash.IsObject())
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError("Key 'hash' does not exist or is not an object", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00 | | | return false;
|
| | | }
|
2026-06-28 17:05:25 -05:00 | | | if(CEnumRegSimpH::GetValNoRef<ENUM_TSN_PHASH_TYPE>(hash["type"].ToString(""), TSN_PHASH_TYPE_FNV1A_64) == TSN_PHASH_TYPE_FNV1A_64)
|
2026-06-26 12:44:41 -05:00 | | | {
|
| | | m_hash = new CHashFnv1A64();
|
| | | }
|
| | | else
|
| | | {
|
| | | m_hash = new CHashXXHash();
|
| | | }
|
2026-06-26 22:13:05 -05:00 | | | if(!m_hash.Init(hash["config"]))
|
2026-06-26 12:44:41 -05:00 | | | return false;
|
| | |
|
2026-06-27 21:28:54 -05:00 | | | //--- Hash final
|
2026-07-28 11:19:10 -05:00 | | | switch(CEnumRegSimpH::GetValNoRef<ENUM_HASH_UL1_TYPE>(root["final_hash"].ToString(""), HASH_UL1_SPLITMIX))
|
| | | {
|
| | | case HASH_UL1_MUR_MUR:
|
| | | m_hash_pf_1 = new CHash1MurMur();
|
| | | break;
|
| | | case HASH_UL1_SPLITMIX:
|
| | | m_hash_pf_1 = new CHash1SplitMix();
|
| | | break;
|
| | | case HASH_UL1_FMIX:
|
| | | m_hash_pf_1 = new CHash1Fmix();
|
| | | break;
|
| | | case HASH_UL1_FIBBO:
|
| | | m_hash_pf_1 = new CHash1Fibbo();
|
| | | break;
|
| | | default:
|
| | | m_hash_pf_1 = new CHash1SplitMix();
|
| | | break;
|
2026-06-27 21:28:54 -05:00 | | | }
|
2026-07-27 15:07:46 -05:00 | | | CSimPHashHaserUl1::m_hasher = m_hash_pf_1; // Seteamos en estatico
|
2026-06-27 09:55:10 -05:00 | | |
|
2026-06-26 12:44:41 -05:00 | | | //--- Mapa
|
| | | CYmlNode map = root["map"];
|
2026-06-27 09:02:27 -05:00 | | | if((map.GetFlag()&TSN_YAML_VTYPE_ARR_F | TSN_YAML_VTYPE_OBJ_F) == 0)
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError("Field 'map' not found in yaml, or it is not an object or array", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00 | | | return false;
|
| | | }
|
| | | m_table_size = map.Size();
|
| | | if(m_table_size < 1)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError("Map has fewer than one element", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00 | | | return false;
|
| | | }
|
| | |
|
2026-06-27 21:28:54 -05:00 | | | //--- Resize de (keys, hashes, poses)
|
2026-06-26 12:44:41 -05:00 | | | ArrayResize(m_keys, m_table_size);
|
2026-06-27 21:28:54 -05:00 | | | ArrayResize(m_prev_hashes, m_table_size);
|
2026-06-26 22:13:05 -05:00 | | | ArrayResize(m_pos, m_table_size);
|
2026-06-26 12:44:41 -05:00 | | | int k = 0;
|
| | |
|
| | | //---
|
2026-06-27 09:02:27 -05:00 | | | if(map.IsObject())
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | // clave:valor
|
2026-06-27 09:02:27 -05:00 | | | CYmlIteratorObj it = map.BeginObj();
|
2026-06-27 09:55:10 -05:00 | | | if(m_use_map_value)
|
2026-06-27 09:02:27 -05:00 | | | {
|
2026-09-06 15:54:03 -05:00 | | | LogInfo("Using map values as values", FUNCION_ACTUAL);
|
2026-06-27 21:28:54 -05:00 | | |
|
2026-06-27 09:55:10 -05:00 | | | //---
|
| | | while(it.IsValid())
|
| | | {
|
| | | m_keys[k] = it.Key();
|
2026-06-28 07:50:05 -05:00 | | | m_prev_hashes[k] = m_hash.Hash(m_keys[k]);
|
2026-06-27 09:55:10 -05:00 | | | m_pos[k] = k; // Orden...
|
| | | k++;
|
| | | it.Next();
|
| | | }
|
| | | }
|
| | | else
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogInfo("Using map values as indices", FUNCION_ACTUAL);
|
2026-06-27 21:28:54 -05:00 | | | // No usamos solo indices.. (intermdio...)
|
2026-06-27 09:55:10 -05:00 | | | while(it.IsValid())
|
| | | {
|
| | | m_keys[k] = it.Key();
|
2026-06-28 07:50:05 -05:00 | | | m_prev_hashes[k] = m_hash.Hash(m_keys[k]);
|
2026-06-27 09:55:10 -05:00 | | | m_pos[k] = int(it.Val().ToInt(0));
|
| | | k++;
|
| | | it.Next();
|
| | | }
|
2026-06-27 09:02:27 -05:00 | | | }
|
| | | }
|
| | | else
|
| | | {
|
2026-06-27 09:55:10 -05:00 | | | if(m_use_map_value)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogError("Cannot use map value on an array, index is inferred..", FUNCION_ACTUAL);
|
2026-06-27 09:55:10 -05:00 | | | return false;
|
| | | }
|
| | |
|
| | | // (clave) (y el indice al que apunta es su posicion en dicho array..)
|
2026-06-27 09:02:27 -05:00 | | | CYmlIteratorArray it = map.BeginArr();
|
| | | while(it.IsValid())
|
| | | {
|
| | | m_keys[k] = it.Val().ToString();
|
2026-06-28 07:50:05 -05:00 | | | m_prev_hashes[k] = m_hash.Hash(m_keys[k]);
|
2026-06-27 09:02:27 -05:00 | | | m_pos[k] = k;
|
| | | k++;
|
| | | it.Next();
|
| | | }
|
2026-06-26 12:44:41 -05:00 | | | }
|
| | |
|
| | | //---
|
2026-06-28 12:17:22 -05:00 | | | // ArrayInitialize(m_out_seeds, 0); ya lo hace
|
2026-06-27 21:28:54 -05:00 | | | // Seed ya se rellena..
|
| | |
|
| | | //--- Perfect hash
|
| | | // Iniciamos el algoritmo..
|
2026-06-28 12:17:22 -05:00 | | | m_perfect_hash.MaxValSeed(m_i_max_attemps);
|
| | | CYmlNode perfect_hash = root["perfect_hash"];
|
| | | m_perfect_hash.InitAlg(m_table_size, perfect_hash["load_factor"].ToDouble(0.80),
|
| | | int(perfect_hash["elements_por_bucket"].ToInt(6)));
|
| | |
|
| | | // Inicialziacion previa de sloots
|
| | | ArrayResize(m_out_slots, m_perfect_hash.m_final_table_size);
|
| | | ArrayInitialize(m_out_slots, -1); // Invalid indices
|
2026-06-28 19:12:45 -05:00 | | | ArrayResize(m_hashes, m_perfect_hash.m_final_table_size);
|
| | | ArrayInitialize(m_hashes, 0ULL); // Invalid hashes
|
2026-06-26 22:13:05 -05:00 | | |
|
| | | //---
|
2026-09-06 15:54:03 -05:00 | | | LogInfo(StringFormat("Perfect hash initialized\nMax attempts per bucket = %d, Table size = %d",
|
2026-06-26 22:13:05 -05:00 | | | m_i_max_attemps, m_table_size), FUNCION_ACTUAL);
|
2026-09-06 15:54:03 -05:00 | | | LogInfo(StringFormat("Number of buckets = %d | Final table size = %d",
|
2026-06-28 17:05:25 -05:00 | | | m_perfect_hash.m_buckets_size, m_perfect_hash.m_final_table_size), FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00 | | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #define PHASH_CODE_ADD_FBLOCK(data) \
|
| | | data += "//+------------------------------------------------------------------+\r\n" + \
|
| | | "//| |\r\n" + \
|
| | | "//+------------------------------------------------------------------+\r\n";
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CPerfectHashGenerator::Save(void)
|
| | | {
|
| | | //--- Header
|
2026-06-27 12:37:19 -05:00 | | | string data = "//+-------------------------------------------------------------------+\r\n" +
|
2026-09-06 15:54:03 -05:00 | | | "//| Include generated by the PerfectHash SimPHash tool |\r\n" +
|
| | | "//| This tool is part of the TSN ecosystem |\r\n" +
|
| | | "//| Repository: https://forge.mql5.io/nique_372/SimPHash |\r\n" +
|
2026-06-27 13:07:56 -05:00 | | | "//+-------------------------------------------------------------------+\r\n" +
|
| | | StringFormat("#property copyright \"%s\"\r\n", m_copyright) +
|
| | | StringFormat("#property link \"%s\"\r\n", m_link) +
|
| | | "#property strict\r\n" + "\r\n";
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-06-28 16:04:15 -05:00 | | | // ....
|
| | | data += "\r\n";
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //--- Includes
|
| | | PHASH_CODE_ADD_FBLOCK(data)
|
| | | m_hash.AddIncludes(data);
|
2026-06-27 21:28:54 -05:00 | | | m_hash_pf_1.AddIncludes(data);
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-06-29 07:41:51 -05:00 | | |
|
| | | //---
|
| | | if(m_guard.Length())
|
| | | {
|
| | | data += "#ifndef " + m_guard + "\r\n";
|
| | | data += "#define " + m_guard + "\r\n";
|
| | | data += "\r\n";
|
| | | }
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //--- Defines
|
2026-06-27 21:28:54 -05:00 | | | // Definimos el tamaño del conjunto de datos de entrada in
|
2026-07-28 22:02:48 -05:00 | | | const string def_name_tsize_last = m_final_table_size_def_name + "_LAST";
|
| | | const string def_name_bsize_last = m_bucket_size_def_name + "_LAST";
|
| | |
|
| | | //----
|
2026-06-26 12:44:41 -05:00 | | | PHASH_CODE_ADD_FBLOCK(data)
|
2026-06-28 12:17:22 -05:00 | | | data += "#define " + m_final_table_size_def_name + " (" + string(m_perfect_hash.m_final_table_size) + "ULL)\r\n";
|
2026-07-28 22:02:48 -05:00 | | | data += "#define " + def_name_tsize_last + " (" + string(m_perfect_hash.m_final_table_size_last) + "ULL)\r\n";
|
2026-06-28 17:05:25 -05:00 | | | data += "#define " + m_bucket_size_def_name + " (" + string(m_perfect_hash.m_buckets_size) + "ULL)\r\n";
|
2026-07-28 22:02:48 -05:00 | | | data += "#define " + def_name_bsize_last + " (" + string(m_perfect_hash.m_buckets_size_last) + "ULL)\r\n";
|
2026-06-26 12:44:41 -05:00 | | | data += "\r\n";
|
| | |
|
| | | //--- Bloque de codiho
|
| | | PHASH_CODE_ADD_FBLOCK(data)
|
| | |
|
| | | //--- Namepsace
|
| | | const bool is_n = m_i_nampespace != "";
|
| | | if(is_n)
|
| | | data += StringFormat("namespace %s\r\n{\r\n", m_i_nampespace);
|
| | |
|
2026-06-27 21:28:54 -05:00 | | | //--- Seeds table
|
| | | const string table_seeds_name = m_table_prefix + "_seeds";
|
2026-06-28 16:04:15 -05:00 | | | data += "const ulong " + table_seeds_name + "[" + m_bucket_size_def_name + "] = \r\n";
|
2026-06-27 21:28:54 -05:00 | | | data += "{\r\n";
|
2026-06-28 12:17:22 -05:00 | | | const int _last = m_perfect_hash.m_buckets_size - 1;
|
2026-06-27 21:28:54 -05:00 | | | for(int i = 0; i < _last; i++)
|
| | | {
|
| | | data += string(m_out_seeds[i]) + "ULL,\r\n";
|
| | | }
|
2026-06-28 07:50:05 -05:00 | | | data += string(m_out_seeds[_last]) + "ULL\r\n";
|
2026-06-27 21:28:54 -05:00 | | | data += "};\r\n";
|
| | | data += "\r\n";
|
| | |
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //--- Hashtable
|
| | | const string table_hash_name = m_table_prefix + "_hashes";
|
2026-06-28 12:17:22 -05:00 | | | data += "const ulong " + table_hash_name + "[" + m_final_table_size_def_name + "] = \r\n";
|
2026-06-26 12:44:41 -05:00 | | | data += "{\r\n";
|
2026-06-27 21:28:54 -05:00 | | | const int _last_ = m_perfect_hash.m_final_table_size - 1;
|
| | | for(int i = 0; i < _last_; i++)
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-06-28 12:17:22 -05:00 | | | data += string(m_hashes[i]) + "ULL," + (m_out_slots[i] == -1 ? (" // invalid") : (" // " + m_keys[m_out_slots[i]])) + "\r\n";
|
2026-06-26 12:44:41 -05:00 | | | }
|
2026-06-27 21:28:54 -05:00 | | | data += string(m_hashes[_last_]) + "ULL\r\n";
|
2026-06-26 12:44:41 -05:00 | | | data += "};\r\n";
|
| | | data += "\r\n";
|
| | |
|
2026-06-27 09:55:10 -05:00 | | | //--- General
|
2026-06-26 12:44:41 -05:00 | | | const string table_slots_name = m_table_prefix + "_tindex";
|
2026-06-27 09:55:10 -05:00 | | | CYmlNode map = m_yml.GetRoot()["map"];
|
| | | const string type_str_v = map.AtObj(0).TypeToMqlStr();
|
| | | const string table_values_nmae = m_table_prefix + "_values";
|
| | |
|
| | | //---
|
| | | if(m_use_map_value) // Talba de valores
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-06-27 09:55:10 -05:00 | | | data += StringFormat("const %s %s[%s] = \r\n", type_str_v, table_values_nmae
|
2026-06-27 21:28:54 -05:00 | | | , m_final_table_size_def_name);
|
2026-06-27 09:55:10 -05:00 | | | data += "{\r\n";
|
| | |
|
| | | //---
|
2026-06-27 21:28:54 -05:00 | | | const int last = m_perfect_hash.m_final_table_size - 1;
|
| | | for(int i = 0; i < last; i++)
|
2026-06-27 09:55:10 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | const int ri = m_out_slots[i]; // ri apunta al valor en si y key
|
| | | if(ri == -1)
|
| | | data += m_invalid_value + ",\r\n";
|
| | | else
|
| | | data += map.AtObj(ri).ToString() + ", // " + m_keys[ri] + "\r\n";
|
2026-06-27 09:55:10 -05:00 | | | }
|
| | |
|
| | | //---
|
2026-06-27 21:28:54 -05:00 | | | const int ri = m_out_slots[last];
|
2026-06-28 12:17:22 -05:00 | | | if(ri != -1)
|
| | | data += string(map.AtObj(ri).ToString()) + " // " + m_keys[ri] + "\r\n";
|
| | | else
|
| | | data += m_invalid_value + "\r\n";
|
| | |
|
| | | //---
|
2026-06-27 09:55:10 -05:00 | | | data += "};\r\n";
|
2026-06-26 12:44:41 -05:00 | | | }
|
2026-06-27 09:55:10 -05:00 | | | else // Tabla de indices..
|
| | | {
|
2026-06-27 21:28:54 -05:00 | | | data += "const int " + table_slots_name + "[" + m_final_table_size_def_name + "] = \r\n";
|
2026-06-27 09:55:10 -05:00 | | | data += "{\r\n";
|
2026-06-27 21:28:54 -05:00 | | | const int last = m_perfect_hash.m_final_table_size - 1;
|
| | | for(int i = 0; i < last; i++)
|
2026-06-27 09:55:10 -05:00 | | | {
|
2026-06-27 13:07:56 -05:00 | | | const int ri = m_out_slots[i];
|
2026-06-28 12:17:22 -05:00 | | | if(ri == -1)
|
| | | data += "-1, \r\n";
|
| | | else
|
| | | data += string(ri) + ", // " + m_keys[ri] + "\r\n";
|
2026-06-27 09:55:10 -05:00 | | | }
|
2026-06-28 12:17:22 -05:00 | | |
|
| | | //---
|
2026-06-27 21:28:54 -05:00 | | | const int ri = m_out_slots[last];
|
2026-06-28 12:17:22 -05:00 | | | if(ri == -1)
|
| | | data += string(ri) + " // " + m_keys[ri] + "\r\n";
|
| | | else
|
| | | data += "-1\r\n";
|
| | |
|
| | | //---
|
2026-06-27 09:55:10 -05:00 | | | data += "};\r\n";
|
| | | }
|
| | |
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //---
|
| | | data += "\r\n";
|
2026-06-28 17:05:25 -05:00 | | | if(m_comment_func)
|
| | | data += "/*\r\n";
|
2026-06-27 09:55:10 -05:00 | | |
|
2026-07-02 16:05:19 -05:00 | | | ////////////// Funcion
|
2026-06-28 17:05:25 -05:00 | | | //---
|
2026-06-27 09:55:10 -05:00 | | | if(m_use_map_value) // Valor directo..
|
| | | {
|
| | | // Obtenemos el tipo del primer valoor
|
| | | data += StringFormat("%s %s(const string& key)\r\n", type_str_v, m_func_name);
|
| | | }
|
| | | else
|
| | | {
|
| | | data += "<return-type> " + m_func_name + "(const string& key)\r\n";
|
| | | }
|
2026-06-26 12:44:41 -05:00 | | | data += "{\r\n";
|
| | |
|
| | | //--- Hash listo
|
| | | m_hash.BuildString(data);
|
| | |
|
2026-06-27 21:28:54 -05:00 | | | //--- Paso intermedio
|
2026-07-28 22:02:48 -05:00 | | | data += StringFormat(" const int seed_index = int(key_hash & %s);\r\n", def_name_bsize_last);
|
2026-06-27 21:28:54 -05:00 | | |
|
2026-06-26 12:44:41 -05:00 | | | //--- Algoritmo
|
2026-06-27 21:28:54 -05:00 | | | m_hash_pf_1.BuildString(data, table_seeds_name);
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-06-27 21:28:54 -05:00 | | | //---
|
2026-07-28 22:02:48 -05:00 | | | data += StringFormat(" const int fi = int(h & %s);\r\n", def_name_tsize_last);
|
2026-06-27 09:55:10 -05:00 | | |
|
2026-06-27 21:28:54 -05:00 | | | //---
|
2026-06-27 09:55:10 -05:00 | | | if(m_use_map_value) // Valor directo.. (no pasa por indice)
|
| | | {
|
2026-06-27 21:28:54 -05:00 | | | data += StringFormat(" return %s[fi] == key_hash ? %s[fi] : %s;\r\n",
|
| | | table_hash_name, table_values_nmae, m_invalid_value);
|
2026-06-27 09:55:10 -05:00 | | | }
|
| | | else
|
| | | {
|
| | | // Pasa por indice.. aqui dejamos que el usuario rellene
|
2026-06-27 21:28:54 -05:00 | | | data += StringFormat(" return %s[fi] == key_hash ? <your table>[%s[fi]] : <return in case fail>;\r\n",
|
2026-06-27 09:55:10 -05:00 | | | table_hash_name, table_slots_name);
|
| | | }
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-06-27 09:02:27 -05:00 | | | //--- Cerramos.. funcion
|
| | | data += "}\r\n";
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-07-02 16:05:19 -05:00 | | | ////////////// Parte dos
|
| | | data += "\r\n";
|
| | |
|
| | | //---
|
| | | if(m_use_map_value) // Valor directo..
|
| | | {
|
| | | // Obtenemos el tipo del primer valoor
|
| | | data += StringFormat("%s %s(const ulong key_hash)\r\n", type_str_v, m_func_name);
|
| | | }
|
| | | else
|
| | | {
|
| | | data += "<return-type> " + m_func_name + "(const ulong key_hash)\r\n";
|
| | | }
|
| | | data += "{\r\n";
|
| | |
|
| | | //--- Paso intermedio
|
2026-07-28 22:02:48 -05:00 | | | data += StringFormat(" const int seed_index = int(key_hash & %s);\r\n", def_name_bsize_last);
|
2026-07-02 16:05:19 -05:00 | | |
|
| | | //--- Algoritmo
|
| | | m_hash_pf_1.BuildString(data, table_seeds_name);
|
| | |
|
| | | //---
|
2026-07-28 22:02:48 -05:00 | | | data += StringFormat(" const int fi = int(h & %s);\r\n", def_name_tsize_last);
|
2026-07-02 16:05:19 -05:00 | | |
|
| | | //---
|
| | | if(m_use_map_value) // Valor directo.. (no pasa por indice)
|
| | | {
|
| | | data += StringFormat(" return %s[fi] == key_hash ? %s[fi] : %s;\r\n",
|
| | | table_hash_name, table_values_nmae, m_invalid_value);
|
| | | }
|
| | | else
|
| | | {
|
| | | // Pasa por indice.. aqui dejamos que el usuario rellene
|
| | | data += StringFormat(" return %s[fi] == key_hash ? <your table>[%s[fi]] : <return in case fail>;\r\n",
|
| | | table_hash_name, table_slots_name);
|
| | | }
|
| | |
|
| | | //--- Cerramos.. funcion
|
| | | data += "}\r\n";
|
| | |
|
| | |
|
| | |
|
| | | //////////////
|
2026-06-28 17:05:25 -05:00 | | | // ---
|
| | | if(m_comment_func)
|
| | | data += "*/\r\n";
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //---
|
| | | if(is_n) // Cierre del namespace
|
2026-06-27 12:37:19 -05:00 | | | data += "}\r\n";
|
2026-06-26 12:44:41 -05:00 | | |
|
2026-06-29 07:41:51 -05:00 | | | //---
|
| | | if(m_guard.Length())
|
| | | data += "#endif // " + m_guard + "\r\n";
|
| | |
|
2026-09-06 09:01:53 -05:00 | | |
|
2026-06-26 12:44:41 -05:00 | | | //---
|
| | | uchar buff[];
|
| | | int l = StringToCharArray(data, buff, 0, StringLen(data));
|
| | |
|
2026-09-06 09:01:53 -05:00 | | | //---
|
| | | #ifdef SIMPHASH_ENABLE_DLL
|
| | | HANDLE handle = kernel32::CreateFileW(m_file_name_out, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err in kernel32 = %d",
|
2026-09-06 09:01:53 -05:00 | | | m_file_name_out, kernel32::GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //---
|
| | | uint writen = 0;
|
| | | kernel32::WriteFile(handle, buff, sizeof(uchar) * l, writen, NULL);
|
| | | kernel32::CloseHandle(handle);
|
| | |
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | |
|
| | | //::ResetLastError();
|
| | | if(!FileSave(m_file_name_out, buff, (m_comon_flag ? FILE_COMMON : 0)))
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to save file = %s, last err = %d",
|
2026-09-06 09:01:53 -05:00 | | | m_file_name_out, ::GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | |
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 12:37:19 -05:00 | | | //---
|
2026-09-06 15:54:03 -05:00 | | | LogInfo(StringFormat("Perfect hash built successfully, check the file:\n%s",
|
2026-06-27 12:37:19 -05:00 | | | m_file_name_out), FUNCION_ACTUAL);
|
| | |
|
2026-06-27 11:10:24 -05:00 | | | //---
|
| | | CYmlNode bin = m_yml.GetRoot()["bin"];
|
| | | if(bin.IsObject())
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogInfo("Saving extra info", FUNCION_ACTUAL);
|
2026-06-27 11:10:24 -05:00 | | | if(!SaveBin(bin))
|
| | | return false;
|
| | | }
|
2026-06-27 12:37:19 -05:00 | | | else
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCaution("Extra info is not being saved", FUNCION_ACTUAL);
|
2026-06-27 12:37:19 -05:00 | | | }
|
2026-06-26 22:14:07 -05:00 | | |
|
2026-06-26 12:44:41 -05:00 | | | //---
|
| | | return true;
|
| | | }
|
| | |
|
2026-06-27 11:10:24 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CPerfectHashGenerator::SaveBin(CYmlNode& bin)
|
| | | {
|
| | | //---
|
| | | uint writen = 0;
|
2026-06-27 21:28:54 -05:00 | | | const int tsize = m_perfect_hash.m_final_table_size;
|
2026-06-28 12:17:22 -05:00 | | | const int bsize = m_perfect_hash.m_buckets_size;
|
2026-06-27 11:10:24 -05:00 | | |
|
| | | //--- Keys..
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 21:28:54 -05:00 | | | HANDLE handle = kernel32::CreateFileW(bin["seeds"].ToString(""), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
2026-06-27 11:10:24 -05:00 | | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err in kernel32 = %d",
|
2026-06-27 21:28:54 -05:00 | | | bin["seeds"].ToString(""), kernel32::GetLastError()), FUNCION_ACTUAL);
|
2026-06-27 11:10:24 -05:00 | | | return false;
|
| | | }
|
2026-06-28 12:17:22 -05:00 | | | kernel32::WriteFile(handle, m_out_seeds, sizeof(ulong) * bsize, writen, NULL);
|
2026-06-27 21:28:54 -05:00 | | | kernel32::CloseHandle(handle);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | //::ResetLastError();
|
| | | if(!FileSave(bin["seeds"].ToString(""), m_out_seeds, (m_comon_flag ? FILE_COMMON : 0)))
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to save 'seeds' to file = %s, last err = %d",
|
2026-09-06 09:01:53 -05:00 | | | bin["seeds"].ToString(""), ::GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
| | |
|
2026-06-27 21:28:54 -05:00 | | |
|
| | | //--- Hash..
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 21:28:54 -05:00 | | | handle = kernel32::CreateFileW(bin["hash"].ToString(""), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err in kernel32 = %d",
|
2026-06-27 21:28:54 -05:00 | | | bin["hash"].ToString(""), kernel32::GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | | kernel32::WriteFile(handle, m_hashes, sizeof(ulong) * tsize, writen, NULL);
|
2026-06-27 11:10:24 -05:00 | | | kernel32::CloseHandle(handle);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | if(!FileSave(bin["hash"].ToString(""), m_hashes, (m_comon_flag ? FILE_COMMON : 0)))
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to save 'hash' to file = %s, last err = %d",
|
2026-09-06 09:01:53 -05:00 | | | bin["hash"].ToString(""), ::GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | |
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 11:10:24 -05:00 | | |
|
| | | //--- Valores
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 21:28:54 -05:00 | | | handle = kernel32::CreateFileW(bin["values"].ToString(""), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
2026-06-27 11:10:24 -05:00 | | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err in kernel32 = %d",
|
2026-06-27 21:28:54 -05:00 | | | bin["values"].ToString(""), kernel32::GetLastError()), FUNCION_ACTUAL);
|
2026-06-27 11:10:24 -05:00 | | | return false;
|
| | | }
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | int handle = FileOpen(bin["values"].ToString(""), FILE_BIN | FILE_WRITE | (m_comon_flag ? FILE_COMMON : 0));
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err = %d",
|
2026-09-06 09:01:53 -05:00 | | | bin["values"].ToString(""), GetLastError()), FUNCION_ACTUAL);
|
| | |
|
| | | return false;
|
| | | }
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 11:10:24 -05:00 | | |
|
| | | //---
|
2026-06-27 12:37:19 -05:00 | | | if(m_use_map_value)
|
2026-06-27 11:10:24 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | CYmlNode root = m_yml.GetRoot();
|
| | | CYmlNode map = root["map"];
|
2026-06-27 12:37:19 -05:00 | | | const int type = map.AtObj(0).GetType();
|
| | | switch(type)
|
2026-06-27 11:10:24 -05:00 | | | {
|
2026-06-27 12:37:19 -05:00 | | | case TSN_YAML_VTYPE_INTEGER:
|
2026-06-27 11:10:24 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | const long in_v = root["invalid_value"].ToInt(-1);
|
| | | for(int i = 0; i < tsize; i++)
|
2026-06-27 12:37:19 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | const int k = m_out_slots[i];
|
| | | long v = k == -1 ? in_v : map.AtObj(k).ToInt(0);
|
2026-09-06 09:01:53 -05:00 | | |
|
| | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 12:37:19 -05:00 | | | kernel32::WriteFile(handle, v, sizeof(long), writen, NULL);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | FileWriteLong(handle, v);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 12:37:19 -05:00 | | | }
|
| | | break;
|
2026-06-27 11:10:24 -05:00 | | | }
|
2026-06-27 12:37:19 -05:00 | | | case TSN_YAML_VTYPE_REAL:
|
2026-06-27 11:10:24 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | const double in_v = root["invalid_value"].ToDouble(0.00);
|
2026-06-27 12:37:19 -05:00 | | | for(int i = 0; i < m_table_size; i++)
|
| | | {
|
2026-06-27 21:28:54 -05:00 | | | const int k = m_out_slots[i];
|
| | | double v = k == -1 ? in_v : map.AtObj(k).ToDouble(0.00);
|
2026-09-06 09:01:53 -05:00 | | |
|
| | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 12:37:19 -05:00 | | | kernel32::WriteFile(handle, v, sizeof(double), writen, NULL);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | FileWriteDouble(handle, v);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
2026-06-27 12:37:19 -05:00 | | | }
|
| | | break;
|
2026-06-27 11:10:24 -05:00 | | | }
|
2026-06-27 12:37:19 -05:00 | | | case TSN_YAML_VTYPE_BOOL:
|
2026-06-27 11:10:24 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | const bool in_v = root["invalid_value"].ToBool(false);
|
| | | for(int i = 0; i < tsize; i++)
|
2026-06-27 12:37:19 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | const int k = m_out_slots[i];
|
| | | bool v = k == -1 ? in_v : map.AtObj(k).ToBool(false);
|
2026-09-06 09:01:53 -05:00 | | |
|
| | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 12:37:19 -05:00 | | | kernel32::WriteFile(handle, v, sizeof(bool), writen, NULL);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | FileWriteInteger(handle, v, CHAR_VALUE);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
2026-06-27 12:37:19 -05:00 | | | }
|
| | | break;
|
2026-06-27 11:10:24 -05:00 | | | }
|
2026-07-28 11:19:10 -05:00 | | | case TSN_YAML_VTYPE_STRING:
|
| | | case TSN_YAML_VTYPE_USTRING:
|
| | | case TSN_YAML_VTYPE_STR_MULTILINE:
|
| | | {
|
| | | // [len][string][len][string]
|
| | | //---
|
| | | uchar in_v[];
|
| | | const int in_v_l = root["invalid_value"].ToStringUArray(in_v);
|
2026-09-06 09:01:53 -05:00 | | | uchar data[];
|
2026-07-28 11:19:10 -05:00 | | |
|
| | | //---
|
| | | for(int i = 0; i < tsize; i++)
|
| | | {
|
| | | const int k = m_out_slots[i];
|
| | | if(k == -1)
|
| | | {
|
| | | // Invalido relleanmos con defualt..
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-07-28 11:19:10 -05:00 | | | kernel32::WriteFile(handle, in_v_l, sizeof(int), writen, NULL);
|
| | | kernel32::WriteFile(handle, in_v, sizeof(uchar) * in_v_l, writen, NULL);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | FileWriteInteger(handle, in_v_l);
|
| | | FileWriteArray(handle, in_v, 0, in_v_l);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-07-28 11:19:10 -05:00 | | | }
|
| | | else
|
| | | {
|
| | | // Valido
|
| | | const int l = map.AtObj(m_out_slots[i]).ToStringUArray(data);
|
2026-09-06 09:01:53 -05:00 | | |
|
| | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-07-28 11:19:10 -05:00 | | | kernel32::WriteFile(handle, l, sizeof(int), writen, NULL);
|
| | | kernel32::WriteFile(handle, data, sizeof(uchar) * l, writen, NULL);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | FileWriteInteger(handle, l);
|
| | | FileWriteArray(handle, data, 0, l);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-07-28 11:19:10 -05:00 | | | }
|
| | | }
|
| | | break;
|
| | | }
|
2026-06-27 11:10:24 -05:00 | | | }
|
| | | }
|
2026-06-27 12:37:19 -05:00 | | | else
|
| | | {
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-28 07:50:05 -05:00 | | | kernel32::WriteFile(handle, m_out_slots, sizeof(int) * tsize, writen, NULL);
|
2026-09-06 09:01:53 -05:00 | | | #else
|
| | | FileWriteArray(handle, m_out_slots, 0, tsize);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 12:37:19 -05:00 | | | }
|
| | |
|
| | | //---
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 11:10:24 -05:00 | | | kernel32::CloseHandle(handle);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | FileClose(handle);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 11:10:24 -05:00 | | |
|
| | | //--- Meta
|
2026-09-06 09:01:53 -05:00 | | | #ifdef SIMPHASH_ENABLE_DLL
|
2026-06-27 21:28:54 -05:00 | | | handle = kernel32::CreateFileW(bin["meta"].ToString(""), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
2026-06-27 11:10:24 -05:00 | | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err in kernel32 = %d",
|
2026-06-27 21:28:54 -05:00 | | | bin["meta"].ToString(""), kernel32::GetLastError()), FUNCION_ACTUAL);
|
2026-06-27 11:10:24 -05:00 | | | return false;
|
| | | }
|
2026-06-28 12:17:22 -05:00 | | | kernel32::WriteFile(handle, bsize, sizeof(int), writen, NULL); // buckets size
|
2026-06-27 21:28:54 -05:00 | | | kernel32::WriteFile(handle, tsize, sizeof(int), writen, NULL); // final table size
|
2026-06-27 11:10:24 -05:00 | | | kernel32::CloseHandle(handle);
|
2026-09-06 09:01:53 -05:00 | | | #else // SIMPHASH_ENABLE_DLL
|
| | | handle = FileOpen(bin["meta"].ToString(""), FILE_BIN | FILE_WRITE | (m_comon_flag ? FILE_COMMON : 0));
|
| | | if(handle == INVALID_HANDLE)
|
| | | {
|
2026-09-06 15:54:03 -05:00 | | | LogCriticalError(StringFormat("Failed to create file:\n'%s'\nLast err = %d",
|
2026-09-06 09:01:53 -05:00 | | | bin["meta"].ToString(""), GetLastError()), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | | FileWriteInteger(handle, bsize);
|
| | | FileWriteInteger(handle, tsize);
|
| | | FileClose(handle);
|
| | | #endif // SIMPHASH_ENABLE_DLL
|
| | |
|
2026-06-27 11:10:24 -05:00 | | |
|
| | | //---
|
| | | return true;
|
| | | }
|
| | |
|
2026-06-26 12:44:41 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CPerfectHashGenerator::RunAlg(void)
|
| | | {
|
2026-06-28 19:12:45 -05:00 | | | //---
|
| | | if(m_perfect_hash.RunWValue(m_prev_hashes, m_pos, m_out_seeds, m_out_slots, m_hashes))
|
2026-06-26 12:44:41 -05:00 | | | {
|
2026-06-27 21:28:54 -05:00 | | | return Save();
|
| | | }
|
2026-06-26 12:44:41 -05:00 | | |
|
| | | //---
|
2026-09-06 15:54:03 -05:00 | | | LogError("Could not generate the perfect hash", FUNCION_ACTUAL);
|
2026-06-27 21:28:54 -05:00 | | | return false;
|
| | | }
|
2026-06-26 12:44:41 -05:00 | | | }
|
| | | //+------------------------------------------------------------------+
|
2026-09-06 15:54:03 -05:00 | | | #endif // SIMPHASH_SRC_PERFECTHASH_MQH
|