SimPHash/README.md
Nique_372 26ce54b34d
2026-08-01 18:44:11 -05:00

148 lines
No EOL
7.1 KiB
Markdown

<p align="center">
<img src="https://img.shields.io/badge/Language-MQL5%20%7C%20YAML-1B6CA8?style=flat-square"/>
<img src="https://img.shields.io/badge/Platform-MetaTrader%205-0D1B2A?style=flat-square"/>
<img src="https://img.shields.io/badge/Author-nique__372-C9D6DF?style=flat-square&logoColor=white"/>
<img src="https://img.shields.io/badge/MQL5.com-nique__372-1B6CA8?style=flat-square"/>
<a href="./LICENSE">
<img src="https://img.shields.io/badge/License-Nique%26Leo%20NL--NC-yellow.svg"/>
</a>
</p>
<p align="center">
Simple perfect hash generator, driven by a YAML config file.<br/> Runs as an EA: reads your key/value map from
YAML, builds a perfect hash with <a href="https://forge.mql5.io/nique_372/PerfectHashByLeo">PerfectHashByLeo</a>,
and emits a ready-to-include <code>.mqh</code> with the tables and lookup function already written.
</p>
---
## Main Features
- **YAML-driven, no code required**: you don't write the perfect hash tables by hand — you list your keys (and optionally values) in a YAML file, run the EA once, and it generates the `.mqh` for you.
- **Two swappable hash stages**, matching how [PerfectHashByLeo](https://forge.mql5.io/nique_372/PerfectHashByLeo) works internally (bucket hash + final displacement hash):
- **Bucket hash (`hash.type`)**: converts each string key into a `ulong` before bucketing. Supported: **`TSN_PHASH_TYPE_FNV1A_64`** (FNV-1a 64-bit, with configurable `basis`/`prime`) and **`TSN_PHASH_TYPE_XXHASH_64`** (xxHash64, with a configurable `seed`).
- **Final hash (`final_hash`)**: the per-bucket displacement hash, applied to the already-bucketed `ulong` key plus a seed. Supported: **`HASH_UL1_MUR_MUR`** (MurMur-style finalizer), **`HASH_UL1_SPLITMIX`** (SplitMix64), **`HASH_UL1_FMIX`** (MurmurHash3 fmix64 finalizer), **`HASH_UL1_FIBBO`** (Fibonacci hashing).
- **Two output modes**: either a table of **final values** (`map_use_value: true` — the generated function returns your mapped value directly) or a table of **indices** (`map_use_value: false` — the function returns a position into your own array, which is useful when the value is too complex to inline).
- **Optional binary export**: alongside the `.mqh`, you can dump the seeds/hashes/values/meta as raw `.bin` files (useful if you want to load the table at runtime instead of compiling it in).
- **Generates a complete, working lookup function** — both a `string`-keyed overload and a pre-hashed `ulong`-keyed overload, so callers who already computed the hash elsewhere can skip re-hashing.
### YAML config parameters
| Parameter | Description |
|---|---|
| `max_attepms` | Maximum displacement attempts (seed values `0, 1, 2, ...`) tried per bucket before giving up. |
| `namespace` | Namespace the generated tables/function are wrapped in (leave empty/`null` to skip). |
| `file_name_out` | Full path of the `.mqh` file to generate. |
| `table_prefix` | Prefix used for all generated table names (`<prefix>_seeds`, `<prefix>_hashes`, `<prefix>_values`/`<prefix>_tindex`). |
| `copyright` | Text written into the generated file's `#property copyright`. |
| `link` | Text written into the generated file's `#property link`. |
| `func_name` | Name of the generated lookup function. |
| `def_name_table_size` | Name of the `#define` for the final table size. |
| `def_bucket_size_name` | Name of the `#define` for the bucket count. |
| `invalid_value` | Value returned by the generated function when a key isn't found (also used to fill unused slots). |
| `comment_funct` | If `true`, the generated function body is wrapped in `/* */` (useful when you only want the tables and will write the function yourself). |
| `guard_name` | Optional `#ifndef`/`#define` include guard name for the generated file. |
| `bin` | Optional object with `seeds`, `values`, `hash` and `meta` file paths — if present, the raw tables are also written as binary files. |
| `hash.type` | Bucket hash algorithm: `TSN_PHASH_TYPE_FNV1A_64` or `TSN_PHASH_TYPE_XXHASH_64`. |
| `hash.config.basis` / `hash.config.prime` | FNV-1a offset basis / prime (use `def` for the standard FNV-1a-64 constants). |
| `hash.config.seed` | xxHash64 seed (only used when `hash.type` is `TSN_PHASH_TYPE_XXHASH_64`). |
| `final_hash` | Final displacement hash: `HASH_UL1_MUR_MUR`, `HASH_UL1_SPLITMIX`, `HASH_UL1_FMIX` or `HASH_UL1_FIBBO`. |
| `perfect_hash.elements_por_bucket` | Target average number of keys per bucket (lower = more buckets, generally faster to find a working seed). |
| `perfect_hash.load_factor` | Final table load factor (keys / final table size) — lower leaves more free slots, easing displacement at the cost of memory. |
| `map_use_value` | `true` = generate a values table (function returns the value directly); `false` = generate an indices table (function returns a position for you to index your own array with). |
| `map` | The key set itself: a YAML object (`KEY: value`) when `map_use_value: true`, or an array of keys otherwise. |
### Usage example
```yaml
# config.yaml
max_attepms: 15000
namespace: TSN
file_name_out: C:\Path\To\Out.mqh
table_prefix: g_table_test
copyright: Copyright 2026, Niquel Mendoza
link: https://www.mql5.com/
func_name: HashCustom
invalid_value: -1
hash:
type: TSN_PHASH_TYPE_FNV1A_64
config:
basis: def
prime: def
final_hash: HASH_UL1_MUR_MUR
perfect_hash:
elements_por_bucket: 3
load_factor: 0.81
map_use_value: true
map: { UNO: 1, DOS: 2, TRES: 3, CUATRO: 4, CINCO: 5 }
```
Run the EA (`EA.mq5`) pointing `InpYamlFileName` to this config, and it generates `Out.mqh` with the seed/hash/value tables plus a ready `HashCustom(const string& key)` / `HashCustom(const ulong key_hash)` function.
---
## Repository Structure
```
SimPHash/
└── Src/ # Generator, hash strategies (Hash/), YAML enum registry (EnumReg/), and test config/output
```
---
## ⚠️ License Notice
This repository requires access to two private repositories (`YamlParserByLeo`, `ExtraCodes`)
to compile. See [Requirements](#requirements) above for how to obtain access.
---
## Requirements
See [dependencies.json](./dependencies.json) for the full list.
---
## Installation
```bash
cd "C:\Users\YOUR_USER\AppData\Roaming\MetaQuotes\Terminal\YOUR_ID\MQL5\Shared Projects"
tsndep install "https://forge.mql5.io/nique_372/SimPHash.git"
```
Requires the `tsndep` package, available on [PyPI](https://pypi.org/project/tsndep). It automatically downloads and installs all declared dependencies.
---
## Quick Start
**1. Download the latest EA from the releases section of the repository**: https://forge.mql5.io/nique_372/SimPHash/releases
**2. Write your YAML config** (see parameters and example above).
**3. Point `EA.mq5` at it and run it:**
```mql5
input string InpYamlFileName = "C:\\...\\config.yaml";
```
**4. Include the generated `.mqh`** in your project and call the generated function.
---
## License
**[Read Full License](./LICENSE)**
By downloading or using this repository, you accept the license terms.
---
## Contact
- **Platform:** [MQL5 Community](https://www.mql5.com/es/users/nique_372)
- **Profile:** https://www.mql5.com/es/users/nique_372
- **Articles:** https://www.mql5.com/es/users/nique_372/publications