152 lines
4 KiB
Markdown
152 lines
4 KiB
Markdown
<p align="center">
|
|
<img src="https://img.shields.io/badge/Language-MQL5-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"/>
|
|
</p>
|
|
|
|
<p align="center">
|
|
A high-performance, memory-free JSON parser for MQL5, based on a flat tape architecture.<br/> Single-pass iterative state machine (as is, without extra loops, "pure" o(n)): no recursion, no dynamic memory fragmentation, no overhead from function calls.
|
|
</p>
|
|
|
|
---
|
|
|
|
## Main Features
|
|
|
|
- **Tape-based zero-alloc model**: the entire JSON is parsed into a single contiguous `long[]` array
|
|
- **Single flat loop**: one `switch` over a token enum, no helper function calls during parsing, strictly O(n)
|
|
- **FNV-1a key hashing**: key lookup in objects without string comparison
|
|
- **Handle-based navigation**: `CJsonNode` is a lightweight struct (pointer + two ints), copying is free
|
|
- **In-place mutation**: `SetInt`, `SetDbl`, `SetBool` modify the tape directly without re-parsing
|
|
- **Iterator support**: `CJsonIteratorObj` and `CJsonIteratorArray` for clean traversal
|
|
|
|
### Parse and navigate
|
|
|
|
```mql5
|
|
#include "Src\\JsonNode.mqh"
|
|
|
|
TSN::CJsonParser parser;
|
|
parser.Assing("{\"symbol\":\"EURUSD\",\"bid\":1.2345,\"ask\":1.2347,\"active\":true}");
|
|
parser.Parse();
|
|
|
|
TSN::CJsonNode root = parser.GetRoot();
|
|
string symbol = root["symbol"].ToString();
|
|
double bid = root["bid"].ToDouble(0.0);
|
|
bool active = root["active"].ToBool(false);
|
|
```
|
|
|
|
### Iterate an object
|
|
|
|
```mql5
|
|
TSN::CJsonIteratorObj it = root.BeginObj();
|
|
while(it.IsValid())
|
|
{
|
|
PrintFormat("%s : %s", it.Key(), it.Val().ToString());
|
|
it.Next();
|
|
}
|
|
```
|
|
|
|
### Iterate an array
|
|
|
|
```mql5
|
|
TSN::CJsonNode arr = root["prices"];
|
|
TSN::CJsonIteratorArray it = arr.BeginArr();
|
|
while(it.IsValid())
|
|
{
|
|
Print(it.Val().ToDouble(0.0));
|
|
it.Next();
|
|
}
|
|
```
|
|
|
|
### Parse from file
|
|
|
|
```mql5
|
|
TSN::CJsonParser parser;
|
|
parser.AssingFile("data.json", false);
|
|
parser.Parse();
|
|
```
|
|
|
|
---
|
|
|
|
## Performance
|
|
|
|
Benchmark: `twitter.json` (616 KB), 1000 iterations, MetaTrader 5 x64 build 5836 started for MetaQuotes Ltd. (Laptop Lenovo (approximately from 2017), Terminal Windows 10 build 19045, 8 x Intel Core i5-8250U @ 1.60GHz, AVX2, 3 / 7 Gb memory, 34 / 222 Gb disk SSD, UAC, GMT-5)
|
|
|
|
| Parser | Time (ms) |
|
|
|--------|-----------|
|
|
| **JsonParserByLeo** | **1094** |
|
|
| fast_json v3.4 (One copy of array) | 1265 |
|
|
|
|
The gap comes from architecture, not micro-optimizations: one flat loop vs. a state machine with separate helper calls and per-iteration reserve checks.
|
|
|
|
---
|
|
|
|
## Repository Structure
|
|
|
|
```
|
|
JsonParserByLeo/
|
|
├── Src/ # Full code (Defines, Node, Parser)
|
|
└── Test/ # Test and Benchmarks (vs)
|
|
```
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
**[Read Full License](./LICENSE)**
|
|
By downloading or using this repository, you accept the license terms.
|
|
|
|
---
|
|
|
|
## 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/JsonParserByLeo.git"
|
|
```
|
|
|
|
Requires the `tsndep` package, available on [PyPI](https://pypi.org/project/tsndep). It automatically downloads and installs all declared dependencies.
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
**1. Include the library:**
|
|
|
|
```mql5
|
|
#include "..\\JsonParserByLeo\\Src\\JsonNode.mqh"
|
|
```
|
|
|
|
**2. Parse and access:**
|
|
|
|
```mql5
|
|
TSN::CJsonParser parser;
|
|
parser.Assing(my_json_string);
|
|
if(parser.Parse())
|
|
{
|
|
TSN::CJsonNode root = parser.GetRoot();
|
|
double price = root["price"].ToDouble(0.0);
|
|
}
|
|
```
|
|
|
|
**3. Re-parse without re-copying (benchmark pattern):**
|
|
|
|
```mql5
|
|
parser.Assing(raw_string); // copy once
|
|
for(int i = 0; i < 1000; i++)
|
|
parser.Parse(); // re-parse in-place
|
|
```
|
|
|
|
---
|
|
|
|
## 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
|