Skip to content

Commit 0a6c7d7

Browse files
committed
Initial commit
0 parents  commit 0a6c7d7

23 files changed

+12533
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
build/
2+
build*/
3+
_tmp_toml_*
4+
_tmp_toml_repo/
5+
_tmp_toml_test_repo/
6+
7+
benchmark/results/*
8+
!benchmark/results/schema.json

CMakeLists.txt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
project(fastoml LANGUAGES C CXX)
4+
5+
set(CMAKE_C_STANDARD 99)
6+
set(CMAKE_C_STANDARD_REQUIRED ON)
7+
set(CMAKE_C_EXTENSIONS OFF)
8+
9+
set(CMAKE_CXX_STANDARD 20)
10+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
11+
12+
option(FASTOML_BUILD_EXAMPLES "Build fastoml examples" ON)
13+
option(FASTOML_BENCH "Build benchmarks" OFF)
14+
option(FASTOML_BENCH_COMPARE_TOML11 "Enable toml11 benchmark" ON)
15+
option(FASTOML_BENCH_COMPARE_TOMLPLUSPLUS "Enable toml++ benchmark" ON)
16+
set(FASTOML_BENCH_REPETITIONS "10" CACHE STRING "Benchmark repetitions")
17+
set(FASTOML_BENCH_WARMUP_SEC "0.1" CACHE STRING "Benchmark warmup seconds")
18+
set(FASTOML_BENCH_OUTPUT_JSON "bench-results.json" CACHE STRING "Benchmark JSON output filename")
19+
20+
add_library(fastoml INTERFACE)
21+
add_library(fastoml::fastoml ALIAS fastoml)
22+
target_include_directories(fastoml INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
23+
24+
if(FASTOML_BUILD_EXAMPLES)
25+
add_subdirectory(example)
26+
endif()
27+
28+
if(FASTOML_BENCH)
29+
add_subdirectory(bench)
30+
endif()

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 EldoDebug
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
# fastoml
2+
3+
A high-performance, single-header TOML parser and serializer written in C.
4+
5+
## Features
6+
7+
- **Single-header library** — drop `fastoml.h` into your project
8+
- **C99 compatible** with C++ friendly
9+
- **SIMD accelerated** — optional AVX2, SSE2, and ARM NEON
10+
- **Complete TOML support** — parse, validate, build, and serialize
11+
- **Arena allocator** — minimal allocation overhead
12+
- **Custom allocators** — plug in your own malloc/realloc/free
13+
- **Detailed error reporting** — line, column, and byte offset on failure
14+
- **Parser reuse** — reset and parse again without reallocating
15+
- **Cross-platform** — Windows, Linux, macOS
16+
17+
## Quick Start
18+
19+
Copy `fastoml.h` into your project. In **exactly one** `.c` file, define the implementation:
20+
21+
```c
22+
#define FASTOML_IMPLEMENTATION
23+
#include "fastoml.h"
24+
```
25+
26+
All other files simply include the header:
27+
28+
```c
29+
#include "fastoml.h"
30+
```
31+
32+
### CMake
33+
34+
```cmake
35+
add_subdirectory(fastoml)
36+
target_link_libraries(your_target PRIVATE fastoml::fastoml)
37+
```
38+
39+
## Usage
40+
41+
### Parsing a TOML string
42+
43+
```c
44+
#include <stdio.h>
45+
#include "fastoml.h"
46+
47+
int main(void) {
48+
const char* input =
49+
"[server]\n"
50+
"host = \"127.0.0.1\"\n"
51+
"port = 8080\n";
52+
53+
fastoml_options options;
54+
fastoml_options_default(&options);
55+
56+
fastoml_parser* parser = fastoml_parser_create(&options);
57+
const fastoml_document* doc = NULL;
58+
fastoml_error err = {0};
59+
60+
fastoml_status st = fastoml_parse(parser, input, strlen(input), &doc, &err);
61+
if (st != FASTOML_OK) {
62+
fprintf(stderr, "parse error: %s (line %u, col %u)\n",
63+
fastoml_status_string(st), err.line, err.column);
64+
fastoml_parser_destroy(parser);
65+
return 1;
66+
}
67+
68+
const fastoml_node* root = fastoml_doc_root(doc);
69+
const fastoml_node* server = fastoml_table_get_cstr(root, "server");
70+
71+
const fastoml_node* host_node = fastoml_table_get_cstr(server, "host");
72+
fastoml_slice host = {0};
73+
fastoml_node_as_slice(host_node, &host);
74+
printf("host = %.*s\n", (int)host.len, host.ptr);
75+
76+
const fastoml_node* port_node = fastoml_table_get_cstr(server, "port");
77+
int64_t port = 0;
78+
fastoml_node_as_int(port_node, &port);
79+
printf("port = %lld\n", (long long)port);
80+
81+
fastoml_parser_destroy(parser);
82+
return 0;
83+
}
84+
```
85+
86+
### Building and serializing a TOML document
87+
88+
```c
89+
#include <stdio.h>
90+
#include "fastoml.h"
91+
92+
int main(void) {
93+
fastoml_builder_options options;
94+
fastoml_builder_options_default(&options);
95+
fastoml_builder* b = fastoml_builder_create(&options);
96+
97+
fastoml_value* root = fastoml_builder_root(b);
98+
fastoml_value* server = fastoml_builder_new_table(b);
99+
fastoml_builder_table_set_cstr(root, "server", server);
100+
fastoml_builder_table_set_cstr(server, "host",
101+
fastoml_builder_new_string(b, (fastoml_slice){"0.0.0.0", 7}));
102+
fastoml_builder_table_set_cstr(server, "port",
103+
fastoml_builder_new_int(b, 3000));
104+
105+
// Serialize to buffer
106+
fastoml_serialize_options ser_opts;
107+
fastoml_serialize_options_default(&ser_opts);
108+
ser_opts.flags |= FASTOML_SERIALIZE_FINAL_NEWLINE;
109+
110+
size_t len = 0;
111+
fastoml_serialize_to_buffer(fastoml_builder_root(b), &ser_opts, NULL, 0, &len);
112+
113+
char* buf = malloc(len + 1);
114+
fastoml_serialize_to_buffer(fastoml_builder_root(b), &ser_opts, buf, len + 1, &len);
115+
printf("%.*s", (int)len, buf);
116+
117+
free(buf);
118+
fastoml_builder_destroy(b);
119+
return 0;
120+
}
121+
```
122+
123+
Output:
124+
125+
```toml
126+
[server]
127+
host = "0.0.0.0"
128+
port = 3000
129+
```
130+
131+
## API Overview
132+
133+
### Parser
134+
135+
| Function | Description |
136+
|---|---|
137+
| `fastoml_parser_create` | Create a new parser instance |
138+
| `fastoml_parser_destroy` | Free parser and all parsed documents |
139+
| `fastoml_parser_reset` | Reset parser for reuse |
140+
| `fastoml_parse` | Parse a TOML string into a document |
141+
| `fastoml_validate` | Validate without building a tree |
142+
143+
### Document Access
144+
145+
| Function | Description |
146+
|---|---|
147+
| `fastoml_doc_root` | Get the root table node |
148+
| `fastoml_node_kindof` | Get the type of a node |
149+
| `fastoml_table_get_cstr` | Look up a key in a table |
150+
| `fastoml_table_size` | Number of entries in a table |
151+
| `fastoml_table_key_at` | Get key at index |
152+
| `fastoml_table_value_at` | Get value at index |
153+
| `fastoml_array_size` | Number of elements in an array |
154+
| `fastoml_array_at` | Get element at index |
155+
156+
### Value Extraction
157+
158+
| Function | Description |
159+
|---|---|
160+
| `fastoml_node_as_bool` | Extract boolean value |
161+
| `fastoml_node_as_int` | Extract 64-bit integer value |
162+
| `fastoml_node_as_float` | Extract double value |
163+
| `fastoml_node_as_slice` | Extract string / datetime slice |
164+
165+
### Builder & Serializer
166+
167+
| Function | Description |
168+
|---|---|
169+
| `fastoml_builder_create` | Create a document builder |
170+
| `fastoml_builder_new_table` | Create a new table value |
171+
| `fastoml_builder_new_array` | Create a new array value |
172+
| `fastoml_builder_new_string` | Create a new string value |
173+
| `fastoml_builder_new_int` | Create a new integer value |
174+
| `fastoml_builder_new_float` | Create a new float value |
175+
| `fastoml_builder_new_bool` | Create a new boolean value |
176+
| `fastoml_builder_table_set_cstr` | Insert a key-value pair |
177+
| `fastoml_builder_array_push` | Append an element to an array |
178+
| `fastoml_serialize_to_buffer` | Serialize to a memory buffer |
179+
| `fastoml_serialize_to_sink` | Serialize with a custom write callback |
180+
181+
### Parse Options
182+
183+
| Flag | Description |
184+
|---|---|
185+
| `FASTOML_PARSE_VALIDATE_ONLY` | Validate syntax without building a tree |
186+
| `FASTOML_PARSE_DISABLE_SIMD` | Disable SIMD optimizations |
187+
| `FASTOML_PARSE_TRUST_UTF8` | Skip UTF-8 validation for trusted input |
188+
189+
## Benchmarks
190+
191+
Parse throughput measured with [Google Benchmark](https://github.com/google/benchmark) (10 repetitions, mean values).
192+
193+
**Environment:** 12th Gen Intel, 12 threads, Windows 11, Clang (Release)
194+
195+
| Input | Size | fastoml | toml++ v3.4.0 | toml11 v4.4.0 |
196+
|---|---|---|---|---|
197+
| small | 184 B | **92.17 MiB/s** | 39.10 MiB/s | 1.28 MiB/s |
198+
| medium | 1,544 B | **232.26 MiB/s** | 38.05 MiB/s | 1.63 MiB/s |
199+
| large | 108,599 B | **242.30 MiB/s** | 32.28 MiB/s | 1.69 MiB/s |
200+
| invalid | 123 B | **79.16 MiB/s** | 20.15 MiB/s | 1.61 MiB/s |
201+
202+
### Speedup vs. alternatives
203+
204+
| Input | vs toml++ | vs toml11 |
205+
|---|---|---|
206+
| small | **2.4x** | **72x** |
207+
| medium | **6.1x** | **142x** |
208+
| large | **7.5x** | **143x** |
209+
| invalid | **3.9x** | **49x** |
210+
211+
> All parsers create and destroy their parser state in every iteration for a fair comparison. I/O is excluded — only the parse call is measured.
212+
213+
## Building
214+
215+
### Requirements
216+
217+
- CMake 3.20+
218+
- C99-compatible compiler (MSVC, GCC, Clang)
219+
220+
### Build the example
221+
222+
```bash
223+
cmake -S . -B build
224+
cmake --build build --config Release
225+
./build/example/fastoml_example
226+
```
227+
228+
### Build and run benchmarks
229+
230+
```bash
231+
cmake -S . -B build -DFASTOML_BENCH=ON
232+
cmake --build build --config Release
233+
./build/bench/fastoml_bench_parse
234+
```
235+
236+
## License
237+
238+
MIT

0 commit comments

Comments
 (0)