forked from nique_372/SimPHash
148 lines
No EOL
7.1 KiB
Markdown
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 |