1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
|
# toml++ — Parsing
## Overview
toml++ provides a recursive-descent parser that converts TOML text into a `toml::table` tree of nodes. The parser handles the full TOML v1.0.0 specification, including all string types, numeric formats, date/time values, inline tables, and arrays of tables.
Key entry points are `toml::parse()` and `toml::parse_file()`, declared in `include/toml++/impl/parser.hpp`.
The parser can be disabled entirely via `TOML_ENABLE_PARSER=0`.
---
## Entry Points
### `parse()` — Parse from String
```cpp
// From std::string_view (most common)
parse_result parse(std::string_view doc, std::string_view source_path = {});
parse_result parse(std::string_view doc, std::string&& source_path);
// From std::istream
parse_result parse(std::istream& doc, std::string_view source_path = {});
parse_result parse(std::istream& doc, std::string&& source_path);
// From char8_t (C++20 u8 strings)
parse_result parse(std::u8string_view doc, std::string_view source_path = {});
```
The `source_path` parameter is stored in `source_region` data and appears in error messages. It does not affect parsing behavior.
```cpp
auto result = toml::parse(R"(
[server]
host = "localhost"
port = 8080
)");
// With source path for error messages:
auto result2 = toml::parse(toml_string, "config.toml");
```
### `parse_file()` — Parse from File Path
```cpp
parse_result parse_file(std::string_view file_path);
// Windows wstring overload (when TOML_ENABLE_WINDOWS_COMPAT=1)
parse_result parse_file(std::wstring_view file_path);
```
Reads the entire file and parses it:
```cpp
auto config = toml::parse_file("settings.toml");
auto config2 = toml::parse_file("/etc/myapp/config.toml");
```
---
## parse_result
`parse_result` is the return type from all parse functions. Its behavior depends on whether exceptions are enabled.
Declared in `include/toml++/impl/parse_result.hpp`.
### With Exceptions (`TOML_EXCEPTIONS=1`, the default)
`parse_result` is simply a type alias for `toml::table`:
```cpp
// Effectively:
using parse_result = table;
```
If parsing fails, `toml::parse_error` (derived from `std::runtime_error`) is thrown:
```cpp
try
{
toml::table config = toml::parse("invalid [[[toml");
}
catch (const toml::parse_error& err)
{
std::cerr << "Parse error: " << err.description() << "\n";
std::cerr << " at: " << err.source() << "\n";
}
```
### Without Exceptions (`TOML_EXCEPTIONS=0`)
`parse_result` is a discriminated union — it holds either a `toml::table` (success) or a `toml::parse_error` (failure):
```cpp
class parse_result
{
public:
// Check success
bool succeeded() const noexcept;
bool failed() const noexcept;
explicit operator bool() const noexcept; // same as succeeded()
// Access the table (success)
table& get() & noexcept;
const table& get() const& noexcept;
table&& get() && noexcept;
table& operator*() & noexcept;
table* operator->() noexcept;
// Access the error (failure)
const parse_error& error() const& noexcept;
// Implicit conversion to table& (success only)
operator table&() noexcept;
operator const table&() const noexcept;
};
```
Usage pattern:
```cpp
auto result = toml::parse("...");
if (result)
{
// Success — use the table
toml::table& config = result;
auto val = config["key"].value_or("default"sv);
}
else
{
// Failure — inspect the error
std::cerr << "Error: " << result.error().description() << "\n";
std::cerr << " at " << result.error().source() << "\n";
}
```
### Internal Storage (No-Exceptions Mode)
`parse_result` uses aligned storage to hold either type:
```cpp
// Simplified internal layout:
alignas(table) mutable unsigned char storage_[sizeof(table)];
bool err_;
parse_error err_val_; // only when err_ == true
```
The `table` is placement-new'd into `storage_` on success. On failure, `err_val_` is populated instead.
---
## parse_error
Declared in `include/toml++/impl/parse_error.hpp`.
### With Exceptions
```cpp
class parse_error : public std::runtime_error
{
public:
std::string_view description() const noexcept;
const source_region& source() const noexcept;
// what() returns the description
};
```
### Without Exceptions
```cpp
class parse_error
{
public:
std::string_view description() const noexcept;
const source_region& source() const noexcept;
// Streaming
friend std::ostream& operator<<(std::ostream&, const parse_error&);
};
```
### Error Information
```cpp
auto result = toml::parse("x = [1, 2,, 3]", "test.toml");
if (!result)
{
const auto& err = result.error();
// Human-readable description
std::cout << err.description() << "\n";
// e.g., "Unexpected character ',' (U+002C) in array"
// Source location
const auto& src = err.source();
std::cout << "File: " << *src.path << "\n"; // "test.toml"
std::cout << "Line: " << src.begin.line << "\n"; // 1
std::cout << "Col: " << src.begin.column << "\n"; // 11
// Full error with location (via operator<<)
std::cout << err << "\n";
// "Unexpected character ',' ... at line 1, column 11 of 'test.toml'"
}
```
---
## Source Tracking
### `source_position`
```cpp
struct source_position
{
source_index line; // 1-based line number
source_index column; // 1-based column number (byte offset, not codepoint)
explicit operator bool() const noexcept; // true if line > 0
friend bool operator==(const source_position&, const source_position&) noexcept;
friend bool operator!=(const source_position&, const source_position&) noexcept;
friend bool operator< (const source_position&, const source_position&) noexcept;
friend bool operator<=(const source_position&, const source_position&) noexcept;
};
```
`source_index` is typically `uint32_t` (or `uint16_t` on small builds via `TOML_SMALL_INT_TYPE`).
### `source_region`
```cpp
struct source_region
{
source_position begin; // start of the element
source_position end; // end of the element
source_path_ptr path; // shared_ptr<const std::string>
};
```
Every `node` in the parsed tree carries a `source_region`:
```cpp
auto tbl = toml::parse(R"(
name = "Alice"
age = 30
)", "config.toml");
const auto& src = tbl["name"].node()->source();
std::cout << "Defined at "
<< *src.path << ":"
<< src.begin.line << ":"
<< src.begin.column << "\n";
// "Defined at config.toml:2:5"
```
`source_path_ptr` is `std::shared_ptr<const std::string>`, shared among all nodes parsed from the same file.
---
## Stream Parsing
Parsing from `std::istream` allows reading from any stream source:
```cpp
#include <fstream>
std::ifstream file("config.toml");
auto config = toml::parse(file, "config.toml");
// From stringstream
std::istringstream ss(R"(key = "value")");
auto tbl = toml::parse(ss);
```
The stream is consumed entirely during parsing.
---
## UTF-8 Handling During Parsing
The parser expects UTF-8 encoded input. It handles:
- **BOM stripping**: A leading UTF-8 BOM (`0xEF 0xBB 0xBF`) is silently consumed
- **Multi-byte sequences**: Bare keys, strings, and comments can contain Unicode
- **Escape sequences in strings**: `\uXXXX` and `\UXXXXXXXX` are decoded
- **Validation**: Invalid UTF-8 sequences are rejected with parse errors
- **Non-characters and surrogates**: Rejected as per the TOML specification
### char8_t Support (C++20)
```cpp
auto tbl = toml::parse(u8R"(
greeting = "Hello, 世界"
)"sv);
```
The `char8_t` overloads allow passing C++20 UTF-8 string literals directly.
---
## Windows Compatibility
When `TOML_ENABLE_WINDOWS_COMPAT=1` (default on Windows):
```cpp
// Accept wstring file paths (converted to UTF-8 internally)
auto config = toml::parse_file(L"C:\\config\\settings.toml");
// Wide string values can be used with value()
auto path = config["path"].value<std::wstring>();
```
---
## Parser Configuration Macros
| Macro | Default | Effect |
|-------|---------|--------|
| `TOML_ENABLE_PARSER` | `1` | Set to `0` to remove the parser entirely (serialize-only builds) |
| `TOML_EXCEPTIONS` | Auto-detected | Controls exception vs. return-code error handling |
| `TOML_UNRELEASED_FEATURES` | `0` | Enable parsing of TOML features not yet in a released spec |
| `TOML_ENABLE_WINDOWS_COMPAT` | `1` on Windows | Enable wstring/wchar_t overloads |
---
## Parsing Specific TOML Features
### Strings
```toml
basic = "hello\nworld" # basic (escape sequences)
literal = 'no \escapes' # literal (no escapes)
multi_basic = """
multiline
string""" # multi-line basic
multi_literal = '''
multiline
literal''' # multi-line literal
```
### Numbers
```toml
int_dec = 42
int_hex = 0xFF
int_oct = 0o755
int_bin = 0b11010110
float_std = 3.14
float_exp = 1e10
float_inf = inf
float_nan = nan
underscore = 1_000_000
```
The parser records the integer format in `value_flags`:
- `0xFF` → `value_flags::format_as_hexadecimal`
- `0o755` → `value_flags::format_as_octal`
- `0b1010` → `value_flags::format_as_binary`
### Inline Tables
```toml
point = { x = 1, y = 2 } # single-line inline table
```
Parsed as a `toml::table` with `is_inline()` returning `true`.
### Arrays of Tables
```toml
[[products]]
name = "Hammer"
price = 9.99
[[products]]
name = "Nail"
price = 0.05
```
Parsed as `table["products"]` → `array` containing two `table` nodes.
---
## Error Recovery
The parser does **not** attempt error recovery. Upon encountering the first error, parsing stops and the error is returned (or thrown). This design ensures:
1. No partially-parsed trees with missing data
2. Clear, unambiguous error messages
3. The error source points to the exact location of the problem
---
## Thread Safety
- Parsing is **thread-safe**: multiple threads can call `parse()` concurrently with different inputs
- The parser uses no global state
- The returned `parse_result` / `table` is independent and owned by the caller
---
## Complete Example
```cpp
#include <toml++/toml.hpp>
#include <iostream>
#include <fstream>
int main()
{
// --- Parse from string ---
auto config = toml::parse(R"(
[database]
server = "192.168.1.1"
ports = [8001, 8001, 8002]
enabled = true
connection_max = 5000
[database.credentials]
username = "admin"
password_file = "/etc/db/pass"
)");
#if TOML_EXCEPTIONS
// With exceptions, config is a toml::table directly
auto server = config["database"]["server"].value_or(""sv);
std::cout << "Server: " << server << "\n";
#else
// Without exceptions, check for success first
if (!config)
{
std::cerr << "Parse failed:\n" << config.error() << "\n";
return 1;
}
auto& tbl = config.get();
auto server = tbl["database"]["server"].value_or(""sv);
std::cout << "Server: " << server << "\n";
#endif
// --- Parse from file ---
try
{
auto file_config = toml::parse_file("app.toml");
std::cout << file_config << "\n";
}
catch (const toml::parse_error& err)
{
std::cerr << "Failed to parse app.toml:\n"
<< err.description() << "\n"
<< " at " << err.source() << "\n";
return 1;
}
// --- Source tracking ---
auto doc = toml::parse(R"(
title = "Example"
[owner]
name = "Tom"
)", "example.toml");
auto* name_node = doc.get("owner");
if (name_node)
{
const auto& src = name_node->source();
std::cout << "owner defined at: "
<< *src.path << ":"
<< src.begin.line << ":"
<< src.begin.column << "\n";
}
// --- Stream parsing ---
std::istringstream ss(R"(key = "from stream")");
auto stream_result = toml::parse(ss, "stream-input");
std::cout << stream_result["key"].value_or(""sv) << "\n";
return 0;
}
```
---
## Related Documentation
- [basic-usage.md](basic-usage.md) — Quick start guide with parsing examples
- [values.md](values.md) — Value types created by the parser
- [tables.md](tables.md) — Root table structure
- [formatting.md](formatting.md) — Serializing parsed data back to TOML
- [unicode-handling.md](unicode-handling.md) — UTF-8 handling details
|