2026-06-26 22:13:05 -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 "Random\\All.mqh"
|
|
|
|
|
#include "Hash\\All.mqh"
|
2026-06-27 11:10:24 -05:00
|
|
|
#include <TSN\\ExtraCodes\\WinApiExt.mqh>
|
2026-06-26 12:44:41 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
namespace TSN
|
|
|
|
|
{
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CPerfectHashGenerator : public CLoggerBase
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
//--- Parser config
|
|
|
|
|
CYamlParser m_yml;
|
2026-06-27 21:28:54 -05:00
|
|
|
CPerfectHashByLeo<ulong> m_perfect_hash;
|
2026-06-26 12:44:41 -05:00
|
|
|
|
|
|
|
|
//---
|
2026-06-27 21:28:54 -05:00
|
|
|
ulong m_i_max_attemps;
|
2026-06-26 12:44:41 -05:00
|
|
|
string m_i_nampespace;
|
|
|
|
|
string m_table_prefix;
|
2026-06-27 21:28:54 -05:00
|
|
|
IHashGenerator* m_hash; // str -> hash
|
|
|
|
|
IRandomGenerator* m_random; // random
|
|
|
|
|
IHashGeneratorWSeed* m_hash_pf_1;
|
2026-06-26 12:44:41 -05:00
|
|
|
string m_copyright;
|
|
|
|
|
string m_link;
|
|
|
|
|
string m_func_name;
|
|
|
|
|
string m_file_name_out;
|
2026-06-28 16:04:15 -05:00
|
|
|
string m_bucket_size_def_name;
|
2026-06-27 21:28:54 -05:00
|
|
|
string m_final_table_size_def_name;
|
2026-06-29 07:41:51 -05:00
|
|
|
string m_guard;
|
2026-06-27 21:28:54 -05:00
|
|
|
string m_invalid_value;
|
2026-06-28 17:05:25 -05:00
|
|
|
bool m_comment_func;
|
2026-06-29 07:41:51 -05:00
|
|
|
bool m_use_map_value;
|
2026-06-26 12:44:41 -05:00
|
|
|
|
|
|
|
|
//--- In
|
|
|
|
|
string m_keys[]; // Clave
|
|
|
|
|
int m_pos[]; // Index
|
|
|
|
|
ulong m_hashes[]; // Hashes
|
|
|
|
|
int m_table_size;
|
|
|
|
|
|
2026-06-27 21:28:54 -05:00
|
|
|
//---
|
|
|
|
|
ulong m_prev_hashes[];
|
|
|
|
|
|
2026-06-26 12:44:41 -05:00
|
|
|
//--- Out
|
2026-06-27 21:28:54 -05:00
|
|
|
ulong m_out_seeds[]; // Semillas
|
2026-06-26 12:44:41 -05:00
|
|
|
int m_out_slots[];
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
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-06-28 16:04:15 -05:00
|
|
|
bool Init(const string& file_name_yaml);
|
2026-06-26 12:44:41 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
bool RunAlg();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CPerfectHashGenerator::CPerfectHashGenerator()
|
|
|
|
|
: m_random(NULL), m_hash(NULL)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CPerfectHashGenerator::~CPerfectHashGenerator()
|
|
|
|
|
{
|
|
|
|
|
if(m_random != NULL)
|
|
|
|
|
delete m_random;
|
|
|
|
|
if(m_hash != NULL)
|
|
|
|
|
delete m_hash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-06-28 16:04:15 -05:00
|
|
|
bool CPerfectHashGenerator::Init(const string &file_name_yaml)
|
2026-06-26 12:44:41 -05:00
|
|
|
{
|
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)
|
|
|
|
|
{
|
|
|
|
|
LogError(StringFormat("Al abrir el archivo = %s, last err = %d",
|
|
|
|
|
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;
|
|
|
|
|
ArrayResize(m_yml.m_yml, m_yml.m_len);
|
|
|
|
|
kernel32::ReadFile(handle, m_yml.m_yml, (uint)Size, Read, 0);
|
|
|
|
|
kernel32::CloseHandle(handle);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if(Read < 5)
|
2026-06-26 12:44:41 -05:00
|
|
|
{
|
2026-06-28 16:04:15 -05:00
|
|
|
LogError("YAML vacio", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-29 09:02:53 -05:00
|
|
|
// Correcion del padding auto..
|
|
|
|
|
m_yml.CorrectPadding();
|
|
|
|
|
|
2026-06-26 12:44:41 -05:00
|
|
|
//---
|
2026-06-28 07:50:05 -05:00
|
|
|
LogInfo("Parseando YAML", FUNCION_ACTUAL);
|
2026-06-28 16:04:15 -05:00
|
|
|
if(!m_yml.Parse())
|
2026-06-26 12:44:41 -05:00
|
|
|
{
|
|
|
|
|
LogError("Fallo al parsear YAML, mensaje del parser: ", FUNCION_ACTUAL);
|
|
|
|
|
m_yml.ErrorInfo();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
return BuildInternal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CPerfectHashGenerator::BuildInternal(void)
|
|
|
|
|
{
|
2026-06-27 12:37:19 -05:00
|
|
|
//---
|
2026-06-29 07:41:51 -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
|
|
|
|
|
|
|
|
//--- Random
|
|
|
|
|
CYmlNode random = root["random"];
|
2026-06-26 22:13:05 -05:00
|
|
|
if(!random.IsObject())
|
2026-06-26 12:44:41 -05:00
|
|
|
{
|
|
|
|
|
LogError("Key 'random' no existe o no es un objeto", FUNCION_ACTUAL);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-06-28 17:05:25 -05:00
|
|
|
if(CEnumRegSimpH::GetValNoRef<ENUM_PHASH_RANDOM>(random["type"].ToString(""), PHASH_RANDOM_MATH_XOSHIRO256) == PHASH_RANDOM_MATH_XOSHIRO256)
|
2026-06-26 12:44:41 -05:00
|
|
|
{
|
|
|
|
|
m_random = new CRandomX256();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_random = new CRandomGeneratorMRand();
|
|
|
|
|
}
|
2026-06-26 22:13:05 -05:00
|
|
|
if(!m_random.Init(random["config"]))
|
2026-06-26 12:44:41 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//--- Hash
|
|
|
|
|
CYmlNode hash = root["hash"];
|
2026-06-26 22:13:05 -05:00
|
|
|
if(!hash.IsObject())
|
2026-06-26 12:44:41 -05:00
|
|
|
{
|
|
|
|
|
LogError("Key 'hash' no existe o no es un objeto", FUNCION_ACTUAL);
|
|
|
|
|
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-06-28 17:05:25 -05:00
|
|
|
if(CEnumRegSimpH::GetValNoRef<ENUM_HASH_UL1_TYPE>(root["final_hash"].ToString(""), HASH_UL1_SPLITMIX) == HASH_UL1_SPLITMIX)
|
2026-06-27 21:28:54 -05:00
|
|
|
{
|
2026-06-28 16:04:15 -05:00
|
|
|
m_hash_pf_1 = new CHash1SplitMix();
|
2026-06-27 21:28:54 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-06-28 16:04:15 -05:00
|
|
|
m_hash_pf_1 = new CHash1MurMur();
|
2026-06-27 21:28:54 -05:00
|
|
|
}
|
|
|
|
|
|
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-06-27 09:02:27 -05:00
|
|
|
LogError("No se encontro el campo 'map' en yaml o este no es un objeto o array", FUNCION_ACTUAL);
|
2026-06-26 12:44:41 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_table_size = map.Size();
|
|
|
|
|
if(m_table_size < 1)
|
|
|
|
|
{
|
|
|
|
|
LogError("Map tiene menos de un elemento", FUNCION_ACTUAL);
|
|
|
|
|
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-06-27 12:37:19 -05:00
|
|
|
LogInfo("Usando map values como valores", 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-06-27 12:37:19 -05:00
|
|
|
LogInfo("Usando map values como 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)
|
|
|
|
|
{
|
|
|
|
|
LogError("No se puede usar map value en un array, se infiere indice..", FUNCION_ACTUAL);
|
|
|
|
|
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 07:50:05 -05:00
|
|
|
m_perfect_hash.DeleteHashers(true);
|
2026-06-28 12:17:22 -05:00
|
|
|
m_perfect_hash.MaxValSeed(m_i_max_attemps);
|
2026-06-27 21:28:54 -05:00
|
|
|
m_perfect_hash.Hasher0(new CHashGeneratorBasis());
|
|
|
|
|
m_perfect_hash.Hasher1(m_hash_pf_1); // Dueño ojo..
|
2026-06-28 12:17:22 -05:00
|
|
|
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-06-28 17:05:25 -05:00
|
|
|
LogInfo(StringFormat("Perfect hash inicado\nNumero de intentos por bucket = %d, Tamaño de tabla = %d",
|
2026-06-26 22:13:05 -05:00
|
|
|
m_i_max_attemps, m_table_size), FUNCION_ACTUAL);
|
2026-06-28 17:05:25 -05:00
|
|
|
LogInfo(StringFormat("Numero de buckets = %d | Tamaño de la tabla final = %d",
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
HANDLE handle = kernel32::CreateFileW(m_file_name_out, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
|
|
|
|
if(handle == INVALID_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
LogCriticalError(StringFormat("Fallo al crear archivo:\n'%s'\nUltimo err in kernel32 = %d",
|
|
|
|
|
m_file_name_out, kernel32::GetLastError()), FUNCION_ACTUAL);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-28 16:04:15 -05:00
|
|
|
|
2026-06-26 12:44:41 -05:00
|
|
|
//--- Header
|
2026-06-27 12:37:19 -05:00
|
|
|
string data = "//+-------------------------------------------------------------------+\r\n" +
|
2026-06-28 16:04:15 -05:00
|
|
|
"//| Include generado por la herramienta PerfectHash SimPHash |\r\n" +
|
|
|
|
|
"//| Esta heramienta forma parte del ecositema TSN |\r\n" +
|
|
|
|
|
"//| Repositorio: 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-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-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-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-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-06-28 16:04:15 -05:00
|
|
|
data += StringFormat(" const int seed_index = int(key_hash %% %s);\r\n", m_bucket_size_def_name);
|
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-06-28 07:50:05 -05:00
|
|
|
data += StringFormat(" const int fi = int(h %% %s);\r\n", m_final_table_size_def_name);
|
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-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-06-26 12:44:41 -05:00
|
|
|
//---
|
|
|
|
|
uchar buff[];
|
|
|
|
|
int l = StringToCharArray(data, buff, 0, StringLen(data));
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
uint writen = 0;
|
|
|
|
|
kernel32::WriteFile(handle, buff, sizeof(uchar) * l, writen, NULL);
|
|
|
|
|
kernel32::CloseHandle(handle);
|
|
|
|
|
|
2026-06-27 12:37:19 -05:00
|
|
|
//---
|
|
|
|
|
LogInfo(StringFormat("Perfect hash contruido existosamente revise el archivo:\n%s",
|
|
|
|
|
m_file_name_out), FUNCION_ACTUAL);
|
|
|
|
|
|
2026-06-27 11:10:24 -05:00
|
|
|
//---
|
|
|
|
|
CYmlNode bin = m_yml.GetRoot()["bin"];
|
|
|
|
|
if(bin.IsObject())
|
|
|
|
|
{
|
2026-06-27 12:37:19 -05:00
|
|
|
LogInfo("Guardando info extra", FUNCION_ACTUAL);
|
2026-06-27 11:10:24 -05:00
|
|
|
if(!SaveBin(bin))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-06-27 12:37:19 -05:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LogCaution("No se esta guardando info extra", FUNCION_ACTUAL);
|
|
|
|
|
}
|
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-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)
|
|
|
|
|
{
|
|
|
|
|
LogCriticalError(StringFormat("Fallo al crear archivo:\n'%s'\nUltimo 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);
|
|
|
|
|
|
|
|
|
|
//--- Hash..
|
|
|
|
|
handle = kernel32::CreateFileW(bin["hash"].ToString(""), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
|
|
|
|
if(handle == INVALID_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
LogCriticalError(StringFormat("Fallo al crear archivo:\n'%s'\nUltimo err in kernel32 = %d",
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
//--- Valores
|
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)
|
|
|
|
|
{
|
|
|
|
|
LogCriticalError(StringFormat("Fallo al crear archivo:\n'%s'\nUltimo 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-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_STRING:
|
|
|
|
|
case TSN_YAML_VTYPE_USTRING:
|
|
|
|
|
case TSN_YAML_VTYPE_STR_MULTILINE:
|
2026-06-27 11:10:24 -05:00
|
|
|
{
|
2026-06-27 12:37:19 -05:00
|
|
|
// [len][string][len][string]
|
2026-06-27 21:28:54 -05:00
|
|
|
//---
|
|
|
|
|
uchar in_v[];
|
|
|
|
|
const int in_v_l = root["invalid_value"].ToStringUArray(in_v);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
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];
|
|
|
|
|
if(k == -1)
|
|
|
|
|
{
|
|
|
|
|
// Invalido relleanmos con defualt..
|
|
|
|
|
kernel32::WriteFile(handle, in_v_l, sizeof(int), writen, NULL);
|
|
|
|
|
kernel32::WriteFile(handle, in_v, sizeof(uchar) * in_v_l, writen, NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Valido
|
|
|
|
|
uchar data[];
|
|
|
|
|
const int l = map.AtObj(m_out_slots[i]).ToStringUArray(data);
|
|
|
|
|
kernel32::WriteFile(handle, l, sizeof(int), writen, NULL);
|
|
|
|
|
kernel32::WriteFile(handle, data, sizeof(uchar) * l, writen, NULL);
|
|
|
|
|
}
|
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_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-06-27 12:37:19 -05:00
|
|
|
kernel32::WriteFile(handle, v, sizeof(long), writen, NULL);
|
|
|
|
|
}
|
|
|
|
|
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-06-27 12:37:19 -05:00
|
|
|
kernel32::WriteFile(handle, v, sizeof(double), writen, NULL);
|
|
|
|
|
}
|
|
|
|
|
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-06-27 12:37:19 -05:00
|
|
|
kernel32::WriteFile(handle, v, sizeof(bool), writen, NULL);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2026-06-27 11:10:24 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-27 12:37:19 -05:00
|
|
|
else
|
|
|
|
|
{
|
2026-06-28 07:50:05 -05:00
|
|
|
kernel32::WriteFile(handle, m_out_slots, sizeof(int) * tsize, writen, NULL);
|
2026-06-27 12:37:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
2026-06-27 11:10:24 -05:00
|
|
|
kernel32::CloseHandle(handle);
|
|
|
|
|
|
|
|
|
|
//--- Meta
|
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)
|
|
|
|
|
{
|
|
|
|
|
LogCriticalError(StringFormat("Fallo al crear archivo:\n'%s'\nUltimo 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);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
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-06-27 21:28:54 -05:00
|
|
|
LogError("No se pudo generar el hash perfecto", FUNCION_ACTUAL);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-06-26 12:44:41 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#endif // SIMPHASH_SRC_PERFECTHASH_MQH
|