STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
toml.hpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------------------------------------------------
2//
3// toml++ v3.4.0
4// https://github.com/marzer/tomlplusplus
5// SPDX-License-Identifier: MIT
6//
7//----------------------------------------------------------------------------------------------------------------------
8//
9// - THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY -
10//
11// If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this
12// file was assembled from a number of smaller files by a python script, and code contributions should not be made
13// against it directly. You should instead make your changes in the relevant source file(s). The file names of the files
14// that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file.
15//
16//----------------------------------------------------------------------------------------------------------------------
17//
18// TOML Language Specifications:
19// latest: https://github.com/toml-lang/toml/blob/master/README.md
20// v1.0.0: https://toml.io/en/v1.0.0
21// v0.5.0: https://toml.io/en/v0.5.0
22// changelog: https://github.com/toml-lang/toml/blob/master/CHANGELOG.md
23//
24//----------------------------------------------------------------------------------------------------------------------
25//
26// MIT License
27//
28// Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
29//
30// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
31// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
32// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
33// permit persons to whom the Software is furnished to do so, subject to the following conditions:
34//
35// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
36// Software.
37//
38// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
39// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
40// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
41// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42//
43//----------------------------------------------------------------------------------------------------------------------
44#ifndef TOMLPLUSPLUS_HPP
45#define TOMLPLUSPLUS_HPP
46
47#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3
48#define TOMLPLUSPLUS_H // guard name used in the legacy toml.h
49
50//******** impl/preprocessor.hpp *************************************************************************************
51
52#ifndef __cplusplus
53#error toml++ is a C++ library.
54#endif
55
56#ifndef TOML_CPP
57#ifdef _MSVC_LANG
58#if _MSVC_LANG > __cplusplus
59#define TOML_CPP _MSVC_LANG
60#endif
61#endif
62#ifndef TOML_CPP
63#define TOML_CPP __cplusplus
64#endif
65#if TOML_CPP >= 202900L
66#undef TOML_CPP
67#define TOML_CPP 29
68#elif TOML_CPP >= 202600L
69#undef TOML_CPP
70#define TOML_CPP 26
71#elif TOML_CPP >= 202302L
72#undef TOML_CPP
73#define TOML_CPP 23
74#elif TOML_CPP >= 202002L
75#undef TOML_CPP
76#define TOML_CPP 20
77#elif TOML_CPP >= 201703L
78#undef TOML_CPP
79#define TOML_CPP 17
80#elif TOML_CPP >= 201402L
81#undef TOML_CPP
82#define TOML_CPP 14
83#elif TOML_CPP >= 201103L
84#undef TOML_CPP
85#define TOML_CPP 11
86#else
87#undef TOML_CPP
88#define TOML_CPP 0
89#endif
90#endif
91
92#if !TOML_CPP
93#error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml
94#elif TOML_CPP < 17
95#error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11
96#endif
97
98#ifndef TOML_MAKE_VERSION
99#define TOML_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + ((patch)))
100#endif
101
102#ifndef TOML_INTELLISENSE
103#ifdef __INTELLISENSE__
104#define TOML_INTELLISENSE 1
105#else
106#define TOML_INTELLISENSE 0
107#endif
108#endif
109
110#ifndef TOML_DOXYGEN
111#if defined(DOXYGEN) || defined(__DOXYGEN) || defined(__DOXYGEN__) || defined(__doxygen__) || defined(__POXY__) \
112 || defined(__poxy__)
113#define TOML_DOXYGEN 1
114#else
115#define TOML_DOXYGEN 0
116#endif
117#endif
118
119#ifndef TOML_CLANG
120#ifdef __clang__
121#define TOML_CLANG __clang_major__
122#else
123#define TOML_CLANG 0
124#endif
125
126// special handling for apple clang; see:
127// - https://github.com/marzer/tomlplusplus/issues/189
128// - https://en.wikipedia.org/wiki/Xcode
129// -
130// https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time
131#if TOML_CLANG && defined(__apple_build_version__)
132#undef TOML_CLANG
133#define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
134#if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0)
135#define TOML_CLANG 16
136#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0)
137#define TOML_CLANG 15
138#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0)
139#define TOML_CLANG 14
140#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6)
141#define TOML_CLANG 13
142#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0)
143#define TOML_CLANG 12
144#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5)
145#define TOML_CLANG 11
146#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0)
147#define TOML_CLANG 10
148#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3)
149#define TOML_CLANG 9
150#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0)
151#define TOML_CLANG 8
152#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1)
153#define TOML_CLANG 7
154#else
155#define TOML_CLANG 6 // not strictly correct but doesn't matter below this
156#endif
157#undef TOML_CLANG_VERSION
158#endif
159#endif
160
161#ifndef TOML_ICC
162#ifdef __INTEL_COMPILER
163#define TOML_ICC __INTEL_COMPILER
164#ifdef __ICL
165#define TOML_ICC_CL TOML_ICC
166#else
167#define TOML_ICC_CL 0
168#endif
169#else
170#define TOML_ICC 0
171#define TOML_ICC_CL 0
172#endif
173#endif
174
175#ifndef TOML_MSVC_LIKE
176#ifdef _MSC_VER
177#define TOML_MSVC_LIKE _MSC_VER
178#else
179#define TOML_MSVC_LIKE 0
180#endif
181#endif
182
183#ifndef TOML_MSVC
184#if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC
185#define TOML_MSVC TOML_MSVC_LIKE
186#else
187#define TOML_MSVC 0
188#endif
189#endif
190
191#ifndef TOML_GCC_LIKE
192#ifdef __GNUC__
193#define TOML_GCC_LIKE __GNUC__
194#else
195#define TOML_GCC_LIKE 0
196#endif
197#endif
198
199#ifndef TOML_GCC
200#if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC
201#define TOML_GCC TOML_GCC_LIKE
202#else
203#define TOML_GCC 0
204#endif
205#endif
206
207#ifndef TOML_CUDA
208#if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__)
209#define TOML_CUDA 1
210#else
211#define TOML_CUDA 0
212#endif
213#endif
214
215#ifndef TOML_ARCH_ITANIUM
216#if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64)
217#define TOML_ARCH_ITANIUM 1
218#define TOML_ARCH_BITNESS 64
219#else
220#define TOML_ARCH_ITANIUM 0
221#endif
222#endif
223
224#ifndef TOML_ARCH_AMD64
225#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
226#define TOML_ARCH_AMD64 1
227#define TOML_ARCH_BITNESS 64
228#else
229#define TOML_ARCH_AMD64 0
230#endif
231#endif
232
233#ifndef TOML_ARCH_X86
234#if defined(__i386__) || defined(_M_IX86)
235#define TOML_ARCH_X86 1
236#define TOML_ARCH_BITNESS 32
237#else
238#define TOML_ARCH_X86 0
239#endif
240#endif
241
242#ifndef TOML_ARCH_ARM
243#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \
244 || defined(_M_ARM64EC)
245#define TOML_ARCH_ARM32 0
246#define TOML_ARCH_ARM64 1
247#define TOML_ARCH_ARM 1
248#define TOML_ARCH_BITNESS 64
249#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE)
250#define TOML_ARCH_ARM32 1
251#define TOML_ARCH_ARM64 0
252#define TOML_ARCH_ARM 1
253#define TOML_ARCH_BITNESS 32
254#else
255#define TOML_ARCH_ARM32 0
256#define TOML_ARCH_ARM64 0
257#define TOML_ARCH_ARM 0
258#endif
259#endif
260
261#ifndef TOML_ARCH_BITNESS
262#define TOML_ARCH_BITNESS 0
263#endif
264
265#ifndef TOML_ARCH_X64
266#if TOML_ARCH_BITNESS == 64
267#define TOML_ARCH_X64 1
268#else
269#define TOML_ARCH_X64 0
270#endif
271#endif
272
273#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__)
274#define TOML_WINDOWS 1
275#else
276#define TOML_WINDOWS 0
277#endif
278
279#ifdef __unix__
280#define TOML_UNIX 1
281#else
282#define TOML_UNIX 0
283#endif
284
285#ifdef __linux__
286#define TOML_LINUX 1
287#else
288#define TOML_LINUX 0
289#endif
290
291// TOML_HAS_INCLUDE
292#ifndef TOML_HAS_INCLUDE
293#ifdef __has_include
294#define TOML_HAS_INCLUDE(header) __has_include(header)
295#else
296#define TOML_HAS_INCLUDE(header) 0
297#endif
298#endif
299
300// TOML_HAS_BUILTIN
301#ifndef TOML_HAS_BUILTIN
302#ifdef __has_builtin
303#define TOML_HAS_BUILTIN(name) __has_builtin(name)
304#else
305#define TOML_HAS_BUILTIN(name) 0
306#endif
307#endif
308
309// TOML_HAS_FEATURE
310#ifndef TOML_HAS_FEATURE
311#ifdef __has_feature
312#define TOML_HAS_FEATURE(name) __has_feature(name)
313#else
314#define TOML_HAS_FEATURE(name) 0
315#endif
316#endif
317
318// TOML_HAS_ATTR
319#ifndef TOML_HAS_ATTR
320#ifdef __has_attribute
321#define TOML_HAS_ATTR(attr) __has_attribute(attr)
322#else
323#define TOML_HAS_ATTR(attr) 0
324#endif
325#endif
326
327// TOML_HAS_CPP_ATTR
328#ifndef TOML_HAS_CPP_ATTR
329#ifdef __has_cpp_attribute
330#define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr)
331#else
332#define TOML_HAS_CPP_ATTR(attr) 0
333#endif
334#endif
335
336// TOML_ATTR (gnu attributes)
337#ifndef TOML_ATTR
338#if TOML_CLANG || TOML_GCC_LIKE
339#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
340#else
341#define TOML_ATTR(...)
342#endif
343#endif
344
345// TOML_DECLSPEC (msvc attributes)
346#ifndef TOML_DECLSPEC
347#if TOML_MSVC_LIKE
348#define TOML_DECLSPEC(...) __declspec(__VA_ARGS__)
349#else
350#define TOML_DECLSPEC(...)
351#endif
352#endif
353
354// TOML_COMPILER_HAS_EXCEPTIONS
355#ifndef TOML_COMPILER_HAS_EXCEPTIONS
356#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions)
357#define TOML_COMPILER_HAS_EXCEPTIONS 1
358#else
359#define TOML_COMPILER_HAS_EXCEPTIONS 0
360#endif
361#endif
362
363// TOML_COMPILER_HAS_RTTI
364#ifndef TOML_COMPILER_HAS_RTTI
365#if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti)
366#define TOML_COMPILER_HAS_RTTI 1
367#else
368#define TOML_COMPILER_HAS_RTTI 0
369#endif
370#endif
371
372// TOML_CONCAT
373#define TOML_CONCAT_1(x, y) x##y
374#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)
375
376// TOML_MAKE_STRING
377#define TOML_MAKE_STRING_1(s) #s
378#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s)
379
380// TOML_PRAGMA_XXXX (compiler-specific pragmas)
381#if TOML_CLANG
382#define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl))
383#else
384#define TOML_PRAGMA_CLANG(decl)
385#endif
386#if TOML_CLANG >= 8
387#define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl)
388#else
389#define TOML_PRAGMA_CLANG_GE_8(decl)
390#endif
391#if TOML_CLANG >= 9
392#define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl)
393#else
394#define TOML_PRAGMA_CLANG_GE_9(decl)
395#endif
396#if TOML_CLANG >= 10
397#define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl)
398#else
399#define TOML_PRAGMA_CLANG_GE_10(decl)
400#endif
401#if TOML_CLANG >= 11
402#define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl)
403#else
404#define TOML_PRAGMA_CLANG_GE_11(decl)
405#endif
406#if TOML_GCC
407#define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl))
408#else
409#define TOML_PRAGMA_GCC(decl)
410#endif
411#if TOML_MSVC
412#define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__)
413#else
414#define TOML_PRAGMA_MSVC(...)
415#endif
416#if TOML_ICC
417#define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__)
418#else
419#define TOML_PRAGMA_ICC(...)
420#endif
421
422// TOML_ALWAYS_INLINE
423#ifdef _MSC_VER
424#define TOML_ALWAYS_INLINE __forceinline
425#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__)
426#define TOML_ALWAYS_INLINE \
427 TOML_ATTR(__always_inline__) \
428 inline
429#else
430#define TOML_ALWAYS_INLINE inline
431#endif
432
433// TOML_NEVER_INLINE
434#ifdef _MSC_VER
435#define TOML_NEVER_INLINE TOML_DECLSPEC(noinline)
436#elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555
437#define TOML_NEVER_INLINE TOML_ATTR(noinline)
438#else
439#if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__)
440#define TOML_NEVER_INLINE TOML_ATTR(__noinline__)
441#endif
442#endif
443#ifndef TOML_NEVER_INLINE
444#define TOML_NEVER_INLINE
445#endif
446
447// MSVC attributes
448#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable)
449#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases)
450
451// TOML_TRIVIAL_ABI
452#if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__)
453#define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__)
454#else
455#define TOML_TRIVIAL_ABI
456#endif
457
458// TOML_NODISCARD
459#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603
460#define TOML_NODISCARD [[nodiscard]]
461#elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__)
462#define TOML_NODISCARD TOML_ATTR(__warn_unused_result__)
463#else
464#define TOML_NODISCARD
465#endif
466
467// TOML_NODISCARD_CTOR
468#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907
469#define TOML_NODISCARD_CTOR [[nodiscard]]
470#else
471#define TOML_NODISCARD_CTOR
472#endif
473
474// pure + const
475#ifndef TOML_PURE
476#ifdef NDEBUG
477#define TOML_PURE \
478 TOML_DECLSPEC(noalias) \
479 TOML_ATTR(pure)
480#else
481#define TOML_PURE
482#endif
483#endif
484#ifndef TOML_CONST
485#ifdef NDEBUG
486#define TOML_CONST \
487 TOML_DECLSPEC(noalias) \
488 TOML_ATTR(const)
489#else
490#define TOML_CONST
491#endif
492#endif
493#ifndef TOML_INLINE_GETTER
494#define TOML_INLINE_GETTER \
495 TOML_NODISCARD \
496 TOML_ALWAYS_INLINE
497#endif
498#ifndef TOML_PURE_GETTER
499#define TOML_PURE_GETTER \
500 TOML_NODISCARD \
501 TOML_PURE
502#endif
503#ifndef TOML_PURE_INLINE_GETTER
504#define TOML_PURE_INLINE_GETTER \
505 TOML_NODISCARD \
506 TOML_ALWAYS_INLINE \
507 TOML_PURE
508#endif
509#ifndef TOML_CONST_GETTER
510#define TOML_CONST_GETTER \
511 TOML_NODISCARD \
512 TOML_CONST
513#endif
514#ifndef TOML_CONST_INLINE_GETTER
515#define TOML_CONST_INLINE_GETTER \
516 TOML_NODISCARD \
517 TOML_ALWAYS_INLINE \
518 TOML_CONST
519#endif
520
521// TOML_ASSUME
522#ifdef _MSC_VER
523#define TOML_ASSUME(expr) __assume(expr)
524#elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume)
525#define TOML_ASSUME(expr) __builtin_assume(expr)
526#elif TOML_HAS_CPP_ATTR(assume) >= 202207
527#define TOML_ASSUME(expr) [[assume(expr)]]
528#elif TOML_HAS_ATTR(__assume__)
529#define TOML_ASSUME(expr) __attribute__((__assume__(expr)))
530#else
531#define TOML_ASSUME(expr) static_cast<void>(0)
532#endif
533
534// TOML_UNREACHABLE
535#ifdef _MSC_VER
536#define TOML_UNREACHABLE __assume(0)
537#elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable)
538#define TOML_UNREACHABLE __builtin_unreachable()
539#else
540#define TOML_UNREACHABLE static_cast<void>(0)
541#endif
542
543// TOML_LIKELY
544#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803
545#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
546#define TOML_LIKELY_CASE [[likely]]
547#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
548#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1))
549#else
550#define TOML_LIKELY(...) (__VA_ARGS__)
551#endif
552#ifndef TOML_LIKELY_CASE
553#define TOML_LIKELY_CASE
554#endif
555
556// TOML_UNLIKELY
557#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803
558#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
559#define TOML_UNLIKELY_CASE [[unlikely]]
560#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
561#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0))
562#else
563#define TOML_UNLIKELY(...) (__VA_ARGS__)
564#endif
565#ifndef TOML_UNLIKELY_CASE
566#define TOML_UNLIKELY_CASE
567#endif
568
569// TOML_FLAGS_ENUM
570#if TOML_CLANG || TOML_HAS_ATTR(flag_enum)
571#define TOML_FLAGS_ENUM __attribute__((flag_enum))
572#else
573#define TOML_FLAGS_ENUM
574#endif
575
576// TOML_OPEN_ENUM + TOML_CLOSED_ENUM
577#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility)
578#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open)))
579#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed)))
580#else
581#define TOML_OPEN_ENUM
582#define TOML_CLOSED_ENUM
583#endif
584
585// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM
586#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM
587#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM
588
589// TOML_MAKE_FLAGS
590#define TOML_MAKE_FLAGS_2(T, op, linkage) \
591 TOML_CONST_INLINE_GETTER \
592 linkage constexpr T operator op(T lhs, T rhs) noexcept \
593 { \
594 using under = std::underlying_type_t<T>; \
595 return static_cast<T>(static_cast<under>(lhs) op static_cast<under>(rhs)); \
596 } \
597 \
598 linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept \
599 { \
600 return lhs = (lhs op rhs); \
601 } \
602 \
603 static_assert(true)
604#define TOML_MAKE_FLAGS_1(T, linkage) \
605 static_assert(std::is_enum_v<T>); \
606 \
607 TOML_MAKE_FLAGS_2(T, &, linkage); \
608 TOML_MAKE_FLAGS_2(T, |, linkage); \
609 TOML_MAKE_FLAGS_2(T, ^, linkage); \
610 \
611 TOML_CONST_INLINE_GETTER \
612 linkage constexpr T operator~(T val) noexcept \
613 { \
614 using under = std::underlying_type_t<T>; \
615 return static_cast<T>(~static_cast<under>(val)); \
616 } \
617 \
618 TOML_CONST_INLINE_GETTER \
619 linkage constexpr bool operator!(T val) noexcept \
620 { \
621 using under = std::underlying_type_t<T>; \
622 return !static_cast<under>(val); \
623 } \
624 \
625 static_assert(true)
626#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, )
627
628#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
629
630#define TOML_DELETE_DEFAULTS(T) \
631 T(const T&) = delete; \
632 T(T&&) = delete; \
633 T& operator=(const T&) = delete; \
634 T& operator=(T&&) = delete
635
636#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
637 __VA_ARGS__ TOML_NODISCARD \
638 friend bool operator==(RHS rhs, LHS lhs) noexcept \
639 { \
640 return lhs == rhs; \
641 } \
642 __VA_ARGS__ TOML_NODISCARD \
643 friend bool operator!=(LHS lhs, RHS rhs) noexcept \
644 { \
645 return !(lhs == rhs); \
646 } \
647 __VA_ARGS__ TOML_NODISCARD \
648 friend bool operator!=(RHS rhs, LHS lhs) noexcept \
649 { \
650 return !(lhs == rhs); \
651 } \
652 static_assert(true)
653
654#define TOML_EVAL_BOOL_1(T, F) T
655#define TOML_EVAL_BOOL_0(T, F) F
656
657#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL)
658#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__
659#endif
660
661// COMPILER-SPECIFIC WARNING MANAGEMENT
662
663#if TOML_CLANG
664
665#define TOML_PUSH_WARNINGS \
666 TOML_PRAGMA_CLANG(diagnostic push) \
667 TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option") \
668 static_assert(true)
669
670#define TOML_DISABLE_SWITCH_WARNINGS \
671 TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch") \
672 static_assert(true)
673
674#define TOML_DISABLE_ARITHMETIC_WARNINGS \
675 TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wimplicit-int-float-conversion") \
676 TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal") \
677 TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \
678 TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \
679 TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow") \
680 static_assert(true)
681
682#define TOML_DISABLE_SPAM_WARNINGS \
683 TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted") \
684 TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported") \
685 TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant") \
686 TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override") \
687 TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") \
688 TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables") \
689 TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \
690 TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \
691 TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers") \
692 TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded") \
693 static_assert(true)
694
695#define TOML_POP_WARNINGS \
696 TOML_PRAGMA_CLANG(diagnostic pop) \
697 static_assert(true)
698
699#define TOML_DISABLE_WARNINGS \
700 TOML_PRAGMA_CLANG(diagnostic push) \
701 TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything") \
702 static_assert(true, "")
703
704#define TOML_ENABLE_WARNINGS \
705 TOML_PRAGMA_CLANG(diagnostic pop) \
706 static_assert(true)
707
708#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1
709
710#elif TOML_MSVC
711
712#define TOML_PUSH_WARNINGS \
713 __pragma(warning(push)) \
714 static_assert(true)
715
716#if TOML_HAS_INCLUDE(<CodeAnalysis/Warnings.h>)
717#pragma warning(push, 0)
718#include <CodeAnalysis/Warnings.h>
719#pragma warning(pop)
720#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \
721 __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) \
722 static_assert(true)
723#else
724#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
725#endif
726
727#define TOML_DISABLE_SWITCH_WARNINGS \
728 __pragma(warning(disable : 4061)) \
729 __pragma(warning(disable : 4062)) \
730 __pragma(warning(disable : 4063)) \
731 __pragma(warning(disable : 5262)) /* switch-case implicit fallthrough (false-positive) */ \
732 __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */ \
733 static_assert(true)
734
735#define TOML_DISABLE_SPAM_WARNINGS \
736 __pragma(warning(disable : 4127)) /* conditional expr is constant */ \
737 __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */ \
738 __pragma(warning(disable : 4348)) \
739 __pragma(warning(disable : 4464)) /* relative include path contains '..' */ \
740 __pragma(warning(disable : 4505)) /* unreferenced local function removed */ \
741 __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */ \
742 __pragma(warning(disable : 4582)) /* constructor is not implicitly called */ \
743 __pragma(warning(disable : 4619)) /* there is no warning number 'XXXX' */ \
744 __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */ \
745 __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */ \
746 __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */ \
747 __pragma(warning(disable : 4710)) /* function not inlined */ \
748 __pragma(warning(disable : 4711)) /* function selected for automatic expansion */ \
749 __pragma(warning(disable : 4820)) /* N bytes padding added */ \
750 __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */ \
751 __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted */ \
752 __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted */ \
753 __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */ \
754 __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */ \
755 __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */ \
756 __pragma(warning(disable : 26451)) \
757 __pragma(warning(disable : 26490)) \
758 __pragma(warning(disable : 26495)) \
759 __pragma(warning(disable : 26812)) \
760 __pragma(warning(disable : 26819)) \
761 static_assert(true)
762
763#define TOML_DISABLE_ARITHMETIC_WARNINGS \
764 __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */ \
765 __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */ \
766 __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */ \
767 static_assert(true)
768
769#define TOML_POP_WARNINGS \
770 __pragma(warning(pop)) \
771 static_assert(true)
772
773#define TOML_DISABLE_WARNINGS \
774 __pragma(warning(push, 0)) \
775 __pragma(warning(disable : 4348)) \
776 __pragma(warning(disable : 4668)) \
777 __pragma(warning(disable : 5105)) \
778 __pragma(warning(disable : 5264)) \
779 TOML_DISABLE_CODE_ANALYSIS_WARNINGS; \
780 TOML_DISABLE_SWITCH_WARNINGS; \
781 TOML_DISABLE_SPAM_WARNINGS; \
782 TOML_DISABLE_ARITHMETIC_WARNINGS; \
783 static_assert(true)
784
785#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
786
787#elif TOML_ICC
788
789#define TOML_PUSH_WARNINGS \
790 __pragma(warning(push)) \
791 static_assert(true)
792
793#define TOML_DISABLE_SPAM_WARNINGS \
794 __pragma(warning(disable : 82)) /* storage class is not first */ \
795 __pragma(warning(disable : 111)) /* statement unreachable (false-positive) */ \
796 __pragma(warning(disable : 869)) /* unreferenced parameter */ \
797 __pragma(warning(disable : 1011)) /* missing return (false-positive) */ \
798 __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */ \
799 static_assert(true)
800
801#define TOML_POP_WARNINGS \
802 __pragma(warning(pop)) \
803 static_assert(true)
804
805#define TOML_DISABLE_WARNINGS \
806 __pragma(warning(push, 0)) \
807 TOML_DISABLE_SPAM_WARNINGS
808
809#define TOML_ENABLE_WARNINGS \
810 __pragma(warning(pop)) \
811 static_assert(true)
812
813#elif TOML_GCC
814
815#define TOML_PUSH_WARNINGS \
816 TOML_PRAGMA_GCC(diagnostic push) \
817 static_assert(true)
818
819#define TOML_DISABLE_SWITCH_WARNINGS \
820 TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch") \
821 TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum") \
822 TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default") \
823 static_assert(true)
824
825#define TOML_DISABLE_ARITHMETIC_WARNINGS \
826 TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal") \
827 TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion") \
828 TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \
829 static_assert(true)
830
831#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \
832 TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const") \
833 TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure") \
834 static_assert(true)
835
836#define TOML_DISABLE_SPAM_WARNINGS \
837 TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded") \
838 TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align") \
839 TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment") \
840 TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits") \
841 TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast") \
842 TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \
843 TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage") \
844 TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers") \
845 TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized") \
846 TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept") \
847 TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference") \
848 TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches") \
849 static_assert(true)
850
851#define TOML_POP_WARNINGS \
852 TOML_PRAGMA_GCC(diagnostic pop) \
853 static_assert(true)
854
855#define TOML_DISABLE_WARNINGS \
856 TOML_PRAGMA_GCC(diagnostic push) \
857 TOML_PRAGMA_GCC(diagnostic ignored "-Wall") \
858 TOML_PRAGMA_GCC(diagnostic ignored "-Wextra") \
859 TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic") \
860 TOML_DISABLE_SWITCH_WARNINGS; \
861 TOML_DISABLE_ARITHMETIC_WARNINGS; \
862 TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \
863 TOML_DISABLE_SPAM_WARNINGS; \
864 static_assert(true)
865
866#define TOML_ENABLE_WARNINGS \
867 TOML_PRAGMA_GCC(diagnostic pop) \
868 static_assert(true)
869
870#endif
871
872#ifndef TOML_PUSH_WARNINGS
873#define TOML_PUSH_WARNINGS static_assert(true)
874#endif
875#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
876#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
877#endif
878#ifndef TOML_DISABLE_SWITCH_WARNINGS
879#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true)
880#endif
881#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
882#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true)
883#endif
884#ifndef TOML_DISABLE_SPAM_WARNINGS
885#define TOML_DISABLE_SPAM_WARNINGS static_assert(true)
886#endif
887#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
888#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true)
889#endif
890#ifndef TOML_POP_WARNINGS
891#define TOML_POP_WARNINGS static_assert(true)
892#endif
893#ifndef TOML_DISABLE_WARNINGS
894#define TOML_DISABLE_WARNINGS static_assert(true)
895#endif
896#ifndef TOML_ENABLE_WARNINGS
897#define TOML_ENABLE_WARNINGS static_assert(true)
898#endif
899#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
900#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0
901#endif
902
903#ifdef TOML_CONFIG_HEADER
904#include TOML_CONFIG_HEADER
905#endif
906
907// is the library being built as a shared lib/dll using meson and friends?
908#ifndef TOML_SHARED_LIB
909#define TOML_SHARED_LIB 0
910#endif
911
912// header-only mode
913#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0
914#define TOML_HEADER_ONLY TOML_ALL_INLINE
915#endif
916#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
917#undef TOML_HEADER_ONLY
918#define TOML_HEADER_ONLY 1
919#endif
920#if TOML_DOXYGEN || TOML_SHARED_LIB
921#undef TOML_HEADER_ONLY
922#define TOML_HEADER_ONLY 0
923#endif
924
925// internal implementation switch
926#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
927#undef TOML_IMPLEMENTATION
928#define TOML_IMPLEMENTATION 1
929#else
930#define TOML_IMPLEMENTATION 0
931#endif
932
933// dll/shared lib function exports (legacy - TOML_API was the old name for this setting)
934#if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && !defined(TOML_EXPORTED_STATIC_FUNCTION) \
935 && !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && defined(TOML_API)
936#define TOML_EXPORTED_MEMBER_FUNCTION TOML_API
937#define TOML_EXPORTED_STATIC_FUNCTION TOML_API
938#define TOML_EXPORTED_FREE_FUNCTION TOML_API
939#endif
940
941// dll/shared lib exports
942#if TOML_SHARED_LIB
943#undef TOML_API
944#undef TOML_EXPORTED_CLASS
945#undef TOML_EXPORTED_MEMBER_FUNCTION
946#undef TOML_EXPORTED_STATIC_FUNCTION
947#undef TOML_EXPORTED_FREE_FUNCTION
948#if TOML_WINDOWS
949#if TOML_IMPLEMENTATION
950#define TOML_EXPORTED_CLASS __declspec(dllexport)
951#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport)
952#else
953#define TOML_EXPORTED_CLASS __declspec(dllimport)
954#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport)
955#endif
956#ifndef TOML_CALLCONV
957#define TOML_CALLCONV __cdecl
958#endif
959#elif defined(__GNUC__) && __GNUC__ >= 4
960#define TOML_EXPORTED_CLASS __attribute__((visibility("default")))
961#define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default")))
962#define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default")))
963#define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default")))
964#endif
965#endif
966#ifndef TOML_EXPORTED_CLASS
967#define TOML_EXPORTED_CLASS
968#endif
969#ifndef TOML_EXPORTED_MEMBER_FUNCTION
970#define TOML_EXPORTED_MEMBER_FUNCTION
971#endif
972#ifndef TOML_EXPORTED_STATIC_FUNCTION
973#define TOML_EXPORTED_STATIC_FUNCTION
974#endif
975#ifndef TOML_EXPORTED_FREE_FUNCTION
976#define TOML_EXPORTED_FREE_FUNCTION
977#endif
978
979// experimental language features
980#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES
981 // pre-3.0
982#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES
983#endif
984#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE
985#undef TOML_ENABLE_UNRELEASED_FEATURES
986#define TOML_ENABLE_UNRELEASED_FEATURES 1
987#endif
988#ifndef TOML_ENABLE_UNRELEASED_FEATURES
989#define TOML_ENABLE_UNRELEASED_FEATURES 0
990#endif
991
992// parser
993#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0
994#define TOML_ENABLE_PARSER TOML_PARSER
995#endif
996#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE
997#undef TOML_ENABLE_PARSER
998#define TOML_ENABLE_PARSER 1
999#endif
1000
1001// formatters
1002#if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE
1003#undef TOML_ENABLE_FORMATTERS
1004#define TOML_ENABLE_FORMATTERS 1
1005#endif
1006
1007// SIMD
1008#if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE
1009#undef TOML_ENABLE_SIMD
1010#define TOML_ENABLE_SIMD 1
1011#endif
1012
1013// windows compat
1014#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0
1015#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT
1016#endif
1017#if !defined(TOML_ENABLE_WINDOWS_COMPAT) || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) \
1018 || TOML_INTELLISENSE
1019#undef TOML_ENABLE_WINDOWS_COMPAT
1020#define TOML_ENABLE_WINDOWS_COMPAT 1
1021#endif
1022
1023#if !TOML_WINDOWS
1024#undef TOML_ENABLE_WINDOWS_COMPAT
1025#define TOML_ENABLE_WINDOWS_COMPAT 0
1026#endif
1027
1028#ifndef TOML_INCLUDE_WINDOWS_H
1029#define TOML_INCLUDE_WINDOWS_H 0
1030#endif
1031
1032// custom optional
1033#ifdef TOML_OPTIONAL_TYPE
1034#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
1035#else
1036#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
1037#endif
1038
1039// exceptions (library use)
1040#if TOML_COMPILER_HAS_EXCEPTIONS
1041#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
1042#undef TOML_EXCEPTIONS
1043#define TOML_EXCEPTIONS 1
1044#endif
1045#else
1046#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS
1047#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler.
1048#endif
1049#undef TOML_EXCEPTIONS
1050#define TOML_EXCEPTIONS 0
1051#endif
1052
1053// calling convention for static/free/friend functions
1054#ifndef TOML_CALLCONV
1055#define TOML_CALLCONV
1056#endif
1057
1058#ifndef TOML_UNDEF_MACROS
1059#define TOML_UNDEF_MACROS 1
1060#endif
1061
1062#ifndef TOML_MAX_NESTED_VALUES
1063#define TOML_MAX_NESTED_VALUES 256
1064// this refers to the depth of nested values, e.g. inline tables and arrays.
1065// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
1066#endif
1067
1068#ifdef TOML_CHAR_8_STRINGS
1069#if TOML_CHAR_8_STRINGS
1070#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly.
1071#endif
1072#endif
1073
1074#ifdef TOML_LARGE_FILES
1075#if !TOML_LARGE_FILES
1076#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0.
1077#endif
1078#endif
1079
1080#ifndef TOML_LIFETIME_HOOKS
1081#define TOML_LIFETIME_HOOKS 0
1082#endif
1083
1084#ifdef NDEBUG
1085#undef TOML_ASSERT
1086#define TOML_ASSERT(expr) static_assert(true)
1087#endif
1088#ifndef TOML_ASSERT
1089#ifndef assert
1091#include <cassert>
1093#endif
1094#define TOML_ASSERT(expr) assert(expr)
1095#endif
1096#ifdef NDEBUG
1097#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr)
1098#else
1099#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr)
1100#endif
1101
1102#ifndef TOML_ENABLE_FLOAT16
1103#define TOML_ENABLE_FLOAT16 0
1104#endif
1105
1106#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL))
1107// not supported by any version of GCC or Clang as of 26/11/2020
1108// not supported by any version of ICC on Linux as of 11/01/2021
1109#define TOML_FLOAT_CHARCONV 0
1110#endif
1111#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__))
1112// causes link errors on emscripten
1113// causes Mac OS SDK version errors on some versions of Apple Clang
1114#define TOML_INT_CHARCONV 0
1115#endif
1116#ifndef TOML_INT_CHARCONV
1117#define TOML_INT_CHARCONV 1
1118#endif
1119#ifndef TOML_FLOAT_CHARCONV
1120#define TOML_FLOAT_CHARCONV 1
1121#endif
1122#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE(<charconv>)
1123#undef TOML_INT_CHARCONV
1124#undef TOML_FLOAT_CHARCONV
1125#define TOML_INT_CHARCONV 0
1126#define TOML_FLOAT_CHARCONV 0
1127#endif
1128
1129#if defined(__cpp_concepts) && __cpp_concepts >= 201907
1130#define TOML_REQUIRES(...) requires(__VA_ARGS__)
1131#else
1132#define TOML_REQUIRES(...)
1133#endif
1134#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0
1135#define TOML_CONSTRAINED_TEMPLATE(condition, ...) \
1136 template <__VA_ARGS__ TOML_ENABLE_IF(condition)> \
1137 TOML_REQUIRES(condition)
1138#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__)
1139
1140#if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && defined(__LDBL_MANT_DIG__) \
1141 && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__
1142#define TOML_FLOAT128 __float128
1143#endif
1144
1145#ifdef __SIZEOF_INT128__
1146#define TOML_INT128 __int128_t
1147#define TOML_UINT128 __uint128_t
1148#endif
1149
1150// clang-format off
1151
1152//******** impl/version.hpp ******************************************************************************************
1153
1154#define TOML_LIB_MAJOR 3
1155#define TOML_LIB_MINOR 4
1156#define TOML_LIB_PATCH 0
1157
1158#define TOML_LANG_MAJOR 1
1159#define TOML_LANG_MINOR 0
1160#define TOML_LANG_PATCH 0
1161
1162//******** impl/preprocessor.hpp *************************************************************************************
1163
1164#define TOML_LIB_SINGLE_HEADER 1
1165
1166#if TOML_ENABLE_UNRELEASED_FEATURES
1167 #define TOML_LANG_EFFECTIVE_VERSION \
1168 TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
1169#else
1170 #define TOML_LANG_EFFECTIVE_VERSION \
1171 TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
1172#endif
1173
1174#define TOML_LANG_HIGHER_THAN(major, minor, patch) \
1175 (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch))
1176
1177#define TOML_LANG_AT_LEAST(major, minor, patch) \
1178 (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch))
1179
1180#define TOML_LANG_UNRELEASED \
1181 TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
1182
1183#ifndef TOML_ABI_NAMESPACES
1184 #if TOML_DOXYGEN
1185 #define TOML_ABI_NAMESPACES 0
1186 #else
1187 #define TOML_ABI_NAMESPACES 1
1188 #endif
1189#endif
1190#if TOML_ABI_NAMESPACES
1191 #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR)
1192 #define TOML_NAMESPACE_END } static_assert(true)
1193 #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR)
1194 #define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true)
1195 #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F))
1196 #define TOML_ABI_NAMESPACE_END } static_assert(true)
1197#else
1198 #define TOML_NAMESPACE_START namespace toml
1199 #define TOML_NAMESPACE_END static_assert(true)
1200 #define TOML_NAMESPACE toml
1201 #define TOML_ABI_NAMESPACE_START(...) static_assert(true)
1202 #define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true)
1203 #define TOML_ABI_NAMESPACE_END static_assert(true)
1204#endif
1205#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl
1206#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END
1207#if TOML_HEADER_ONLY
1208 #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START
1209 #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END
1210 #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl
1211 #define TOML_EXTERNAL_LINKAGE inline
1212 #define TOML_INTERNAL_LINKAGE inline
1213#else
1214 #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \
1215 using namespace toml; \
1216 namespace
1217 #define TOML_ANON_NAMESPACE_END static_assert(true)
1218 #define TOML_ANON_NAMESPACE
1219 #define TOML_EXTERNAL_LINKAGE
1220 #define TOML_INTERNAL_LINKAGE static
1221#endif
1222
1223// clang-format on
1224
1225// clang-format off
1226
1227#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES
1228
1229 #define TOML_SA_NEWLINE " "
1230 #define TOML_SA_LIST_SEP ", "
1231 #define TOML_SA_LIST_BEG " ("
1232 #define TOML_SA_LIST_END ")"
1233 #define TOML_SA_LIST_NEW " "
1234 #define TOML_SA_LIST_NXT ", "
1235
1236#else
1237
1238 #define TOML_SA_NEWLINE "\n| "
1239 #define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - "
1240 #define TOML_SA_LIST_BEG TOML_SA_LIST_SEP
1241 #define TOML_SA_LIST_END
1242 #define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE
1243 #define TOML_SA_LIST_NXT TOML_SA_LIST_NEW
1244
1245#endif
1246
1247#define TOML_SA_NATIVE_VALUE_TYPE_LIST \
1248 TOML_SA_LIST_BEG "std::string" \
1249 TOML_SA_LIST_SEP "int64_t" \
1250 TOML_SA_LIST_SEP "double" \
1251 TOML_SA_LIST_SEP "bool" \
1252 TOML_SA_LIST_SEP "toml::date" \
1253 TOML_SA_LIST_SEP "toml::time" \
1254 TOML_SA_LIST_SEP "toml::date_time" \
1255 TOML_SA_LIST_END
1256
1257#define TOML_SA_NODE_TYPE_LIST \
1258 TOML_SA_LIST_BEG "toml::table" \
1259 TOML_SA_LIST_SEP "toml::array" \
1260 TOML_SA_LIST_SEP "toml::value<std::string>" \
1261 TOML_SA_LIST_SEP "toml::value<int64_t>" \
1262 TOML_SA_LIST_SEP "toml::value<double>" \
1263 TOML_SA_LIST_SEP "toml::value<bool>" \
1264 TOML_SA_LIST_SEP "toml::value<toml::date>" \
1265 TOML_SA_LIST_SEP "toml::value<toml::time>" \
1266 TOML_SA_LIST_SEP "toml::value<toml::date_time>" \
1267 TOML_SA_LIST_END
1268
1269#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \
1270 TOML_SA_LIST_NEW "A native TOML value type" \
1271 TOML_SA_NATIVE_VALUE_TYPE_LIST \
1272 \
1273 TOML_SA_LIST_NXT "A TOML node type" \
1274 TOML_SA_NODE_TYPE_LIST
1275
1276// clang-format on
1277
1282
1283// misc warning false-positives
1284#if TOML_MSVC
1285#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
1286#if TOML_SHARED_LIB
1287#pragma warning(disable : 4251) // dll exports for std lib types
1288#endif
1289#elif TOML_CLANG
1290TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene")
1291#if TOML_CLANG >= 12
1292TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions")
1293#endif
1294#if TOML_CLANG == 13
1295TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier")
1296#endif
1297#endif
1298
1299//******** impl/std_new.hpp ******************************************************************************************
1300
1302#include <new>
1304
1305#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914
1306#define TOML_LAUNDER(x) __builtin_launder(x)
1307#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
1308#define TOML_LAUNDER(x) std::launder(x)
1309#else
1310#define TOML_LAUNDER(x) x
1311#endif
1312
1313//******** impl/std_string.hpp ***************************************************************************************
1314
1316#include <string_view>
1317#include <string>
1319
1320#if TOML_DOXYGEN \
1321 || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \
1322 && __cpp_lib_char8_t >= 201907)
1323#define TOML_HAS_CHAR8 1
1324#else
1325#define TOML_HAS_CHAR8 0
1326#endif
1327
1328namespace toml // non-abi namespace; this is not an error
1329{
1330 using namespace std::string_literals;
1331 using namespace std::string_view_literals;
1332}
1333
1334#if TOML_ENABLE_WINDOWS_COMPAT
1335
1337{
1340 std::string narrow(std::wstring_view);
1341
1344 std::wstring widen(std::string_view);
1345
1346#if TOML_HAS_CHAR8
1347
1350 std::wstring widen(std::u8string_view);
1351
1352#endif
1353}
1355
1356#endif // TOML_ENABLE_WINDOWS_COMPAT
1357
1358//******** impl/std_optional.hpp *************************************************************************************
1359
1361#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
1362#include <optional>
1363#endif
1365
1367{
1368#if TOML_HAS_CUSTOM_OPTIONAL_TYPE
1369
1370 template <typename T>
1371 using optional = TOML_OPTIONAL_TYPE<T>;
1372
1373#else
1374
1375 template <typename T>
1376 using optional = std::optional<T>;
1377
1378#endif
1379}
1381
1382//******** impl/forward_declarations.hpp *****************************************************************************
1383
1385#include <cstdint>
1386#include <cstddef>
1387#include <cstring>
1388#include <cfloat>
1389#include <climits>
1390#include <cmath>
1391#include <limits>
1392#include <memory>
1393#include <iosfwd>
1394#include <type_traits>
1397#ifdef _MSC_VER
1398#ifndef __clang__
1399#pragma inline_recursion(on)
1400#endif
1401#pragma push_macro("min")
1402#pragma push_macro("max")
1403#undef min
1404#undef max
1405#endif
1406
1407#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS
1408#define TOML_ENV_MESSAGE \
1409 "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \
1410 "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \
1411 "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \
1412 "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \
1413 "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. " \
1414 "Thanks!"
1415
1416static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE);
1417#ifdef FLT_RADIX
1418static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE);
1419#endif
1420static_assert('A' == 65, TOML_ENV_MESSAGE);
1421static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE);
1422static_assert(std::numeric_limits<double>::is_iec559, TOML_ENV_MESSAGE);
1423static_assert(std::numeric_limits<double>::digits == 53, TOML_ENV_MESSAGE);
1424static_assert(std::numeric_limits<double>::digits10 == 15, TOML_ENV_MESSAGE);
1425static_assert(std::numeric_limits<double>::radix == 2, TOML_ENV_MESSAGE);
1426
1427#undef TOML_ENV_MESSAGE
1428#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS
1429
1430// undocumented forward declarations are hidden from doxygen because they fuck it up =/
1431
1432namespace toml // non-abi namespace; this is not an error
1433{
1434 using ::std::size_t;
1435 using ::std::intptr_t;
1436 using ::std::uintptr_t;
1437 using ::std::ptrdiff_t;
1438 using ::std::nullptr_t;
1439 using ::std::int8_t;
1440 using ::std::int16_t;
1441 using ::std::int32_t;
1442 using ::std::int64_t;
1443 using ::std::uint8_t;
1444 using ::std::uint16_t;
1445 using ::std::uint32_t;
1446 using ::std::uint64_t;
1447 using ::std::uint_least32_t;
1448 using ::std::uint_least64_t;
1449}
1450
1452{
1453 struct date;
1454 struct time;
1455 struct time_offset;
1456
1458 struct date_time;
1460
1461 struct source_position;
1462 struct source_region;
1463
1464 class node;
1465 template <typename>
1467
1468 class key;
1469 class array;
1470 class table;
1471 template <typename>
1472 class value;
1473
1474 class path;
1475
1476 class toml_formatter;
1477 class json_formatter;
1478 class yaml_formatter;
1479
1481#if TOML_EXCEPTIONS
1482 using parse_result = table;
1483#else
1484 class parse_result;
1485#endif
1486 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
1487}
1489
1491{
1492 using node_ptr = std::unique_ptr<node>;
1493
1495 class parser;
1496 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
1497
1498 // clang-format off
1499
1500 inline constexpr std::string_view control_char_escapes[] =
1501 {
1502 "\\u0000"sv,
1503 "\\u0001"sv,
1504 "\\u0002"sv,
1505 "\\u0003"sv,
1506 "\\u0004"sv,
1507 "\\u0005"sv,
1508 "\\u0006"sv,
1509 "\\u0007"sv,
1510 "\\b"sv,
1511 "\\t"sv,
1512 "\\n"sv,
1513 "\\u000B"sv,
1514 "\\f"sv,
1515 "\\r"sv,
1516 "\\u000E"sv,
1517 "\\u000F"sv,
1518 "\\u0010"sv,
1519 "\\u0011"sv,
1520 "\\u0012"sv,
1521 "\\u0013"sv,
1522 "\\u0014"sv,
1523 "\\u0015"sv,
1524 "\\u0016"sv,
1525 "\\u0017"sv,
1526 "\\u0018"sv,
1527 "\\u0019"sv,
1528 "\\u001A"sv,
1529 "\\u001B"sv,
1530 "\\u001C"sv,
1531 "\\u001D"sv,
1532 "\\u001E"sv,
1533 "\\u001F"sv,
1534 };
1535
1536 inline constexpr std::string_view node_type_friendly_names[] =
1537 {
1538 "none"sv,
1539 "table"sv,
1540 "array"sv,
1541 "string"sv,
1542 "integer"sv,
1543 "floating-point"sv,
1544 "boolean"sv,
1545 "date"sv,
1546 "time"sv,
1547 "date-time"sv
1548 };
1549
1550 // clang-format on
1551}
1553
1554#if TOML_ABI_NAMESPACES
1555#if TOML_EXCEPTIONS
1556#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser
1557#else
1558#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser
1559#endif
1560#else
1561#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser
1562#endif
1563
1564namespace toml
1565{
1566}
1567
1568TOML_NAMESPACE_START // abi namespace
1569{
1570 inline namespace literals
1571 {
1572 }
1573
1574 enum class TOML_CLOSED_ENUM node_type : uint8_t
1575 {
1576 none,
1577 table,
1578 array,
1579 string,
1580 integer,
1581 floating_point,
1582 boolean,
1583 date,
1584 time,
1585 date_time
1586 };
1587
1588 template <typename Char>
1589 inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, node_type rhs)
1590 {
1591 const auto str = impl::node_type_friendly_names[static_cast<std::underlying_type_t<node_type>>(rhs)];
1592 using str_char_t = decltype(str)::value_type;
1593 if constexpr (std::is_same_v<Char, str_char_t>)
1594 return lhs << str;
1595 else
1596 {
1597 if constexpr (sizeof(Char) == sizeof(str_char_t))
1598 return lhs << std::basic_string_view<Char>{ reinterpret_cast<const Char*>(str.data()), str.length() };
1599 else
1600 return lhs << str.data();
1601 }
1602 }
1603
1604 enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error
1605 {
1606 none,
1610 };
1612
1614 POXY_IMPLEMENTATION_DETAIL(value_flags{ static_cast<std::underlying_type_t<value_flags>>(-1) });
1615
1617 {
1618 none,
1628 indent_sub_tables = (1ull << 9),
1633 };
1635
1636 template <typename T>
1638 {
1639 static_assert(std::is_reference_v<T>);
1640
1642 };
1643 template <typename T>
1645 template <typename T>
1647
1648 using default_formatter = toml_formatter;
1649}
1651
1653{
1654 template <typename T>
1655 using remove_cvref = std::remove_cv_t<std::remove_reference_t<T>>;
1656
1657 template <typename... T>
1658 using common_signed_type = std::common_type_t<std::make_signed_t<T>...>;
1659
1660 template <typename T, typename... U>
1661 inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, U>);
1662
1663 template <typename... T>
1664 inline constexpr bool all_integral = (std::is_integral_v<T> && ...);
1665
1666 template <typename T>
1667 inline constexpr bool is_cvref = std::is_reference_v<T> || std::is_const_v<T> || std::is_volatile_v<T>;
1668
1669 template <typename T>
1670 inline constexpr bool is_wide_string =
1671 is_one_of<std::decay_t<T>, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>;
1672
1673 template <typename T>
1674 inline constexpr bool value_retrieval_is_nothrow = !std::is_same_v<remove_cvref<T>, std::string>
1675#if TOML_HAS_CHAR8
1676 && !std::is_same_v<remove_cvref<T>, std::u8string>
1677#endif
1678
1680
1681 template <typename, typename>
1682 struct copy_ref_;
1683 template <typename Dest, typename Src>
1685
1686 template <typename Dest, typename Src>
1688 {
1689 using type = Dest;
1690 };
1691
1692 template <typename Dest, typename Src>
1693 struct copy_ref_<Dest, Src&>
1694 {
1695 using type = std::add_lvalue_reference_t<Dest>;
1696 };
1697
1698 template <typename Dest, typename Src>
1699 struct copy_ref_<Dest, Src&&>
1700 {
1701 using type = std::add_rvalue_reference_t<Dest>;
1702 };
1703
1704 template <typename, typename>
1705 struct copy_cv_;
1706 template <typename Dest, typename Src>
1708
1709 template <typename Dest, typename Src>
1711 {
1712 using type = Dest;
1713 };
1714
1715 template <typename Dest, typename Src>
1716 struct copy_cv_<Dest, const Src>
1717 {
1718 using type = std::add_const_t<Dest>;
1719 };
1720
1721 template <typename Dest, typename Src>
1722 struct copy_cv_<Dest, volatile Src>
1723 {
1724 using type = std::add_volatile_t<Dest>;
1725 };
1726
1727 template <typename Dest, typename Src>
1728 struct copy_cv_<Dest, const volatile Src>
1729 {
1730 using type = std::add_cv_t<Dest>;
1731 };
1732
1733 template <typename Dest, typename Src>
1735 copy_ref<copy_ref<copy_cv<std::remove_reference_t<Dest>, std::remove_reference_t<Src>>, Dest>, Src>;
1736
1737 template <typename...>
1738 inline constexpr bool always_false = false;
1739
1740 template <typename T, typename... U>
1741 inline constexpr bool first_is_same = false;
1742 template <typename T, typename... U>
1743 inline constexpr bool first_is_same<T, T, U...> = true;
1744
1745 template <typename T, bool = std::is_enum_v<T>>
1747 {
1748 using type = std::underlying_type_t<T>;
1749 };
1750 template <typename T>
1751 struct underlying_type_<T, false>
1752 {
1753 using type = T;
1754 };
1755 template <typename T>
1757
1758 // general value traits
1759 // (as they relate to their equivalent native TOML type)
1761 {
1762 using native_type = void;
1763 static constexpr bool is_native = false;
1764 static constexpr bool is_losslessly_convertible_to_native = false;
1765 static constexpr bool can_represent_native = false;
1766 static constexpr bool can_partially_represent_native = false;
1767 static constexpr auto type = node_type::none;
1768 };
1769
1770 template <typename T>
1771 struct value_traits;
1772
1773 template <typename T, bool = std::is_enum_v<T>>
1775 {
1776 static_assert(!is_cvref<T>);
1777
1779 };
1780 template <typename T>
1782 {
1783 static_assert(!is_cvref<T>);
1784
1786 };
1787
1788 template <typename T>
1791 template <typename T>
1792 struct value_traits<const T> : value_traits<T>
1793 {};
1794 template <typename T>
1795 struct value_traits<volatile T> : value_traits<T>
1796 {};
1797 template <typename T>
1798 struct value_traits<const volatile T> : value_traits<T>
1799 {};
1800 template <typename T>
1802 {};
1803 template <typename T>
1805 {};
1806
1807 // integer value_traits specializations - standard types
1808 template <typename T>
1810 {
1811 static constexpr T min = T{ (std::numeric_limits<underlying_type<T>>::min)() };
1812 static constexpr T max = T{ (std::numeric_limits<underlying_type<T>>::max)() };
1813 };
1814 template <typename T>
1816 {
1817 using native_type = int64_t;
1818 static constexpr bool is_native = std::is_same_v<underlying_type<T>, native_type>;
1819 static constexpr bool is_signed = static_cast<underlying_type<T>>(-1) < underlying_type<T>{};
1820 static constexpr auto type = node_type::integer;
1821 static constexpr bool can_partially_represent_native = true;
1822 };
1823 template <typename T>
1825 {
1827 integer_limits<underlying_type<T>>::max <= 9223372036854775807ULL;
1828 static constexpr bool can_represent_native = false;
1829 };
1830 template <typename T>
1832 {
1833 using native_type = int64_t;
1835 integer_limits<underlying_type<T>>::min >= (-9223372036854775807LL - 1LL)
1836 && integer_limits<underlying_type<T>>::max <= 9223372036854775807LL;
1837 static constexpr bool can_represent_native =
1838 integer_limits<underlying_type<T>>::min <= (-9223372036854775807LL - 1LL)
1839 && integer_limits<underlying_type<T>>::max >= 9223372036854775807LL;
1840 };
1841 template <typename T, bool S = integer_traits_base<T>::is_signed>
1844 template <typename T>
1846 {};
1847 template <>
1848 struct value_traits<signed char> : integer_traits<signed char>
1849 {};
1850 template <>
1851 struct value_traits<unsigned char> : integer_traits<unsigned char>
1852 {};
1853 template <>
1854 struct value_traits<signed short> : integer_traits<signed short>
1855 {};
1856 template <>
1857 struct value_traits<unsigned short> : integer_traits<unsigned short>
1858 {};
1859 template <>
1860 struct value_traits<signed int> : integer_traits<signed int>
1861 {};
1862 template <>
1863 struct value_traits<unsigned int> : integer_traits<unsigned int>
1864 {};
1865 template <>
1866 struct value_traits<signed long> : integer_traits<signed long>
1867 {};
1868 template <>
1869 struct value_traits<unsigned long> : integer_traits<unsigned long>
1870 {};
1871 template <>
1872 struct value_traits<signed long long> : integer_traits<signed long long>
1873 {};
1874 template <>
1875 struct value_traits<unsigned long long> : integer_traits<unsigned long long>
1876 {};
1877 static_assert(value_traits<int64_t>::is_native);
1878 static_assert(value_traits<int64_t>::is_signed);
1882
1883 // integer value_traits specializations - non-standard types
1884#ifdef TOML_INT128
1885 template <>
1886 struct integer_limits<TOML_INT128>
1887 {
1888 static constexpr TOML_INT128 max =
1889 static_cast<TOML_INT128>((TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1);
1890 static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 };
1891 };
1892 template <>
1893 struct integer_limits<TOML_UINT128>
1894 {
1895 static constexpr TOML_UINT128 min = TOML_UINT128{};
1896 static constexpr TOML_UINT128 max = (2u * static_cast<TOML_UINT128>(integer_limits<TOML_INT128>::max)) + 1u;
1897 };
1898 template <>
1899 struct value_traits<TOML_INT128> : integer_traits<TOML_INT128>
1900 {};
1901 template <>
1902 struct value_traits<TOML_UINT128> : integer_traits<TOML_UINT128>
1903 {};
1904#endif
1905#ifdef TOML_SMALL_INT_TYPE
1906 template <>
1907 struct value_traits<TOML_SMALL_INT_TYPE> : signed_integer_traits<TOML_SMALL_INT_TYPE>
1908 {};
1909#endif
1910
1911 // floating-point traits base
1912 template <typename T, int MantissaDigits, int DecimalDigits>
1914 {
1915 static constexpr auto type = node_type::floating_point;
1916 using native_type = double;
1917 static constexpr bool is_native = std::is_same_v<T, native_type>;
1918 static constexpr bool is_signed = true;
1919
1920 static constexpr int bits = static_cast<int>(sizeof(T) * CHAR_BIT);
1921 static constexpr int digits = MantissaDigits;
1922 static constexpr int digits10 = DecimalDigits;
1923
1924 static constexpr bool is_losslessly_convertible_to_native = bits <= 64 //
1925 && digits <= 53 // DBL_MANT_DIG
1926 && digits10 <= 15; // DBL_DIG
1927
1928 static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG
1929 && digits10 >= 15; // DBL_DIG
1930
1931 static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0;
1932 };
1933 template <typename T>
1934 struct float_traits : float_traits_base<T, std::numeric_limits<T>::digits, std::numeric_limits<T>::digits10>
1935 {};
1936#if TOML_ENABLE_FLOAT16
1937 template <>
1938 struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__>
1939 {};
1940#endif
1941#ifdef TOML_FLOAT128
1942 template <>
1943 struct float_traits<TOML_FLOAT128> : float_traits_base<TOML_FLOAT128, __FLT128_MANT_DIG__, __FLT128_DIG__>
1944 {};
1945#endif
1946
1947 // floating-point traits
1948 template <>
1949 struct value_traits<float> : float_traits<float>
1950 {};
1951 template <>
1952 struct value_traits<double> : float_traits<double>
1953 {};
1954 template <>
1955 struct value_traits<long double> : float_traits<long double>
1956 {};
1957#if TOML_ENABLE_FLOAT16
1958 template <>
1959 struct value_traits<_Float16> : float_traits<_Float16>
1960 {};
1961#endif
1962#ifdef TOML_FLOAT128
1963 template <>
1964 struct value_traits<TOML_FLOAT128> : float_traits<TOML_FLOAT128>
1965 {};
1966#endif
1967#ifdef TOML_SMALL_FLOAT_TYPE
1968 template <>
1969 struct value_traits<TOML_SMALL_FLOAT_TYPE> : float_traits<TOML_SMALL_FLOAT_TYPE>
1970 {};
1971#endif
1972 static_assert(value_traits<double>::is_native);
1976
1977 // string value_traits specializations - char-based strings
1978 template <typename T>
1980 {
1981 using native_type = std::string;
1982 static constexpr bool is_native = std::is_same_v<T, native_type>;
1983 static constexpr bool is_losslessly_convertible_to_native = true;
1984 static constexpr bool can_represent_native =
1985 !std::is_array_v<T> && (!std::is_pointer_v<T> || std::is_const_v<std::remove_pointer_t<T>>);
1987 static constexpr auto type = node_type::string;
1988 };
1989 template <>
1990 struct value_traits<std::string> : string_traits<std::string>
1991 {};
1992 template <>
1993 struct value_traits<std::string_view> : string_traits<std::string_view>
1994 {};
1995 template <>
1997 {};
1998 template <size_t N>
1999 struct value_traits<const char[N]> : string_traits<const char[N]>
2000 {};
2001 template <>
2003 {};
2004 template <size_t N>
2005 struct value_traits<char[N]> : string_traits<char[N]>
2006 {};
2007
2008 // string value_traits specializations - char8_t-based strings
2009#if TOML_HAS_CHAR8
2010 template <>
2011 struct value_traits<std::u8string> : string_traits<std::u8string>
2012 {};
2013 template <>
2014 struct value_traits<std::u8string_view> : string_traits<std::u8string_view>
2015 {};
2016 template <>
2017 struct value_traits<const char8_t*> : string_traits<const char8_t*>
2018 {};
2019 template <size_t N>
2020 struct value_traits<const char8_t[N]> : string_traits<const char8_t[N]>
2021 {};
2022 template <>
2023 struct value_traits<char8_t*> : string_traits<char8_t*>
2024 {};
2025 template <size_t N>
2026 struct value_traits<char8_t[N]> : string_traits<char8_t[N]>
2027 {};
2028#endif
2029
2030 // string value_traits specializations - wchar_t-based strings on Windows
2031#if TOML_ENABLE_WINDOWS_COMPAT
2032 template <typename T>
2033 struct wstring_traits
2034 {
2035 using native_type = std::string;
2036 static constexpr bool is_native = false;
2037 static constexpr bool is_losslessly_convertible_to_native = true; // narrow
2038 static constexpr bool can_represent_native = std::is_same_v<T, std::wstring>; // widen
2040 static constexpr auto type = node_type::string;
2041 };
2042 template <>
2043 struct value_traits<std::wstring> : wstring_traits<std::wstring>
2044 {};
2045 template <>
2046 struct value_traits<std::wstring_view> : wstring_traits<std::wstring_view>
2047 {};
2048 template <>
2049 struct value_traits<const wchar_t*> : wstring_traits<const wchar_t*>
2050 {};
2051 template <size_t N>
2052 struct value_traits<const wchar_t[N]> : wstring_traits<const wchar_t[N]>
2053 {};
2054 template <>
2055 struct value_traits<wchar_t*> : wstring_traits<wchar_t*>
2056 {};
2057 template <size_t N>
2058 struct value_traits<wchar_t[N]> : wstring_traits<wchar_t[N]>
2059 {};
2060#endif
2061
2062 // other 'native' value_traits specializations
2063 template <typename T, node_type NodeType>
2065 {
2066 using native_type = T;
2067 static constexpr bool is_native = true;
2068 static constexpr bool is_losslessly_convertible_to_native = true;
2069 static constexpr bool can_represent_native = true;
2070 static constexpr bool can_partially_represent_native = true;
2071 static constexpr auto type = NodeType;
2072 };
2073 template <>
2074 struct value_traits<bool> : native_value_traits<bool, node_type::boolean>
2075 {};
2076 template <>
2077 struct value_traits<date> : native_value_traits<date, node_type::date>
2078 {};
2079 template <>
2080 struct value_traits<time> : native_value_traits<time, node_type::time>
2081 {};
2082 template <>
2083 struct value_traits<date_time> : native_value_traits<date_time, node_type::date_time>
2084 {};
2085
2086 // native value category queries
2087 template <typename T>
2089 template <typename T>
2090 inline constexpr bool is_native = value_traits<T>::is_native;
2091 template <typename T>
2093 template <typename T>
2095 template <typename T>
2097 template <typename T, typename... U>
2098 inline constexpr bool is_natively_one_of = is_one_of<native_type_of<T>, U...>;
2099
2100 // native value types => nodes
2101 template <typename T>
2103 {
2104 using type = T;
2105 };
2106 template <typename T>
2107 struct node_wrapper<const T>
2108 {
2109 using type = std::add_const_t<typename node_wrapper<T>::type>;
2110 };
2111 template <typename T>
2112 struct node_wrapper<volatile T>
2113 {
2114 using type = std::add_volatile_t<typename node_wrapper<T>::type>;
2115 };
2116 template <typename T>
2117 struct node_wrapper<const volatile T>
2118 {
2119 using type = std::add_const_t<std::add_volatile_t<typename node_wrapper<T>::type>>;
2120 };
2121 template <>
2122 struct node_wrapper<std::string>
2123 {
2125 };
2126 template <>
2127 struct node_wrapper<int64_t>
2128 {
2130 };
2131 template <>
2132 struct node_wrapper<double>
2133 {
2135 };
2136 template <>
2137 struct node_wrapper<bool>
2138 {
2140 };
2141 template <>
2142 struct node_wrapper<date>
2143 {
2145 };
2146 template <>
2148 {
2150 };
2151 template <>
2153 {
2155 };
2156 template <typename T>
2158
2159 // nodes => native value types
2160 template <typename T>
2162 {
2163 using type = T;
2164 };
2165 template <typename T>
2167 {
2168 using type = T;
2169 };
2170 template <typename T>
2171 struct node_unwrapper<const value<T>>
2172 {
2173 using type = std::add_const_t<T>;
2174 };
2175 template <typename T>
2176 struct node_unwrapper<volatile value<T>>
2177 {
2178 using type = std::add_volatile_t<T>;
2179 };
2180 template <typename T>
2181 struct node_unwrapper<const volatile value<T>>
2182 {
2183 using type = std::add_volatile_t<std::add_const_t<T>>;
2184 };
2185 template <typename T>
2187
2188 template <typename T>
2190 {
2191 static constexpr auto value = value_traits<T>::type;
2192 };
2193 template <>
2195 {
2196 static constexpr auto value = node_type::table;
2197 };
2198 template <>
2200 {
2201 static constexpr auto value = node_type::array;
2202 };
2203 template <>
2204 struct node_type_getter<void>
2205 {
2206 static constexpr auto value = node_type::none;
2207 };
2208 template <typename T>
2210
2211 template <typename T, typename ConvertFrom>
2212 inline constexpr bool is_constructible_or_convertible = std::is_constructible_v<T, ConvertFrom> //
2213 || std::is_convertible_v<ConvertFrom, T>;
2214}
2216
2218{
2219 template <typename T>
2220 inline constexpr bool is_table = std::is_same_v<impl::remove_cvref<T>, table>;
2221
2222 template <typename T>
2223 inline constexpr bool is_array = std::is_same_v<impl::remove_cvref<T>, array>;
2224
2225 template <typename T>
2226 inline constexpr bool is_container = is_table<T> || is_array<T>;
2227
2228 template <typename T>
2229 inline constexpr bool is_string = std::is_same_v< //
2230 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2232
2233 template <typename T>
2234 inline constexpr bool is_integer = std::is_same_v< //
2235 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2237
2238 template <typename T>
2239 inline constexpr bool is_floating_point = std::is_same_v< //
2240 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2242
2243 template <typename T>
2245
2246 template <typename T>
2247 inline constexpr bool is_boolean = std::is_same_v< //
2248 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2249 value<bool>>;
2250
2251 template <typename T>
2252 inline constexpr bool is_date = std::is_same_v< //
2253 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2254 value<date>>;
2255
2256 template <typename T>
2257 inline constexpr bool is_time = std::is_same_v< //
2258 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2259 value<time>>;
2260
2261 template <typename T>
2262 inline constexpr bool is_date_time = std::is_same_v< //
2263 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2265
2266 template <typename T>
2268
2269 template <typename T>
2271
2272 template <typename T>
2273 inline constexpr bool is_node = std::is_same_v<toml::node, impl::remove_cvref<T>> //
2274 || std::is_base_of_v<toml::node, impl::remove_cvref<T>>;
2275
2276 template <typename T>
2277 inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref<T>, node_view<node>, node_view<const node>>;
2278}
2280
2282{
2283 template <typename T>
2285 constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept
2286 {
2287 return static_cast<std::underlying_type_t<T>>(val);
2288 }
2289
2290 // Q: "why not use std::fpclassify?"
2291 // A: Because it gets broken by -ffast-math and friends
2292 enum class TOML_CLOSED_ENUM fp_class : unsigned
2293 {
2294 ok,
2295 neg_inf,
2296 pos_inf,
2297 nan
2298 };
2299
2301 inline fp_class fpclassify(const double& val) noexcept
2302 {
2303 static_assert(sizeof(uint64_t) == sizeof(double));
2304
2305 static constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
2306 static constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
2307 static constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
2308
2309 uint64_t val_bits;
2310 std::memcpy(&val_bits, &val, sizeof(val));
2311 if ((val_bits & exponent) != exponent)
2312 return fp_class::ok;
2313 if ((val_bits & mantissa))
2314 return fp_class::nan;
2315 return (val_bits & sign) ? fp_class::neg_inf : fp_class::pos_inf;
2316 }
2317
2318 // Q: "why not use std::find and std::min?"
2319 // A: Because <algorithm> is _huge_ and these would be the only things I used from it.
2320 // I don't want to impose such a heavy compile-time burden on users.
2321
2322 template <typename Iterator, typename T>
2324 inline auto find(Iterator start, Iterator end, const T& needle) noexcept //
2325 ->decltype(&(*start))
2326 {
2327 for (; start != end; start++)
2328 if (*start == needle)
2329 return &(*start);
2330 return nullptr;
2331 }
2332
2333 template <typename T>
2335 constexpr const T& min(const T& a, const T& b) noexcept //
2336 {
2337 return a < b ? a : b;
2338 }
2339}
2341
2342#ifdef _MSC_VER
2343#pragma pop_macro("min")
2344#pragma pop_macro("max")
2345#ifndef __clang__
2346#pragma inline_recursion(off)
2347#endif
2348#endif
2350
2351//******** impl/print_to_stream.hpp **********************************************************************************
2352
2354#ifdef _MSC_VER
2355#ifndef __clang__
2356#pragma inline_recursion(on)
2357#endif
2358#pragma push_macro("min")
2359#pragma push_macro("max")
2360#undef min
2361#undef max
2362#endif
2363
2365{
2366 // Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
2367 // A: - I'm using <charconv> to format numerics. Faster and locale-independent.
2368 // - I can (potentially) avoid forcing users to drag in <sstream> and <iomanip>.
2369 // - Strings in C++. Honestly.
2370
2372 TOML_ATTR(nonnull)
2373 void TOML_CALLCONV print_to_stream(std::ostream&, const char*, size_t);
2374
2376 void TOML_CALLCONV print_to_stream(std::ostream&, std::string_view);
2377
2379 void TOML_CALLCONV print_to_stream(std::ostream&, const std::string&);
2380
2382 void TOML_CALLCONV print_to_stream(std::ostream&, char);
2383
2385 void TOML_CALLCONV print_to_stream(std::ostream&, signed char, value_flags = {}, size_t min_digits = 0);
2386
2388 void TOML_CALLCONV print_to_stream(std::ostream&, signed short, value_flags = {}, size_t min_digits = 0);
2389
2391 void TOML_CALLCONV print_to_stream(std::ostream&, signed int, value_flags = {}, size_t min_digits = 0);
2392
2394 void TOML_CALLCONV print_to_stream(std::ostream&, signed long, value_flags = {}, size_t min_digits = 0);
2395
2397 void TOML_CALLCONV print_to_stream(std::ostream&, signed long long, value_flags = {}, size_t min_digits = 0);
2398
2400 void TOML_CALLCONV print_to_stream(std::ostream&, unsigned char, value_flags = {}, size_t min_digits = 0);
2401
2403 void TOML_CALLCONV print_to_stream(std::ostream&, unsigned short, value_flags = {}, size_t min_digits = 0);
2404
2406 void TOML_CALLCONV print_to_stream(std::ostream&, unsigned int, value_flags = {}, size_t min_digits = 0);
2407
2409 void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long, value_flags = {}, size_t min_digits = 0);
2410
2412 void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long long, value_flags = {}, size_t min_digits = 0);
2413
2415 void TOML_CALLCONV print_to_stream(std::ostream&, float, value_flags = {}, bool relaxed_precision = false);
2416
2418 void TOML_CALLCONV print_to_stream(std::ostream&, double, value_flags = {}, bool relaxed_precision = false);
2419
2421 void TOML_CALLCONV print_to_stream(std::ostream&, bool);
2422
2424 void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date&);
2425
2427 void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time&);
2428
2430 void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time_offset&);
2431
2433 void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date_time&);
2434
2436 void TOML_CALLCONV print_to_stream(std::ostream&, const source_position&);
2437
2439 void TOML_CALLCONV print_to_stream(std::ostream&, const source_region&);
2440
2441#if TOML_ENABLE_FORMATTERS
2442
2444 void TOML_CALLCONV print_to_stream(std::ostream&, const array&);
2445
2447 void TOML_CALLCONV print_to_stream(std::ostream&, const table&);
2448
2451
2453 void TOML_CALLCONV print_to_stream(std::ostream&, const value<int64_t>&);
2454
2456 void TOML_CALLCONV print_to_stream(std::ostream&, const value<double>&);
2457
2459 void TOML_CALLCONV print_to_stream(std::ostream&, const value<bool>&);
2460
2462 void TOML_CALLCONV print_to_stream(std::ostream&, const value<date>&);
2463
2465 void TOML_CALLCONV print_to_stream(std::ostream&, const value<time>&);
2466
2469
2470#endif
2471
2472 template <typename T, typename U>
2473 inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend)
2474 {
2475 print_to_stream(stream, bookend);
2476 print_to_stream(stream, val);
2477 print_to_stream(stream, bookend);
2478 }
2479}
2481
2482#ifdef _MSC_VER
2483#pragma pop_macro("min")
2484#pragma pop_macro("max")
2485#ifndef __clang__
2486#pragma inline_recursion(off)
2487#endif
2488#endif
2490
2491//******** impl/source_region.hpp ************************************************************************************
2492
2494#ifdef _MSC_VER
2495#ifndef __clang__
2496#pragma inline_recursion(on)
2497#endif
2498#pragma push_macro("min")
2499#pragma push_macro("max")
2500#undef min
2501#undef max
2502#endif
2503
2505{
2506 using source_index = uint32_t;
2507
2508 using source_path_ptr = std::shared_ptr<const std::string>;
2509
2511 {
2512 source_index line;
2513
2514 source_index column;
2515
2517 explicit constexpr operator bool() const noexcept
2518 {
2519 return line > source_index{} //
2520 && column > source_index{};
2521 }
2522
2524 friend constexpr bool operator==(const source_position& lhs, const source_position& rhs) noexcept
2525 {
2526 return lhs.line == rhs.line //
2527 && lhs.column == rhs.column;
2528 }
2529
2531 friend constexpr bool operator!=(const source_position& lhs, const source_position& rhs) noexcept
2532 {
2533 return !(lhs == rhs);
2534 }
2535
2536 private:
2537
2539 static constexpr uint64_t pack(const source_position& pos) noexcept
2540 {
2541 return static_cast<uint64_t>(pos.line) << 32 | static_cast<uint64_t>(pos.column);
2542 }
2543
2544 public:
2545
2547 friend constexpr bool operator<(const source_position& lhs, const source_position& rhs) noexcept
2548 {
2549 return pack(lhs) < pack(rhs);
2550 }
2551
2553 friend constexpr bool operator<=(const source_position& lhs, const source_position& rhs) noexcept
2554 {
2555 return pack(lhs) <= pack(rhs);
2556 }
2557
2559 friend constexpr bool operator>(const source_position& lhs, const source_position& rhs) noexcept
2560 {
2561 return pack(lhs) > pack(rhs);
2562 }
2563
2565 friend constexpr bool operator>=(const source_position& lhs, const source_position& rhs) noexcept
2566 {
2567 return pack(lhs) >= pack(rhs);
2568 }
2569
2570 friend std::ostream& operator<<(std::ostream& lhs, const source_position& rhs)
2571 {
2572 impl::print_to_stream(lhs, rhs);
2573 return lhs;
2574 }
2575 };
2576
2578 {
2580
2582
2584
2585#if TOML_ENABLE_WINDOWS_COMPAT
2586
2588 optional<std::wstring> wide_path() const
2589 {
2590 if (!path || path->empty())
2591 return {};
2592 return { impl::widen(*path) };
2593 }
2594
2595#endif
2596
2597 friend std::ostream& operator<<(std::ostream& lhs, const source_region& rhs)
2598 {
2599 impl::print_to_stream(lhs, rhs);
2600 return lhs;
2601 }
2602 };
2603}
2605
2606#ifdef _MSC_VER
2607#pragma pop_macro("min")
2608#pragma pop_macro("max")
2609#ifndef __clang__
2610#pragma inline_recursion(off)
2611#endif
2612#endif
2614
2615//******** impl/date_time.hpp ****************************************************************************************
2616
2618#ifdef _MSC_VER
2619#ifndef __clang__
2620#pragma inline_recursion(on)
2621#endif
2622#pragma push_macro("min")
2623#pragma push_macro("max")
2624#undef min
2625#undef max
2626#endif
2627
2629{
2630 struct TOML_TRIVIAL_ABI date
2631 {
2632 uint16_t year;
2633
2634 uint8_t month;
2635
2636 uint8_t day;
2637
2639 date() noexcept = default;
2640
2641 TOML_CONSTRAINED_TEMPLATE((impl::all_integral<Y, M, D>), typename Y, typename M, typename D)
2643 constexpr date(Y y, M m, D d) noexcept //
2644 : year{ static_cast<uint16_t>(y) },
2645 month{ static_cast<uint8_t>(m) },
2646 day{ static_cast<uint8_t>(d) }
2647 {}
2648
2650 friend constexpr bool operator==(const date& lhs, const date& rhs) noexcept
2651 {
2652 return lhs.year == rhs.year //
2653 && lhs.month == rhs.month //
2654 && lhs.day == rhs.day;
2655 }
2656
2658 friend constexpr bool operator!=(const date& lhs, const date& rhs) noexcept
2659 {
2660 return !(lhs == rhs);
2661 }
2662
2663 private:
2664
2666 static constexpr uint32_t pack(const date& d) noexcept
2667 {
2668 return (static_cast<uint32_t>(d.year) << 16) | (static_cast<uint32_t>(d.month) << 8)
2669 | static_cast<uint32_t>(d.day);
2670 }
2671
2672 public:
2673
2675 friend constexpr bool operator<(const date& lhs, const date& rhs) noexcept
2676 {
2677 return pack(lhs) < pack(rhs);
2678 }
2679
2681 friend constexpr bool operator<=(const date& lhs, const date& rhs) noexcept
2682 {
2683 return pack(lhs) <= pack(rhs);
2684 }
2685
2687 friend constexpr bool operator>(const date& lhs, const date& rhs) noexcept
2688 {
2689 return pack(lhs) > pack(rhs);
2690 }
2691
2693 friend constexpr bool operator>=(const date& lhs, const date& rhs) noexcept
2694 {
2695 return pack(lhs) >= pack(rhs);
2696 }
2697
2698 friend std::ostream& operator<<(std::ostream& lhs, const date& rhs)
2699 {
2700 impl::print_to_stream(lhs, rhs);
2701 return lhs;
2702 }
2703 };
2704
2706 {
2707 uint8_t hour;
2708
2709 uint8_t minute;
2710
2711 uint8_t second;
2712
2713 uint32_t nanosecond;
2714
2716 time() noexcept = default;
2717
2719 typename H,
2720 typename M,
2721 typename S = uint8_t,
2722 typename NS = uint32_t)
2724 constexpr time(H h, M m, S s = S{}, NS ns = NS{}) noexcept //
2725 : hour{ static_cast<uint8_t>(h) },
2726 minute{ static_cast<uint8_t>(m) },
2727 second{ static_cast<uint8_t>(s) },
2728 nanosecond{ static_cast<uint32_t>(ns) }
2729 {}
2730
2732 friend constexpr bool operator==(const time& lhs, const time& rhs) noexcept
2733 {
2734 return lhs.hour == rhs.hour //
2735 && lhs.minute == rhs.minute //
2736 && lhs.second == rhs.second //
2737 && lhs.nanosecond == rhs.nanosecond;
2738 }
2739
2741 friend constexpr bool operator!=(const time& lhs, const time& rhs) noexcept
2742 {
2743 return !(lhs == rhs);
2744 }
2745
2746 private:
2747
2749 static constexpr uint64_t pack(const time& t) noexcept
2750 {
2751 return static_cast<uint64_t>(t.hour) << 48 | static_cast<uint64_t>(t.minute) << 40
2752 | static_cast<uint64_t>(t.second) << 32 | static_cast<uint64_t>(t.nanosecond);
2753 }
2754
2755 public:
2756
2758 friend constexpr bool operator<(const time& lhs, const time& rhs) noexcept
2759 {
2760 return pack(lhs) < pack(rhs);
2761 }
2762
2764 friend constexpr bool operator<=(const time& lhs, const time& rhs) noexcept
2765 {
2766 return pack(lhs) <= pack(rhs);
2767 }
2768
2770 friend constexpr bool operator>(const time& lhs, const time& rhs) noexcept
2771 {
2772 return pack(lhs) > pack(rhs);
2773 }
2774
2776 friend constexpr bool operator>=(const time& lhs, const time& rhs) noexcept
2777 {
2778 return pack(lhs) >= pack(rhs);
2779 }
2780
2781 friend std::ostream& operator<<(std::ostream& lhs, const time& rhs)
2782 {
2783 impl::print_to_stream(lhs, rhs);
2784 return lhs;
2785 }
2786 };
2787
2789 {
2790 int16_t minutes;
2791
2793 time_offset() noexcept = default;
2794
2795 TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M>), typename H, typename M)
2797 constexpr time_offset(H h, M m) noexcept //
2798 : minutes{ static_cast<int16_t>(static_cast<impl::common_signed_type<H, M>>(h)
2799 * impl::common_signed_type<H, M>{ 60 }
2800 + static_cast<impl::common_signed_type<H, M>>(m)) }
2801 {}
2802
2804 friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
2805 {
2806 return lhs.minutes == rhs.minutes;
2807 }
2808
2810 friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
2811 {
2812 return lhs.minutes != rhs.minutes;
2813 }
2814
2816 friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
2817 {
2818 return lhs.minutes < rhs.minutes;
2819 }
2820
2822 friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
2823 {
2824 return lhs.minutes <= rhs.minutes;
2825 }
2826
2828 friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
2829 {
2830 return lhs.minutes > rhs.minutes;
2831 }
2832
2834 friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
2835 {
2836 return lhs.minutes >= rhs.minutes;
2837 }
2838
2839 friend std::ostream& operator<<(std::ostream& lhs, const time_offset& rhs)
2840 {
2841 impl::print_to_stream(lhs, rhs);
2842 return lhs;
2843 }
2844 };
2845
2847
2849 {
2850 toml::date date;
2851
2852 toml::time time;
2853
2854 optional<toml::time_offset> offset;
2855
2857 date_time() noexcept = default;
2858
2860 constexpr date_time(const toml::date& d, const toml::time& t) noexcept //
2861 : date{ d },
2862 time{ t },
2863 offset{} // TINAE - icc bugfix
2864 {}
2865
2867 explicit constexpr date_time(const toml::date& d) noexcept //
2868 : date{ d },
2869 time{},
2870 offset{} // TINAE - icc bugfix
2871 {}
2872
2874 explicit constexpr date_time(const toml::time& t) noexcept //
2875 : date{},
2876 time{ t },
2877 offset{} // TINAE - icc bugfix
2878 {}
2879
2881 constexpr date_time(const toml::date& d, const toml::time& t, const toml::time_offset& off) noexcept
2882 : date{ d },
2883 time{ t },
2884 offset{ off }
2885 {}
2886
2888 constexpr bool is_local() const noexcept
2889 {
2890 return !offset.has_value();
2891 }
2892
2894 friend constexpr bool operator==(const date_time& lhs, const date_time& rhs) noexcept
2895 {
2896 return lhs.date == rhs.date //
2897 && lhs.time == rhs.time //
2898 && lhs.offset == rhs.offset;
2899 }
2900
2902 friend constexpr bool operator!=(const date_time& lhs, const date_time& rhs) noexcept
2903 {
2904 return !(lhs == rhs);
2905 }
2906
2908 friend constexpr bool operator<(const date_time& lhs, const date_time& rhs) noexcept
2909 {
2910 if (lhs.date != rhs.date)
2911 return lhs.date < rhs.date;
2912 if (lhs.time != rhs.time)
2913 return lhs.time < rhs.time;
2914 return lhs.offset < rhs.offset;
2915 }
2916
2918 friend constexpr bool operator<=(const date_time& lhs, const date_time& rhs) noexcept
2919 {
2920 if (lhs.date != rhs.date)
2921 return lhs.date < rhs.date;
2922 if (lhs.time != rhs.time)
2923 return lhs.time < rhs.time;
2924 return lhs.offset <= rhs.offset;
2925 }
2926
2928 friend constexpr bool operator>(const date_time& lhs, const date_time& rhs) noexcept
2929 {
2930 return !(lhs <= rhs);
2931 }
2932
2934 friend constexpr bool operator>=(const date_time& lhs, const date_time& rhs) noexcept
2935 {
2936 return !(lhs < rhs);
2937 }
2938
2939 friend std::ostream& operator<<(std::ostream& lhs, const date_time& rhs)
2940 {
2941 impl::print_to_stream(lhs, rhs);
2942 return lhs;
2943 }
2944 };
2945
2946 TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
2947}
2949
2950#ifdef _MSC_VER
2951#pragma pop_macro("min")
2952#pragma pop_macro("max")
2953#ifndef __clang__
2954#pragma inline_recursion(off)
2955#endif
2956#endif
2958
2959//******** impl/at_path.hpp ******************************************************************************************
2960
2962{
2963 template <typename T>
2964 using parse_path_callback = bool(TOML_CALLCONV*)(void*, T);
2965
2967 bool TOML_CALLCONV parse_path(std::string_view,
2968 void*,
2969 parse_path_callback<std::string_view>,
2970 parse_path_callback<size_t>);
2971}
2973
2975{
2978 node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept;
2979
2982 node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept;
2983
2984#if TOML_ENABLE_WINDOWS_COMPAT
2985
2988 node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path);
2989
2992 node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path);
2993
2994#endif
2995}
2997
2998//******** impl/std_vector.hpp ***************************************************************************************
2999
3001#include <vector>
3002#include <iterator>
3004
3005//******** impl/path.hpp *********************************************************************************************
3006
3008#ifdef _MSC_VER
3009#ifndef __clang__
3010#pragma inline_recursion(on)
3011#endif
3012#pragma push_macro("min")
3013#pragma push_macro("max")
3014#undef min
3015#undef max
3016#endif
3017
3019{
3020 enum class TOML_CLOSED_ENUM path_component_type : uint8_t
3021 {
3022 key = 0x1,
3023 array_index = 0x2
3024 };
3025
3027 {
3029 {
3030 static constexpr size_t size =
3031 (sizeof(size_t) < sizeof(std::string) ? sizeof(std::string) : sizeof(size_t));
3032 static constexpr size_t align =
3033 (alignof(size_t) < alignof(std::string) ? alignof(std::string) : alignof(size_t));
3034
3035 alignas(align) unsigned char bytes[size];
3036 };
3038
3039 path_component_type type_;
3040
3043 static bool TOML_CALLCONV equal(const path_component&, const path_component&) noexcept;
3044
3045 template <typename Type>
3047 static Type* get_as(storage_t& s) noexcept
3048 {
3049 return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
3050 }
3051
3052 static void store_key(std::string_view key, storage_t& storage_)
3053 {
3054 ::new (static_cast<void*>(storage_.bytes)) std::string{ key };
3055 }
3056
3057 static void store_index(size_t index, storage_t& storage_) noexcept
3058 {
3059 ::new (static_cast<void*>(storage_.bytes)) std::size_t{ index };
3060 }
3061
3062 void destroy() noexcept
3063 {
3064 if (type_ == path_component_type::key)
3065 get_as<std::string>(value_storage_)->~basic_string();
3066 }
3067
3069 size_t& index_ref() noexcept
3070 {
3071 TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
3073 }
3074
3076 std::string& key_ref() noexcept
3077 {
3078 TOML_ASSERT_ASSUME(type_ == path_component_type::key);
3080 }
3081
3082 public:
3083
3087
3090 path_component(size_t index) noexcept;
3091
3094 path_component(std::string_view key);
3095
3096#if TOML_ENABLE_WINDOWS_COMPAT
3097
3100 path_component(std::wstring_view key);
3101
3102#endif
3103
3107
3111
3114
3117
3119 path_component& operator=(size_t new_index) noexcept;
3120
3122 path_component& operator=(std::string_view new_key);
3123
3124#if TOML_ENABLE_WINDOWS_COMPAT
3125
3127 path_component& operator=(std::wstring_view new_key);
3128
3129#endif
3130
3132 {
3133 destroy();
3134 }
3135
3137 size_t index() const noexcept
3138 {
3139 TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
3141 }
3142
3144 explicit operator size_t() const noexcept
3145 {
3146 return index();
3147 }
3148
3150 const std::string& key() const noexcept
3151 {
3152 TOML_ASSERT_ASSUME(type_ == path_component_type::key);
3154 }
3155
3157 explicit operator const std::string&() const noexcept
3158 {
3159 return key();
3160 }
3161
3163 path_component_type type() const noexcept
3164 {
3165 return type_;
3166 }
3167
3169 friend bool operator==(const path_component& lhs, const path_component& rhs) noexcept
3170 {
3171 return equal(lhs, rhs);
3172 }
3173
3175 friend bool operator!=(const path_component& lhs, const path_component& rhs) noexcept
3176 {
3177 return !equal(lhs, rhs);
3178 }
3179 };
3180
3182 {
3183 private:
3184
3185 std::vector<path_component> components_;
3186
3188 void print_to(std::ostream&) const;
3189
3192 static bool TOML_CALLCONV equal(const path&, const path&) noexcept;
3193
3194 public:
3195
3197 path() noexcept = default;
3198
3201 explicit path(std::string_view);
3202
3203#if TOML_ENABLE_WINDOWS_COMPAT
3204
3207 explicit path(std::wstring_view);
3208
3209#endif
3210
3211 ~path() noexcept = default;
3212
3214 path(const path&) = default;
3215
3217 path(path&&) noexcept = default;
3218
3220 size_t size() const noexcept
3221 {
3222 return components_.size();
3223 }
3224
3226 explicit operator bool() const noexcept
3227 {
3228 return !components_.empty();
3229 }
3230
3232 bool empty() const noexcept
3233 {
3234 return components_.empty();
3235 }
3236
3238 path_component& operator[](size_t index) noexcept
3239 {
3240 TOML_ASSERT(index < size());
3241 return components_[index];
3242 }
3243
3245 const path_component& operator[](size_t index) const noexcept
3246 {
3247 TOML_ASSERT(index < size());
3248 return components_[index];
3249 }
3250
3251 path& operator=(const path&) = default;
3252
3253 path& operator=(path&&) noexcept = default;
3254
3256 path& operator=(std::string_view);
3257
3258#if TOML_ENABLE_WINDOWS_COMPAT
3259
3261 path& operator=(std::wstring_view);
3262
3263#endif
3264
3267 {
3268 return *this = p;
3269 }
3270
3272 path& assign(path&& p) noexcept
3273 {
3274 return *this = std::move(p);
3275 }
3276
3278 path& assign(std::string_view str)
3279 {
3280 return *this = str;
3281 }
3282
3283#if TOML_ENABLE_WINDOWS_COMPAT
3284
3286 path& assign(std::wstring_view str)
3287 {
3288 return *this = str;
3289 }
3290
3291#endif
3292
3295
3298
3300 path& operator+=(std::string_view);
3301
3302#if TOML_ENABLE_WINDOWS_COMPAT
3303
3305 path& operator+=(std::wstring_view);
3306
3307#endif
3308
3311 {
3312 return *this += p;
3313 }
3314
3317 {
3318 return *this += std::move(p);
3319 }
3320
3322 path& append(std::string_view str)
3323 {
3324 return *this += str;
3325 }
3326
3327#if TOML_ENABLE_WINDOWS_COMPAT
3328
3330 path& append(std::wstring_view str)
3331 {
3332 return *this += str;
3333 }
3334
3335#endif
3336
3339
3342
3344 path& prepend(std::string_view);
3345
3346#if TOML_ENABLE_WINDOWS_COMPAT
3347
3349 path& prepend(std::wstring_view);
3350
3351#endif
3352
3354 friend path operator+(const path& lhs, const path& rhs)
3355 {
3356 path result = lhs;
3357 result += rhs;
3358 return result;
3359 }
3360
3362 friend path operator+(const path& lhs, std::string_view rhs)
3363 {
3364 path result = lhs;
3365 result += rhs;
3366 return result;
3367 }
3368
3370 friend path operator+(std::string_view lhs, const path& rhs)
3371 {
3372 path result = rhs;
3373 result.prepend(lhs);
3374 return result;
3375 }
3376
3377#if TOML_ENABLE_WINDOWS_COMPAT
3378
3380 friend path operator+(const path& lhs, std::wstring_view rhs)
3381 {
3382 path result = lhs;
3383 result += rhs;
3384 return result;
3385 }
3386
3388 friend path operator+(std::wstring_view lhs, const path& rhs)
3389 {
3390 path result = rhs;
3391 result.prepend(lhs);
3392 return result;
3393 }
3394
3395#endif
3396
3398 friend std::ostream& operator<<(std::ostream& os, const path& rhs)
3399 {
3400 rhs.print_to(os);
3401 return os;
3402 }
3403
3406 std::string str() const;
3407
3410 explicit operator std::string() const
3411 {
3412 return str();
3413 }
3414
3415#if TOML_ENABLE_WINDOWS_COMPAT
3416
3419 std::wstring wide_str() const;
3420
3423 explicit operator std::wstring() const
3424 {
3425 return wide_str();
3426 }
3427
3428#endif
3429
3431 friend bool operator==(const path& lhs, const path& rhs) noexcept
3432 {
3433 return equal(lhs, rhs);
3434 }
3435
3437 friend bool operator!=(const path& lhs, const path& rhs) noexcept
3438 {
3439 return !equal(lhs, rhs);
3440 }
3441
3444 friend bool operator==(const path& lhs, std::string_view rhs)
3445 {
3446 return lhs == path{ rhs };
3447 }
3448
3451 friend bool operator==(std::string_view lhs, const path& rhs)
3452 {
3453 return rhs == lhs;
3454 }
3455
3458 friend bool operator!=(const path& lhs, std::string_view rhs)
3459 {
3460 return lhs != path{ rhs };
3461 }
3462
3465 friend bool operator!=(std::string_view lhs, const path& rhs)
3466 {
3467 return rhs != lhs;
3468 }
3469
3470#if TOML_ENABLE_WINDOWS_COMPAT
3471
3474 friend bool operator==(const path& lhs, std::wstring_view rhs)
3475 {
3476 return lhs == path{ rhs };
3477 }
3478
3481 friend bool operator==(std::wstring_view lhs, const path& rhs)
3482 {
3483 return rhs == lhs;
3484 }
3485
3488 friend bool operator!=(const path& lhs, std::wstring_view rhs)
3489 {
3490 return lhs != path{ rhs };
3491 }
3492
3495 friend bool operator!=(std::wstring_view lhs, const path& rhs)
3496 {
3497 return rhs != lhs;
3498 }
3499
3500#endif // TOML_ENABLE_WINDOWS_COMPAT
3501
3502 using iterator = std::vector<path_component>::iterator;
3503
3504 using const_iterator = std::vector<path_component>::const_iterator;
3505
3507 iterator begin() noexcept
3508 {
3509 return components_.begin();
3510 }
3511
3513 iterator end() noexcept
3514 {
3515 return components_.end();
3516 }
3517
3519 const_iterator begin() const noexcept
3520 {
3521 return components_.begin();
3522 }
3523
3525 const_iterator end() const noexcept
3526 {
3527 return components_.end();
3528 }
3529
3531 const_iterator cbegin() const noexcept
3532 {
3533 return components_.begin();
3534 }
3535
3537 const_iterator cend() const noexcept
3538 {
3539 return components_.end();
3540 }
3541
3543 void clear() noexcept;
3544
3546 path& truncate(size_t n);
3547
3550 path truncated(size_t n) const;
3551
3554 path parent() const;
3555
3558 path leaf(size_t n = 1) const;
3559
3563
3566 path subpath(size_t start, size_t length) const;
3567 };
3568
3569 inline namespace literals
3570 {
3573 path operator"" _tpath(const char* str, size_t len)
3574 {
3575 return path(std::string_view{ str, len });
3576 }
3577 }
3578
3581 node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept;
3582
3585 node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept;
3586}
3588
3589#ifdef _MSC_VER
3590#pragma pop_macro("min")
3591#pragma pop_macro("max")
3592#ifndef __clang__
3593#pragma inline_recursion(off)
3594#endif
3595#endif
3597
3598//******** impl/std_utility.hpp **************************************************************************************
3599
3601#include <utility>
3603
3604//******** impl/node.hpp *********************************************************************************************
3605
3607#ifdef _MSC_VER
3608#ifndef __clang__
3609#pragma inline_recursion(on)
3610#endif
3611#pragma push_macro("min")
3612#pragma push_macro("max")
3613#undef min
3614#undef max
3615#endif
3616
3618{
3620 {
3621 private:
3622
3623 friend class TOML_PARSER_TYPENAME;
3624 source_region source_{};
3625
3626 template <typename T>
3628 decltype(auto) get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
3629
3630 template <typename T, typename N>
3631 using ref_type_ = std::conditional_t< //
3632 std::is_reference_v<T>, //
3633 impl::copy_ref<impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>, T>, //
3634 impl::copy_cvref<impl::unwrap_node<T>, N> //
3635 >;
3636
3637 template <typename T, typename N>
3638 using ref_type = std::conditional_t< //
3639 std::is_reference_v<N>, //
3640 ref_type_<T, N>, //
3641 ref_type_<T, std::add_lvalue_reference_t<N>> //
3642 >;
3643
3644 template <typename T, typename N>
3646 static ref_type<T, N&&> do_ref(N&& n) noexcept
3647 {
3648 using unwrapped_type = impl::unwrap_node<T>;
3649 static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3650 "The template type argument of node::ref() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3651
3653 n.template is<unwrapped_type>()
3654 && "template type argument provided to toml::node::ref() didn't match the node's actual type");
3655
3656 using node_ref = std::remove_volatile_t<std::remove_reference_t<N>>&;
3657 using val_type = std::remove_volatile_t<unwrapped_type>;
3658 using out_ref = ref_type<T, N&&>;
3659 static_assert(std::is_reference_v<out_ref>);
3660
3661 if constexpr (toml::is_value<unwrapped_type>)
3662 return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>().get());
3663 else
3664 return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>());
3665 }
3666
3667 protected:
3669 node() noexcept;
3670
3672 node(const node&) noexcept;
3673
3675 node(node&&) noexcept;
3676
3678 node& operator=(const node&) noexcept;
3679
3681 node& operator=(node&&) noexcept;
3682
3683 template <typename T, typename N>
3684 using ref_cast_type_ = std::conditional_t< //
3685 std::is_reference_v<T>, //
3686 impl::copy_ref<impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>, T>, //
3687 impl::copy_cvref<impl::wrap_node<T>, N> //
3688 >;
3689
3690 template <typename T, typename N>
3691 using ref_cast_type = std::conditional_t< //
3692 std::is_reference_v<N>, //
3693 ref_cast_type_<T, N>, //
3694 ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
3695 >;
3696
3697 template <typename T>
3699 ref_cast_type<T, node&> ref_cast() & noexcept
3700 {
3701 using out_ref = ref_cast_type<T, node&>;
3702 using out_type = std::remove_reference_t<out_ref>;
3703 return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3704 }
3705
3706 template <typename T>
3708 ref_cast_type<T, node&&> ref_cast() && noexcept
3709 {
3710 using out_ref = ref_cast_type<T, node&&>;
3711 using out_type = std::remove_reference_t<out_ref>;
3712 return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3713 }
3714
3715 template <typename T>
3717 ref_cast_type<T, const node&> ref_cast() const& noexcept
3718 {
3719 using out_ref = ref_cast_type<T, const node&>;
3720 using out_type = std::remove_reference_t<out_ref>;
3721 return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3722 }
3723
3724 template <typename T>
3726 ref_cast_type<T, const node&&> ref_cast() const&& noexcept
3727 {
3728 using out_ref = ref_cast_type<T, const node&&>;
3729 using out_type = std::remove_reference_t<out_ref>;
3730 return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3731 }
3732
3733 public:
3735 virtual ~node() noexcept;
3736
3738 virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
3739
3741 virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
3742
3744 virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
3745
3746 template <typename ElemType = void>
3748 bool is_homogeneous() const noexcept
3749 {
3750 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
3751 static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
3752 "The template type argument of node::is_homogeneous() must be void or one "
3754
3755 return is_homogeneous(impl::node_type_of<type>);
3756 }
3757
3759 virtual node_type type() const noexcept = 0;
3760
3762 virtual bool is_table() const noexcept = 0;
3763
3765 virtual bool is_array() const noexcept = 0;
3766
3768 virtual bool is_array_of_tables() const noexcept = 0;
3769
3771 virtual bool is_value() const noexcept = 0;
3772
3774 virtual bool is_string() const noexcept = 0;
3775
3777 virtual bool is_integer() const noexcept = 0;
3778
3780 virtual bool is_floating_point() const noexcept = 0;
3781
3783 virtual bool is_number() const noexcept = 0;
3784
3786 virtual bool is_boolean() const noexcept = 0;
3787
3789 virtual bool is_date() const noexcept = 0;
3790
3792 virtual bool is_time() const noexcept = 0;
3793
3795 virtual bool is_date_time() const noexcept = 0;
3796
3797 template <typename T>
3799 bool is() const noexcept
3800 {
3801 using type = impl::remove_cvref<impl::unwrap_node<T>>;
3802 static_assert(toml::is_value<type> || toml::is_container<type>,
3803 "The template type argument of node::is() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3804
3805 if constexpr (std::is_same_v<type, table>)
3806 return is_table();
3807 else if constexpr (std::is_same_v<type, array>)
3808 return is_array();
3809 else if constexpr (std::is_same_v<type, std::string>)
3810 return is_string();
3811 else if constexpr (std::is_same_v<type, int64_t>)
3812 return is_integer();
3813 else if constexpr (std::is_same_v<type, double>)
3814 return is_floating_point();
3815 else if constexpr (std::is_same_v<type, bool>)
3816 return is_boolean();
3817 else if constexpr (std::is_same_v<type, date>)
3818 return is_date();
3819 else if constexpr (std::is_same_v<type, time>)
3820 return is_time();
3821 else if constexpr (std::is_same_v<type, date_time>)
3822 return is_date_time();
3823 }
3824
3826 virtual table* as_table() noexcept = 0;
3827
3829 virtual array* as_array() noexcept = 0;
3830
3832 virtual toml::value<std::string>* as_string() noexcept = 0;
3833
3835 virtual toml::value<int64_t>* as_integer() noexcept = 0;
3836
3838 virtual toml::value<double>* as_floating_point() noexcept = 0;
3839
3841 virtual toml::value<bool>* as_boolean() noexcept = 0;
3842
3844 virtual toml::value<date>* as_date() noexcept = 0;
3845
3847 virtual toml::value<time>* as_time() noexcept = 0;
3848
3850 virtual toml::value<date_time>* as_date_time() noexcept = 0;
3851
3853 virtual const table* as_table() const noexcept = 0;
3854
3856 virtual const array* as_array() const noexcept = 0;
3857
3859 virtual const toml::value<std::string>* as_string() const noexcept = 0;
3860
3862 virtual const toml::value<int64_t>* as_integer() const noexcept = 0;
3863
3865 virtual const toml::value<double>* as_floating_point() const noexcept = 0;
3866
3868 virtual const toml::value<bool>* as_boolean() const noexcept = 0;
3869
3871 virtual const toml::value<date>* as_date() const noexcept = 0;
3872
3874 virtual const toml::value<time>* as_time() const noexcept = 0;
3875
3877 virtual const toml::value<date_time>* as_date_time() const noexcept = 0;
3878
3879 template <typename T>
3881 impl::wrap_node<T>* as() noexcept
3882 {
3883 using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
3884 static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3885 "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3886
3887 if constexpr (std::is_same_v<unwrapped_type, table>)
3888 return as_table();
3889 else if constexpr (std::is_same_v<unwrapped_type, array>)
3890 return as_array();
3891 else if constexpr (std::is_same_v<unwrapped_type, std::string>)
3892 return as_string();
3893 else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
3894 return as_integer();
3895 else if constexpr (std::is_same_v<unwrapped_type, double>)
3896 return as_floating_point();
3897 else if constexpr (std::is_same_v<unwrapped_type, bool>)
3898 return as_boolean();
3899 else if constexpr (std::is_same_v<unwrapped_type, date>)
3900 return as_date();
3901 else if constexpr (std::is_same_v<unwrapped_type, time>)
3902 return as_time();
3903 else if constexpr (std::is_same_v<unwrapped_type, date_time>)
3904 return as_date_time();
3905 }
3906
3907 template <typename T>
3909 const impl::wrap_node<T>* as() const noexcept
3910 {
3911 using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
3912 static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3913 "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3914
3915 if constexpr (std::is_same_v<unwrapped_type, table>)
3916 return as_table();
3917 else if constexpr (std::is_same_v<unwrapped_type, array>)
3918 return as_array();
3919 else if constexpr (std::is_same_v<unwrapped_type, std::string>)
3920 return as_string();
3921 else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
3922 return as_integer();
3923 else if constexpr (std::is_same_v<unwrapped_type, double>)
3924 return as_floating_point();
3925 else if constexpr (std::is_same_v<unwrapped_type, bool>)
3926 return as_boolean();
3927 else if constexpr (std::is_same_v<unwrapped_type, date>)
3928 return as_date();
3929 else if constexpr (std::is_same_v<unwrapped_type, time>)
3930 return as_time();
3931 else if constexpr (std::is_same_v<unwrapped_type, date_time>)
3932 return as_date_time();
3933 }
3934
3935 template <typename T>
3937 optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
3938
3939 template <typename T>
3941 optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>);
3942
3943 template <typename T>
3945 auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>);
3946
3947 template <typename T>
3949 decltype(auto) ref() & noexcept
3950 {
3951 return do_ref<T>(*this);
3952 }
3953
3954 template <typename T>
3956 decltype(auto) ref() && noexcept
3957 {
3958 return do_ref<T>(std::move(*this));
3959 }
3960
3961 template <typename T>
3963 decltype(auto) ref() const& noexcept
3964 {
3965 return do_ref<T>(*this);
3966 }
3967
3968 template <typename T>
3970 decltype(auto) ref() const&& noexcept
3971 {
3972 return do_ref<T>(std::move(*this));
3973 }
3974
3976 const source_region& source() const noexcept
3977 {
3978 return source_;
3979 }
3980
3981 private:
3982
3983 template <typename Func, typename Node, typename T>
3984 static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, Node>>;
3985
3986 template <typename Func, typename Node, typename T>
3987 static constexpr bool can_visit_nothrow = std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>;
3988
3989 template <typename Func, typename Node>
3990 static constexpr bool can_visit_any = can_visit<Func, Node, table> //
3991 || can_visit<Func, Node, array> //
3992 || can_visit<Func, Node, std::string> //
3993 || can_visit<Func, Node, int64_t> //
3994 || can_visit<Func, Node, double> //
3995 || can_visit<Func, Node, bool> //
3996 || can_visit<Func, Node, date> //
3997 || can_visit<Func, Node, time> //
3998 || can_visit<Func, Node, date_time>;
3999
4000 // clang-format off
4001
4002 template <typename Func, typename Node>
4003 static constexpr bool can_visit_all = can_visit<Func, Node, table> //
4004 && can_visit<Func, Node, array> //
4005 && can_visit<Func, Node, std::string> //
4006 && can_visit<Func, Node, int64_t> //
4007 && can_visit<Func, Node, double> //
4008 && can_visit<Func, Node, bool> //
4009 && can_visit<Func, Node, date> //
4010 && can_visit<Func, Node, time> //
4011 && can_visit<Func, Node, date_time>;
4012
4013 template <typename Func, typename Node, typename T>
4014 static constexpr bool visit_is_nothrow_one = !can_visit<Func, Node, T> || can_visit_nothrow<Func, Node, T>;
4015
4016 template <typename Func, typename Node>
4017 static constexpr bool visit_is_nothrow = visit_is_nothrow_one<Func, Node, table> //
4018 && visit_is_nothrow_one<Func, Node, array> //
4019 && visit_is_nothrow_one<Func, Node, std::string> //
4020 && visit_is_nothrow_one<Func, Node, int64_t> //
4021 && visit_is_nothrow_one<Func, Node, double> //
4022 && visit_is_nothrow_one<Func, Node, bool> //
4023 && visit_is_nothrow_one<Func, Node, date> //
4024 && visit_is_nothrow_one<Func, Node, time> //
4025 && visit_is_nothrow_one<Func, Node, date_time>;
4026
4027 // clang-format on
4028
4029 template <typename Func, typename Node, typename T, bool = can_visit<Func, Node, T>>
4030 struct visit_return_type_
4031 {
4032 using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>()));
4033 };
4034 template <typename Func, typename Node, typename T>
4035 struct visit_return_type_<Func, Node, T, false>
4036 {
4037 using type = void;
4038 };
4039
4040 template <typename Func, typename Node, typename T>
4041 using visit_return_type = typename visit_return_type_<Func, Node, T>::type;
4042
4043 template <typename A, typename B>
4044 using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
4045
4046 template <typename Func, typename Node>
4047 static decltype(auto) do_visit(Func&& visitor, Node&& n) noexcept(visit_is_nothrow<Func&&, Node&&>)
4048 {
4049 static_assert(can_visit_any<Func&&, Node&&>,
4050 "TOML node visitors must be invocable for at least one of the toml::node "
4051 "specializations:" TOML_SA_NODE_TYPE_LIST);
4052
4053 switch (n.type())
4054 {
4055 case node_type::table:
4056 if constexpr (can_visit<Func&&, Node&&, table>)
4057 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<table>());
4058 break;
4059
4060 case node_type::array:
4061 if constexpr (can_visit<Func&&, Node&&, array>)
4062 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<array>());
4063 break;
4064
4065 case node_type::string:
4066 if constexpr (can_visit<Func&&, Node&&, std::string>)
4067 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<std::string>());
4068 break;
4069
4070 case node_type::integer:
4071 if constexpr (can_visit<Func&&, Node&&, int64_t>)
4072 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<int64_t>());
4073 break;
4074
4075 case node_type::floating_point:
4076 if constexpr (can_visit<Func&&, Node&&, double>)
4077 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<double>());
4078 break;
4079
4080 case node_type::boolean:
4081 if constexpr (can_visit<Func&&, Node&&, bool>)
4082 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<bool>());
4083 break;
4084
4085 case node_type::date:
4086 if constexpr (can_visit<Func&&, Node&&, date>)
4087 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date>());
4088 break;
4089
4090 case node_type::time:
4091 if constexpr (can_visit<Func&&, Node&&, time>)
4092 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<time>());
4093 break;
4094
4095 case node_type::date_time:
4096 if constexpr (can_visit<Func&&, Node&&, date_time>)
4097 return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date_time>());
4098 break;
4099
4100 case node_type::none: TOML_UNREACHABLE;
4101 default: TOML_UNREACHABLE;
4102 }
4103
4104 if constexpr (!can_visit_all<Func&&, Node&&>)
4105 {
4106 // clang-format off
4107
4108 using return_type =
4109 nonvoid<visit_return_type<Func&&, Node&&, table>,
4110 nonvoid<visit_return_type<Func&&, Node&&, array>,
4111 nonvoid<visit_return_type<Func&&, Node&&, std::string>,
4112 nonvoid<visit_return_type<Func&&, Node&&, int64_t>,
4113 nonvoid<visit_return_type<Func&&, Node&&, double>,
4114 nonvoid<visit_return_type<Func&&, Node&&, bool>,
4115 nonvoid<visit_return_type<Func&&, Node&&, date>,
4116 nonvoid<visit_return_type<Func&&, Node&&, time>,
4117 visit_return_type<Func&&, Node&&, date_time>
4118 >>>>>>>>;
4119
4120 // clang-format on
4121
4122 if constexpr (!std::is_void_v<return_type>)
4123 {
4124 static_assert(std::is_default_constructible_v<return_type>,
4125 "Non-exhaustive visitors must return a default-constructible type, or void");
4126 return return_type{};
4127 }
4128 }
4129 }
4130
4131 public:
4132
4133 template <typename Func>
4134 decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>)
4135 {
4136 return do_visit(static_cast<Func&&>(visitor), *this);
4137 }
4138
4139 template <typename Func>
4140 decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>)
4141 {
4142 return do_visit(static_cast<Func&&>(visitor), static_cast<node&&>(*this));
4143 }
4144
4145 template <typename Func>
4146 decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>)
4147 {
4148 return do_visit(static_cast<Func&&>(visitor), *this);
4149 }
4150
4151 template <typename Func>
4152 decltype(auto) visit(Func&& visitor) const&& noexcept(visit_is_nothrow<Func&&, const node&&>)
4153 {
4154 return do_visit(static_cast<Func&&>(visitor), static_cast<const node&&>(*this));
4155 }
4156
4158 explicit operator node_view<node>() noexcept;
4159
4161 explicit operator node_view<const node>() const noexcept;
4162
4165 node_view<node> at_path(std::string_view path) noexcept;
4166
4169 node_view<const node> at_path(std::string_view path) const noexcept;
4170
4173 node_view<node> at_path(const toml::path& path) noexcept;
4174
4177 node_view<const node> at_path(const toml::path& path) const noexcept;
4178
4179#if TOML_ENABLE_WINDOWS_COMPAT
4180
4183 node_view<node> at_path(std::wstring_view path);
4184
4187 node_view<const node> at_path(std::wstring_view path) const;
4188
4189#endif // TOML_ENABLE_WINDOWS_COMPAT
4190
4193 node_view<node> operator[](const toml::path& path) noexcept;
4194
4197 node_view<const node> operator[](const toml::path& path) const noexcept;
4198 };
4199}
4201
4203{
4206 bool TOML_CALLCONV node_deep_equality(const node*, const node*) noexcept;
4207}
4209
4210#ifdef _MSC_VER
4211#pragma pop_macro("min")
4212#pragma pop_macro("max")
4213#ifndef __clang__
4214#pragma inline_recursion(off)
4215#endif
4216#endif
4218
4219//******** impl/std_initializer_list.hpp *****************************************************************************
4220
4222#include <initializer_list>
4224
4225//******** impl/node_view.hpp ****************************************************************************************
4226
4228#ifdef _MSC_VER
4229#ifndef __clang__
4230#pragma inline_recursion(on)
4231#endif
4232#pragma push_macro("min")
4233#pragma push_macro("max")
4234#undef min
4235#undef max
4236#endif
4237
4239
4241{
4242 template <typename ViewedType>
4244 {
4245 static_assert(impl::is_one_of<ViewedType, toml::node, const toml::node>,
4246 "A toml::node_view<> must wrap toml::node or const toml::node.");
4247
4248 public:
4249
4250 using viewed_type = ViewedType;
4251
4252 private:
4253 template <typename T>
4254 friend class node_view;
4255
4256 mutable viewed_type* node_ = nullptr;
4257
4258 public:
4259
4261 node_view() noexcept = default;
4262
4264 explicit node_view(viewed_type* node) noexcept //
4265 : node_{ node }
4266 {}
4267
4269 explicit node_view(viewed_type& node) noexcept //
4270 : node_{ &node }
4271 {}
4272
4274 node_view(const node_view&) noexcept = default;
4275
4277 node_view(node_view&&) noexcept = default;
4278
4279 node_view& operator=(const node_view&) & noexcept = default;
4280
4281 node_view& operator=(node_view&&) & noexcept = default;
4282
4284 explicit operator bool() const noexcept
4285 {
4286 return node_ != nullptr;
4287 }
4288
4290 viewed_type* node() const noexcept
4291 {
4292 return node_;
4293 }
4294
4296 node_type type() const noexcept
4297 {
4298 return node_ ? node_->type() : node_type::none;
4299 }
4300
4302 bool is_table() const noexcept
4303 {
4304 return node_ && node_->is_table();
4305 }
4306
4308 bool is_array() const noexcept
4309 {
4310 return node_ && node_->is_array();
4311 }
4312
4314 bool is_value() const noexcept
4315 {
4316 return node_ && node_->is_value();
4317 }
4318
4320 bool is_string() const noexcept
4321 {
4322 return node_ && node_->is_string();
4323 }
4324
4326 bool is_integer() const noexcept
4327 {
4328 return node_ && node_->is_integer();
4329 }
4330
4332 bool is_floating_point() const noexcept
4333 {
4334 return node_ && node_->is_floating_point();
4335 }
4336
4338 bool is_number() const noexcept
4339 {
4340 return node_ && node_->is_number();
4341 }
4342
4344 bool is_boolean() const noexcept
4345 {
4346 return node_ && node_->is_boolean();
4347 }
4348
4350 bool is_date() const noexcept
4351 {
4352 return node_ && node_->is_date();
4353 }
4354
4356 bool is_time() const noexcept
4357 {
4358 return node_ && node_->is_time();
4359 }
4360
4362 bool is_date_time() const noexcept
4363 {
4364 return node_ && node_->is_date_time();
4365 }
4366
4368 bool is_array_of_tables() const noexcept
4369 {
4370 return node_ && node_->is_array_of_tables();
4371 }
4372
4373 template <typename T>
4375 bool is() const noexcept
4376 {
4377 return node_ ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>() : false;
4378 }
4379
4381 bool is_homogeneous(node_type ntype, viewed_type*& first_nonmatch) const noexcept
4382 {
4383 if (!node_)
4384 {
4385 first_nonmatch = {};
4386 return false;
4387 }
4388 return node_->is_homogeneous(ntype, first_nonmatch);
4389 }
4390
4392 bool is_homogeneous(node_type ntype) const noexcept
4393 {
4394 return node_ ? node_->is_homogeneous(ntype) : false;
4395 }
4396
4397 template <typename ElemType = void>
4399 bool is_homogeneous() const noexcept
4400 {
4401 return node_ ? node_->template is_homogeneous<impl::unwrap_node<impl::remove_cvref<ElemType>>>() : false;
4402 }
4403
4404 template <typename T>
4406 auto* as() const noexcept
4407 {
4408 return node_ ? node_->template as<T>() : nullptr;
4409 }
4410
4412 auto* as_table() const noexcept
4413 {
4414 return as<table>();
4415 }
4416
4418 auto* as_array() const noexcept
4419 {
4420 return as<array>();
4421 }
4422
4424 auto* as_string() const noexcept
4425 {
4426 return as<std::string>();
4427 }
4428
4430 auto* as_integer() const noexcept
4431 {
4432 return as<int64_t>();
4433 }
4434
4436 auto* as_floating_point() const noexcept
4437 {
4438 return as<double>();
4439 }
4440
4442 auto* as_boolean() const noexcept
4443 {
4444 return as<bool>();
4445 }
4446
4448 auto* as_date() const noexcept
4449 {
4450 return as<date>();
4451 }
4452
4454 auto* as_time() const noexcept
4455 {
4456 return as<time>();
4457 }
4458
4460 auto* as_date_time() const noexcept
4461 {
4462 return as<date_time>();
4463 }
4464
4465 template <typename T>
4467 optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
4468 {
4469 if (node_)
4470 return node_->template value_exact<T>();
4471 return {};
4472 }
4473
4474 template <typename T>
4476 optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>)
4477 {
4478 if (node_)
4479 return node_->template value<T>();
4480 return {};
4481 }
4482
4483 template <typename T>
4485 auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
4486 {
4487 using namespace ::toml::impl;
4488
4490 "Retrieving values as wide-character strings is only "
4491 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
4492
4493 if constexpr (is_wide_string<T>)
4494 {
4495#if TOML_ENABLE_WINDOWS_COMPAT
4496
4497 if (node_)
4498 return node_->value_or(static_cast<T&&>(default_value));
4499 return std::wstring{ static_cast<T&&>(default_value) };
4500
4501#else
4502
4503 static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
4504
4505#endif
4506 }
4507 else
4508 {
4509 using value_type =
4510 std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
4511 std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
4512 std::decay_t<T>>;
4513
4514 if (node_)
4515 return node_->value_or(static_cast<T&&>(default_value));
4516 if constexpr (std::is_pointer_v<value_type>)
4517 return value_type{ default_value };
4518 else
4519 return static_cast<T&&>(default_value);
4520 }
4521 }
4522
4523 template <typename T>
4525 decltype(auto) ref() const noexcept
4526 {
4527 TOML_ASSERT_ASSUME(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
4528 return node_->template ref<T>();
4529 }
4530
4531 private:
4532
4533 template <typename Func>
4534 static constexpr bool visit_is_nothrow = noexcept(std::declval<viewed_type*>()->visit(std::declval<Func>()));
4535
4536 public:
4537
4538 template <typename Func>
4539 decltype(auto) visit(Func&& visitor) const noexcept(visit_is_nothrow<Func&&>)
4540 {
4541 using return_type = decltype(node_->visit(static_cast<Func&&>(visitor)));
4542 if (node_)
4543 return node_->visit(static_cast<Func&&>(visitor));
4544 if constexpr (!std::is_void_v<return_type>)
4545 return return_type{};
4546 }
4547
4548 public:
4549
4550 template <typename T>
4552 friend bool operator==(const node_view& lhs, const node_view<T>& rhs) noexcept
4553 {
4554 return impl::node_deep_equality(lhs.node_, rhs.node_);
4555 }
4556
4557 template <typename T>
4559 friend bool operator!=(const node_view& lhs, const node_view<T>& rhs) noexcept
4560 {
4561 return !impl::node_deep_equality(lhs.node_, rhs.node_);
4562 }
4563
4565 friend bool operator==(const node_view& lhs, const table& rhs) noexcept
4566 {
4567 if (lhs.node_ == &rhs)
4568 return true;
4569 const auto tbl = lhs.as<table>();
4570 return tbl && *tbl == rhs;
4571 }
4573
4575 friend bool operator==(const node_view& lhs, const array& rhs) noexcept
4576 {
4577 if (lhs.node_ == &rhs)
4578 return true;
4579 const auto arr = lhs.as<array>();
4580 return arr && *arr == rhs;
4581 }
4583
4584 template <typename T>
4586 friend bool operator==(const node_view& lhs, const toml::value<T>& rhs) noexcept
4587 {
4588 if (lhs.node_ == &rhs)
4589 return true;
4590 const auto val = lhs.as<T>();
4591 return val && *val == rhs;
4592 }
4593 TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<T>&, template <typename T>);
4594
4595 TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
4597 friend bool operator==(const node_view& lhs, const T& rhs) noexcept(!impl::is_wide_string<T>)
4598 {
4599 static_assert(!impl::is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
4600 "Comparison with wide-character strings is only "
4601 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
4602
4603 if constexpr (impl::is_wide_string<T>)
4604 {
4605#if TOML_ENABLE_WINDOWS_COMPAT
4606 return lhs == impl::narrow(rhs);
4607#else
4608 static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
4609#endif
4610 }
4611 else
4612 {
4613 const auto val = lhs.as<impl::native_type_of<T>>();
4614 return val && *val == rhs;
4615 }
4616 }
4618 const T&,
4619 TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>,
4620 typename T));
4621
4622 template <typename T>
4624 friend bool operator==(const node_view& lhs,
4625 const std::initializer_list<T>& rhs) noexcept(!impl::is_wide_string<T>)
4626 {
4627 const auto arr = lhs.as<array>();
4628 return arr && *arr == rhs;
4629 }
4630 TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<T>&, template <typename T>);
4631
4632 template <typename T>
4634 friend bool operator==(const node_view& lhs, const std::vector<T>& rhs) noexcept(!impl::is_wide_string<T>)
4635 {
4636 const auto arr = lhs.as<array>();
4637 return arr && *arr == rhs;
4638 }
4639 TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<T>&, template <typename T>);
4640
4642 node_view operator[](std::string_view key) const noexcept
4643 {
4644 if (auto tbl = this->as_table())
4645 return node_view{ tbl->get(key) };
4646 return {};
4647 }
4648
4650 node_view operator[](const toml::path& path) const noexcept
4651 {
4652 return node_ ? node_->at_path(path) : node_view{};
4653 }
4654
4656 node_view at_path(std::string_view path) const noexcept
4657 {
4658 return node_ ? node_->at_path(path) : node_view{};
4659 }
4660
4662 node_view at_path(const toml::path& path) const noexcept
4663 {
4664 return node_ ? node_->at_path(path) : node_view{};
4665 }
4666
4667#if TOML_ENABLE_WINDOWS_COMPAT
4668
4670 node_view operator[](std::wstring_view key) const
4671 {
4672 if (auto tbl = this->as_table())
4673 return node_view{ tbl->get(key) };
4674 return {};
4675 }
4676
4678 node_view at_path(std::wstring_view path) const
4679 {
4680 return node_ ? node_->at_path(path) : node_view{};
4681 }
4682
4683#endif // TOML_ENABLE_WINDOWS_COMPAT
4684
4686 node_view operator[](size_t index) const noexcept
4687 {
4688 if (auto arr = this->as_array())
4689 return node_view{ arr->get(index) };
4690 return {};
4691 }
4692
4693#if TOML_ENABLE_FORMATTERS
4694
4695 friend std::ostream& operator<<(std::ostream& os, const node_view& nv)
4696 {
4697 if (nv.node_)
4698 nv.node_->visit([&os](const auto& n) { os << n; });
4699 return os;
4700 }
4701
4702#endif
4703 };
4704
4705 template <typename T>
4707
4708 template <typename T>
4710
4711 template <typename T>
4713
4714 template <typename T>
4716}
4718
4720{
4721 inline node::operator node_view<node>() noexcept
4722 {
4723 return node_view<node>{ this };
4724 }
4725
4726 inline node::operator node_view<const node>() const noexcept
4727 {
4728 return node_view<const node>{ this };
4729 }
4730}
4732
4733#ifdef _MSC_VER
4734#pragma pop_macro("min")
4735#pragma pop_macro("max")
4736#ifndef __clang__
4737#pragma inline_recursion(off)
4738#endif
4739#endif
4741
4742//******** impl/value.hpp ********************************************************************************************
4743
4745#ifdef _MSC_VER
4746#ifndef __clang__
4747#pragma inline_recursion(on)
4748#endif
4749#pragma push_macro("min")
4750#pragma push_macro("max")
4751#undef min
4752#undef max
4753#endif
4754
4756
4757// clang-format off
4758
4759#if TOML_ENABLE_WINDOWS_COMPAT
4760 #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
4761#else
4762 #define TOML_SA_VALUE_MESSAGE_WSTRING
4763#endif
4764#if TOML_HAS_CHAR8
4765 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
4766 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
4767#else
4768 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
4769 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
4770#endif
4771
4772#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
4773 "The " type_arg " must be one of:" \
4774 TOML_SA_LIST_NEW "A native TOML value type" \
4775 TOML_SA_NATIVE_VALUE_TYPE_LIST \
4776 \
4777 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
4778 TOML_SA_LIST_BEG "std::string" \
4779 TOML_SA_VALUE_MESSAGE_WSTRING \
4780 TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
4781 TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
4782 TOML_SA_LIST_END \
4783 \
4784 TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
4785 TOML_SA_LIST_BEG "std::string_view" \
4786 TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
4787 TOML_SA_LIST_SEP "const char*" \
4788 TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
4789 TOML_SA_LIST_END
4790
4791#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
4792 "The " type_arg " must be one of:" \
4793 TOML_SA_LIST_NEW "A native TOML value type" \
4794 TOML_SA_NATIVE_VALUE_TYPE_LIST \
4795 \
4796 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
4797 TOML_SA_LIST_BEG "std::string" \
4798 TOML_SA_VALUE_MESSAGE_WSTRING \
4799 TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
4800 TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
4801 TOML_SA_LIST_END \
4802 \
4803 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
4804 TOML_SA_LIST_BEG "any other integral type" \
4805 TOML_SA_LIST_SEP "any floating-point type" \
4806 TOML_SA_LIST_END \
4807 \
4808 TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
4809 TOML_SA_LIST_BEG "std::string_view" \
4810 TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
4811 TOML_SA_LIST_SEP "const char*" \
4812 TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
4813 TOML_SA_LIST_END
4814
4815// clang-format on
4817{
4818 template <typename T, typename...>
4819 struct native_value_maker
4820 {
4821 template <typename... Args>
4823 static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
4824 {
4825 if constexpr (std::is_aggregate_v<T>)
4826 return T{ static_cast<Args&&>(args)... };
4827 else
4828 return T(static_cast<Args&&>(args)...);
4829 }
4830 };
4831
4832 template <typename T>
4833 struct native_value_maker<T, T>
4834 {
4835 template <typename U>
4838 static U&& make(U&& val) noexcept
4839 {
4840 return static_cast<U&&>(val);
4841 }
4842 };
4843
4844#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
4845
4846 struct string_maker
4847 {
4848 template <typename T>
4850 static std::string make(T&& arg)
4851 {
4852 using arg_type = std::decay_t<T>;
4853#if TOML_HAS_CHAR8
4855 {
4856 return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
4857 }
4859 {
4860 return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())),
4861 arg.length());
4862 }
4863#endif
4864
4865#if TOML_ENABLE_WINDOWS_COMPAT
4866 if constexpr (is_wide_string<arg_type>)
4867 {
4868 return narrow(static_cast<T&&>(arg));
4869 }
4870#endif
4871 }
4872 };
4873
4874#if TOML_HAS_CHAR8
4875 template <>
4876 struct native_value_maker<std::string, char8_t*> : string_maker
4877 {};
4878 template <>
4879 struct native_value_maker<std::string, const char8_t*> : string_maker
4880 {};
4881 template <>
4882 struct native_value_maker<std::string, std::u8string> : string_maker
4883 {};
4884 template <>
4885 struct native_value_maker<std::string, std::u8string_view> : string_maker
4886 {};
4887#endif // TOML_HAS_CHAR8
4888
4889#if TOML_ENABLE_WINDOWS_COMPAT
4890 template <>
4891 struct native_value_maker<std::string, wchar_t*> : string_maker
4892 {};
4893 template <>
4894 struct native_value_maker<std::string, const wchar_t*> : string_maker
4895 {};
4896 template <>
4897 struct native_value_maker<std::string, std::wstring> : string_maker
4898 {};
4899 template <>
4900 struct native_value_maker<std::string, std::wstring_view> : string_maker
4901 {};
4902#endif // TOML_ENABLE_WINDOWS_COMPAT
4903
4904#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
4905
4906 template <typename T>
4908 inline optional<T> node_integer_cast(int64_t val) noexcept
4909 {
4910 static_assert(node_type_of<T> == node_type::integer);
4911 static_assert(!is_cvref<T>);
4912
4913 using traits = value_traits<T>;
4914 if constexpr (!traits::is_signed)
4915 {
4916 if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
4917 {
4918 using common_t = decltype(int64_t{} + T{});
4919 if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
4920 return {};
4921 }
4922 else
4923 {
4924 if (val < int64_t{})
4925 return {};
4926 }
4927 }
4928 else
4929 {
4930 if (val < traits::min || val > traits::max)
4931 return {};
4932 }
4933 return { static_cast<T>(val) };
4934 }
4935
4936 template <typename...>
4937 struct value_variadic_ctor_allowed : std::true_type
4938 {};
4939
4940 template <typename T, typename... Args>
4941 struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type
4942 {};
4943}
4945
4947{
4948 template <typename ValueType>
4949 class value : public node
4950 {
4951 static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
4952 "A toml::value<> must model one of the native TOML value types:" TOML_SA_NATIVE_VALUE_TYPE_LIST);
4953
4954 private:
4955
4956 friend class TOML_PARSER_TYPENAME;
4957
4958 template <typename T, typename U>
4960 static auto as_value([[maybe_unused]] U* ptr) noexcept
4961 {
4962 if constexpr (std::is_same_v<value_type, T>)
4963 return ptr;
4964 else
4965 return nullptr;
4966 }
4967
4968 ValueType val_;
4969 value_flags flags_ = value_flags::none;
4970
4971 public:
4972
4973 using value_type = ValueType;
4974
4975 using value_arg = POXY_IMPLEMENTATION_DETAIL(
4976 std::conditional_t<
4977 std::is_same_v<value_type, std::string>,
4978 std::string_view,
4979 std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>>);
4980
4982 (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value),
4983 typename... Args)
4985 explicit value(Args&&... args) noexcept(noexcept(value_type(
4986 impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))))
4987 : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))
4988 {
4989#if TOML_LIFETIME_HOOKS
4990 TOML_VALUE_CREATED;
4991#endif
4992 }
4993
4995 value(const value& other) noexcept //
4996 : node(other),
4997 val_{ other.val_ },
4998 flags_{ other.flags_ }
4999 {
5000#if TOML_LIFETIME_HOOKS
5001 TOML_VALUE_CREATED;
5002#endif
5003 }
5004
5006 value(const value& other, value_flags flags) noexcept //
5007 : node(other),
5008 val_{ other.val_ },
5009 flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
5010 {
5011#if TOML_LIFETIME_HOOKS
5012 TOML_VALUE_CREATED;
5013#endif
5014 }
5015
5017 value(value&& other) noexcept //
5018 : node(std::move(other)),
5019 val_{ std::move(other.val_) },
5020 flags_{ std::exchange(other.flags_, value_flags{}) }
5021 {
5022#if TOML_LIFETIME_HOOKS
5023 TOML_VALUE_CREATED;
5024#endif
5025 }
5026
5028 value(value&& other, value_flags flags) noexcept //
5029 : node(std::move(other)),
5030 val_{ std::move(other.val_) },
5031 flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
5032 {
5033#if TOML_LIFETIME_HOOKS
5034 TOML_VALUE_CREATED;
5035#endif
5036 other.flags_ = {};
5037 }
5038
5039 value& operator=(const value& rhs) noexcept
5040 {
5041 node::operator=(rhs);
5042 val_ = rhs.val_;
5043 flags_ = rhs.flags_;
5044 return *this;
5045 }
5046
5047 value& operator=(value&& rhs) noexcept
5048 {
5049 if (&rhs != this)
5050 {
5051 node::operator=(std::move(rhs));
5052 val_ = std::move(rhs.val_);
5053 flags_ = std::exchange(rhs.flags_, value_flags{});
5054 }
5055 return *this;
5056 }
5057
5058#if TOML_LIFETIME_HOOKS
5059 ~value() noexcept
5060 {
5061 TOML_VALUE_DESTROYED;
5062 }
5063#endif
5064
5066 node_type type() const noexcept final
5067 {
5068 return impl::node_type_of<value_type>;
5069 }
5070
5072 bool is_homogeneous(node_type ntype) const noexcept final
5073 {
5074 return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
5075 }
5076
5078 bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final
5079 {
5080 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
5081 {
5082 first_nonmatch = this;
5083 return false;
5084 }
5085 return true;
5086 }
5087
5089 bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final
5090 {
5091 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
5092 {
5093 first_nonmatch = this;
5094 return false;
5095 }
5096 return true;
5097 }
5098
5099 template <typename ElemType = void>
5101 bool is_homogeneous() const noexcept
5102 {
5103 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
5104 static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
5105 "The template type argument of value::is_homogeneous() must be void or one "
5107
5108 if constexpr (std::is_void_v<type>)
5109 return true;
5110 else
5111 return impl::node_type_of<type> == impl::node_type_of<value_type>;
5112 }
5114 bool is_table() const noexcept final
5115 {
5116 return false;
5117 }
5118
5120 bool is_array() const noexcept final
5121 {
5122 return false;
5123 }
5124
5126 bool is_array_of_tables() const noexcept final
5127 {
5128 return false;
5129 }
5130
5132 bool is_value() const noexcept final
5133 {
5134 return true;
5135 }
5136
5138 bool is_string() const noexcept final
5139 {
5140 return std::is_same_v<value_type, std::string>;
5141 }
5142
5144 bool is_integer() const noexcept final
5145 {
5146 return std::is_same_v<value_type, int64_t>;
5147 }
5148
5150 bool is_floating_point() const noexcept final
5151 {
5152 return std::is_same_v<value_type, double>;
5153 }
5154
5156 bool is_number() const noexcept final
5157 {
5158 return impl::is_one_of<value_type, int64_t, double>;
5159 }
5160
5162 bool is_boolean() const noexcept final
5163 {
5164 return std::is_same_v<value_type, bool>;
5165 }
5166
5168 bool is_date() const noexcept final
5169 {
5170 return std::is_same_v<value_type, date>;
5171 }
5172
5174 bool is_time() const noexcept final
5175 {
5176 return std::is_same_v<value_type, time>;
5177 }
5178
5180 bool is_date_time() const noexcept final
5181 {
5182 return std::is_same_v<value_type, date_time>;
5183 }
5184
5186 table* as_table() noexcept final
5187 {
5188 return nullptr;
5189 }
5190
5192 array* as_array() noexcept final
5193 {
5194 return nullptr;
5195 }
5196
5198 value<std::string>* as_string() noexcept final
5199 {
5200 return as_value<std::string>(this);
5201 }
5202
5204 value<int64_t>* as_integer() noexcept final
5205 {
5206 return as_value<int64_t>(this);
5207 }
5208
5210 value<double>* as_floating_point() noexcept final
5211 {
5212 return as_value<double>(this);
5213 }
5214
5216 value<bool>* as_boolean() noexcept final
5217 {
5218 return as_value<bool>(this);
5219 }
5220
5222 value<date>* as_date() noexcept final
5223 {
5224 return as_value<date>(this);
5225 }
5226
5228 value<time>* as_time() noexcept final
5229 {
5230 return as_value<time>(this);
5231 }
5232
5234 value<date_time>* as_date_time() noexcept final
5235 {
5236 return as_value<date_time>(this);
5237 }
5238
5240 const table* as_table() const noexcept final
5241 {
5242 return nullptr;
5243 }
5244
5246 const array* as_array() const noexcept final
5247 {
5248 return nullptr;
5249 }
5250
5252 const value<std::string>* as_string() const noexcept final
5253 {
5254 return as_value<std::string>(this);
5255 }
5256
5258 const value<int64_t>* as_integer() const noexcept final
5259 {
5260 return as_value<int64_t>(this);
5261 }
5262
5264 const value<double>* as_floating_point() const noexcept final
5265 {
5266 return as_value<double>(this);
5267 }
5268
5270 const value<bool>* as_boolean() const noexcept final
5271 {
5272 return as_value<bool>(this);
5273 }
5274
5276 const value<date>* as_date() const noexcept final
5277 {
5278 return as_value<date>(this);
5279 }
5280
5282 const value<time>* as_time() const noexcept final
5283 {
5284 return as_value<time>(this);
5285 }
5286
5288 const value<date_time>* as_date_time() const noexcept final
5289 {
5290 return as_value<date_time>(this);
5291 }
5292
5294 value_type& get() & noexcept
5295 {
5296 return val_;
5297 }
5298
5300 value_type&& get() && noexcept
5301 {
5302 return static_cast<value_type&&>(val_);
5303 }
5304
5306 const value_type& get() const& noexcept
5307 {
5308 return val_;
5309 }
5310
5312 const value_type&& get() const&& noexcept
5313 {
5314 return static_cast<const value_type&&>(val_);
5315 }
5316
5318 value_type& operator*() & noexcept
5319 {
5320 return val_;
5321 }
5322
5324 value_type&& operator*() && noexcept
5325 {
5326 return static_cast<value_type&&>(val_);
5327 }
5328
5330 const value_type& operator*() const& noexcept
5331 {
5332 return val_;
5333 }
5334
5336 const value_type&& operator*() const&& noexcept
5337 {
5338 return static_cast<const value_type&&>(val_);
5339 }
5340
5342 explicit operator value_type&() & noexcept
5343 {
5344 return val_;
5345 }
5346
5348 explicit operator value_type&&() && noexcept
5349 {
5350 return static_cast<value_type&&>(val_);
5351 }
5352
5354 explicit operator const value_type&() const& noexcept
5355 {
5356 return val_;
5357 }
5358
5360 explicit operator const value_type&&() && noexcept
5361 {
5362 return static_cast<const value_type&&>(val_);
5363 }
5364
5365 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
5367 value_type* operator->() noexcept
5368 {
5369 return &val_;
5370 }
5371
5372 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
5374 const value_type* operator->() const noexcept
5375 {
5376 return &val_;
5377 }
5378
5380 value_flags flags() const noexcept
5381 {
5382 return flags_;
5383 }
5384
5385 value& flags(value_flags new_flags) noexcept
5386 {
5387 flags_ = new_flags;
5388 return *this;
5389 }
5390
5391 value& operator=(value_arg rhs) noexcept
5392 {
5393 if constexpr (std::is_same_v<value_type, std::string>)
5394 val_.assign(rhs);
5395 else
5396 val_ = rhs;
5397 return *this;
5398 }
5399
5400 TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type)
5401 value& operator=(std::string&& rhs) noexcept
5402 {
5403 val_ = std::move(rhs);
5404 return *this;
5405 }
5406
5408 friend bool operator==(const value& lhs, value_arg rhs) noexcept
5409 {
5410 if constexpr (std::is_same_v<value_type, double>)
5411 {
5412 const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan;
5413 const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan;
5414 if (lhs_nan != rhs_nan)
5415 return false;
5416 if (lhs_nan)
5417 return true;
5418 }
5419 return lhs.val_ == rhs;
5420 }
5421 TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, );
5422
5424 friend bool operator<(const value& lhs, value_arg rhs) noexcept
5425 {
5426 return lhs.val_ < rhs;
5427 }
5428
5430 friend bool operator<(value_arg lhs, const value& rhs) noexcept
5431 {
5432 return lhs < rhs.val_;
5433 }
5434
5436 friend bool operator<=(const value& lhs, value_arg rhs) noexcept
5437 {
5438 return lhs.val_ <= rhs;
5439 }
5440
5442 friend bool operator<=(value_arg lhs, const value& rhs) noexcept
5443 {
5444 return lhs <= rhs.val_;
5445 }
5446
5448 friend bool operator>(const value& lhs, value_arg rhs) noexcept
5449 {
5450 return lhs.val_ > rhs;
5451 }
5452
5454 friend bool operator>(value_arg lhs, const value& rhs) noexcept
5455 {
5456 return lhs > rhs.val_;
5457 }
5458
5460 friend bool operator>=(const value& lhs, value_arg rhs) noexcept
5461 {
5462 return lhs.val_ >= rhs;
5463 }
5464
5466 friend bool operator>=(value_arg lhs, const value& rhs) noexcept
5467 {
5468 return lhs >= rhs.val_;
5469 }
5470
5471 template <typename T>
5473 friend bool operator==(const value& lhs, const value<T>& rhs) noexcept
5474 {
5475 if constexpr (std::is_same_v<value_type, T>)
5476 return lhs == rhs.val_; // calls asymmetrical value-equality operator defined above
5477 else
5478 return false;
5479 }
5480
5481 template <typename T>
5483 friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept
5484 {
5485 return !(lhs == rhs);
5486 }
5487
5488 template <typename T>
5490 friend bool operator<(const value& lhs, const value<T>& rhs) noexcept
5491 {
5492 if constexpr (std::is_same_v<value_type, T>)
5493 return lhs.val_ < rhs.val_;
5494 else
5495 return impl::node_type_of<value_type> < impl::node_type_of<T>;
5496 }
5497
5498 template <typename T>
5500 friend bool operator<=(const value& lhs, const value<T>& rhs) noexcept
5501 {
5502 if constexpr (std::is_same_v<value_type, T>)
5503 return lhs.val_ <= rhs.val_;
5504 else
5505 return impl::node_type_of<value_type> <= impl::node_type_of<T>;
5506 }
5507
5508 template <typename T>
5510 friend bool operator>(const value& lhs, const value<T>& rhs) noexcept
5511 {
5512 if constexpr (std::is_same_v<value_type, T>)
5513 return lhs.val_ > rhs.val_;
5514 else
5515 return impl::node_type_of<value_type> > impl::node_type_of<T>;
5516 }
5517
5518 template <typename T>
5520 friend bool operator>=(const value& lhs, const value<T>& rhs) noexcept
5521 {
5522 if constexpr (std::is_same_v<value_type, T>)
5523 return lhs.val_ >= rhs.val_;
5524 else
5525 return impl::node_type_of<value_type> >= impl::node_type_of<T>;
5526 }
5527
5528#if TOML_ENABLE_FORMATTERS
5529
5530 friend std::ostream& operator<<(std::ostream& lhs, const value& rhs)
5531 {
5532 impl::print_to_stream(lhs, rhs);
5533 return lhs;
5534 }
5535
5536#endif
5537 };
5538
5539 template <typename T>
5541 template <typename T>
5543
5544 template <typename T>
5546 inline decltype(auto) node::get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
5547 {
5548 using namespace impl;
5549
5550 static_assert(node_type_of<T> != node_type::none);
5551 static_assert(node_type_of<T> != node_type::table);
5552 static_assert(node_type_of<T> != node_type::array);
5553 static_assert(is_native<T> || can_represent_native<T>);
5554 static_assert(!is_cvref<T>);
5555 TOML_ASSERT(this->type() == node_type_of<T>);
5556
5557 if constexpr (node_type_of<T> == node_type::string)
5558 {
5559 const auto& str = *ref_cast<std::string>();
5560 if constexpr (std::is_same_v<T, std::string>)
5561 return str;
5562 else if constexpr (std::is_same_v<T, std::string_view>)
5563 return T{ str };
5564 else if constexpr (std::is_same_v<T, const char*>)
5565 return str.c_str();
5566
5567 else if constexpr (std::is_same_v<T, std::wstring>)
5568 {
5569#if TOML_ENABLE_WINDOWS_COMPAT
5570 return widen(str);
5571#else
5572 static_assert(always_false<T>, "Evaluated unreachable branch!");
5573#endif
5574 }
5575
5576#if TOML_HAS_CHAR8
5577
5578 // char -> char8_t (potentially unsafe - the feature is 'experimental'!)
5580 return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length());
5581 else if constexpr (std::is_same_v<T, const char8_t*>)
5582 return reinterpret_cast<const char8_t*>(str.c_str());
5583 else
5584 static_assert(always_false<T>, "Evaluated unreachable branch!");
5585
5586#endif
5587 }
5588 else
5589 return static_cast<T>(*ref_cast<native_type_of<T>>());
5590 }
5591
5592 template <typename T>
5594 inline optional<T> node::value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
5595 {
5596 using namespace impl;
5597
5599 "Retrieving values as wide-character strings with node::value_exact() is only "
5600 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5601
5603 TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()"));
5604
5605 // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
5607 {
5608 if (type() == node_type_of<T>)
5609 return { this->get_value_exact<T>() };
5610 else
5611 return {};
5612 }
5613 }
5614
5615 template <typename T>
5617 inline optional<T> node::value() const noexcept(impl::value_retrieval_is_nothrow<T>)
5618 {
5619 using namespace impl;
5620
5622 "Retrieving values as wide-character strings with node::value() is only "
5623 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5625 TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
5626
5627 // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
5628 // semantics to be mindful of so the exact retrieval is enough.
5630 {
5631 if (type() == node_type_of<T>)
5632 return { this->get_value_exact<T>() };
5633 else
5634 return {};
5635 }
5636
5637 // everything else requires a bit of logicking.
5638 else
5639 {
5640 switch (type())
5641 {
5642 // int -> *
5643 case node_type::integer:
5644 {
5645 // int -> int
5646 if constexpr (is_natively_one_of<T, int64_t>)
5647 {
5648 if constexpr (is_native<T> || can_represent_native<T>)
5649 return static_cast<T>(*ref_cast<int64_t>());
5650 else
5651 return node_integer_cast<T>(*ref_cast<int64_t>());
5652 }
5653
5654 // int -> float
5655 else if constexpr (is_natively_one_of<T, double>)
5656 {
5657 const int64_t val = *ref_cast<int64_t>();
5658 if constexpr (std::numeric_limits<T>::digits < 64)
5659 {
5660 constexpr auto largest_whole_float = (int64_t{ 1 } << std::numeric_limits<T>::digits);
5661 if (val < -largest_whole_float || val > largest_whole_float)
5662 return {};
5663 }
5664 return static_cast<T>(val);
5665 }
5666
5667 // int -> bool
5668 else if constexpr (is_natively_one_of<T, bool>)
5669 return static_cast<bool>(*ref_cast<int64_t>());
5670
5671 // int -> anything else
5672 else
5673 return {};
5674 }
5675
5676 // float -> *
5677 case node_type::floating_point:
5678 {
5679 // float -> float
5680 if constexpr (is_natively_one_of<T, double>)
5681 {
5682 if constexpr (is_native<T> || can_represent_native<T>)
5683 return { static_cast<T>(*ref_cast<double>()) };
5684 else
5685 {
5686 const double val = *ref_cast<double>();
5687 if (impl::fpclassify(val) == fp_class::ok
5688 && (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)()))
5689 return {};
5690 return { static_cast<T>(val) };
5691 }
5692 }
5693
5694 // float -> int
5695 else if constexpr (is_natively_one_of<T, int64_t>)
5696 {
5697 const double val = *ref_cast<double>();
5698 if (impl::fpclassify(val) == fp_class::ok
5699 && static_cast<double>(static_cast<int64_t>(val)) == val)
5700 return node_integer_cast<T>(static_cast<int64_t>(val));
5701 else
5702 return {};
5703 }
5704
5705 // float -> anything else
5706 else
5707 return {};
5708 }
5709
5710 // bool -> *
5711 case node_type::boolean:
5712 {
5713 // bool -> bool
5714 if constexpr (is_natively_one_of<T, bool>)
5715 return { *ref_cast<bool>() };
5716
5717 // bool -> int
5718 else if constexpr (is_natively_one_of<T, int64_t>)
5719 return { static_cast<T>(*ref_cast<bool>()) };
5720
5721 // bool -> anything else
5722 else
5723 return {};
5724 }
5725 }
5726
5727 // non-values, or 'exact' types covered above
5728 return {};
5729 }
5730 }
5731
5732 template <typename T>
5734 inline auto node::value_or(T && default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
5735 {
5736 using namespace impl;
5737
5739 "Retrieving values as wide-character strings with node::value_or() is only "
5740 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5741
5742 if constexpr (is_wide_string<T>)
5743 {
5744#if TOML_ENABLE_WINDOWS_COMPAT
5745
5746 if (type() == node_type::string)
5747 return widen(*ref_cast<std::string>());
5748 return std::wstring{ static_cast<T&&>(default_value) };
5749
5750#else
5751
5752 static_assert(always_false<T>, "Evaluated unreachable branch!");
5753
5754#endif
5755 }
5756 else
5757 {
5758 using value_type =
5759 std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
5760 std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
5761 std::decay_t<T>>;
5762 using traits = value_traits<value_type>;
5763
5764 // clang-format off
5765
5766 static_assert(
5767 traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
5768 "The default value type of node::value_or() must be one of:"
5769 TOML_SA_LIST_NEW "A native TOML value type"
5771
5772 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
5773 TOML_SA_LIST_BEG "std::string"
5774 #if TOML_ENABLE_WINDOWS_COMPAT
5775 TOML_SA_LIST_SEP "std::wstring"
5776 #endif
5777 TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
5778 TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
5780
5781 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
5782 TOML_SA_LIST_BEG "any other integral type"
5783 TOML_SA_LIST_SEP "any floating-point type"
5785
5786 TOML_SA_LIST_NXT "A compatible view type"
5787 TOML_SA_LIST_BEG "std::string_view"
5788 #if TOML_HAS_CHAR8
5789 TOML_SA_LIST_SEP "std::u8string_view"
5790 #endif
5791 #if TOML_ENABLE_WINDOWS_COMPAT
5792 TOML_SA_LIST_SEP "std::wstring_view"
5793 #endif
5794 TOML_SA_LIST_SEP "const char*"
5795 #if TOML_HAS_CHAR8
5796 TOML_SA_LIST_SEP "const char8_t*"
5797 #endif
5798 #if TOML_ENABLE_WINDOWS_COMPAT
5799 TOML_SA_LIST_SEP "const wchar_t*"
5800 #endif
5802 );
5803
5804 // clang-format on
5805
5806 // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
5807 if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
5808 {
5809 if constexpr (traits::is_native)
5810 {
5811 if (type() == node_type_of<value_type>)
5812 return *ref_cast<typename traits::native_type>();
5813 }
5814 if (auto val = this->value<value_type>())
5815 return *val;
5816 if constexpr (std::is_pointer_v<value_type>)
5817 return value_type{ default_value };
5818 else
5819 return static_cast<T&&>(default_value);
5820 }
5821 }
5822 }
5823}
5825
5826#ifdef _MSC_VER
5827#pragma pop_macro("min")
5828#pragma pop_macro("max")
5829#ifndef __clang__
5830#pragma inline_recursion(off)
5831#endif
5832#endif
5834
5835//******** impl/make_node.hpp ****************************************************************************************
5836
5838#ifdef _MSC_VER
5839#ifndef __clang__
5840#pragma inline_recursion(on)
5841#endif
5842#pragma push_macro("min")
5843#pragma push_macro("max")
5844#undef min
5845#undef max
5846#endif
5847
5849{
5850 template <typename T>
5852 TOML_ATTR(returns_nonnull)
5853 auto* make_node_impl_specialized(T && val, [[maybe_unused]] value_flags flags)
5854 {
5855 using unwrapped_type = unwrap_node<remove_cvref<T>>;
5856 static_assert(!std::is_same_v<unwrapped_type, node>);
5857 static_assert(!is_node_view<unwrapped_type>);
5858
5859 // arrays + tables - invoke copy/move ctor
5861 {
5862 return new unwrapped_type(static_cast<T&&>(val));
5863 }
5864
5865 // values
5866 else
5867 {
5868 using native_type = native_type_of<unwrapped_type>;
5870
5871 value_type* out;
5872
5873 // copy/move ctor
5874 if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
5875 {
5876 out = new value_type{ static_cast<T&&>(val), flags };
5877 }
5878
5879 // creating from raw value
5880 else
5881 {
5883 "Instantiating values from wide-character strings is only "
5884 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5885
5887 {
5888 if constexpr (std::is_same_v<native_type, int64_t>)
5889 static_assert(always_false<T>,
5890 "Integral value initializers must be losslessly convertible to int64_t");
5891 else if constexpr (std::is_same_v<native_type, double>)
5892 static_assert(always_false<T>,
5893 "Floating-point value initializers must be losslessly convertible to double");
5894 else
5895 static_assert(
5897 "Value initializers must be losslessly convertible to one of the TOML value types");
5898 }
5899
5900 if constexpr (is_wide_string<T>)
5901 {
5902#if TOML_ENABLE_WINDOWS_COMPAT
5903 out = new value_type{ narrow(static_cast<T&&>(val)) };
5904#else
5905 static_assert(always_false<T>, "Evaluated unreachable branch!");
5906#endif
5907 }
5908 else
5909 out = new value_type{ static_cast<T&&>(val) };
5910
5911 if (flags != preserve_source_value_flags)
5912 out->flags(flags);
5913 }
5914
5915 return out;
5916 }
5917 }
5918
5919 template <typename T>
5921 auto* make_node_impl(T && val, value_flags flags = preserve_source_value_flags)
5922 {
5923 using unwrapped_type = unwrap_node<remove_cvref<T>>;
5924 if constexpr (std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>)
5925 {
5926 if constexpr (is_node_view<unwrapped_type>)
5927 {
5928 if (!val)
5929 return static_cast<toml::node*>(nullptr);
5930 }
5931
5932 return static_cast<T&&>(val).visit(
5933 [flags](auto&& concrete) {
5934 return static_cast<toml::node*>(
5935 make_node_impl_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
5936 });
5937 }
5938 else
5939 return make_node_impl_specialized(static_cast<T&&>(val), flags);
5940 }
5941
5942 template <typename T>
5944 auto* make_node_impl(inserter<T> && val, value_flags flags = preserve_source_value_flags)
5945 {
5946 return make_node_impl(static_cast<T&&>(val.value), flags);
5947 }
5948
5949 template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
5950 struct inserted_type_of_
5951 {
5952 using type = std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
5953 };
5954
5955 template <typename T>
5956 struct inserted_type_of_<inserter<T>, false>
5957 {
5958 using type = typename inserted_type_of_<remove_cvref<T>>::type;
5959 };
5960
5961 template <typename T>
5962 struct inserted_type_of_<T, false>
5963 {
5964 using type = void;
5965 };
5966
5967 template <typename T>
5970 {
5971 return node_ptr{ make_node_impl(static_cast<T&&>(val), flags) };
5972 }
5973
5974 template <typename... T>
5976 {
5977 using type = void;
5978 };
5979
5980 template <typename T>
5982 {
5983 using type = std::conditional_t<is_one_of<T, node, node_view<node>, node_view<const node>>,
5984 void,
5985 typename inserted_type_of_<T>::type>;
5986 };
5987
5988 template <typename T>
5993
5994 template <typename... T>
5996}
5998
6000{
6001 template <typename T>
6002 using inserted_type_of = POXY_IMPLEMENTATION_DETAIL(typename impl::inserted_type_of_<impl::remove_cvref<T>>::type);
6003}
6005
6006#ifdef _MSC_VER
6007#pragma pop_macro("min")
6008#pragma pop_macro("max")
6009#ifndef __clang__
6010#pragma inline_recursion(off)
6011#endif
6012#endif
6014
6015//******** impl/array.hpp ********************************************************************************************
6016
6018#ifdef _MSC_VER
6019#ifndef __clang__
6020#pragma inline_recursion(on)
6021#endif
6022#pragma push_macro("min")
6023#pragma push_macro("max")
6024#undef min
6025#undef max
6026#endif
6027
6028#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
6029#if TOML_GCC && TOML_GCC <= 7
6030#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1
6031#else
6032#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0
6033#endif
6034#endif
6035
6036#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
6037#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE \
6038 "If you're seeing this error it's because you're using one of toml++'s for_each() functions on a compiler with " \
6039 "known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or bool-convertible) value from the " \
6040 "for_each() callable causes spurious compilation failures, while returning nothing (void) works fine. " \
6041 "If you believe this message is incorrect for your compiler, you can try your luck by #defining " \
6042 "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know at " \
6043 "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for early-exiting from " \
6044 "for_each(), you can suppress this error by #defining TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED " \
6045 "and moving on with your life."
6046#endif
6047
6049{
6050 template <bool IsConst>
6051 class TOML_TRIVIAL_ABI array_iterator
6052 {
6053 private:
6054 template <bool>
6055 friend class array_iterator;
6056
6057 using mutable_vector_iterator = std::vector<node_ptr>::iterator;
6058 using const_vector_iterator = std::vector<node_ptr>::const_iterator;
6059 using vector_iterator = std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
6060
6061 mutable vector_iterator iter_;
6062
6063 public:
6064 using value_type = std::conditional_t<IsConst, const node, node>;
6065 using reference = value_type&;
6066 using pointer = value_type*;
6067 using difference_type = ptrdiff_t;
6068 using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;
6069
6071 array_iterator() noexcept = default;
6072
6074 explicit array_iterator(mutable_vector_iterator iter) noexcept //
6075 : iter_{ iter }
6076 {}
6077
6078 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
6080 explicit array_iterator(const_vector_iterator iter) noexcept //
6081 : iter_{ iter }
6082 {}
6083
6084 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
6086 array_iterator(const array_iterator<false>& other) noexcept //
6087 : iter_{ other.iter_ }
6088 {}
6089
6091 array_iterator(const array_iterator&) noexcept = default;
6092
6093 array_iterator& operator=(const array_iterator&) noexcept = default;
6094
6095 array_iterator& operator++() noexcept // ++pre
6096 {
6097 ++iter_;
6098 return *this;
6099 }
6100
6101 array_iterator operator++(int) noexcept // post++
6102 {
6103 array_iterator out{ iter_ };
6104 ++iter_;
6105 return out;
6106 }
6107
6108 array_iterator& operator--() noexcept // --pre
6109 {
6110 --iter_;
6111 return *this;
6112 }
6113
6114 array_iterator operator--(int) noexcept // post--
6115 {
6116 array_iterator out{ iter_ };
6117 --iter_;
6118 return out;
6119 }
6120
6122 reference operator*() const noexcept
6123 {
6124 return *iter_->get();
6125 }
6126
6128 pointer operator->() const noexcept
6129 {
6130 return iter_->get();
6131 }
6132
6134 explicit operator const vector_iterator&() const noexcept
6135 {
6136 return iter_;
6137 }
6138
6139 TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
6141 explicit operator const const_vector_iterator() const noexcept
6142 {
6143 return iter_;
6144 }
6145
6146 array_iterator& operator+=(ptrdiff_t rhs) noexcept
6147 {
6148 iter_ += rhs;
6149 return *this;
6150 }
6151
6152 array_iterator& operator-=(ptrdiff_t rhs) noexcept
6153 {
6154 iter_ -= rhs;
6155 return *this;
6156 }
6157
6159 friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept
6160 {
6161 return array_iterator{ lhs.iter_ + rhs };
6162 }
6163
6165 friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept
6166 {
6167 return array_iterator{ rhs.iter_ + lhs };
6168 }
6169
6171 friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept
6172 {
6173 return array_iterator{ lhs.iter_ - rhs };
6174 }
6175
6177 friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept
6178 {
6179 return lhs.iter_ - rhs.iter_;
6180 }
6181
6183 friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept
6184 {
6185 return lhs.iter_ == rhs.iter_;
6186 }
6187
6189 friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept
6190 {
6191 return lhs.iter_ != rhs.iter_;
6192 }
6193
6195 friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept
6196 {
6197 return lhs.iter_ < rhs.iter_;
6198 }
6199
6201 friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept
6202 {
6203 return lhs.iter_ <= rhs.iter_;
6204 }
6205
6207 friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept
6208 {
6209 return lhs.iter_ > rhs.iter_;
6210 }
6211
6213 friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept
6214 {
6215 return lhs.iter_ >= rhs.iter_;
6216 }
6217
6219 reference operator[](ptrdiff_t idx) const noexcept
6220 {
6221 return *(iter_ + idx)->get();
6222 }
6223 };
6224
6226 {
6227 mutable node_ptr value;
6228
6229 template <typename T>
6232 : value{ make_node(static_cast<T&&>(val), flags) }
6233 {}
6234 };
6235}
6237
6239{
6240 using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);
6241
6242 using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);
6243
6244 class TOML_EXPORTED_CLASS array : public node
6245 {
6246 private:
6247
6248 using vector_type = std::vector<impl::node_ptr>;
6249 using vector_iterator = typename vector_type::iterator;
6250 using const_vector_iterator = typename vector_type::const_iterator;
6252
6255 array(const impl::array_init_elem*, const impl::array_init_elem*);
6256
6258 array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
6259 : array{ elems.begin(), elems.end() }
6260 {}
6261
6263 void preinsertion_resize(size_t idx, size_t count);
6264
6266 void insert_at_back(impl::node_ptr&&);
6267
6270
6271 template <typename T>
6273 {
6274 if constexpr (is_node_view<T>)
6275 {
6276 if (!val)
6277 return;
6278 }
6279 insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
6280 }
6281
6284 size_t total_leaf_count() const noexcept;
6285
6287 void flatten_child(array&& child, size_t& dest_index) noexcept;
6288
6289 public:
6290 using value_type = node;
6291 using size_type = size_t;
6292 using difference_type = ptrdiff_t;
6293 using reference = node&;
6294 using const_reference = const node&;
6295
6298 array() noexcept;
6299
6301 ~array() noexcept;
6302
6305 array(const array&);
6306
6309 array(array&& other) noexcept;
6310
6311 TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0 || !std::is_same_v<impl::remove_cvref<ElemType>, array>),
6312 typename ElemType,
6313 typename... ElemTypes)
6315 explicit array(ElemType&& val, ElemTypes&&... vals)
6316 : array{ std::false_type{},
6317 std::initializer_list<impl::array_init_elem>{ static_cast<ElemType&&>(val),
6318 static_cast<ElemTypes&&>(vals)... } }
6319 {}
6320
6322 array& operator=(const array&);
6323
6325 array& operator=(array&& rhs) noexcept;
6326
6328 node_type type() const noexcept final
6329 {
6330 return node_type::array;
6331 }
6332
6335 bool is_homogeneous(node_type ntype) const noexcept final;
6336
6339 bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;
6340
6343 bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;
6344
6345 template <typename ElemType = void>
6347 bool is_homogeneous() const noexcept
6348 {
6349 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
6350 static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
6351 "The template type argument of array::is_homogeneous() must be void or one "
6353
6354 return is_homogeneous(impl::node_type_of<type>);
6355 }
6357 bool is_table() const noexcept final
6358 {
6359 return false;
6360 }
6361
6363 bool is_array() const noexcept final
6364 {
6365 return true;
6366 }
6367
6369 bool is_array_of_tables() const noexcept final
6370 {
6371 return is_homogeneous(node_type::table);
6372 }
6373
6375 bool is_value() const noexcept final
6376 {
6377 return false;
6378 }
6379
6381 bool is_string() const noexcept final
6382 {
6383 return false;
6384 }
6385
6387 bool is_integer() const noexcept final
6388 {
6389 return false;
6390 }
6391
6393 bool is_floating_point() const noexcept final
6394 {
6395 return false;
6396 }
6397
6399 bool is_number() const noexcept final
6400 {
6401 return false;
6402 }
6403
6405 bool is_boolean() const noexcept final
6406 {
6407 return false;
6408 }
6409
6411 bool is_date() const noexcept final
6412 {
6413 return false;
6414 }
6415
6417 bool is_time() const noexcept final
6418 {
6419 return false;
6420 }
6421
6423 bool is_date_time() const noexcept final
6424 {
6425 return false;
6426 }
6427
6429 table* as_table() noexcept final
6430 {
6431 return nullptr;
6432 }
6433
6435 array* as_array() noexcept final
6436 {
6437 return this;
6438 }
6439
6441 toml::value<std::string>* as_string() noexcept final
6442 {
6443 return nullptr;
6444 }
6445
6447 toml::value<int64_t>* as_integer() noexcept final
6448 {
6449 return nullptr;
6450 }
6451
6453 toml::value<double>* as_floating_point() noexcept final
6454 {
6455 return nullptr;
6456 }
6457
6459 toml::value<bool>* as_boolean() noexcept final
6460 {
6461 return nullptr;
6462 }
6463
6465 toml::value<date>* as_date() noexcept final
6466 {
6467 return nullptr;
6468 }
6469
6471 toml::value<time>* as_time() noexcept final
6472 {
6473 return nullptr;
6474 }
6475
6477 toml::value<date_time>* as_date_time() noexcept final
6478 {
6479 return nullptr;
6480 }
6481
6483 const table* as_table() const noexcept final
6484 {
6485 return nullptr;
6486 }
6487
6489 const array* as_array() const noexcept final
6490 {
6491 return this;
6492 }
6493
6495 const toml::value<std::string>* as_string() const noexcept final
6496 {
6497 return nullptr;
6498 }
6499
6501 const toml::value<int64_t>* as_integer() const noexcept final
6502 {
6503 return nullptr;
6504 }
6505
6507 const toml::value<double>* as_floating_point() const noexcept final
6508 {
6509 return nullptr;
6510 }
6511
6513 const toml::value<bool>* as_boolean() const noexcept final
6514 {
6515 return nullptr;
6516 }
6517
6519 const toml::value<date>* as_date() const noexcept final
6520 {
6521 return nullptr;
6522 }
6523
6525 const toml::value<time>* as_time() const noexcept final
6526 {
6527 return nullptr;
6528 }
6529
6531 const toml::value<date_time>* as_date_time() const noexcept final
6532 {
6533 return nullptr;
6534 }
6535
6537 node* get(size_t index) noexcept
6538 {
6539 return index < elems_.size() ? elems_[index].get() : nullptr;
6540 }
6541
6543 const node* get(size_t index) const noexcept
6544 {
6545 return const_cast<array&>(*this).get(index);
6546 }
6547
6548 template <typename ElemType>
6550 impl::wrap_node<ElemType>* get_as(size_t index) noexcept
6551 {
6552 if (auto val = get(index))
6553 return val->template as<ElemType>();
6554 return nullptr;
6555 }
6556
6557 template <typename ElemType>
6559 const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
6560 {
6561 return const_cast<array&>(*this).template get_as<ElemType>(index);
6562 }
6563
6564 using node::operator[]; // inherit operator[toml::path]
6566 node& operator[](size_t index) noexcept
6567 {
6568 return *elems_[index];
6569 }
6570
6572 const node& operator[](size_t index) const noexcept
6573 {
6574 return *elems_[index];
6575 }
6576
6579 node& at(size_t index);
6580
6582 const node& at(size_t index) const
6583 {
6584 return const_cast<array&>(*this).at(index);
6585 }
6586
6588 node& front() noexcept
6589 {
6590 return *elems_.front();
6591 }
6592
6594 const node& front() const noexcept
6595 {
6596 return *elems_.front();
6597 }
6598
6600 node& back() noexcept
6601 {
6602 return *elems_.back();
6603 }
6604
6606 const node& back() const noexcept
6607 {
6608 return *elems_.back();
6609 }
6610
6611 using iterator = array_iterator;
6612
6614
6616 iterator begin() noexcept
6617 {
6618 return iterator{ elems_.begin() };
6619 }
6620
6622 const_iterator begin() const noexcept
6623 {
6624 return const_iterator{ elems_.cbegin() };
6625 }
6626
6628 const_iterator cbegin() const noexcept
6629 {
6630 return const_iterator{ elems_.cbegin() };
6631 }
6632
6634 iterator end() noexcept
6635 {
6636 return iterator{ elems_.end() };
6637 }
6638
6640 const_iterator end() const noexcept
6641 {
6642 return const_iterator{ elems_.cend() };
6643 }
6644
6646 const_iterator cend() const noexcept
6647 {
6648 return const_iterator{ elems_.cend() };
6649 }
6650
6651 private:
6652
6653 template <typename T, typename Array>
6654 using for_each_elem_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;
6655
6656 template <typename Func, typename Array, typename T>
6657 using can_for_each = std::disjunction<std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
6658 std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
6659 std::is_invocable<Func, for_each_elem_ref<T, Array>>>;
6660
6661 template <typename Func, typename Array, typename T>
6662 using can_for_each_nothrow = std::conditional_t<
6663 // first form
6664 std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
6665 std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
6666 std::conditional_t<
6667 // second form
6668 std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
6669 std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
6670 std::conditional_t<
6671 // third form
6672 std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
6673 std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>,
6674 std::false_type>>>;
6675
6676 template <typename Func, typename Array>
6677 using can_for_each_any = std::disjunction<can_for_each<Func, Array, table>,
6686
6687 template <typename Func, typename Array, typename T>
6688 using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Array, T>>, //
6690
6691 template <typename Func, typename Array>
6692 using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Array, table>,
6701
6702 template <typename Func, typename Array>
6703 static void do_for_each(Func&& visitor, Array&& arr) //
6705 {
6707 "TOML array for_each visitors must be invocable for at least one of the toml::node "
6708 "specializations:" TOML_SA_NODE_TYPE_LIST);
6709
6710 for (size_t i = 0; i < arr.size(); i++)
6711 {
6712 using node_ref = impl::copy_cvref<toml::node, Array&&>;
6713 static_assert(std::is_reference_v<node_ref>);
6714
6715#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
6716
6717#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
6718 static_assert(impl::always_false<Func, Array, node_ref>, //
6719 TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
6720#endif
6721
6722 static_cast<node_ref>(static_cast<Array&&>(arr)[i])
6723 .visit(
6724 [&]([[maybe_unused]] auto&& elem) //
6725 noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
6726 {
6727 using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
6728 static_assert(std::is_reference_v<elem_ref>);
6729
6730 // func(elem, i)
6731 if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
6732 {
6733 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
6734 }
6735
6736 // func(i, elem)
6737 else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
6738 {
6739 static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
6740 }
6741
6742 // func(elem)
6743 else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
6744 {
6745 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
6746 }
6747 });
6748
6749#else
6750 const auto keep_going =
6751 static_cast<node_ref>(static_cast<Array&&>(arr)[i])
6752 .visit(
6753 [&]([[maybe_unused]] auto&& elem) //
6754 noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
6755 {
6756 using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
6757 static_assert(std::is_reference_v<elem_ref>);
6758
6759 // func(elem, i)
6760 if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
6761 {
6762 using return_type =
6763 decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
6764
6765 if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
6766 {
6767 return static_cast<bool>(
6768 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
6769 }
6770 else
6771 {
6772 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
6773 return true;
6774 }
6775 }
6776
6777 // func(i, elem)
6778 else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
6779 {
6780 using return_type =
6781 decltype(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
6782
6783 if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
6784 {
6785 return static_cast<bool>(
6786 static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
6787 }
6788 else
6789 {
6790 static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
6791 return true;
6792 }
6793 }
6794
6795 // func(elem)
6796 else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
6797 {
6798 using return_type =
6799 decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
6800
6801 if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
6802 {
6803 return static_cast<bool>(
6804 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
6805 }
6806 else
6807 {
6808 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
6809 return true;
6810 }
6811 }
6812
6813 // visitor not compatible with this particular type
6814 else
6815 return true;
6816 });
6817
6818 if (!keep_going)
6819 return;
6820#endif
6821 }
6822 }
6823
6824 public:
6825
6826 template <typename Func>
6827 array& for_each(Func&& visitor) & //
6829 {
6830 do_for_each(static_cast<Func&&>(visitor), *this);
6831 return *this;
6832 }
6833
6834 template <typename Func>
6835 array&& for_each(Func&& visitor) && //
6837 {
6838 do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
6839 return static_cast<array&&>(*this);
6840 }
6841
6842 template <typename Func>
6843 const array& for_each(Func&& visitor) const& //
6845 {
6846 do_for_each(static_cast<Func&&>(visitor), *this);
6847 return *this;
6848 }
6849
6850 template <typename Func>
6851 const array&& for_each(Func&& visitor) const&& //
6853 {
6854 do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
6855 return static_cast<const array&&>(*this);
6856 }
6857
6859 bool empty() const noexcept
6860 {
6861 return elems_.empty();
6862 }
6863
6865 size_t size() const noexcept
6866 {
6867 return elems_.size();
6868 }
6869
6871 size_t max_size() const noexcept
6872 {
6873 return elems_.max_size();
6874 }
6875
6877 size_t capacity() const noexcept
6878 {
6879 return elems_.capacity();
6880 }
6881
6883 void reserve(size_t new_capacity);
6884
6887
6889 void truncate(size_t new_size);
6890
6891 template <typename ElemType>
6892 void resize(size_t new_size,
6893 ElemType&& default_init_val,
6894 value_flags default_init_flags = preserve_source_value_flags)
6895 {
6896 static_assert(!is_node_view<ElemType>,
6897 "The default element type argument to toml::array::resize may not be toml::node_view.");
6898
6899 if (!new_size)
6900 clear();
6901 else if (new_size > elems_.size())
6902 insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
6903 else
6904 truncate(new_size);
6905 }
6906
6909
6912
6915
6917 {
6918 return static_cast<toml::array&&>(this->flatten());
6919 }
6920
6922 array& prune(bool recursive = true) & noexcept;
6923
6924 array&& prune(bool recursive = true) && noexcept
6925 {
6926 return static_cast<toml::array&&>(this->prune(recursive));
6927 }
6928
6930 void pop_back() noexcept;
6931
6933 void clear() noexcept;
6934
6935 template <typename ElemType>
6937 {
6938 if constexpr (is_node_view<ElemType>)
6939 {
6940 if (!val)
6941 return end();
6942 }
6944 impl::make_node(static_cast<ElemType&&>(val), flags)) };
6945 }
6946
6947 template <typename ElemType>
6949 size_t count,
6950 ElemType&& val,
6952 {
6953 if constexpr (is_node_view<ElemType>)
6954 {
6955 if (!val)
6956 return end();
6957 }
6958 switch (count)
6959 {
6960 case 0: return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
6961 case 1: return insert(pos, static_cast<ElemType&&>(val), flags);
6962 default:
6963 {
6964 const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
6965 preinsertion_resize(start_idx, count);
6966 size_t i = start_idx;
6967 for (size_t e = start_idx + count - 1u; i < e; i++)
6968 elems_[i] = impl::make_node(val, flags);
6969
6970 elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
6971 return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
6972 }
6973 }
6974 }
6975
6976 template <typename Iter>
6978 {
6979 const auto distance = std::distance(first, last);
6980 if (distance <= 0)
6981 return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
6982 else
6983 {
6984 auto count = distance;
6985 using deref_type = decltype(*first);
6986 if constexpr (is_node_view<deref_type>)
6987 {
6988 for (auto it = first; it != last; it++)
6989 if (!(*it))
6990 count--;
6991 if (!count)
6992 return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
6993 }
6994 const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
6995 preinsertion_resize(start_idx, static_cast<size_t>(count));
6996 size_t i = start_idx;
6997 for (auto it = first; it != last; it++)
6998 {
6999 if constexpr (is_node_view<deref_type>)
7000 {
7001 if (!(*it))
7002 continue;
7003 }
7004 if constexpr (std::is_rvalue_reference_v<deref_type>)
7005 elems_[i++] = impl::make_node(std::move(*it), flags);
7006 else
7007 elems_[i++] = impl::make_node(*it, flags);
7008 }
7009 return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
7010 }
7011 }
7012
7013 template <typename ElemType>
7015 std::initializer_list<ElemType> ilist,
7017 {
7018 return insert(pos, ilist.begin(), ilist.end(), flags);
7019 }
7020
7021 template <typename ElemType = void, typename... Args>
7022 iterator emplace(const_iterator pos, Args&&... args)
7023 {
7024 using raw_elem_type = impl::remove_cvref<ElemType>;
7025 using elem_type = std::conditional_t<std::is_void_v<raw_elem_type>, //
7026 impl::emplaced_type_of<Args&&...>,
7027 raw_elem_type>;
7028
7029 using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
7030 static_assert(impl::is_native<type> || impl::is_one_of<type, table, array>,
7031 "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
7032
7034 impl::node_ptr{ new impl::wrap_node<type>{ static_cast<Args&&>(args)... } }) };
7035 }
7036
7037 template <typename ElemType>
7039 {
7040 TOML_ASSERT(pos >= cbegin() && pos < cend());
7041
7042 if constexpr (is_node_view<ElemType>)
7043 {
7044 if (!val)
7045 return end();
7046 }
7047
7048 const auto it = elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin());
7049 *it = impl::make_node(static_cast<ElemType&&>(val), flags);
7050 return iterator{ it };
7051 }
7052
7053 template <typename ElemType>
7055 {
7056 emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
7057 }
7058
7059 template <typename ElemType = void, typename... Args>
7060 decltype(auto) emplace_back(Args&&... args)
7061 {
7062 using raw_elem_type = impl::remove_cvref<ElemType>;
7063 using elem_type = std::conditional_t<std::is_void_v<raw_elem_type>, //
7064 impl::emplaced_type_of<Args&&...>,
7065 raw_elem_type>;
7066
7067 static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
7068 && sizeof...(Args) == 1u //
7069 && impl::first_is_same<impl::node_ptr&&, Args&&...>;
7070
7071 using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
7072
7073 static_assert(
7074 moving_node_ptr //
7075 || impl::is_native<unwrapped_type> //
7076 || impl::is_one_of<unwrapped_type, table, array>, //
7077 "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
7078
7079 if constexpr (moving_node_ptr)
7080 {
7081 insert_at_back(static_cast<Args&&>(args)...);
7082 return *elems_.back();
7083 }
7084 else
7085 {
7086 auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<Args&&>(args)... };
7087 insert_at_back(impl::node_ptr{ ptr });
7088 return *ptr;
7089 }
7090 }
7091
7092 private:
7093
7096 static bool TOML_CALLCONV equal(const array&, const array&) noexcept;
7097
7098 template <typename T>
7100 static bool equal_to_container(const array& lhs, const T& rhs) noexcept
7101 {
7102 using element_type = std::remove_const_t<typename T::value_type>;
7103 static_assert(impl::is_losslessly_convertible_to_native<element_type>,
7104 "Container element type must be losslessly convertible one of the native TOML value types");
7105
7106 if (lhs.size() != rhs.size())
7107 return false;
7108 if (rhs.size() == 0u)
7109 return true;
7110
7111 size_t i{};
7112 for (auto& list_elem : rhs)
7113 {
7114 const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
7115 if (!elem || *elem != list_elem)
7116 return false;
7117 }
7118
7119 return true;
7120 }
7121
7122 public:
7123
7125 friend bool operator==(const array& lhs, const array& rhs) noexcept
7126 {
7127 return equal(lhs, rhs);
7128 }
7129
7131 friend bool operator!=(const array& lhs, const array& rhs) noexcept
7132 {
7133 return !equal(lhs, rhs);
7134 }
7135
7136 template <typename T>
7138 friend bool operator==(const array& lhs, const std::initializer_list<T>& rhs) noexcept
7139 {
7140 return equal_to_container(lhs, rhs);
7141 }
7142 TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>);
7143
7144 template <typename T>
7146 friend bool operator==(const array& lhs, const std::vector<T>& rhs) noexcept
7147 {
7148 return equal_to_container(lhs, rhs);
7149 }
7150 TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>);
7151
7152#if TOML_ENABLE_FORMATTERS
7153
7154 friend std::ostream& operator<<(std::ostream& lhs, const array& rhs)
7155 {
7156 impl::print_to_stream(lhs, rhs);
7157 return lhs;
7158 }
7159
7160#endif
7161 };
7162}
7164
7165#ifdef _MSC_VER
7166#pragma pop_macro("min")
7167#pragma pop_macro("max")
7168#ifndef __clang__
7169#pragma inline_recursion(off)
7170#endif
7171#endif
7173
7174//******** impl/key.hpp **********************************************************************************************
7175
7177#ifdef _MSC_VER
7178#ifndef __clang__
7179#pragma inline_recursion(on)
7180#endif
7181#pragma push_macro("min")
7182#pragma push_macro("max")
7183#undef min
7184#undef max
7185#endif
7186
7188{
7189 class key
7190 {
7191 private:
7192 std::string key_;
7193 source_region source_;
7194
7195 public:
7196
7198 key() noexcept = default;
7199
7201 explicit key(std::string_view k, source_region&& src = {}) //
7202 : key_{ k },
7203 source_{ std::move(src) }
7204 {}
7205
7207 explicit key(std::string_view k, const source_region& src) //
7208 : key_{ k },
7209 source_{ src }
7210 {}
7211
7213 explicit key(std::string&& k, source_region&& src = {}) noexcept //
7214 : key_{ std::move(k) },
7215 source_{ std::move(src) }
7216 {}
7217
7219 explicit key(std::string&& k, const source_region& src) noexcept //
7220 : key_{ std::move(k) },
7221 source_{ src }
7222 {}
7223
7225 explicit key(const char* k, source_region&& src = {}) //
7226 : key_{ k },
7227 source_{ std::move(src) }
7228 {}
7229
7231 explicit key(const char* k, const source_region& src) //
7232 : key_{ k },
7233 source_{ src }
7234 {}
7235
7236#if TOML_ENABLE_WINDOWS_COMPAT
7237
7239 explicit key(std::wstring_view k, source_region&& src = {}) //
7240 : key_{ impl::narrow(k) },
7241 source_{ std::move(src) }
7242 {}
7243
7245 explicit key(std::wstring_view k, const source_region& src) //
7246 : key_{ impl::narrow(k) },
7247 source_{ src }
7248 {}
7249
7250#endif
7251
7253 std::string_view str() const noexcept
7254 {
7255 return std::string_view{ key_ };
7256 }
7257
7259 /*implicit*/ operator std::string_view() const noexcept
7260 {
7261 return str();
7262 }
7263
7265 bool empty() const noexcept
7266 {
7267 return key_.empty();
7268 }
7269
7271 const char* data() const noexcept
7272 {
7273 return key_.data();
7274 }
7275
7277 size_t length() const noexcept
7278 {
7279 return key_.length();
7280 }
7281
7283 const source_region& source() const noexcept
7284 {
7285 return source_;
7286 }
7287
7289 friend bool operator==(const key& lhs, const key& rhs) noexcept
7290 {
7291 return lhs.key_ == rhs.key_;
7292 }
7293
7295 friend bool operator!=(const key& lhs, const key& rhs) noexcept
7296 {
7297 return lhs.key_ != rhs.key_;
7298 }
7299
7301 friend bool operator<(const key& lhs, const key& rhs) noexcept
7302 {
7303 return lhs.key_ < rhs.key_;
7304 }
7305
7307 friend bool operator<=(const key& lhs, const key& rhs) noexcept
7308 {
7309 return lhs.key_ <= rhs.key_;
7310 }
7311
7313 friend bool operator>(const key& lhs, const key& rhs) noexcept
7314 {
7315 return lhs.key_ > rhs.key_;
7316 }
7317
7319 friend bool operator>=(const key& lhs, const key& rhs) noexcept
7320 {
7321 return lhs.key_ >= rhs.key_;
7322 }
7323
7325 friend bool operator==(const key& lhs, std::string_view rhs) noexcept
7326 {
7327 return lhs.key_ == rhs;
7328 }
7329
7331 friend bool operator!=(const key& lhs, std::string_view rhs) noexcept
7332 {
7333 return lhs.key_ != rhs;
7334 }
7335
7337 friend bool operator<(const key& lhs, std::string_view rhs) noexcept
7338 {
7339 return lhs.key_ < rhs;
7340 }
7341
7343 friend bool operator<=(const key& lhs, std::string_view rhs) noexcept
7344 {
7345 return lhs.key_ <= rhs;
7346 }
7347
7349 friend bool operator>(const key& lhs, std::string_view rhs) noexcept
7350 {
7351 return lhs.key_ > rhs;
7352 }
7353
7355 friend bool operator>=(const key& lhs, std::string_view rhs) noexcept
7356 {
7357 return lhs.key_ >= rhs;
7358 }
7359
7361 friend bool operator==(std::string_view lhs, const key& rhs) noexcept
7362 {
7363 return lhs == rhs.key_;
7364 }
7365
7367 friend bool operator!=(std::string_view lhs, const key& rhs) noexcept
7368 {
7369 return lhs != rhs.key_;
7370 }
7371
7373 friend bool operator<(std::string_view lhs, const key& rhs) noexcept
7374 {
7375 return lhs < rhs.key_;
7376 }
7377
7379 friend bool operator<=(std::string_view lhs, const key& rhs) noexcept
7380 {
7381 return lhs <= rhs.key_;
7382 }
7383
7385 friend bool operator>(std::string_view lhs, const key& rhs) noexcept
7386 {
7387 return lhs > rhs.key_;
7388 }
7389
7391 friend bool operator>=(std::string_view lhs, const key& rhs) noexcept
7392 {
7393 return lhs >= rhs.key_;
7394 }
7395
7396 using const_iterator = const char*;
7397
7398 using iterator = const_iterator;
7399
7401 const_iterator begin() const noexcept
7402 {
7403 return key_.data();
7404 }
7405
7407 const_iterator end() const noexcept
7408 {
7409 return key_.data() + key_.length();
7410 }
7411
7412 friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
7413 {
7414 impl::print_to_stream(lhs, rhs.key_);
7415 return lhs;
7416 }
7417 };
7418
7419 template <typename T>
7420 inline constexpr bool is_key = std::is_same_v<impl::remove_cvref<T>, toml::key>;
7421
7422 template <typename T>
7423 inline constexpr bool is_key_or_convertible = is_key<T> //
7424 || impl::is_constructible_or_convertible<toml::key, T>;
7425}
7427
7428#ifdef _MSC_VER
7429#pragma pop_macro("min")
7430#pragma pop_macro("max")
7431#ifndef __clang__
7432#pragma inline_recursion(off)
7433#endif
7434#endif
7436
7437//******** impl/std_map.hpp ******************************************************************************************
7438
7440#include <map>
7441#include <iterator>
7443
7444//******** impl/table.hpp ********************************************************************************************
7445
7447#ifdef _MSC_VER
7448#ifndef __clang__
7449#pragma inline_recursion(on)
7450#endif
7451#pragma push_macro("min")
7452#pragma push_macro("max")
7453#undef min
7454#undef max
7455#endif
7456
7458{
7459 template <bool IsConst>
7460 struct table_proxy_pair
7461 {
7462 using value_type = std::conditional_t<IsConst, const node, node>;
7463
7464 const toml::key& first;
7465 value_type& second;
7466 };
7467
7468 template <bool IsConst>
7470 {
7471 private:
7472 template <bool>
7473 friend class table_iterator;
7474
7475 using proxy_type = table_proxy_pair<IsConst>;
7476 using mutable_map_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator;
7477 using const_map_iterator = std::map<toml::key, node_ptr, std::less<>>::const_iterator;
7478 using map_iterator = std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>;
7479
7481 alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)];
7482 mutable bool proxy_instantiated_ = false;
7483
7485 proxy_type* get_proxy() const noexcept
7486 {
7488 {
7489 auto p = ::new (static_cast<void*>(proxy_)) proxy_type{ iter_->first, *iter_->second.get() };
7490 proxy_instantiated_ = true;
7491 return p;
7492 }
7493 else
7494 return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_));
7495 }
7496
7497 public:
7499 table_iterator() noexcept = default;
7500
7502 explicit table_iterator(mutable_map_iterator iter) noexcept //
7503 : iter_{ iter }
7504 {}
7505
7506 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
7508 explicit table_iterator(const_map_iterator iter) noexcept //
7509 : iter_{ iter }
7510 {}
7511
7512 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
7514 table_iterator(const table_iterator<false>& other) noexcept //
7515 : iter_{ other.iter_ }
7516 {}
7517
7519 table_iterator(const table_iterator& other) noexcept //
7520 : iter_{ other.iter_ }
7521 {}
7522
7524 {
7525 iter_ = rhs.iter_;
7526 proxy_instantiated_ = false;
7527 return *this;
7528 }
7529
7530 using value_type = table_proxy_pair<IsConst>;
7533 using difference_type = typename std::iterator_traits<map_iterator>::difference_type;
7534 using iterator_category = typename std::iterator_traits<map_iterator>::iterator_category;
7535
7536 table_iterator& operator++() noexcept // ++pre
7537 {
7538 ++iter_;
7539 proxy_instantiated_ = false;
7540 return *this;
7541 }
7542
7543 table_iterator operator++(int) noexcept // post++
7544 {
7545 table_iterator out{ iter_ };
7546 ++iter_;
7547 proxy_instantiated_ = false;
7548 return out;
7549 }
7550
7551 table_iterator& operator--() noexcept // --pre
7552 {
7553 --iter_;
7554 proxy_instantiated_ = false;
7555 return *this;
7556 }
7557
7558 table_iterator operator--(int) noexcept // post--
7559 {
7560 table_iterator out{ iter_ };
7561 --iter_;
7562 proxy_instantiated_ = false;
7563 return out;
7564 }
7565
7567 reference operator*() const noexcept
7568 {
7569 return *get_proxy();
7570 }
7571
7573 pointer operator->() const noexcept
7574 {
7575 return get_proxy();
7576 }
7577
7579 explicit operator const map_iterator&() const noexcept
7580 {
7581 return iter_;
7582 }
7583
7584 TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
7586 explicit operator const const_map_iterator() const noexcept
7587 {
7588 return iter_;
7589 }
7590
7592 friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept
7593 {
7594 return lhs.iter_ == rhs.iter_;
7595 }
7596
7598 friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept
7599 {
7600 return lhs.iter_ != rhs.iter_;
7601 }
7602 };
7603
7605 {
7606 mutable toml::key key;
7607 mutable node_ptr value;
7608
7609 template <typename K, typename V>
7612 : key{ static_cast<K&&>(k) },
7613 value{ make_node(static_cast<V&&>(v), flags) }
7614 {}
7615 };
7616}
7618
7620{
7621 using table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>);
7622
7623 using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>);
7624
7625 class TOML_EXPORTED_CLASS table : public node
7626 {
7627 private:
7628
7629 using map_type = std::map<toml::key, impl::node_ptr, std::less<>>;
7630 using map_pair = std::pair<const toml::key, impl::node_ptr>;
7631 using map_iterator = typename map_type::iterator;
7632 using const_map_iterator = typename map_type::const_iterator;
7634
7635 bool inline_ = false;
7636
7639 table(const impl::table_init_pair*, const impl::table_init_pair*);
7640
7641 public:
7642
7645 table() noexcept;
7646
7648 ~table() noexcept;
7649
7652 table(const table&);
7653
7656 table(table&& other) noexcept;
7657
7660 explicit table(std::initializer_list<impl::table_init_pair> kvps) //
7661 : table(kvps.begin(), kvps.end())
7662 {}
7663
7666
7668 table& operator=(table&& rhs) noexcept;
7669
7671 node_type type() const noexcept final
7672 {
7673 return node_type::table;
7674 }
7675
7678 bool is_homogeneous(node_type ntype) const noexcept final;
7679
7682 bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;
7683
7686 bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;
7687
7688 template <typename ElemType = void>
7690 bool is_homogeneous() const noexcept
7691 {
7692 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
7693 static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
7694 "The template type argument of table::is_homogeneous() must be void or one "
7696
7697 return is_homogeneous(impl::node_type_of<type>);
7698 }
7700 bool is_table() const noexcept final
7701 {
7702 return true;
7703 }
7704
7706 bool is_array() const noexcept final
7707 {
7708 return false;
7709 }
7710
7712 bool is_array_of_tables() const noexcept final
7713 {
7714 return false;
7715 }
7716
7718 bool is_value() const noexcept final
7719 {
7720 return false;
7721 }
7722
7724 bool is_string() const noexcept final
7725 {
7726 return false;
7727 }
7728
7730 bool is_integer() const noexcept final
7731 {
7732 return false;
7733 }
7734
7736 bool is_floating_point() const noexcept final
7737 {
7738 return false;
7739 }
7740
7742 bool is_number() const noexcept final
7743 {
7744 return false;
7745 }
7746
7748 bool is_boolean() const noexcept final
7749 {
7750 return false;
7751 }
7752
7754 bool is_date() const noexcept final
7755 {
7756 return false;
7757 }
7758
7760 bool is_time() const noexcept final
7761 {
7762 return false;
7763 }
7764
7766 bool is_date_time() const noexcept final
7767 {
7768 return false;
7769 }
7770
7772 table* as_table() noexcept final
7773 {
7774 return this;
7775 }
7776
7778 array* as_array() noexcept final
7779 {
7780 return nullptr;
7781 }
7782
7784 toml::value<std::string>* as_string() noexcept final
7785 {
7786 return nullptr;
7787 }
7788
7790 toml::value<int64_t>* as_integer() noexcept final
7791 {
7792 return nullptr;
7793 }
7794
7796 toml::value<double>* as_floating_point() noexcept final
7797 {
7798 return nullptr;
7799 }
7800
7802 toml::value<bool>* as_boolean() noexcept final
7803 {
7804 return nullptr;
7805 }
7806
7808 toml::value<date>* as_date() noexcept final
7809 {
7810 return nullptr;
7811 }
7812
7814 toml::value<time>* as_time() noexcept final
7815 {
7816 return nullptr;
7817 }
7818
7820 toml::value<date_time>* as_date_time() noexcept final
7821 {
7822 return nullptr;
7823 }
7824
7826 const table* as_table() const noexcept final
7827 {
7828 return this;
7829 }
7830
7832 const array* as_array() const noexcept final
7833 {
7834 return nullptr;
7835 }
7836
7838 const toml::value<std::string>* as_string() const noexcept final
7839 {
7840 return nullptr;
7841 }
7842
7844 const toml::value<int64_t>* as_integer() const noexcept final
7845 {
7846 return nullptr;
7847 }
7848
7850 const toml::value<double>* as_floating_point() const noexcept final
7851 {
7852 return nullptr;
7853 }
7854
7856 const toml::value<bool>* as_boolean() const noexcept final
7857 {
7858 return nullptr;
7859 }
7860
7862 const toml::value<date>* as_date() const noexcept final
7863 {
7864 return nullptr;
7865 }
7866
7868 const toml::value<time>* as_time() const noexcept final
7869 {
7870 return nullptr;
7871 }
7872
7874 const toml::value<date_time>* as_date_time() const noexcept final
7875 {
7876 return nullptr;
7877 }
7878
7880 bool is_inline() const noexcept
7881 {
7882 return inline_;
7883 }
7884
7885 void is_inline(bool val) noexcept
7886 {
7887 inline_ = val;
7888 }
7889
7892 node* get(std::string_view key) noexcept;
7893
7895 const node* get(std::string_view key) const noexcept
7896 {
7897 return const_cast<table&>(*this).get(key);
7898 }
7899
7900#if TOML_ENABLE_WINDOWS_COMPAT
7901
7903 node* get(std::wstring_view key)
7904 {
7905 if (empty())
7906 return nullptr;
7907
7908 return get(impl::narrow(key));
7909 }
7910
7912 const node* get(std::wstring_view key) const
7913 {
7914 return const_cast<table&>(*this).get(key);
7915 }
7916
7917#endif // TOML_ENABLE_WINDOWS_COMPAT
7918
7919 template <typename T>
7921 impl::wrap_node<T>* get_as(std::string_view key) noexcept
7922 {
7923 const auto n = this->get(key);
7924 return n ? n->template as<T>() : nullptr;
7925 }
7926
7927 template <typename T>
7929 const impl::wrap_node<T>* get_as(std::string_view key) const noexcept
7930 {
7931 return const_cast<table&>(*this).template get_as<T>(key);
7932 }
7933
7934#if TOML_ENABLE_WINDOWS_COMPAT
7935
7936 template <typename T>
7938 impl::wrap_node<T>* get_as(std::wstring_view key)
7939 {
7940 if (empty())
7941 return nullptr;
7942
7943 return get_as<T>(impl::narrow(key));
7944 }
7945
7946 template <typename T>
7948 const impl::wrap_node<T>* get_as(std::wstring_view key) const
7949 {
7950 return const_cast<table&>(*this).template get_as<T>(key);
7951 }
7952
7953#endif // TOML_ENABLE_WINDOWS_COMPAT
7954
7957 node& at(std::string_view key);
7958
7960 const node& at(std::string_view key) const
7961 {
7962 return const_cast<table&>(*this).at(key);
7963 }
7964
7965#if TOML_ENABLE_WINDOWS_COMPAT
7966
7968 node& at(std::wstring_view key)
7969 {
7970 return at(impl::narrow(key));
7971 }
7972
7974 const node& at(std::wstring_view key) const
7975 {
7976 return const_cast<table&>(*this).at(key);
7977 }
7978
7979#endif // TOML_ENABLE_WINDOWS_COMPAT
7980
7981 using iterator = toml::table_iterator;
7982
7983 using const_iterator = toml::const_table_iterator;
7984
7986 iterator begin() noexcept
7987 {
7988 return iterator{ map_.begin() };
7989 }
7990
7992 const_iterator begin() const noexcept
7993 {
7994 return const_iterator{ map_.cbegin() };
7995 }
7996
7998 const_iterator cbegin() const noexcept
7999 {
8000 return const_iterator{ map_.cbegin() };
8001 }
8002
8004 iterator end() noexcept
8005 {
8006 return iterator{ map_.end() };
8007 }
8008
8010 const_iterator end() const noexcept
8011 {
8012 return const_iterator{ map_.cend() };
8013 }
8014
8016 const_iterator cend() const noexcept
8017 {
8018 return const_iterator{ map_.cend() };
8019 }
8020
8021 private:
8022
8023 template <typename T, typename Table>
8024 using for_each_value_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Table>;
8025
8026 template <typename Func, typename Table, typename T>
8027 using can_for_each = std::disjunction<std::is_invocable<Func, const key&, for_each_value_ref<T, Table>>, //
8028 std::is_invocable<Func, for_each_value_ref<T, Table>>>;
8029
8030 template <typename Func, typename Table, typename T>
8031 using can_for_each_nothrow = std::conditional_t<
8032 // first form
8033 std::is_invocable_v<Func, const key&, for_each_value_ref<T, Table>>,
8034 std::is_nothrow_invocable<Func, const key&, for_each_value_ref<T, Table>>,
8035 std::conditional_t<
8036 // second form
8037 std::is_invocable_v<Func, for_each_value_ref<T, Table>>,
8038 std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>,
8039 std::false_type>>;
8040
8041 template <typename Func, typename Table>
8042 using can_for_each_any = std::disjunction<can_for_each<Func, Table, table>,
8051
8052 template <typename Func, typename Table, typename T>
8053 using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Table, T>>, //
8055
8056 template <typename Func, typename Table>
8057 using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Table, table>,
8066
8067 template <typename Func, typename Table>
8068 static void do_for_each(Func&& visitor, Table&& tbl) //
8070 {
8072 "TOML table for_each visitors must be invocable for at least one of the toml::node "
8073 "specializations:" TOML_SA_NODE_TYPE_LIST);
8074
8075 using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>;
8076
8077 for (kvp_type& kvp : tbl.map_)
8078 {
8079 using node_ref = impl::copy_cvref<toml::node, Table&&>;
8080 static_assert(std::is_reference_v<node_ref>);
8081
8082#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
8083
8084#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
8085 static_assert(impl::always_false<Func, Table, kvp_type, node_ref>, //
8086 TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
8087#endif
8088
8089 static_cast<node_ref>(*kvp.second)
8090 .visit(
8091 [&]([[maybe_unused]] auto&& v) //
8092 noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value)
8093 {
8094 using value_ref = for_each_value_ref<decltype(v), Table&&>;
8095 static_assert(std::is_reference_v<value_ref>);
8096
8097 // func(key, val)
8098 if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>)
8099 {
8100 static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first),
8101 static_cast<value_ref>(v));
8102 }
8103
8104 // func(val)
8105 else if constexpr (std::is_invocable_v<Func&&, value_ref>)
8106 {
8107 static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
8108 }
8109 });
8110
8111#else
8112 const auto keep_going =
8113 static_cast<node_ref>(*kvp.second)
8114 .visit(
8115 [&]([[maybe_unused]] auto&& v) //
8116 noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value)
8117 {
8118 using value_ref = for_each_value_ref<decltype(v), Table&&>;
8119 static_assert(std::is_reference_v<value_ref>);
8120
8121 // func(key, val)
8122 if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>)
8123 {
8124 using return_type = decltype(static_cast<Func&&>(
8125 visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v)));
8126
8127 if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
8128 {
8129 return static_cast<bool>(static_cast<Func&&>(
8130 visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v)));
8131 }
8132 else
8133 {
8134 static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first),
8135 static_cast<value_ref>(v));
8136 return true;
8137 }
8138 }
8139
8140 // func(val)
8141 else if constexpr (std::is_invocable_v<Func&&, value_ref>)
8142 {
8143 using return_type =
8144 decltype(static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
8145
8146 if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
8147 {
8148 return static_cast<bool>(
8149 static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
8150 }
8151 else
8152 {
8153 static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
8154 return true;
8155 }
8156 }
8157
8158 // visitor not compatible with this particular type
8159 else
8160 return true;
8161 });
8162
8163 if (!keep_going)
8164 return;
8165#endif
8166 }
8167 }
8168
8169 public:
8170
8171 template <typename Func>
8172 table& for_each(Func&& visitor) & //
8174 {
8175 do_for_each(static_cast<Func&&>(visitor), *this);
8176 return *this;
8177 }
8178
8179 template <typename Func>
8180 table&& for_each(Func&& visitor) && //
8182 {
8183 do_for_each(static_cast<Func&&>(visitor), static_cast<table&&>(*this));
8184 return static_cast<table&&>(*this);
8185 }
8186
8187 template <typename Func>
8188 const table& for_each(Func&& visitor) const& //
8190 {
8191 do_for_each(static_cast<Func&&>(visitor), *this);
8192 return *this;
8193 }
8194
8195 template <typename Func>
8196 const table&& for_each(Func&& visitor) const&& //
8198 {
8199 do_for_each(static_cast<Func&&>(visitor), static_cast<const table&&>(*this));
8200 return static_cast<const table&&>(*this);
8201 }
8202
8204 bool empty() const noexcept
8205 {
8206 return map_.empty();
8207 }
8208
8210 size_t size() const noexcept
8211 {
8212 return map_.size();
8213 }
8214
8215 private:
8216
8219 map_iterator get_lower_bound(std::string_view) noexcept;
8220
8221 public:
8222
8224 iterator lower_bound(std::string_view key) noexcept
8225 {
8226 return iterator{ get_lower_bound(key) };
8227 }
8228
8230 const_iterator lower_bound(std::string_view key) const noexcept
8231 {
8232 return const_iterator{ const_cast<table&>(*this).get_lower_bound(key) };
8233 }
8234
8235#if TOML_ENABLE_WINDOWS_COMPAT
8236
8238 iterator lower_bound(std::wstring_view key)
8239 {
8240 if (empty())
8241 return end();
8242
8243 return lower_bound(impl::narrow(key));
8244 }
8245
8247 const_iterator lower_bound(std::wstring_view key) const
8248 {
8249 if (empty())
8250 return end();
8251
8252 return lower_bound(impl::narrow(key));
8253 }
8254
8255#endif // TOML_ENABLE_WINDOWS_COMPAT
8256
8259 iterator find(std::string_view key) noexcept;
8260
8263 const_iterator find(std::string_view key) const noexcept;
8264
8266 bool contains(std::string_view key) const noexcept
8267 {
8268 return get(key) != nullptr;
8269 }
8270
8271#if TOML_ENABLE_WINDOWS_COMPAT
8272
8274 iterator find(std::wstring_view key)
8275 {
8276 if (empty())
8277 return end();
8278
8279 return find(impl::narrow(key));
8280 }
8281
8283 const_iterator find(std::wstring_view key) const
8284 {
8285 return find(impl::narrow(key));
8286 }
8287
8289 bool contains(std::wstring_view key) const
8290 {
8291 return contains(impl::narrow(key));
8292 }
8293
8294#endif // TOML_ENABLE_WINDOWS_COMPAT
8295
8296 private:
8297
8300
8303
8304 public:
8305
8307 {
8308 return iterator{ erase(const_map_iterator{ pos }) };
8309 }
8310
8312 {
8313 return iterator{ erase(const_map_iterator{ pos }) };
8314 }
8315
8320
8322 size_t erase(std::string_view key) noexcept;
8323
8324#if TOML_ENABLE_WINDOWS_COMPAT
8325
8326 size_t erase(std::wstring_view key)
8327 {
8328 if (empty())
8329 return false;
8330
8331 return erase(impl::narrow(key));
8332 }
8333
8334#endif // TOML_ENABLE_WINDOWS_COMPAT
8335
8337 table& prune(bool recursive = true) & noexcept;
8338
8339 table&& prune(bool recursive = true) && noexcept
8340 {
8341 return static_cast<toml::table&&>(this->prune(recursive));
8342 }
8343
8345 void clear() noexcept;
8346
8347 private:
8348
8351
8352 public:
8353
8355 typename ValueType = void,
8356 typename KeyType,
8357 typename... ValueArgs)
8358 iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args)
8359 {
8360 static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8361 "Emplacement using wide-character keys is only supported on Windows with "
8362 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8363
8364 using raw_value_type = impl::remove_cvref<ValueType>;
8365 using value_type = std::
8366 conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
8367
8368 if constexpr (impl::is_wide_string<KeyType>)
8369 {
8370#if TOML_ENABLE_WINDOWS_COMPAT
8371 return emplace_hint<value_type>(hint,
8372 impl::narrow(static_cast<KeyType&&>(key)),
8373 static_cast<ValueArgs&&>(args)...);
8374#else
8375 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8376#endif
8377 }
8378 else
8379 {
8380 static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
8381 && sizeof...(ValueArgs) == 1u //
8382 && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
8383 using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
8384
8385 static_assert(moving_node_ptr //
8386 || impl::is_native<unwrapped_type> //
8387 || impl::is_one_of<unwrapped_type, table, array>, //
8388 "ValueType argument of table::emplace_hint() must be one "
8390
8391 map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr);
8392
8393 // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
8394 // so now we have to construct the actual value
8395 if (!ipos->second)
8396 {
8397 if constexpr (moving_node_ptr)
8398 ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
8399 else
8400 {
8401#if TOML_COMPILER_HAS_EXCEPTIONS
8402 try
8403 {
8404#endif
8405 ipos->second.reset(
8406 new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
8407#if TOML_COMPILER_HAS_EXCEPTIONS
8408 }
8409 catch (...)
8410 {
8411 erase(const_map_iterator{ ipos }); // strong exception guarantee
8412 throw;
8413 }
8414#endif
8415 }
8416 }
8417 return iterator{ ipos };
8418 }
8419 }
8420
8422 typename KeyType,
8423 typename ValueType)
8424 std::pair<iterator, bool> insert(KeyType&& key,
8425 ValueType&& val,
8427 {
8428 static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8429 "Insertion using wide-character keys is only supported on Windows with "
8430 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8431
8432 if constexpr (is_node_view<ValueType>)
8433 {
8434 if (!val)
8435 return { end(), false };
8436 }
8437
8438 if constexpr (impl::is_wide_string<KeyType>)
8439 {
8440#if TOML_ENABLE_WINDOWS_COMPAT
8441 return insert(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), flags);
8442#else
8443 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8444#endif
8445 }
8446 else
8447 {
8448 const auto key_view = std::string_view{ key };
8449 map_iterator ipos = get_lower_bound(key_view);
8450 if (ipos == map_.end() || ipos->first != key_view)
8451 {
8453 toml::key{ static_cast<KeyType&&>(key) },
8454 impl::make_node(static_cast<ValueType&&>(val), flags));
8455 return { iterator{ ipos }, true };
8456 }
8457 return { iterator{ ipos }, false };
8458 }
8459 }
8460
8461 TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), typename Iter)
8463 {
8464 if (begin == end)
8465 return;
8466 for (auto it = begin; it != end; it++)
8467 {
8468 if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
8469 insert(std::move((*it).first), std::move((*it).second), flags);
8470 else
8471 insert((*it).first, (*it).second, flags);
8472 }
8473 }
8474
8476 typename KeyType,
8477 typename ValueType)
8478 std::pair<iterator, bool> insert_or_assign(KeyType&& key,
8479 ValueType&& val,
8481 {
8482 static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8483 "Insertion using wide-character keys is only supported on Windows with "
8484 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8485
8486 if constexpr (is_node_view<ValueType>)
8487 {
8488 if (!val)
8489 return { end(), false };
8490 }
8491
8492 if constexpr (impl::is_wide_string<KeyType>)
8493 {
8494#if TOML_ENABLE_WINDOWS_COMPAT
8495 return insert_or_assign(impl::narrow(static_cast<KeyType&&>(key)),
8496 static_cast<ValueType&&>(val),
8497 flags);
8498#else
8499 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8500#endif
8501 }
8502 else
8503 {
8504 const auto key_view = std::string_view{ key };
8505 map_iterator ipos = get_lower_bound(key_view);
8506 if (ipos == map_.end() || ipos->first != key_view)
8507 {
8509 toml::key{ static_cast<KeyType&&>(key) },
8510 impl::make_node(static_cast<ValueType&&>(val), flags));
8511 return { iterator{ ipos }, true };
8512 }
8513 else
8514 {
8515 (*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags);
8516 return { iterator{ ipos }, false };
8517 }
8518 }
8519 }
8520
8522 typename ValueType = void,
8523 typename KeyType,
8524 typename... ValueArgs)
8525 std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args)
8526 {
8527 static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8528 "Emplacement using wide-character keys is only supported on Windows with "
8529 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8530
8531 using raw_value_type = impl::remove_cvref<ValueType>;
8532 using value_type = std::
8533 conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
8534
8535 if constexpr (impl::is_wide_string<KeyType>)
8536 {
8537#if TOML_ENABLE_WINDOWS_COMPAT
8538 return emplace<value_type>(impl::narrow(static_cast<KeyType&&>(key)),
8539 static_cast<ValueArgs&&>(args)...);
8540#else
8541 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8542#endif
8543 }
8544 else
8545 {
8546 using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
8547 static_assert((impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
8548 "ValueType argument of table::emplace() must be one "
8550
8551 const auto key_view = std::string_view{ key };
8552 auto ipos = get_lower_bound(key_view);
8553 if (ipos == map_.end() || ipos->first != key_view)
8554 {
8557 toml::key{ static_cast<KeyType&&>(key) },
8558 impl::node_ptr{ new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... } });
8559 return { iterator{ ipos }, true };
8560 }
8561 return { iterator{ ipos }, false };
8562 }
8563 }
8564
8565 using node::operator[]; // inherit operator[toml::path]
8566
8568 node_view<node> operator[](std::string_view key) noexcept
8569 {
8570 return node_view<node>{ get(key) };
8571 }
8572
8574 node_view<const node> operator[](std::string_view key) const noexcept
8575 {
8576 return node_view<const node>{ get(key) };
8577 }
8578
8579#if TOML_ENABLE_WINDOWS_COMPAT
8580
8582 node_view<node> operator[](std::wstring_view key)
8583 {
8584 return node_view<node>{ get(key) };
8585 }
8586
8588 node_view<const node> operator[](std::wstring_view key) const
8589 {
8590 return node_view<const node>{ get(key) };
8591 }
8592
8593#endif // TOML_ENABLE_WINDOWS_COMPAT
8594
8595 private:
8596
8599 static bool TOML_CALLCONV equal(const table&, const table&) noexcept;
8600
8601 public:
8602
8604 friend bool operator==(const table& lhs, const table& rhs) noexcept
8605 {
8606 return equal(lhs, rhs);
8607 }
8608
8610 friend bool operator!=(const table& lhs, const table& rhs) noexcept
8611 {
8612 return !equal(lhs, rhs);
8613 }
8614
8615#if TOML_ENABLE_FORMATTERS
8616
8617 friend std::ostream& operator<<(std::ostream& lhs, const table& rhs)
8618 {
8619 impl::print_to_stream(lhs, rhs);
8620 return lhs;
8621 }
8622
8623#endif
8624 };
8625}
8627
8628#ifdef _MSC_VER
8629#pragma pop_macro("min")
8630#pragma pop_macro("max")
8631#ifndef __clang__
8632#pragma inline_recursion(off)
8633#endif
8634#endif
8636
8637//******** impl/unicode_autogenerated.hpp ****************************************************************************
8638
8640#ifdef _MSC_VER
8641#ifndef __clang__
8642#pragma inline_recursion(on)
8643#endif
8644#pragma push_macro("min")
8645#pragma push_macro("max")
8646#undef min
8647#undef max
8648#endif
8649
8650#if TOML_GCC && TOML_GCC < 9
8651#pragma GCC push_options
8652#pragma GCC optimize("O1") // codegen bugs
8653#endif
8654
8655// the functions in this namespace block are automatically generated by a tool - they are not meant to be hand-edited
8656
8658{
8660 constexpr bool is_ascii_horizontal_whitespace(char32_t c) noexcept
8661 {
8662 return c == U'\t' || c == U' ';
8663 }
8664
8666 constexpr bool is_non_ascii_horizontal_whitespace(char32_t c) noexcept
8667 {
8668 // 20 code units from 8 ranges (spanning a search area of 65120)
8669
8670 if (c < U'\xA0' || c > U'\uFEFF')
8671 return false;
8672
8673 const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xA0ull) / 0x3FAull;
8674 if ((1ull << child_index_0) & 0x7FFFFFFFFFFFF75Eull)
8675 return false;
8676 if (c == U'\xA0' || c == U'\u3000' || c == U'\uFEFF')
8677 return true;
8678 switch (child_index_0)
8679 {
8680 case 0x05: return c == U'\u1680' || c == U'\u180E';
8681 case 0x07:
8682 return (U'\u2000' <= c && c <= U'\u200B') || (U'\u205F' <= c && c <= U'\u2060') || c == U'\u202F';
8683 default: TOML_UNREACHABLE;
8684 }
8685
8687 }
8688
8690 constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept
8691 {
8692 return c >= U'\n' && c <= U'\r';
8693 }
8694
8696 constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept
8697 {
8698 return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
8699 }
8700
8702 constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
8703 {
8704#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
8705 if TOML_UNLIKELY(c == U'+')
8706 return true;
8707#endif
8708 // 64 code units from 5 ranges (spanning a search area of 78)
8709
8710 if (c < U'-' || c > U'z')
8711 return false;
8712
8713 return (((static_cast<uint_least64_t>(c) - 0x2Dull) / 0x40ull) != 0ull)
8714 || ((1ull << (static_cast<uint_least64_t>(c) - 0x2Dull)) & 0xFFF43FFFFFF01FF9ull);
8715 }
8716
8717#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
8718
8720 constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept
8721 {
8722 // 971732 code units from 16 ranges (spanning a search area of 982862)
8723
8724 if (c < U'\xB2' || c > U'\U000EFFFF')
8725 return false;
8726
8727 const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xB2ull) / 0x3BFEull;
8728 if ((1ull << child_index_0) & 0xFFFFFFFFFFFFFFE6ull)
8729 return true;
8730 switch (child_index_0)
8731 {
8732 case 0x00: // [0] 00B2 - 3CAF
8733 {
8734 // 12710 code units from 13 ranges (spanning a search area of 15358)
8735
8736 TOML_ASSUME(c >= U'\xB2' && c <= U'\u3CAF');
8737
8738 constexpr uint_least64_t bitmask_table_1[] = {
8739 0xFFFFFFDFFFFFDC83u, 0xFFFFFFFFFFFFFFDFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8740 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8741 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFEFFFu,
8742 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8743 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8744 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8745 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8746 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8747 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8748 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8749 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8750 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8751 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8752 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8753 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8754 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8755 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8756 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8757 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8758 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8759 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8760 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8761 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8762 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8763 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8764 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8765 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8766 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8767 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8768 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8769 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8770 0xFFFFFFFFFFFFFFFFu, 0x000000000C003FFFu, 0xC000000000006000u, 0xFFFFFFFFFFFFFFFFu,
8771 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000000003FFFFFFFu,
8772 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8773 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8774 0x0000000000000000u, 0x0000000000000000u, 0xFFFFC00000000000u, 0xFFFFFFFFFFFFFFFFu,
8775 0xFFFFFFFFFFFFFFFFu, 0x0000000000003FFFu, 0x0000000000000000u, 0x0000000000000000u,
8776 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8777 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8778 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8779 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8780 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8781 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8782 0x0000000000000000u, 0xFFFFFFFFFFFFC000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8783 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8784 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8785 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8786 0x3FFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFF8000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8787 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8788 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8789 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8790 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8791 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8792 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8793 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8794 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8795 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8796 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8797 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8798 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu,
8799 };
8800 return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xB2ull) / 0x40ull]
8801 & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xB2ull) % 0x40ull));
8802 }
8803 case 0x03: return c <= U'\uD7FF';
8804 case 0x04:
8805 return (U'\uF900' <= c && c <= U'\uFDCF') || (U'\uFDF0' <= c && c <= U'\uFFFD') || U'\U00010000' <= c;
8806 default: TOML_UNREACHABLE;
8807 }
8808
8810 }
8811
8812#endif // TOML_LANG_UNRELEASED
8813}
8815
8816#if TOML_GCC && TOML_GCC < 9
8817#pragma GCC pop_options
8818#endif
8819
8820#ifdef _MSC_VER
8821#pragma pop_macro("min")
8822#pragma pop_macro("max")
8823#ifndef __clang__
8824#pragma inline_recursion(off)
8825#endif
8826#endif
8828
8829//******** impl/unicode.hpp ******************************************************************************************
8830
8832#ifdef _MSC_VER
8833#ifndef __clang__
8834#pragma inline_recursion(on)
8835#endif
8836#pragma push_macro("min")
8837#pragma push_macro("max")
8838#undef min
8839#undef max
8840#endif
8841
8843{
8845 constexpr bool is_string_delimiter(char32_t c) noexcept
8846 {
8847 return c == U'"' || c == U'\'';
8848 }
8849
8851 constexpr bool is_ascii_letter(char32_t c) noexcept
8852 {
8853 return (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z');
8854 }
8855
8857 constexpr bool is_binary_digit(char32_t c) noexcept
8858 {
8859 return c == U'0' || c == U'1';
8860 }
8861
8863 constexpr bool is_octal_digit(char32_t c) noexcept
8864 {
8865 return (c >= U'0' && c <= U'7');
8866 }
8867
8869 constexpr bool is_decimal_digit(char32_t c) noexcept
8870 {
8871 return (c >= U'0' && c <= U'9');
8872 }
8873
8875 constexpr bool is_hexadecimal_digit(char32_t c) noexcept
8876 {
8877 return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
8878 }
8879
8880 template <typename T>
8882 constexpr uint_least32_t hex_to_dec(const T c) noexcept
8883 {
8884 if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
8885 return c >= 0x41u // >= 'A'
8886 ? 10u + (c | 0x20u) - 0x61u // - 'a'
8887 : c - 0x30u // - '0'
8888 ;
8889 else
8890 return hex_to_dec(static_cast<uint_least32_t>(c));
8891 }
8892
8894 constexpr bool is_horizontal_whitespace(char32_t c) noexcept
8895 {
8896 return is_ascii_horizontal_whitespace(c) || is_non_ascii_horizontal_whitespace(c);
8897 }
8898
8900 constexpr bool is_vertical_whitespace(char32_t c) noexcept
8901 {
8902 return is_ascii_vertical_whitespace(c) || is_non_ascii_vertical_whitespace(c);
8903 }
8904
8906 constexpr bool is_whitespace(char32_t c) noexcept
8907 {
8908 return is_horizontal_whitespace(c) || is_vertical_whitespace(c);
8909 }
8910
8912 constexpr bool is_bare_key_character(char32_t c) noexcept
8913 {
8914 return is_ascii_bare_key_character(c)
8915#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
8916 || is_non_ascii_bare_key_character(c)
8917#endif
8918 ;
8919 }
8920
8922 constexpr bool is_value_terminator(char32_t c) noexcept
8923 {
8924 return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
8925 }
8926
8928 constexpr bool is_control_character(char c) noexcept
8929 {
8930 return c <= '\u001F' || c == '\u007F';
8931 }
8932
8934 constexpr bool is_control_character(char32_t c) noexcept
8935 {
8936 return c <= U'\u001F' || c == U'\u007F';
8937 }
8938
8940 constexpr bool is_nontab_control_character(char32_t c) noexcept
8941 {
8942 return c <= U'\u0008' || (c >= U'\u000A' && c <= U'\u001F') || c == U'\u007F';
8943 }
8944
8946 constexpr bool is_unicode_surrogate(char32_t c) noexcept
8947 {
8948 return c >= 0xD800u && c <= 0xDFFF;
8949 }
8950
8951 struct utf8_decoder
8952 {
8953 // utf8_decoder based on this: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
8954 // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
8955
8956 uint_least32_t state{};
8957 char32_t codepoint{};
8958
8959 static constexpr uint8_t state_table[]{
8960 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8961 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8962 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8963 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8964 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
8965 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7,
8966 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8967 7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
8968 2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6,
8969 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8970 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12,
8971 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12,
8972 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12,
8973 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
8974 };
8975
8977 constexpr bool error() const noexcept
8978 {
8979 return state == uint_least32_t{ 12u };
8980 }
8981
8983 constexpr bool has_code_point() const noexcept
8984 {
8985 return state == uint_least32_t{};
8986 }
8987
8989 constexpr bool needs_more_input() const noexcept
8990 {
8991 return !has_code_point() && !error();
8992 }
8993
8994 constexpr void operator()(uint8_t byte) noexcept
8995 {
8997
8998 const auto type = state_table[byte];
8999
9000 codepoint = static_cast<char32_t>(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte
9001 : (byte & uint_least32_t{ 63u })
9002 | (static_cast<uint_least32_t>(codepoint) << 6));
9003
9004 state = state_table[state + uint_least32_t{ 256u } + type];
9005 }
9006
9008 constexpr void operator()(char c) noexcept
9009 {
9010 operator()(static_cast<uint8_t>(c));
9011 }
9012
9014 constexpr void reset() noexcept
9015 {
9016 state = {};
9017 }
9018 };
9019
9021 TOML_ATTR(nonnull)
9022 bool is_ascii(const char* str, size_t len) noexcept;
9023}
9025
9026#ifdef _MSC_VER
9027#pragma pop_macro("min")
9028#pragma pop_macro("max")
9029#ifndef __clang__
9030#pragma inline_recursion(off)
9031#endif
9032#endif
9034
9035//******** impl/parse_error.hpp **************************************************************************************
9036
9037#if TOML_ENABLE_PARSER
9038
9039//******** impl/std_except.hpp ***************************************************************************************
9040
9042#if TOML_EXCEPTIONS
9043#include <stdexcept>
9044#endif
9046
9047//******** impl/parse_error.hpp **************************************************************************************
9048
9050#ifdef _MSC_VER
9051#ifndef __clang__
9052#pragma inline_recursion(on)
9053#endif
9054#pragma push_macro("min")
9055#pragma push_macro("max")
9056#undef min
9057#undef max
9058#endif
9059
9060#if TOML_DOXYGEN || !TOML_EXCEPTIONS
9061#define TOML_PARSE_ERROR_BASE
9062#else
9063#define TOML_PARSE_ERROR_BASE : public std::runtime_error
9064#endif
9065
9067{
9069
9071 {
9072 private:
9073#if !TOML_EXCEPTIONS
9074 std::string description_;
9075#endif
9077
9078 public:
9079#if TOML_EXCEPTIONS
9080
9082 TOML_ATTR(nonnull)
9083 parse_error(const char* desc, source_region&& src) noexcept //
9084 : std::runtime_error{ desc },
9085 source_{ std::move(src) }
9086 {}
9087
9089 TOML_ATTR(nonnull)
9090 parse_error(const char* desc, const source_region& src) noexcept //
9091 : parse_error{ desc, source_region{ src } }
9092 {}
9093
9095 TOML_ATTR(nonnull)
9096 parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept
9097 : parse_error{ desc, source_region{ position, position, path } }
9098 {}
9099
9100#else
9101
9103 parse_error(std::string&& desc, source_region&& src) noexcept //
9104 : description_{ std::move(desc) },
9105 source_{ std::move(src) }
9106 {}
9107
9109 parse_error(std::string&& desc, const source_region& src) noexcept //
9110 : parse_error{ std::move(desc), source_region{ src } }
9111 {}
9112
9114 parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
9115 : parse_error{ std::move(desc), source_region{ position, position, path } }
9116 {}
9117
9118#endif
9119
9121 std::string_view description() const noexcept
9122 {
9123#if TOML_EXCEPTIONS
9124 return std::string_view{ what() };
9125#else
9126 return description_;
9127#endif
9128 }
9129
9131 const source_region& source() const noexcept
9132 {
9133 return source_;
9134 }
9135
9136 friend std::ostream& operator<<(std::ostream& lhs, const parse_error& rhs)
9137 {
9138 impl::print_to_stream(lhs, rhs.description());
9139 impl::print_to_stream(lhs, "\n\t(error occurred at "sv);
9140 impl::print_to_stream(lhs, rhs.source());
9141 impl::print_to_stream(lhs, ")"sv);
9142 return lhs;
9143 }
9144 };
9145
9146 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9147}
9149
9150#undef TOML_PARSE_ERROR_BASE
9151
9152#ifdef _MSC_VER
9153#pragma pop_macro("min")
9154#pragma pop_macro("max")
9155#ifndef __clang__
9156#pragma inline_recursion(off)
9157#endif
9158#endif
9160
9161#endif // TOML_ENABLE_PARSER
9162
9163//******** impl/parse_result.hpp *************************************************************************************
9164
9165#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
9166
9168#ifdef _MSC_VER
9169#ifndef __clang__
9170#pragma inline_recursion(on)
9171#endif
9172#pragma push_macro("min")
9173#pragma push_macro("max")
9174#undef min
9175#undef max
9176#endif
9177
9179{
9181
9183 {
9184 private:
9186 {
9187 static constexpr size_t size =
9188 (sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(toml::table));
9189 static constexpr size_t align =
9190 (alignof(toml::table) < alignof(parse_error) ? alignof(parse_error) : alignof(toml::table));
9191
9192 alignas(align) unsigned char bytes[size];
9193 };
9194
9196 bool err_;
9197
9198 template <typename Type>
9201 static Type* get_as(storage_t& s) noexcept
9202 {
9203 return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
9204 }
9205
9206 void destroy() noexcept
9207 {
9208 if (err_)
9209 get_as<parse_error>(storage_)->~parse_error();
9210 else
9211 get_as<toml::table>(storage_)->~table();
9212 }
9213
9214 public:
9215
9217 parse_result() noexcept //
9218 : err_{ true }
9219 {
9220 ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::string{}, source_region{} };
9221 }
9222
9224 explicit parse_result(toml::table&& tbl) noexcept //
9225 : err_{ false }
9226 {
9227 ::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(tbl) };
9228 }
9229
9231 explicit parse_result(parse_error&& err) noexcept //
9232 : err_{ true }
9233 {
9234 ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(err) };
9235 }
9236
9239 : err_{ res.err_ }
9240 {
9241 if (err_)
9242 ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(res).error() };
9243 else
9244 ::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(res).table() };
9245 }
9246
9248 {
9249 if (err_ != rhs.err_)
9250 {
9251 destroy();
9252 err_ = rhs.err_;
9253 if (err_)
9254 ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(rhs).error() };
9255 else
9256 ::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(rhs).table() };
9257 }
9258 else
9259 {
9260 if (err_)
9261 error() = std::move(rhs).error();
9262 else
9263 table() = std::move(rhs).table();
9264 }
9265 return *this;
9266 }
9267
9268 ~parse_result() noexcept
9269 {
9270 destroy();
9271 }
9272
9274 bool succeeded() const noexcept
9275 {
9276 return !err_;
9277 }
9278
9280 bool failed() const noexcept
9281 {
9282 return err_;
9283 }
9284
9286 explicit operator bool() const noexcept
9287 {
9288 return !err_;
9289 }
9290
9292 toml::table& table() & noexcept
9293 {
9296 }
9297
9299 toml::table&& table() && noexcept
9300 {
9302 return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
9303 }
9304
9306 const toml::table& table() const& noexcept
9307 {
9310 }
9311
9313 /* implicit */ operator toml::table&() noexcept
9314 {
9315 return table();
9316 }
9317
9319 /* implicit */ operator toml::table&&() noexcept
9320 {
9321 return std::move(table());
9322 }
9323
9325 /* implicit */ operator const toml::table&() const noexcept
9326 {
9327 return table();
9328 }
9329
9331 parse_error& error() & noexcept
9332 {
9335 }
9336
9338 parse_error&& error() && noexcept
9339 {
9341 return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
9342 }
9343
9345 const parse_error& error() const& noexcept
9346 {
9349 }
9350
9352 explicit operator parse_error&() noexcept
9353 {
9354 return error();
9355 }
9356
9358 explicit operator parse_error&&() noexcept
9359 {
9360 return std::move(error());
9361 }
9362
9364 explicit operator const parse_error&() const noexcept
9365 {
9366 return error();
9367 }
9368
9370
9372
9375 {
9376 return err_ ? table_iterator{} : table().begin();
9377 }
9378
9381 {
9382 return err_ ? const_table_iterator{} : table().begin();
9383 }
9384
9387 {
9388 return err_ ? const_table_iterator{} : table().cbegin();
9389 }
9390
9393 {
9394 return err_ ? table_iterator{} : table().end();
9395 }
9396
9398 const_table_iterator end() const noexcept
9399 {
9400 return err_ ? const_table_iterator{} : table().end();
9401 }
9402
9405 {
9406 return err_ ? const_table_iterator{} : table().cend();
9407 }
9408
9410 node_view<node> at_path(std::string_view path) noexcept
9411 {
9412 return err_ ? node_view<node>{} : table().at_path(path);
9413 }
9414
9416 node_view<const node> at_path(std::string_view path) const noexcept
9417 {
9418 return err_ ? node_view<const node>{} : table().at_path(path);
9419 }
9420
9422 node_view<node> at_path(const toml::path& path) noexcept
9423 {
9424 return err_ ? node_view<node>{} : table().at_path(path);
9425 }
9426
9428 node_view<const node> at_path(const toml::path& path) const noexcept
9429 {
9430 return err_ ? node_view<const node>{} : table().at_path(path);
9431 }
9432
9433#if TOML_ENABLE_WINDOWS_COMPAT
9434
9436 node_view<node> at_path(std::wstring_view path)
9437 {
9438 return err_ ? node_view<node>{} : table().at_path(path);
9439 }
9440
9442 node_view<const node> at_path(std::wstring_view path) const
9443 {
9444 return err_ ? node_view<const node>{} : table().at_path(path);
9445 }
9446
9447#endif
9448
9450 node_view<node> operator[](const toml::path& path) noexcept
9451 {
9452 return err_ ? node_view<node>{} : table()[path];
9453 }
9454
9456 node_view<const node> operator[](const toml::path& path) const noexcept
9457 {
9458 return err_ ? node_view<const node>{} : table()[path];
9459 }
9460
9462 node_view<node> operator[](std::string_view key) noexcept
9463 {
9464 return err_ ? node_view<node>{} : table()[key];
9465 }
9466
9468 node_view<const node> operator[](std::string_view key) const noexcept
9469 {
9470 return err_ ? node_view<const node>{} : table()[key];
9471 }
9472
9473#if TOML_ENABLE_WINDOWS_COMPAT
9474
9476 node_view<node> operator[](std::wstring_view key)
9477 {
9478 return err_ ? node_view<node>{} : table()[key];
9479 }
9480
9482 node_view<const node> operator[](std::wstring_view key) const
9483 {
9484 return err_ ? node_view<const node>{} : table()[key];
9485 }
9486
9487#endif // TOML_ENABLE_WINDOWS_COMPAT
9488
9489#if TOML_ENABLE_FORMATTERS
9490
9491 friend std::ostream& operator<<(std::ostream& os, const parse_result& result)
9492 {
9493 return result.err_ ? (os << result.error()) : (os << result.table());
9494 }
9495
9496#endif
9497 };
9498
9500}
9502
9503#ifdef _MSC_VER
9504#pragma pop_macro("min")
9505#pragma pop_macro("max")
9506#ifndef __clang__
9507#pragma inline_recursion(off)
9508#endif
9509#endif
9511
9512#endif // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
9513
9514//******** impl/parser.hpp *******************************************************************************************
9515
9516#if TOML_ENABLE_PARSER
9517
9519#ifdef _MSC_VER
9520#ifndef __clang__
9521#pragma inline_recursion(on)
9522#endif
9523#pragma push_macro("min")
9524#pragma push_macro("max")
9525#undef min
9526#undef max
9527#endif
9528
9530{
9532
9535 parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path = {});
9536
9539 parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path);
9540
9543 parse_result TOML_CALLCONV parse_file(std::string_view file_path);
9544
9545#if TOML_HAS_CHAR8
9546
9549 parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path = {});
9550
9553 parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path);
9554
9557 parse_result TOML_CALLCONV parse_file(std::u8string_view file_path);
9558
9559#endif // TOML_HAS_CHAR8
9560
9561#if TOML_ENABLE_WINDOWS_COMPAT
9562
9565 parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path);
9566
9569 parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path);
9570
9573 parse_result TOML_CALLCONV parse_file(std::wstring_view file_path);
9574
9575#endif // TOML_ENABLE_WINDOWS_COMPAT
9576
9577#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
9578
9581 parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path);
9582
9583#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
9584
9587 parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path = {});
9588
9591 parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path);
9592
9593 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9594
9595 inline namespace literals
9596 {
9598
9601 parse_result operator"" _toml(const char* str, size_t len)
9602 {
9603 return parse(std::string_view{ str, len });
9604 }
9605
9606#if TOML_HAS_CHAR8
9607
9610 parse_result operator"" _toml(const char8_t* str, size_t len)
9611 {
9612 return parse(std::u8string_view{ str, len });
9613 }
9614
9615#endif // TOML_HAS_CHAR8
9616
9617 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9618 }
9619}
9621
9622#ifdef _MSC_VER
9623#pragma pop_macro("min")
9624#pragma pop_macro("max")
9625#ifndef __clang__
9626#pragma inline_recursion(off)
9627#endif
9628#endif
9630
9631#endif // TOML_ENABLE_PARSER
9632
9633//******** impl/formatter.hpp ****************************************************************************************
9634
9635#if TOML_ENABLE_FORMATTERS
9636
9638#ifdef _MSC_VER
9639#ifndef __clang__
9640#pragma inline_recursion(on)
9641#endif
9642#pragma push_macro("min")
9643#pragma push_macro("max")
9644#undef min
9645#undef max
9646#endif
9647
9649{
9650 struct formatter_constants
9651 {
9652 format_flags mandatory_flags;
9653 format_flags ignored_flags;
9654
9655 std::string_view float_pos_inf;
9656 std::string_view float_neg_inf;
9657 std::string_view float_nan;
9658
9659 std::string_view bool_true;
9660 std::string_view bool_false;
9661 };
9662
9664 {
9666 std::string_view indent;
9667 };
9668
9670 {
9671 private:
9672 const node* source_;
9673#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
9675#endif
9676 const formatter_constants* constants_;
9680 std::ostream* stream_; //
9681 int indent_; // these are set in attach()
9683
9684 protected:
9686 const node& source() const noexcept
9687 {
9688 return *source_;
9689 }
9690
9692 std::ostream& stream() const noexcept
9693 {
9694 return *stream_;
9695 }
9696
9698 int indent() const noexcept
9699 {
9700 return indent_;
9701 }
9702
9703 void indent(int level) noexcept
9704 {
9705 indent_ = level;
9706 }
9707
9708 void increase_indent() noexcept
9709 {
9710 indent_++;
9711 }
9712
9713 void decrease_indent() noexcept
9714 {
9715 indent_--;
9716 }
9717
9719 size_t indent_columns() const noexcept
9720 {
9721 return indent_columns_;
9722 }
9723
9725 bool indent_array_elements() const noexcept
9726 {
9727 return !!(config_.flags & format_flags::indent_array_elements);
9728 }
9729
9731 bool indent_sub_tables() const noexcept
9732 {
9733 return !!(config_.flags & format_flags::indent_sub_tables);
9734 }
9735
9737 bool literal_strings_allowed() const noexcept
9738 {
9739 return !!(config_.flags & format_flags::allow_literal_strings);
9740 }
9741
9743 bool multi_line_strings_allowed() const noexcept
9744 {
9745 return !!(config_.flags & format_flags::allow_multi_line_strings);
9746 }
9747
9749 bool real_tabs_in_strings_allowed() const noexcept
9750 {
9751 return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
9752 }
9753
9755 bool unicode_strings_allowed() const noexcept
9756 {
9757 return !!(config_.flags & format_flags::allow_unicode_strings);
9758 }
9759
9761 bool terse_kvps() const noexcept
9762 {
9763 return !!(config_.flags & format_flags::terse_key_value_pairs);
9764 }
9765
9767 void attach(std::ostream& stream) noexcept;
9768
9770 void detach() noexcept;
9771
9773 void print_newline(bool force = false);
9774
9776 void print_indent();
9777
9779 void print_unformatted(char);
9780
9782 void print_unformatted(std::string_view);
9783
9785 void print_string(std::string_view str,
9786 bool allow_multi_line = true,
9787 bool allow_bare = false,
9788 bool allow_literal_whitespace = true);
9789
9791 void print(const value<std::string>&);
9792
9794 void print(const value<int64_t>&);
9795
9797 void print(const value<double>&);
9798
9800 void print(const value<bool>&);
9801
9803 void print(const value<date>&);
9804
9806 void print(const value<time>&);
9807
9809 void print(const value<date_time>&);
9810
9812 void print_value(const node&, node_type);
9813
9816 bool dump_failed_parse_result();
9817
9820 formatter(const node*, const parse_result*, const formatter_constants&, const formatter_config&) noexcept;
9821 };
9822}
9824
9825#ifdef _MSC_VER
9826#pragma pop_macro("min")
9827#pragma pop_macro("max")
9828#ifndef __clang__
9829#pragma inline_recursion(off)
9830#endif
9831#endif
9833
9834#endif // TOML_ENABLE_FORMATTERS
9835
9836//******** impl/toml_formatter.hpp ***********************************************************************************
9837
9838#if TOML_ENABLE_FORMATTERS
9839
9841#ifdef _MSC_VER
9842#ifndef __clang__
9843#pragma inline_recursion(on)
9844#endif
9845#pragma push_macro("min")
9846#pragma push_macro("max")
9847#undef min
9848#undef max
9849#endif
9850
9852{
9853 class TOML_EXPORTED_CLASS toml_formatter : impl::formatter
9854 {
9855 private:
9856
9857 using base = impl::formatter;
9858 std::vector<const key*> key_path_;
9859 bool pending_table_separator_ = false;
9860
9862 void print_pending_table_separator();
9863
9865 void print(const key&);
9866
9868 void print_inline(const toml::table&);
9869
9871 void print(const toml::array&);
9872
9874 void print(const toml::table&);
9875
9877 void print();
9878
9879 static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory
9880 format_flags::none, // ignored
9881 "inf"sv,
9882 "-inf"sv,
9883 "nan"sv,
9884 "true"sv,
9885 "false"sv };
9886
9887 public:
9888
9889 static constexpr format_flags default_flags = constants.mandatory_flags //
9890 | format_flags::allow_literal_strings //
9891 | format_flags::allow_multi_line_strings //
9892 | format_flags::allow_unicode_strings //
9893 | format_flags::allow_real_tabs_in_strings //
9894 | format_flags::allow_binary_integers //
9895 | format_flags::allow_octal_integers //
9896 | format_flags::allow_hexadecimal_integers //
9897 | format_flags::indentation;
9898
9900 explicit toml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
9901 : base{ &source, nullptr, constants, { flags, " "sv } }
9902 {}
9903
9904#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
9905
9907 explicit toml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
9908 : base{ nullptr, &result, constants, { flags, " "sv } }
9909 {}
9910
9911#endif
9912
9913 friend std::ostream& operator<<(std::ostream& lhs, toml_formatter& rhs)
9914 {
9915 rhs.attach(lhs);
9916 rhs.key_path_.clear();
9917 rhs.print();
9918 rhs.detach();
9919 return lhs;
9920 }
9921
9922 friend std::ostream& operator<<(std::ostream& lhs, toml_formatter&& rhs)
9923 {
9924 return lhs << rhs; // as lvalue
9925 }
9926 };
9927}
9929
9930#ifdef _MSC_VER
9931#pragma pop_macro("min")
9932#pragma pop_macro("max")
9933#ifndef __clang__
9934#pragma inline_recursion(off)
9935#endif
9936#endif
9938
9939#endif // TOML_ENABLE_FORMATTERS
9940
9941//******** impl/json_formatter.hpp ***********************************************************************************
9942
9943#if TOML_ENABLE_FORMATTERS
9944
9946#ifdef _MSC_VER
9947#ifndef __clang__
9948#pragma inline_recursion(on)
9949#endif
9950#pragma push_macro("min")
9951#pragma push_macro("max")
9952#undef min
9953#undef max
9954#endif
9955
9957{
9958 class TOML_EXPORTED_CLASS json_formatter : impl::formatter
9959 {
9960 private:
9961
9962 using base = impl::formatter;
9963
9965 void print(const toml::table&);
9966
9968 void print(const toml::array&);
9969
9971 void print();
9972
9973 static constexpr impl::formatter_constants constants = {
9974 format_flags::quote_dates_and_times, // mandatory
9975 format_flags::allow_literal_strings | format_flags::allow_multi_line_strings, // ignored
9976 "Infinity"sv,
9977 "-Infinity"sv,
9978 "NaN"sv,
9979 "true"sv,
9980 "false"sv
9981 };
9982
9983 public:
9984
9985 static constexpr format_flags default_flags = constants.mandatory_flags //
9986 | format_flags::quote_infinities_and_nans //
9987 | format_flags::allow_unicode_strings //
9988 | format_flags::indentation;
9989
9991 explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
9992 : base{ &source, nullptr, constants, { flags, " "sv } }
9993 {}
9994
9995#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
9996
9998 explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
9999 : base{ nullptr, &result, constants, { flags, " "sv } }
10000 {}
10001
10002#endif
10003
10004 friend std::ostream& operator<<(std::ostream& lhs, json_formatter& rhs)
10005 {
10006 rhs.attach(lhs);
10007 rhs.print();
10008 rhs.detach();
10009 return lhs;
10010 }
10011
10012 friend std::ostream& operator<<(std::ostream& lhs, json_formatter&& rhs)
10013 {
10014 return lhs << rhs; // as lvalue
10015 }
10016 };
10017}
10019
10020#ifdef _MSC_VER
10021#pragma pop_macro("min")
10022#pragma pop_macro("max")
10023#ifndef __clang__
10024#pragma inline_recursion(off)
10025#endif
10026#endif
10028
10029#endif // TOML_ENABLE_FORMATTERS
10030
10031//******** impl/yaml_formatter.hpp ***********************************************************************************
10032
10033#if TOML_ENABLE_FORMATTERS
10034
10036#ifdef _MSC_VER
10037#ifndef __clang__
10038#pragma inline_recursion(on)
10039#endif
10040#pragma push_macro("min")
10041#pragma push_macro("max")
10042#undef min
10043#undef max
10044#endif
10045
10047{
10048 class TOML_EXPORTED_CLASS yaml_formatter : impl::formatter
10049 {
10050 private:
10051
10052 using base = impl::formatter;
10053
10055 void print_yaml_string(const value<std::string>&);
10056
10058 void print(const toml::table&, bool = false);
10059
10061 void print(const toml::array&, bool = false);
10062
10064 void print();
10065
10066 static constexpr impl::formatter_constants constants = {
10067 //
10068 format_flags::quote_dates_and_times | format_flags::indentation, // mandatory
10069 format_flags::allow_multi_line_strings, // ignored
10070 ".inf"sv,
10071 "-.inf"sv,
10072 ".NAN"sv,
10073 "true"sv,
10074 "false"sv
10075 };
10076
10077 public:
10078
10079 static constexpr format_flags default_flags = constants.mandatory_flags //
10080 | format_flags::allow_literal_strings //
10081 | format_flags::allow_unicode_strings //
10082 | format_flags::allow_octal_integers //
10083 | format_flags::allow_hexadecimal_integers;
10084
10086 explicit yaml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
10087 : base{ &source, nullptr, constants, { flags, " "sv } }
10088 {}
10089
10090#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
10091
10093 explicit yaml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
10094 : base{ nullptr, &result, constants, { flags, " "sv } }
10095 {}
10096
10097#endif
10098
10099 friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter& rhs)
10100 {
10101 rhs.attach(lhs);
10102 rhs.print();
10103 rhs.detach();
10104 return lhs;
10105 }
10106
10107 friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter&& rhs)
10108 {
10109 return lhs << rhs; // as lvalue
10110 }
10111 };
10112}
10114
10115#ifdef _MSC_VER
10116#pragma pop_macro("min")
10117#pragma pop_macro("max")
10118#ifndef __clang__
10119#pragma inline_recursion(off)
10120#endif
10121#endif
10123
10124#endif // TOML_ENABLE_FORMATTERS
10125
10126#if TOML_IMPLEMENTATION
10127
10128//******** impl/std_string.inl ***************************************************************************************
10129
10130#if TOML_WINDOWS
10131
10132#ifndef _WINDOWS_
10133#if TOML_INCLUDE_WINDOWS_H
10134#include <Windows.h>
10135#else
10136
10137extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int CodePage,
10138 unsigned long dwFlags,
10139 const wchar_t* lpWideCharStr,
10140 int cchWideChar,
10141 char* lpMultiByteStr,
10142 int cbMultiByte,
10143 const char* lpDefaultChar,
10144 int* lpUsedDefaultChar);
10145
10146extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage,
10147 unsigned long dwFlags,
10148 const char* lpMultiByteStr,
10149 int cbMultiByte,
10150 wchar_t* lpWideCharStr,
10151 int cchWideChar);
10152
10153#endif // TOML_INCLUDE_WINDOWS_H
10154#endif // _WINDOWS_
10155
10157#ifdef _MSC_VER
10158#ifndef __clang__
10159#pragma inline_recursion(on)
10160#endif
10161#pragma push_macro("min")
10162#pragma push_macro("max")
10163#undef min
10164#undef max
10165#endif
10166
10168{
10170 std::string narrow(std::wstring_view str)
10171 {
10172 if (str.empty())
10173 return {};
10174
10175 std::string s;
10176 const auto len =
10177 ::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
10178 if (len)
10179 {
10180 s.resize(static_cast<size_t>(len));
10181 ::WideCharToMultiByte(65001,
10182 0,
10183 str.data(),
10184 static_cast<int>(str.length()),
10185 s.data(),
10186 len,
10187 nullptr,
10188 nullptr);
10189 }
10190 return s;
10191 }
10192
10194 std::wstring widen(std::string_view str)
10195 {
10196 if (str.empty())
10197 return {};
10198
10199 std::wstring s;
10200 const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
10201 if (len)
10202 {
10203 s.resize(static_cast<size_t>(len));
10204 ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
10205 }
10206 return s;
10207 }
10208
10209#if TOML_HAS_CHAR8
10210
10212 std::wstring widen(std::u8string_view str)
10213 {
10214 if (str.empty())
10215 return {};
10216
10217 return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
10218 }
10219
10220#endif // TOML_HAS_CHAR8
10221}
10223
10224#ifdef _MSC_VER
10225#pragma pop_macro("min")
10226#pragma pop_macro("max")
10227#ifndef __clang__
10228#pragma inline_recursion(off)
10229#endif
10230#endif
10232
10233#endif // TOML_WINDOWS
10234
10235//******** impl/print_to_stream.inl **********************************************************************************
10236
10238#include <ostream>
10239#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
10240#include <charconv>
10241#endif
10242#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
10243#include <sstream>
10244#endif
10245#if !TOML_INT_CHARCONV
10246#include <iomanip>
10247#endif
10250#ifdef _MSC_VER
10251#ifndef __clang__
10252#pragma inline_recursion(on)
10253#endif
10254#pragma push_macro("min")
10255#pragma push_macro("max")
10256#undef min
10257#undef max
10258#endif
10259
10261{
10262 template <typename T>
10263 inline constexpr size_t charconv_buffer_length = 0;
10264
10265 template <>
10266 inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
10267
10268 template <>
10269 inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
10270
10271 template <>
10272 inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
10273
10274 template <>
10275 inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
10276
10277 template <>
10278 inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
10279
10280 template <>
10281 inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
10282
10283 template <>
10284 inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
10285
10286 template <>
10287 inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
10288
10289 template <>
10290 inline constexpr size_t charconv_buffer_length<float> = 64;
10291
10292 template <>
10293 inline constexpr size_t charconv_buffer_length<double> = 64;
10294
10295 template <typename T>
10297 void print_integer_to_stream(std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0)
10298 {
10299 if (!val)
10300 {
10301 if (!min_digits)
10302 min_digits = 1;
10303
10304 for (size_t i = 0; i < min_digits; i++)
10305 stream.put('0');
10306
10307 return;
10308 }
10309
10310 static constexpr auto value_flags_mask =
10311 value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
10312 format &= value_flags_mask;
10313
10314 int base = 10;
10315 if (format != value_flags::none && val > T{})
10316 {
10317 switch (format)
10318 {
10319 case value_flags::format_as_binary: base = 2; break;
10320 case value_flags::format_as_octal: base = 8; break;
10321 case value_flags::format_as_hexadecimal: base = 16; break;
10322 default: break;
10323 }
10324 }
10325
10326#if TOML_INT_CHARCONV
10327
10328 char buf[(sizeof(T) * CHAR_BIT)];
10329 const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
10330 const auto len = static_cast<size_t>(res.ptr - buf);
10331 for (size_t i = len; i < min_digits; i++)
10332 stream.put('0');
10333 if (base == 16)
10334 {
10335 for (size_t i = 0; i < len; i++)
10336 if (buf[i] >= 'a')
10337 buf[i] -= 32;
10338 }
10339 impl::print_to_stream(stream, buf, len);
10340
10341#else
10342
10343 using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
10344 using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
10345
10346 if (base == 2)
10347 {
10348 const auto len = sizeof(T) * CHAR_BIT;
10349 for (size_t i = len; i < min_digits; i++)
10350 stream.put('0');
10351
10352 bool found_one = false;
10353 const auto v = static_cast<unsigned_type>(val);
10354 unsigned_type mask = unsigned_type{ 1 } << (len - 1u);
10355 for (size_t i = 0; i < len; i++)
10356 {
10357 if ((v & mask))
10358 {
10359 stream.put('1');
10360 found_one = true;
10361 }
10362 else if (found_one)
10363 stream.put('0');
10364 mask >>= 1;
10365 }
10366 }
10367 else
10368 {
10369 std::ostringstream ss;
10370 ss.imbue(std::locale::classic());
10371 ss << std::uppercase << std::setbase(base);
10372 if (min_digits)
10373 ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
10374 ss << static_cast<cast_type>(val);
10375 const auto str = std::move(ss).str();
10376 impl::print_to_stream(stream, str);
10377 }
10378
10379#endif
10380 }
10381
10382 template <typename T>
10384 void print_floating_point_to_stream(std::ostream & stream,
10385 T val,
10387 [[maybe_unused]] bool relaxed_precision)
10388 {
10389 switch (impl::fpclassify(val))
10390 {
10391 case impl::fp_class::neg_inf: impl::print_to_stream(stream, "-inf"sv); break;
10392
10393 case impl::fp_class::pos_inf: impl::print_to_stream(stream, "inf"sv); break;
10394
10395 case impl::fp_class::nan: impl::print_to_stream(stream, "nan"sv); break;
10396
10397 case impl::fp_class::ok:
10398 {
10399 static constexpr auto needs_decimal_point = [](auto&& s) noexcept
10400 {
10401 for (auto c : s)
10402 if (c == '.' || c == 'E' || c == 'e')
10403 return false;
10404 return true;
10405 };
10406
10407#if TOML_FLOAT_CHARCONV
10408
10409 const auto hex = !!(format & value_flags::format_as_hexadecimal);
10410 char buf[charconv_buffer_length<T>];
10411 auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
10412 : std::to_chars(buf, buf + sizeof(buf), val);
10413 auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
10414
10415 char buf2[charconv_buffer_length<T>];
10416 if (!hex && relaxed_precision)
10417 {
10418 res = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
10419 const auto str2 = std::string_view{ buf2, static_cast<size_t>(res.ptr - buf2) };
10420 if (str2.length() < str.length())
10421 str = str2;
10422 }
10423
10424 impl::print_to_stream(stream, str);
10425 if (!hex && needs_decimal_point(str))
10426 toml::impl::print_to_stream(stream, ".0"sv);
10427
10428#else
10429
10430 std::ostringstream ss;
10431 ss.imbue(std::locale::classic());
10432 if (!relaxed_precision)
10433 ss.precision(std::numeric_limits<T>::max_digits10);
10434 if (!!(format & value_flags::format_as_hexadecimal))
10435 ss << std::hexfloat;
10436 ss << val;
10437 const auto str = std::move(ss).str();
10438 impl::print_to_stream(stream, str);
10439 if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
10440 impl::print_to_stream(stream, ".0"sv);
10441
10442#endif
10443 }
10444 break;
10445
10446 default: TOML_UNREACHABLE;
10447 }
10448 }
10449}
10451
10453{
10455 TOML_ATTR(nonnull)
10456 void TOML_CALLCONV print_to_stream(std::ostream & stream, const char* val, size_t len)
10457 {
10458 stream.write(val, static_cast<std::streamsize>(len));
10459 }
10460
10462 void TOML_CALLCONV print_to_stream(std::ostream & stream, std::string_view val)
10463 {
10464 stream.write(val.data(), static_cast<std::streamsize>(val.length()));
10465 }
10466
10468 void TOML_CALLCONV print_to_stream(std::ostream & stream, const std::string& val)
10469 {
10470 stream.write(val.data(), static_cast<std::streamsize>(val.length()));
10471 }
10472
10474 void TOML_CALLCONV print_to_stream(std::ostream & stream, char val)
10475 {
10476 stream.put(val);
10477 }
10478
10480 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed char val, value_flags format, size_t min_digits)
10481 {
10482 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10483 }
10484
10486 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed short val, value_flags format, size_t min_digits)
10487 {
10488 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10489 }
10490
10492 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed int val, value_flags format, size_t min_digits)
10493 {
10494 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10495 }
10496
10498 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long val, value_flags format, size_t min_digits)
10499 {
10500 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10501 }
10502
10504 void TOML_CALLCONV print_to_stream(std::ostream & stream,
10505 signed long long val,
10507 size_t min_digits)
10508 {
10509 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10510 }
10511
10513 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned char val, value_flags format, size_t min_digits)
10514 {
10515 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10516 }
10517
10519 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned short val, value_flags format, size_t min_digits)
10520 {
10521 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10522 }
10523
10525 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned int val, value_flags format, size_t min_digits)
10526 {
10527 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10528 }
10529
10531 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long val, value_flags format, size_t min_digits)
10532 {
10533 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10534 }
10535
10537 void TOML_CALLCONV print_to_stream(std::ostream & stream,
10538 unsigned long long val,
10540 size_t min_digits)
10541 {
10542 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10543 }
10544
10546 void TOML_CALLCONV print_to_stream(std::ostream & stream, float val, value_flags format, bool relaxed_precision)
10547 {
10548 TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
10549 }
10550
10552 void TOML_CALLCONV print_to_stream(std::ostream & stream, double val, value_flags format, bool relaxed_precision)
10553 {
10554 TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
10555 }
10556
10558 void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val)
10559 {
10560 print_to_stream(stream, val ? "true"sv : "false"sv);
10561 }
10562
10564 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date& val)
10565 {
10566 print_to_stream(stream, val.year, {}, 4);
10567 stream.put('-');
10568 print_to_stream(stream, val.month, {}, 2);
10569 stream.put('-');
10570 print_to_stream(stream, val.day, {}, 2);
10571 }
10572
10574 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time& val)
10575 {
10576 print_to_stream(stream, val.hour, {}, 2);
10577 stream.put(':');
10578 print_to_stream(stream, val.minute, {}, 2);
10579 stream.put(':');
10580 print_to_stream(stream, val.second, {}, 2);
10581 if (val.nanosecond && val.nanosecond <= 999999999u)
10582 {
10583 stream.put('.');
10584 auto ns = val.nanosecond;
10585 size_t digits = 9u;
10586 while (ns % 10u == 0u)
10587 {
10588 ns /= 10u;
10589 digits--;
10590 }
10591 print_to_stream(stream, ns, {}, digits);
10592 }
10593 }
10594
10596 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time_offset& val)
10597 {
10598 if (!val.minutes)
10599 {
10600 stream.put('Z');
10601 return;
10602 }
10603
10604 auto mins = static_cast<int>(val.minutes);
10605 if (mins < 0)
10606 {
10607 stream.put('-');
10608 mins = -mins;
10609 }
10610 else
10611 stream.put('+');
10612 const auto hours = mins / 60;
10613 if (hours)
10614 {
10615 print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
10616 mins -= hours * 60;
10617 }
10618 else
10619 print_to_stream(stream, "00"sv);
10620 stream.put(':');
10621 print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
10622 }
10623
10625 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date_time& val)
10626 {
10627 print_to_stream(stream, val.date);
10628 stream.put('T');
10629 print_to_stream(stream, val.time);
10630 if (val.offset)
10631 print_to_stream(stream, *val.offset);
10632 }
10633
10635 void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_position& val)
10636 {
10637 print_to_stream(stream, "line "sv);
10638 print_to_stream(stream, val.line);
10639 print_to_stream(stream, ", column "sv);
10640 print_to_stream(stream, val.column);
10641 }
10642
10644 void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_region& val)
10645 {
10646 print_to_stream(stream, val.begin);
10647 if (val.path)
10648 {
10649 print_to_stream(stream, " of '"sv);
10650 print_to_stream(stream, *val.path);
10651 stream.put('\'');
10652 }
10653 }
10654
10655#if TOML_ENABLE_FORMATTERS
10656
10658 void TOML_CALLCONV print_to_stream(std::ostream & stream, const array& arr)
10659 {
10660 stream << toml_formatter{ arr };
10661 }
10662
10664 void TOML_CALLCONV print_to_stream(std::ostream & stream, const table& tbl)
10665 {
10666 stream << toml_formatter{ tbl };
10667 }
10668
10670 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<std::string>& val)
10671 {
10672 stream << toml_formatter{ val };
10673 }
10674
10676 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<int64_t>& val)
10677 {
10678 stream << toml_formatter{ val };
10679 }
10680
10682 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<double>& val)
10683 {
10684 stream << toml_formatter{ val };
10685 }
10686
10688 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<bool>& val)
10689 {
10690 stream << toml_formatter{ val };
10691 }
10692
10694 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date>& val)
10695 {
10696 stream << toml_formatter{ val };
10697 }
10698
10700 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<time>& val)
10701 {
10702 stream << toml_formatter{ val };
10703 }
10704
10706 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date_time>& val)
10707 {
10708 stream << toml_formatter{ val };
10709 }
10710
10711#endif
10712}
10714
10715#ifdef _MSC_VER
10716#pragma pop_macro("min")
10717#pragma pop_macro("max")
10718#ifndef __clang__
10719#pragma inline_recursion(off)
10720#endif
10721#endif
10723
10724//******** impl/node.inl *********************************************************************************************
10725
10727#ifdef _MSC_VER
10728#ifndef __clang__
10729#pragma inline_recursion(on)
10730#endif
10731#pragma push_macro("min")
10732#pragma push_macro("max")
10733#undef min
10734#undef max
10735#endif
10736
10738{
10740 node::node() noexcept = default;
10741
10743 node::~node() noexcept = default;
10744
10746 node::node(node && other) noexcept //
10747 : source_{ std::exchange(other.source_, {}) }
10748 {}
10749
10751 node::node(const node& /*other*/) noexcept
10752 {
10753 // does not copy source information - this is not an error
10754 //
10755 // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
10756 }
10757
10759 node& node::operator=(const node& /*rhs*/) noexcept
10760 {
10761 // does not copy source information - this is not an error
10762 //
10763 // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
10764
10765 source_ = {};
10766 return *this;
10767 }
10768
10770 node& node::operator=(node&& rhs) noexcept
10771 {
10772 if (&rhs != this)
10773 source_ = std::exchange(rhs.source_, {});
10774 return *this;
10775 }
10776
10778 node_view<node> node::at_path(std::string_view path) noexcept
10779 {
10780 return toml::at_path(*this, path);
10781 }
10782
10784 node_view<const node> node::at_path(std::string_view path) const noexcept
10785 {
10786 return toml::at_path(*this, path);
10787 }
10788
10790 node_view<node> node::at_path(const path& p) noexcept
10791 {
10792 return toml::at_path(*this, p);
10793 }
10794
10796 node_view<const node> node::at_path(const path& p) const noexcept
10797 {
10798 return toml::at_path(*this, p);
10799 }
10800
10801#if TOML_ENABLE_WINDOWS_COMPAT
10802
10804 node_view<node> node::at_path(std::wstring_view path)
10805 {
10806 return toml::at_path(*this, path);
10807 }
10808
10810 node_view<const node> node::at_path(std::wstring_view path) const
10811 {
10812 return toml::at_path(*this, path);
10813 }
10814
10815#endif // TOML_ENABLE_WINDOWS_COMPAT
10816
10818 node_view<node> node::operator[](const path& p) noexcept
10819 {
10820 return toml::at_path(*this, p);
10821 }
10822
10824 node_view<const node> node::operator[](const path& p) const noexcept
10825 {
10826 return toml::at_path(*this, p);
10827 }
10828}
10830
10832{
10835 bool TOML_CALLCONV node_deep_equality(const node* lhs, const node* rhs) noexcept
10836 {
10837 // both same or both null
10838 if (lhs == rhs)
10839 return true;
10840
10841 // lhs null != rhs null or different types
10842 if ((!lhs != !rhs) || lhs->type() != rhs->type())
10843 return false;
10844
10845 return lhs->visit(
10846 [=](auto& l) noexcept
10847 {
10848 using concrete_type = remove_cvref<decltype(l)>;
10849
10850 return l == *(rhs->as<concrete_type>());
10851 });
10852 }
10853}
10855
10856#ifdef _MSC_VER
10857#pragma pop_macro("min")
10858#pragma pop_macro("max")
10859#ifndef __clang__
10860#pragma inline_recursion(off)
10861#endif
10862#endif
10864
10865//******** impl/at_path.inl ******************************************************************************************
10866
10868#if TOML_INT_CHARCONV
10869#include <charconv>
10870#else
10871#include <sstream>
10872#endif
10875#ifdef _MSC_VER
10876#ifndef __clang__
10877#pragma inline_recursion(on)
10878#endif
10879#pragma push_macro("min")
10880#pragma push_macro("max")
10881#undef min
10882#undef max
10883#endif
10884
10886{
10888 bool TOML_CALLCONV parse_path(const std::string_view path,
10889 void* const data,
10890 const parse_path_callback<std::string_view> on_key,
10891 const parse_path_callback<size_t> on_index)
10892 {
10893 // a blank string is a valid path; it's just one component representing the "" key
10894 if (path.empty())
10895 return on_key(data, ""sv);
10896
10897 size_t pos = 0;
10898 const auto end = path.length();
10899 bool prev_was_array_indexer = false;
10900 bool prev_was_dot = true; // invisible root 'dot'
10901
10902 while (pos < end)
10903 {
10904 // start of an array indexer
10905 if (path[pos] == '[')
10906 {
10907 // find first digit in index
10908 size_t index_start = pos + 1u;
10909 while (true)
10910 {
10911 if TOML_UNLIKELY(index_start >= path.length())
10912 return false;
10913
10914 const auto c = path[index_start];
10915 if TOML_LIKELY(c >= '0' && c <= '9')
10916 break;
10917 else if (c == ' ' || c == '\t')
10918 index_start++;
10919 else
10920 return false;
10921 }
10922 TOML_ASSERT(path[index_start] >= '0');
10923 TOML_ASSERT(path[index_start] <= '9');
10924
10925 // find end of index (first non-digit character)
10926 size_t index_end = index_start + 1u;
10927 while (true)
10928 {
10929 // if an array indexer is missing the trailing ']' at the end of the string, permissively accept it
10930 if TOML_UNLIKELY(index_end >= path.length())
10931 break;
10932
10933 const auto c = path[index_end];
10934 if (c >= '0' && c <= '9')
10935 index_end++;
10936 else if (c == ']' || c == ' ' || c == '\t' || c == '.' || c == '[')
10937 break;
10938 else
10939 return false;
10940 }
10941 TOML_ASSERT(path[index_end - 1u] >= '0');
10942 TOML_ASSERT(path[index_end - 1u] <= '9');
10943
10944 // move pos to after indexer (char after closing ']' or permissively EOL/subkey '.'/next opening '[')
10945 pos = index_end;
10946 while (true)
10947 {
10948 if TOML_UNLIKELY(pos >= path.length())
10949 break;
10950
10951 const auto c = path[pos];
10952 if (c == ']')
10953 {
10954 pos++;
10955 break;
10956 }
10957 else if TOML_UNLIKELY(c == '.' || c == '[')
10958 break;
10959 else if (c == '\t' || c == ' ')
10960 pos++;
10961 else
10962 return false;
10963 }
10964
10965 // get array index substring
10966 auto index_str = path.substr(index_start, index_end - index_start);
10967
10968 // parse the actual array index to an integer type
10969 size_t index;
10970 if (index_str.length() == 1u)
10971 index = static_cast<size_t>(index_str[0] - '0');
10972 else
10973 {
10974#if TOML_INT_CHARCONV
10975
10976 auto fc_result = std::from_chars(index_str.data(), index_str.data() + index_str.length(), index);
10977 if (fc_result.ec != std::errc{})
10978 return false;
10979
10980#else
10981
10982 std::stringstream ss;
10983 ss.imbue(std::locale::classic());
10984 ss.write(index_str.data(), static_cast<std::streamsize>(index_str.length()));
10985 if (!(ss >> index))
10986 return false;
10987
10988#endif
10989 }
10990
10991 prev_was_dot = false;
10992 prev_was_array_indexer = true;
10993
10994 if (!on_index(data, index))
10995 return false;
10996 }
10997
10998 // start of a new table child
10999 else if (path[pos] == '.')
11000 {
11001 // a dot immediately following another dot (or at the beginning of the string) is as if we'd asked
11002 // for an empty child in between, e.g.
11003 //
11004 // foo..bar
11005 //
11006 // is equivalent to
11007 //
11008 // "foo".""."bar"
11009 //
11010 if (prev_was_dot && !on_key(data, ""sv))
11011 return false;
11012
11013 pos++;
11014 prev_was_dot = true;
11015 prev_was_array_indexer = false;
11016 }
11017
11018 // an errant closing ']'
11019 else if TOML_UNLIKELY(path[pos] == ']')
11020 return false;
11021
11022 // some regular subkey
11023 else
11024 {
11025 const auto subkey_start = pos;
11026 const auto subkey_len =
11027 impl::min(path.find_first_of(".[]"sv, subkey_start + 1u), path.length()) - subkey_start;
11028 const auto subkey = path.substr(subkey_start, subkey_len);
11029
11030 // a regular subkey segment immediately after an array indexer is OK if it was all whitespace, e.g.:
11031 //
11032 // "foo[0] .bar"
11033 // ^^ skip this
11034 //
11035 // otherwise its an error (since it would have to be preceeded by a dot)
11036 if (prev_was_array_indexer)
11037 {
11038 auto non_ws = subkey.find_first_not_of(" \t");
11039 if (non_ws == std::string_view::npos)
11040 {
11041 pos += subkey_len;
11042 prev_was_dot = false;
11043 prev_was_array_indexer = false;
11044 continue;
11045 }
11046 else
11047 return false;
11048 }
11049
11050 pos += subkey_len;
11051 prev_was_dot = false;
11052 prev_was_array_indexer = false;
11053
11054 if (!on_key(data, subkey))
11055 return false;
11056 }
11057 }
11058
11059 // Last character was a '.', which implies an empty string key at the end of the path
11060 if (prev_was_dot && !on_key(data, ""sv))
11061 return false;
11062
11063 return true;
11064 }
11065}
11067
11069{
11071 node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept
11072 {
11073 // early-exit sanity-checks
11074 if (root.is_value())
11075 return {};
11076 if (auto tbl = root.as_table(); tbl && tbl->empty())
11077 return {};
11078 if (auto arr = root.as_array(); arr && arr->empty())
11079 return {};
11080
11081 node* current = &root;
11082
11083 static constexpr auto on_key = [](void* data, std::string_view key) noexcept -> bool
11084 {
11085 auto& curr = *static_cast<node**>(data);
11086 TOML_ASSERT_ASSUME(curr);
11087
11088 const auto current_table = curr->as<table>();
11089 if (!current_table)
11090 return false;
11091
11092 curr = current_table->get(key);
11093 return curr != nullptr;
11094 };
11095
11096 static constexpr auto on_index = [](void* data, size_t index) noexcept -> bool
11097 {
11098 auto& curr = *static_cast<node**>(data);
11099 TOML_ASSERT_ASSUME(curr);
11100
11101 const auto current_array = curr->as<array>();
11102 if (!current_array)
11103 return false;
11104
11105 curr = current_array->get(index);
11106 return curr != nullptr;
11107 };
11108
11109 if (!impl::parse_path(path, &current, on_key, on_index))
11110 current = nullptr;
11111
11112 return node_view{ current };
11113 }
11114
11116 node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept
11117 {
11118 return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
11119 }
11120
11121#if TOML_ENABLE_WINDOWS_COMPAT
11122
11124 node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path)
11125 {
11126 // these are the same top-level checks from the narrow-string version;
11127 // they're hoisted up here to avoid doing the wide -> narrow conversion where it would not be necessary
11128 // (avoids an allocation)
11129 if (root.is_value())
11130 return {};
11131 if (auto tbl = root.as_table(); tbl && tbl->empty())
11132 return {};
11133 if (auto arr = root.as_array(); arr && arr->empty())
11134 return {};
11135
11136 return at_path(root, impl::narrow(path));
11137 }
11138
11140 node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path)
11141 {
11142 return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
11143 }
11144
11145#endif // TOML_ENABLE_WINDOWS_COMPAT
11146}
11148
11149#ifdef _MSC_VER
11150#pragma pop_macro("min")
11151#pragma pop_macro("max")
11152#ifndef __clang__
11153#pragma inline_recursion(off)
11154#endif
11155#endif
11157
11158//******** impl/path.inl *********************************************************************************************
11159
11161#if TOML_INT_CHARCONV
11162#include <charconv>
11163#endif
11164#include <sstream>
11167#ifdef _MSC_VER
11168#ifndef __clang__
11169#pragma inline_recursion(on)
11170#endif
11171#pragma push_macro("min")
11172#pragma push_macro("max")
11173#undef min
11174#undef max
11175#endif
11176
11178{
11181 : type_{ path_component_type::key }
11182 {
11183 store_key("", value_storage_);
11184 }
11185
11187 path_component::path_component(size_t index) noexcept //
11188 : type_(path_component_type::array_index)
11189 {
11190 store_index(index, value_storage_);
11191 }
11192
11194 path_component::path_component(std::string_view key) //
11195 : type_(path_component_type::key)
11196 {
11197 store_key(key, value_storage_);
11198 }
11199
11200#if TOML_ENABLE_WINDOWS_COMPAT
11201
11203 path_component::path_component(std::wstring_view key) //
11204 : path_component(impl::narrow(key))
11205 {}
11206
11207#endif
11208
11211 : type_{ pc.type_ }
11212 {
11213 if (type_ == path_component_type::array_index)
11214 store_index(pc.index(), value_storage_);
11215 else
11216 store_key(pc.key(), value_storage_);
11217 }
11218
11221 : type_{ pc.type_ }
11222 {
11223 if (type_ == path_component_type::array_index)
11224 store_index(pc.index_ref(), value_storage_);
11225 else
11226 store_key(std::move(pc.key_ref()), value_storage_);
11227 }
11228
11231 {
11232 if (type_ != rhs.type_)
11233 {
11234 destroy();
11235
11236 type_ = rhs.type_;
11237 if (type_ == path_component_type::array_index)
11238 store_index(rhs.index(), value_storage_);
11239 else
11241 }
11242 else
11243 {
11244 if (type_ == path_component_type::array_index)
11245 index_ref() = rhs.index();
11246 else
11247 key_ref() = rhs.key();
11248 }
11249 return *this;
11250 }
11251
11254 {
11255 if (type_ != rhs.type_)
11256 {
11257 destroy();
11258
11259 type_ = rhs.type_;
11260 if (type_ == path_component_type::array_index)
11261 store_index(rhs.index(), value_storage_);
11262 else
11263 store_key(std::move(rhs.key_ref()), value_storage_);
11264 }
11265 else
11266 {
11267 if (type_ == path_component_type::array_index)
11268 index_ref() = rhs.index();
11269 else
11270 key_ref() = std::move(rhs.key_ref());
11271 }
11272 return *this;
11273 }
11274
11277 bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept
11278 {
11279 // Different comparison depending on contents
11280 if (lhs.type_ != rhs.type_)
11281 return false;
11282
11283 if (lhs.type_ == path_component_type::array_index)
11284 return lhs.index() == rhs.index();
11285 else // path_component_type::key
11286 return lhs.key() == rhs.key();
11287 }
11288
11290 path_component& path_component::operator=(size_t new_index) noexcept
11291 {
11292 // If currently a key, string will need to be destroyed regardless
11293 destroy();
11294
11295 type_ = path_component_type::array_index;
11296 store_index(new_index, value_storage_);
11297
11298 return *this;
11299 }
11300
11302 path_component& path_component::operator=(std::string_view new_key)
11303 {
11304 if (type_ == path_component_type::key)
11305 key_ref() = new_key;
11306 else
11307 {
11308 type_ = path_component_type::key;
11309 store_key(new_key, value_storage_);
11310 }
11311
11312 return *this;
11313 }
11314
11315#if TOML_ENABLE_WINDOWS_COMPAT
11316
11318 path_component& path_component::operator=(std::wstring_view new_key)
11319 {
11320 if (type_ == path_component_type::key)
11321 key_ref() = impl::narrow(new_key);
11322 else
11323 {
11324 type_ = path_component_type::key;
11325 store_key(impl::narrow(new_key), value_storage_);
11326 }
11327
11328 return *this;
11329 }
11330
11331#endif
11332}
11334
11336{
11338 bool parse_path_into(std::string_view path_str, std::vector<path_component> & components)
11339 {
11340 using components_type = std::remove_reference_t<decltype(components)>;
11341
11342 const auto original_size = components.size();
11343
11344 static constexpr auto on_key = [](void* data, std::string_view key) -> bool
11345 {
11346 auto& comps = *static_cast<components_type*>(data);
11347 comps.emplace_back(key);
11348 return true;
11349 };
11350
11351 static constexpr auto on_index = [](void* data, size_t index) -> bool
11352 {
11353 auto& comps = *static_cast<components_type*>(data);
11354 comps.emplace_back(index);
11355 return true;
11356 };
11357
11358 if (!impl::parse_path(path_str, &components, on_key, on_index))
11359 {
11360 components.resize(original_size);
11361 return false;
11362 }
11363
11364 return true;
11365 }
11366}
11368
11370{
11372 void path::print_to(std::ostream & os) const
11373 {
11374 bool root = true;
11375 for (const auto& component : components_)
11376 {
11377 if (component.type() == path_component_type::key) // key
11378 {
11379 if (!root)
11380 impl::print_to_stream(os, '.');
11381 impl::print_to_stream(os, component.key());
11382 }
11383 else if (component.type() == path_component_type::array_index) // array
11384 {
11385 impl::print_to_stream(os, '[');
11386 impl::print_to_stream(os, component.index());
11387 impl::print_to_stream(os, ']');
11388 }
11389 root = false;
11390 }
11391 }
11392
11395 bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept
11396 {
11397 return lhs.components_ == rhs.components_;
11398 }
11399
11401 path::path(std::string_view str) //
11402 {
11403 TOML_ANON_NAMESPACE::parse_path_into(str, components_);
11404 }
11405
11406#if TOML_ENABLE_WINDOWS_COMPAT
11407
11409 path::path(std::wstring_view str) //
11410 : path(impl::narrow(str))
11411 {}
11412
11413#endif
11414
11416 path& path::operator=(std::string_view rhs)
11417 {
11418 components_.clear();
11419 TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
11420 return *this;
11421 }
11422
11423#if TOML_ENABLE_WINDOWS_COMPAT
11424
11426 path& path::operator=(std::wstring_view rhs)
11427 {
11428 return assign(impl::narrow(rhs));
11429 }
11430
11431#endif
11432
11434 path& path::operator+=(const path& rhs)
11435 {
11436 components_.insert(components_.cend(), rhs.begin(), rhs.end());
11437 return *this;
11438 }
11439
11442 {
11443 components_.insert(components_.end(),
11444 std::make_move_iterator(rhs.components_.begin()),
11445 std::make_move_iterator(rhs.components_.end()));
11446 return *this;
11447 }
11448
11450 path& path::operator+=(std::string_view str)
11451 {
11452 TOML_ANON_NAMESPACE::parse_path_into(str, components_);
11453 return *this;
11454 }
11455
11456#if TOML_ENABLE_WINDOWS_COMPAT
11457
11459 path& path::operator+=(std::wstring_view str)
11460 {
11461 return *this += impl::narrow(str);
11462 }
11463
11464#endif
11465
11467 path& path::prepend(const path& source)
11468 {
11469 components_.insert(components_.begin(), source.components_.begin(), source.components_.end());
11470 return *this;
11471 }
11472
11474 path& path::prepend(path && source)
11475 {
11476 components_.insert(components_.begin(),
11477 std::make_move_iterator(source.components_.begin()),
11478 std::make_move_iterator(source.components_.end()));
11479 return *this;
11480 }
11481
11483 path& path::prepend(std::string_view source)
11484 {
11485 return prepend(path{ source });
11486 }
11487
11488#if TOML_ENABLE_WINDOWS_COMPAT
11489
11491 path& path::prepend(std::wstring_view source)
11492 {
11493 return prepend(impl::narrow(source));
11494 }
11495
11496#endif
11497
11499 std::string path::str() const
11500 {
11501 if (empty())
11502 return "";
11503
11504 std::ostringstream ss;
11505 print_to(ss);
11506 return std::move(ss).str();
11507 }
11508
11509#if TOML_ENABLE_WINDOWS_COMPAT
11510
11512 std::wstring path::wide_str() const
11513 {
11514 return impl::widen(str());
11515 }
11516
11517#endif
11518
11520 void path::clear() noexcept
11521 {
11522 components_.clear();
11523 }
11524
11526 path& path::truncate(size_t n)
11527 {
11528 n = n > components_.size() ? components_.size() : n;
11529
11530 auto it_end = components_.end();
11531 components_.erase(it_end - static_cast<int>(n), it_end);
11532
11533 return *this;
11534 }
11535
11537 path path::truncated(size_t n) const
11538 {
11539 path truncated_path{};
11540
11541 n = n > components_.size() ? components_.size() : n;
11542
11543 // Copy all components except one
11544 // Need at least two path components to have a parent, since if there is
11545 // only one path component, the parent is the root/null path ""
11546 truncated_path.components_.insert(truncated_path.components_.begin(),
11547 components_.begin(),
11548 components_.end() - static_cast<int>(n));
11549
11550 return truncated_path;
11551 }
11552
11554 path path::parent() const
11555 {
11556 return truncated(1);
11557 }
11558
11560 path path::leaf(size_t n) const
11561 {
11562 path leaf_path{};
11563
11564 n = n > components_.size() ? components_.size() : n;
11565
11566 if (n > 0)
11567 {
11568 leaf_path.components_.insert(leaf_path.components_.begin(),
11569 components_.end() - static_cast<int>(n),
11570 components_.end());
11571 }
11572
11573 return leaf_path;
11574 }
11575
11577 path path::subpath(std::vector<path_component>::const_iterator start,
11578 std::vector<path_component>::const_iterator end) const
11579 {
11580 if (start >= end)
11581 return {};
11582
11583 path subpath;
11584 subpath.components_.insert(subpath.components_.begin(), start, end);
11585 return subpath;
11586 }
11587
11589 path path::subpath(size_t start, size_t length) const
11590 {
11591 return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length));
11592 }
11593}
11595
11597{
11599 node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept
11600 {
11601 // early-exit sanity-checks
11602 if (root.is_value())
11603 return {};
11604 if (auto tbl = root.as_table(); tbl && tbl->empty())
11605 return {};
11606 if (auto arr = root.as_array(); arr && arr->empty())
11607 return {};
11608
11609 node* current = &root;
11610
11611 for (const auto& component : path)
11612 {
11613 auto type = component.type();
11614 if (type == path_component_type::array_index)
11615 {
11616 const auto current_array = current->as<array>();
11617 if (!current_array)
11618 return {}; // not an array, using array index doesn't work
11619
11620 current = current_array->get(component.index());
11621 }
11622 else if (type == path_component_type::key)
11623 {
11624 const auto current_table = current->as<table>();
11625 if (!current_table)
11626 return {};
11627
11628 current = current_table->get(component.key());
11629 }
11630 else
11631 {
11632 // Error: invalid component
11633 return {};
11634 }
11635
11636 if (!current)
11637 return {}; // not found
11638 }
11639
11640 return node_view{ current };
11641 }
11642
11644 node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept
11645 {
11646 return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
11647 }
11648}
11650
11651#ifdef _MSC_VER
11652#pragma pop_macro("min")
11653#pragma pop_macro("max")
11654#ifndef __clang__
11655#pragma inline_recursion(off)
11656#endif
11657#endif
11659
11660//******** impl/array.inl ********************************************************************************************
11661
11663#ifdef _MSC_VER
11664#ifndef __clang__
11665#pragma inline_recursion(on)
11666#endif
11667#pragma push_macro("min")
11668#pragma push_macro("max")
11669#undef min
11670#undef max
11671#endif
11672
11674{
11676 array::array() noexcept
11677 {
11678#if TOML_LIFETIME_HOOKS
11679 TOML_ARRAY_CREATED;
11680#endif
11681 }
11682
11684 array::~array() noexcept
11685 {
11686#if TOML_LIFETIME_HOOKS
11687 TOML_ARRAY_DESTROYED;
11688#endif
11689 }
11690
11692 array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
11693 {
11694#if TOML_LIFETIME_HOOKS
11695 TOML_ARRAY_CREATED;
11696#endif
11697
11700 TOML_ASSERT_ASSUME(b <= e);
11701
11702 if TOML_UNLIKELY(b == e)
11703 return;
11704
11705 size_t cap{};
11706 for (auto it = b; it != e; it++)
11707 {
11708 if (it->value)
11709 cap++;
11710 }
11711 if TOML_UNLIKELY(!cap)
11712 return;
11713
11714 elems_.reserve(cap);
11715 for (; b != e; b++)
11716 {
11717 if (b->value)
11718 elems_.push_back(std::move(b->value));
11719 }
11720 }
11721
11723 array::array(const array& other) //
11724 : node(other)
11725 {
11726 elems_.reserve(other.elems_.size());
11727 for (const auto& elem : other)
11728 elems_.emplace_back(impl::make_node(elem));
11729
11731 TOML_ARRAY_CREATED;
11732#endif
11733 }
11734
11736 array::array(array && other) noexcept //
11737 : node(std::move(other)),
11738 elems_(std::move(other.elems_))
11739 {
11740#if TOML_LIFETIME_HOOKS
11741 TOML_ARRAY_CREATED;
11742#endif
11743 }
11744
11747 {
11748 if (&rhs != this)
11749 {
11750 node::operator=(rhs);
11751 elems_.clear();
11752 elems_.reserve(rhs.elems_.size());
11753 for (const auto& elem : rhs)
11754 elems_.emplace_back(impl::make_node(elem));
11755 }
11756 return *this;
11757 }
11758
11760 array& array::operator=(array&& rhs) noexcept
11761 {
11762 if (&rhs != this)
11763 {
11764 node::operator=(std::move(rhs));
11765 elems_ = std::move(rhs.elems_);
11766 }
11767 return *this;
11768 }
11769
11771 void array::preinsertion_resize(size_t idx, size_t count)
11772 {
11773 TOML_ASSERT(idx <= elems_.size());
11775 const auto old_size = elems_.size();
11776 const auto new_size = old_size + count;
11777 const auto inserting_at_end = idx == old_size;
11778 elems_.resize(new_size);
11779 if (!inserting_at_end)
11780 {
11781 for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
11782 elems_[right] = std::move(elems_[left]);
11783 }
11784 }
11785
11787 void array::insert_at_back(impl::node_ptr && elem)
11788 {
11789 TOML_ASSERT(elem);
11790 elems_.push_back(std::move(elem));
11791 }
11792
11794 array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem)
11795 {
11796 return elems_.insert(pos, std::move(elem));
11797 }
11798
11801 bool array::is_homogeneous(node_type ntype) const noexcept
11802 {
11803 if (elems_.empty())
11804 return false;
11805
11806 if (ntype == node_type::none)
11807 ntype = elems_[0]->type();
11808
11809 for (const auto& val : elems_)
11810 if (val->type() != ntype)
11811 return false;
11812
11813 return true;
11814 }
11815
11818 bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
11819 {
11820 if (elems_.empty())
11821 {
11822 first_nonmatch = {};
11823 return false;
11824 }
11825 if (ntype == node_type::none)
11826 ntype = elems_[0]->type();
11827 for (const auto& val : elems_)
11828 {
11829 if (val->type() != ntype)
11830 {
11831 first_nonmatch = val.get();
11832 return false;
11833 }
11834 }
11835 return true;
11836 }
11837
11840 bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
11841 {
11842 node* fnm = nullptr;
11843 const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
11844 first_nonmatch = fnm;
11845 return result;
11846 }
11847
11849 node& array::at(size_t index)
11850 {
11851#if TOML_COMPILER_HAS_EXCEPTIONS
11852
11853 return *elems_.at(index);
11854
11855#else
11856
11857 auto n = get(index);
11858 TOML_ASSERT_ASSUME(n && "element index not found in array!");
11859 return *n;
11860
11861#endif
11862 }
11863
11865 void array::reserve(size_t new_capacity)
11866 {
11867 elems_.reserve(new_capacity);
11868 }
11869
11872 {
11873 elems_.shrink_to_fit();
11874 }
11875
11877 void array::truncate(size_t new_size)
11878 {
11879 if (new_size < elems_.size())
11880 elems_.resize(new_size);
11881 }
11882
11885 {
11886 return iterator{ elems_.erase(const_vector_iterator{ pos }) };
11887 }
11888
11891 {
11892 return iterator{ elems_.erase(const_vector_iterator{ first }, const_vector_iterator{ last }) };
11893 }
11894
11896 size_t array::total_leaf_count() const noexcept
11897 {
11898 size_t leaves{};
11899 for (size_t i = 0, e = elems_.size(); i < e; i++)
11900 {
11901 auto arr = elems_[i]->as_array();
11902 leaves += arr ? arr->total_leaf_count() : size_t{ 1 };
11903 }
11904 return leaves;
11905 }
11906
11908 void array::flatten_child(array && child, size_t & dest_index) noexcept
11909 {
11910 for (size_t i = 0, e = child.size(); i < e; i++)
11911 {
11912 auto type = child.elems_[i]->type();
11913 if (type == node_type::array)
11914 {
11915 array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
11916 if (!arr.empty())
11917 flatten_child(std::move(arr), dest_index);
11918 }
11919 else
11920 elems_[dest_index++] = std::move(child.elems_[i]);
11921 }
11922 }
11923
11926 {
11927 if (elems_.empty())
11928 return *this;
11929
11930 bool requires_flattening = false;
11931 size_t size_after_flattening = elems_.size();
11932 for (size_t i = elems_.size(); i-- > 0u;)
11933 {
11934 auto arr = elems_[i]->as_array();
11935 if (!arr)
11936 continue;
11937 size_after_flattening--; // discount the array itself
11938 const auto leaf_count = arr->total_leaf_count();
11939 if (leaf_count > 0u)
11940 {
11941 requires_flattening = true;
11942 size_after_flattening += leaf_count;
11943 }
11944 else
11945 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
11946 }
11947
11948 if (!requires_flattening)
11949 return *this;
11950
11951 elems_.reserve(size_after_flattening);
11952
11953 size_t i = 0;
11954 while (i < elems_.size())
11955 {
11956 auto arr = elems_[i]->as_array();
11957 if (!arr)
11958 {
11959 i++;
11960 continue;
11961 }
11962
11963 impl::node_ptr arr_storage = std::move(elems_[i]);
11964 const auto leaf_count = arr->total_leaf_count();
11965 if (leaf_count > 1u)
11966 preinsertion_resize(i + 1u, leaf_count - 1u);
11967 flatten_child(std::move(*arr), i); // increments i
11968 }
11969
11970 return *this;
11971 }
11972
11974 array& array::prune(bool recursive)& noexcept
11975 {
11976 if (elems_.empty())
11977 return *this;
11978
11979 for (size_t i = elems_.size(); i-- > 0u;)
11980 {
11981 if (auto arr = elems_[i]->as_array())
11982 {
11983 if (recursive)
11984 arr->prune(true);
11985 if (arr->empty())
11986 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
11987 }
11988 else if (auto tbl = elems_[i]->as_table())
11989 {
11990 if (recursive)
11991 tbl->prune(true);
11992 if (tbl->empty())
11993 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
11994 }
11995 }
11996
11997 return *this;
11998 }
11999
12001 void array::pop_back() noexcept
12002 {
12003 elems_.pop_back();
12004 }
12005
12007 void array::clear() noexcept
12008 {
12009 elems_.clear();
12010 }
12011
12013 bool TOML_CALLCONV array::equal(const array& lhs, const array& rhs) noexcept
12014 {
12015 if (&lhs == &rhs)
12016 return true;
12017 if (lhs.elems_.size() != rhs.elems_.size())
12018 return false;
12019 for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
12020 {
12021 const auto lhs_type = lhs.elems_[i]->type();
12022 const node& rhs_ = *rhs.elems_[i];
12023 const auto rhs_type = rhs_.type();
12024 if (lhs_type != rhs_type)
12025 return false;
12026
12027 const bool equal = lhs.elems_[i]->visit(
12028 [&](const auto& lhs_) noexcept
12029 { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
12030 if (!equal)
12031 return false;
12032 }
12033 return true;
12034 }
12035}
12037
12038#ifdef _MSC_VER
12039#pragma pop_macro("min")
12040#pragma pop_macro("max")
12041#ifndef __clang__
12042#pragma inline_recursion(off)
12043#endif
12044#endif
12046
12047//******** impl/table.inl ********************************************************************************************
12048
12050#ifdef _MSC_VER
12051#ifndef __clang__
12052#pragma inline_recursion(on)
12053#endif
12054#pragma push_macro("min")
12055#pragma push_macro("max")
12056#undef min
12057#undef max
12058#endif
12059
12061{
12063 table::table() noexcept
12064 {
12065#if TOML_LIFETIME_HOOKS
12066 TOML_TABLE_CREATED;
12067#endif
12068 }
12069
12071 table::~table() noexcept
12072 {
12073#if TOML_LIFETIME_HOOKS
12074 TOML_TABLE_DESTROYED;
12075#endif
12076 }
12077
12079 table::table(const impl::table_init_pair* b, const impl::table_init_pair* e)
12080 {
12081#if TOML_LIFETIME_HOOKS
12082 TOML_TABLE_CREATED;
12083#endif
12084
12087 TOML_ASSERT_ASSUME(b <= e);
12088
12089 if TOML_UNLIKELY(b == e)
12090 return;
12091
12092 for (; b != e; b++)
12093 {
12094 if (!b->value) // empty node_views
12095 continue;
12096
12097 map_.insert_or_assign(std::move(b->key), std::move(b->value));
12098 }
12099 }
12100
12102 table::table(const table& other) //
12103 : node(other),
12104 inline_{ other.inline_ }
12105 {
12106 for (auto&& [k, v] : other.map_)
12107 map_.emplace_hint(map_.end(), k, impl::make_node(*v));
12108
12110 TOML_TABLE_CREATED;
12111#endif
12112 }
12113
12115 table::table(table && other) noexcept //
12116 : node(std::move(other)),
12117 map_{ std::move(other.map_) },
12118 inline_{ other.inline_ }
12119 {
12120#if TOML_LIFETIME_HOOKS
12121 TOML_TABLE_CREATED;
12122#endif
12123 }
12124
12127 {
12128 if (&rhs != this)
12129 {
12130 node::operator=(rhs);
12131 map_.clear();
12132 for (auto&& [k, v] : rhs.map_)
12133 map_.emplace_hint(map_.end(), k, impl::make_node(*v));
12134 inline_ = rhs.inline_;
12135 }
12136 return *this;
12137 }
12138
12140 table& table::operator=(table&& rhs) noexcept
12141 {
12142 if (&rhs != this)
12143 {
12144 node::operator=(std::move(rhs));
12145 map_ = std::move(rhs.map_);
12146 inline_ = rhs.inline_;
12147 }
12148 return *this;
12149 }
12150
12153 bool table::is_homogeneous(node_type ntype) const noexcept
12154 {
12155 if (map_.empty())
12156 return false;
12157
12158 if (ntype == node_type::none)
12159 ntype = map_.cbegin()->second->type();
12160
12161 for (auto&& [k, v] : map_)
12162 {
12163 TOML_UNUSED(k);
12164 if (v->type() != ntype)
12165 return false;
12166 }
12167
12168 return true;
12169 }
12170
12173 bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
12174 {
12175 if (map_.empty())
12176 {
12177 first_nonmatch = {};
12178 return false;
12179 }
12180 if (ntype == node_type::none)
12181 ntype = map_.cbegin()->second->type();
12182 for (const auto& [k, v] : map_)
12183 {
12184 TOML_UNUSED(k);
12185 if (v->type() != ntype)
12186 {
12187 first_nonmatch = v.get();
12188 return false;
12189 }
12190 }
12191 return true;
12192 }
12193
12196 bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
12197 {
12198 node* fnm = nullptr;
12199 const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
12200 first_nonmatch = fnm;
12201 return result;
12202 }
12203
12206 node* table::get(std::string_view key) noexcept
12207 {
12208 if (auto it = map_.find(key); it != map_.end())
12209 return it->second.get();
12210 return nullptr;
12211 }
12212
12214 node& table::at(std::string_view key)
12215 {
12216 auto n = get(key);
12217
12218#if TOML_COMPILER_HAS_EXCEPTIONS
12219
12220 if (!n)
12221 {
12222 auto err = "key '"s;
12223 err.append(key);
12224 err.append("' not found in table"sv);
12225 throw std::out_of_range{ err };
12226 }
12227
12228#else
12229
12230 TOML_ASSERT_ASSUME(n && "key not found in table!");
12231
12232#endif
12233
12234 return *n;
12235 }
12236
12239 table::map_iterator table::get_lower_bound(std::string_view key) noexcept
12240 {
12241 return map_.lower_bound(key);
12242 }
12243
12246 table::iterator table::find(std::string_view key) noexcept
12247 {
12248 return iterator{ map_.find(key) };
12249 }
12250
12253 table::const_iterator table::find(std::string_view key) const noexcept
12254 {
12255 return const_iterator{ map_.find(key) };
12256 }
12257
12259 table::map_iterator table::erase(const_map_iterator pos) noexcept
12260 {
12261 return map_.erase(pos);
12262 }
12263
12265 table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept
12266 {
12267 return map_.erase(begin, end);
12268 }
12269
12271 size_t table::erase(std::string_view key) noexcept
12272 {
12273 if (auto it = map_.find(key); it != map_.end())
12274 {
12275 map_.erase(it);
12276 return size_t{ 1 };
12277 }
12278 return size_t{};
12279 }
12280
12282 table& table::prune(bool recursive)& noexcept
12283 {
12284 if (map_.empty())
12285 return *this;
12286
12287 for (auto it = map_.begin(); it != map_.end();)
12288 {
12289 if (auto arr = it->second->as_array())
12290 {
12291 if (recursive)
12292 arr->prune(true);
12293
12294 if (arr->empty())
12295 {
12296 it = map_.erase(it);
12297 continue;
12298 }
12299 }
12300 else if (auto tbl = it->second->as_table())
12301 {
12302 if (recursive)
12303 tbl->prune(true);
12304
12305 if (tbl->empty())
12306 {
12307 it = map_.erase(it);
12308 continue;
12309 }
12310 }
12311 it++;
12312 }
12313
12314 return *this;
12315 }
12316
12318 void table::clear() noexcept
12319 {
12320 map_.clear();
12321 }
12322
12324 table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v)
12325 {
12326 return map_.emplace_hint(const_map_iterator{ hint }, std::move(k), std::move(v));
12327 }
12328
12331 bool TOML_CALLCONV table::equal(const table& lhs, const table& rhs) noexcept
12332 {
12333 if (&lhs == &rhs)
12334 return true;
12335 if (lhs.map_.size() != rhs.map_.size())
12336 return false;
12337
12338 for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++)
12339 {
12340 if (l->first != r->first)
12341 return false;
12342
12343 const auto lhs_type = l->second->type();
12344 const node& rhs_ = *r->second;
12345 const auto rhs_type = rhs_.type();
12346 if (lhs_type != rhs_type)
12347 return false;
12348
12349 const bool equal = l->second->visit(
12350 [&](const auto& lhs_) noexcept
12351 { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
12352 if (!equal)
12353 return false;
12354 }
12355 return true;
12356 }
12357}
12359
12360#ifdef _MSC_VER
12361#pragma pop_macro("min")
12362#pragma pop_macro("max")
12363#ifndef __clang__
12364#pragma inline_recursion(off)
12365#endif
12366#endif
12368
12369//******** impl/simd.hpp *********************************************************************************************
12370
12371#if TOML_ENABLE_SIMD
12372
12373#if defined(__SSE2__) \
12374 || (defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))
12375#define TOML_HAS_SSE2 1
12376#endif
12377
12378#if defined(__SSE4_1__) || (defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__)))
12379#define TOML_HAS_SSE4_1 1
12380#endif
12381
12382#endif // TOML_ENABLE_SIMD
12383
12384#ifndef TOML_HAS_SSE2
12385#define TOML_HAS_SSE2 0
12386#endif
12387#ifndef TOML_HAS_SSE4_1
12388#define TOML_HAS_SSE4_1 0
12389#endif
12390
12392#if TOML_HAS_SSE4_1
12393#include <smmintrin.h>
12394#endif
12395#if TOML_HAS_SSE2
12396#include <emmintrin.h>
12397#endif
12399
12400//******** impl/unicode.inl ******************************************************************************************
12401
12403#ifdef _MSC_VER
12404#ifndef __clang__
12405#pragma inline_recursion(on)
12406#endif
12407#pragma push_macro("min")
12408#pragma push_macro("max")
12409#undef min
12410#undef max
12411#endif
12412
12414{
12417 bool is_ascii(const char* str, size_t len) noexcept
12418 {
12419 const char* const end = str + len;
12420
12421#if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
12422 {
12423 constexpr size_t chars_per_vector = 128u / CHAR_BIT;
12424
12425 if (const size_t simdable = len - (len % chars_per_vector))
12426 {
12427 __m128i mask = _mm_setzero_si128();
12428 for (const char* const e = str + simdable; str < e; str += chars_per_vector)
12429 {
12430 const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
12431 mask = _mm_or_si128(mask, current_bytes);
12432 }
12433 const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
12434
12435#if TOML_HAS_SSE4_1
12436 if (!_mm_testz_si128(has_error, has_error))
12437 return false;
12438#else
12439 if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
12440 return false;
12441#endif
12442 }
12443 }
12444#endif
12445
12446 for (; str < end; str++)
12447 if (static_cast<unsigned char>(*str) > 127u)
12448 return false;
12449
12450 return true;
12451 }
12452}
12454
12455#ifdef _MSC_VER
12456#pragma pop_macro("min")
12457#pragma pop_macro("max")
12458#ifndef __clang__
12459#pragma inline_recursion(off)
12460#endif
12461#endif
12463
12464//******** impl/parser.inl *******************************************************************************************
12465
12466#if TOML_ENABLE_PARSER
12467
12469#include <istream>
12470#include <fstream>
12471#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
12472#include <charconv>
12473#endif
12474#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
12475#include <sstream>
12476#endif
12477#if !TOML_INT_CHARCONV
12478#include <iomanip>
12479#endif
12482#ifdef _MSC_VER
12483#ifndef __clang__
12484#pragma inline_recursion(on)
12485#endif
12486#pragma push_macro("min")
12487#pragma push_macro("max")
12488#undef min
12489#undef max
12490#endif
12491
12493{
12494 template <typename T>
12495 class utf8_byte_stream;
12496
12498 constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
12499
12500 template <typename Char>
12501 class utf8_byte_stream<std::basic_string_view<Char>>
12502 {
12503 static_assert(sizeof(Char) == 1);
12504
12505 private:
12506 std::basic_string_view<Char> source_;
12507 size_t position_ = {};
12508
12509 public:
12511 explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept //
12512 : source_{ sv }
12513 {
12514 // skip bom
12515 if (source_.length() >= 3u && memcmp(utf8_byte_order_mark.data(), source_.data(), 3u) == 0)
12516 position_ += 3u;
12517 }
12518
12520 constexpr bool error() const noexcept
12521 {
12522 return false;
12523 }
12524
12526 constexpr bool eof() const noexcept
12527 {
12528 return position_ >= source_.length();
12529 }
12530
12532 explicit constexpr operator bool() const noexcept
12533 {
12534 return !eof();
12535 }
12536
12538 constexpr bool peek_eof() const noexcept
12539 {
12540 return eof();
12541 }
12542
12544 TOML_ATTR(nonnull)
12545 size_t operator()(void* dest, size_t num) noexcept
12546 {
12548
12549 num = impl::min(position_ + num, source_.length()) - position_;
12550 std::memcpy(dest, source_.data() + position_, num);
12551 position_ += num;
12552 return num;
12553 }
12554 };
12555
12556 template <>
12557 class utf8_byte_stream<std::istream>
12558 {
12559 private:
12560 std::istream* source_;
12561
12562 public:
12564 explicit utf8_byte_stream(std::istream& stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) //
12565 : source_{ &stream }
12566 {
12567 if (!*this) // eof, bad
12568 return;
12569
12570 const auto initial_pos = source_->tellg();
12571 char bom[3];
12572 source_->read(bom, 3);
12573 if (source_->bad() || (source_->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3u) == 0))
12574 return;
12575
12576 source_->clear();
12577 source_->seekg(initial_pos, std::istream::beg);
12578 }
12579
12581 bool error() const noexcept
12582 {
12583 return !!(source_->rdstate() & std::istream::badbit);
12584 }
12585
12587 bool eof() const noexcept
12588 {
12589 return !!(source_->rdstate() & std::istream::eofbit);
12590 }
12591
12593 explicit operator bool() const noexcept
12594 {
12595 return !(source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
12596 }
12597
12600 {
12601 return eof() || source_->peek() == std::istream::traits_type::eof();
12602 }
12603
12605 TOML_ATTR(nonnull)
12606 size_t operator()(void* dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
12607 {
12608 TOML_ASSERT(*this);
12609
12610 source_->read(static_cast<char*>(dest), static_cast<std::streamsize>(num));
12611 return static_cast<size_t>(source_->gcount());
12612 }
12613 };
12614
12616 {
12617 char32_t value;
12618 char bytes[4];
12619 size_t count;
12621
12623 constexpr operator const char32_t&() const noexcept
12624 {
12625 return value;
12626 }
12627
12629 constexpr const char32_t& operator*() const noexcept
12630 {
12631 return value;
12632 }
12633 };
12634 static_assert(std::is_trivial_v<utf8_codepoint>);
12635 static_assert(std::is_standard_layout_v<utf8_codepoint>);
12636
12638 {
12640 virtual const source_path_ptr& source_path() const noexcept = 0;
12641
12644
12646 virtual bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
12647
12648#if !TOML_EXCEPTIONS
12649
12651 virtual optional<parse_error>&& error() noexcept = 0;
12652
12653#endif
12654
12655 virtual ~utf8_reader_interface() noexcept = default;
12656 };
12657
12658#if TOML_EXCEPTIONS
12659#define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
12660#define utf8_reader_return_after_error(...) static_assert(true)
12661#define utf8_reader_error_check(...) static_assert(true)
12662#else
12663#define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
12664#define utf8_reader_return_after_error(...) return __VA_ARGS__
12665#define utf8_reader_error_check(...) \
12666 do \
12667 { \
12668 if TOML_UNLIKELY(err_) \
12669 return __VA_ARGS__; \
12670 } \
12671 while (false)
12672
12673#endif
12674
12675#if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
12676#define TOML_OVERALIGNED
12677#else
12678#define TOML_OVERALIGNED alignas(32)
12679#endif
12680
12681 template <typename T>
12683 {
12684 private:
12685 static constexpr size_t block_capacity = 32;
12686 utf8_byte_stream<T> stream_;
12688
12689 impl::utf8_decoder decoder_;
12691 {
12692 char bytes[4];
12693 size_t count;
12694 } currently_decoding_;
12695
12702
12704
12705#if !TOML_EXCEPTIONS
12706 optional<parse_error> err_;
12707#endif
12708
12710 {
12712
12713 TOML_OVERALIGNED char raw_bytes[block_capacity];
12714 size_t raw_bytes_read;
12715
12716 // read the next raw (encoded) block in from the stream
12717 if constexpr (noexcept(stream_(raw_bytes, block_capacity)) || !TOML_EXCEPTIONS)
12718 {
12719 raw_bytes_read = stream_(raw_bytes, block_capacity);
12720 }
12721#if TOML_EXCEPTIONS
12722 else
12723 {
12724 try
12725 {
12726 raw_bytes_read = stream_(raw_bytes, block_capacity);
12727 }
12728 catch (const std::exception& exc)
12729 {
12730 throw parse_error{ exc.what(), next_pos_, source_path_ };
12731 }
12732 catch (...)
12733 {
12734 throw parse_error{ "An unspecified error occurred", next_pos_, source_path_ };
12735 }
12736 }
12737#endif // TOML_EXCEPTIONS
12738
12739 // handle a zero-byte read
12740 if TOML_UNLIKELY(!raw_bytes_read)
12741 {
12742 if (stream_.eof())
12743 {
12744 // EOF only sets the error state if the decoder wants more input, otherwise
12745 // a zero-byte read might have just caused the underlying stream to realize it's exhaused and set
12746 // the EOF flag, and that's totally fine
12747 if (decoder_.needs_more_input())
12748 utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
12749 next_pos_,
12750 source_path_);
12751 }
12752 else
12753 {
12754 utf8_reader_error("Reading from the underlying stream failed - zero bytes read",
12755 next_pos_,
12756 source_path_);
12757 }
12758 return false;
12759 }
12760
12761 TOML_ASSERT_ASSUME(raw_bytes_read);
12762 std::memset(&codepoints_, 0, sizeof(codepoints_));
12763
12764 // helper for calculating decoded codepoint line+cols
12765 const auto calc_positions = [&]() noexcept
12766 {
12767 for (size_t i = 0; i < codepoints_.count; i++)
12768 {
12769 auto& cp = codepoints_.buffer[i];
12770 cp.position = next_pos_;
12771
12772 if (cp == U'\n')
12773 {
12774 next_pos_.line++;
12775 next_pos_.column = source_index{ 1 };
12776 }
12777 else
12778 next_pos_.column++;
12779 }
12780 };
12781
12782 // decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
12783 const auto ascii_fast_path = !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
12784
12785 // ASCII fast-path
12786 if (ascii_fast_path)
12787 {
12788 decoder_.reset();
12789 currently_decoding_.count = {};
12790
12791 codepoints_.count = raw_bytes_read;
12792 for (size_t i = 0; i < codepoints_.count; i++)
12793 {
12794 auto& cp = codepoints_.buffer[i];
12795 cp.value = static_cast<char32_t>(raw_bytes[i]);
12796 cp.bytes[0] = raw_bytes[i];
12797 cp.count = 1u;
12798 }
12799 }
12800
12801 // UTF-8 slow-path
12802 else
12803 {
12804 // helper for getting precise error location
12805 const auto error_pos = [&]() noexcept -> const source_position&
12806 { //
12807 return codepoints_.count ? codepoints_.buffer[codepoints_.count - 1u].position : next_pos_;
12808 };
12809
12810 for (size_t i = 0; i < raw_bytes_read; i++)
12811 {
12812 decoder_(static_cast<uint8_t>(raw_bytes[i]));
12813 if TOML_UNLIKELY(decoder_.error())
12814 {
12815 calc_positions();
12816 utf8_reader_error("Encountered invalid utf-8 sequence", error_pos(), source_path_);
12818 }
12819
12820 currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];
12821
12822 if (decoder_.has_code_point())
12823 {
12824 auto& cp = codepoints_.buffer[codepoints_.count++];
12825
12826 cp.value = decoder_.codepoint;
12827 cp.count = currently_decoding_.count;
12828 std::memcpy(cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
12829 currently_decoding_.count = {};
12830 }
12831 else if TOML_UNLIKELY(currently_decoding_.count == 4u)
12832 {
12833 calc_positions();
12834 utf8_reader_error("Encountered overlong utf-8 sequence", error_pos(), source_path_);
12836 }
12837 }
12838 if TOML_UNLIKELY(decoder_.needs_more_input() && stream_.eof())
12839 {
12840 calc_positions();
12841 utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
12842 error_pos(),
12843 source_path_);
12845 }
12846 }
12847
12849 calc_positions();
12850
12851 // handle general I/O errors
12852 // (down here so the next_pos_ benefits from calc_positions())
12853 if TOML_UNLIKELY(stream_.error())
12854 {
12855 utf8_reader_error("An I/O error occurred while reading from the underlying stream",
12856 next_pos_,
12857 source_path_);
12859 }
12860
12861 return true;
12862 }
12863
12864 public:
12865 template <typename U, typename String = std::string_view>
12867 explicit utf8_reader(U&& source, String&& source_path = {}) noexcept(
12868 std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
12869 : stream_{ static_cast<U&&>(source) }
12870 {
12871 currently_decoding_.count = {};
12872
12873 codepoints_.current = {};
12874 codepoints_.count = {};
12875
12876 if (!source_path.empty())
12877 source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
12878 }
12879
12881 const source_path_ptr& source_path() const noexcept final
12882 {
12883 return source_path_;
12884 }
12885
12888 {
12890
12891 if (codepoints_.current == codepoints_.count)
12892 {
12894 return nullptr;
12895
12897 }
12901
12902 return &codepoints_.buffer[codepoints_.current++];
12903 }
12904
12906 bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
12907 {
12908 return stream_.peek_eof();
12909 }
12910
12911#if !TOML_EXCEPTIONS
12912
12914 optional<parse_error>&& error() noexcept final
12915 {
12916 return std::move(err_);
12917 }
12918
12919#endif
12920 };
12921
12922 template <typename Char>
12923 utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
12924 template <typename Char>
12925 utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
12926 template <typename Char>
12927 utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
12928 template <typename Char>
12929 utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
12930
12931#if TOML_EXCEPTIONS
12932#define utf8_buffered_reader_error_check(...) static_assert(true)
12933#else
12934#define utf8_buffered_reader_error_check(...) \
12935 do \
12936 { \
12937 if TOML_UNLIKELY(reader_.error()) \
12938 return __VA_ARGS__; \
12939 } \
12940 while (false)
12941
12942#endif
12943
12945 {
12946 public:
12947 static constexpr size_t max_history_length = 128;
12948
12949 private:
12950 static constexpr size_t history_buffer_size = max_history_length - 1; //'head' is stored in the reader
12952 struct
12953 {
12955 size_t count, first;
12956 } history_ = {};
12958 size_t negative_offset_ = {};
12959
12960 public:
12962 explicit utf8_buffered_reader(utf8_reader_interface& reader) noexcept //
12963 : reader_{ reader }
12964 {}
12965
12967 const source_path_ptr& source_path() const noexcept
12968 {
12969 return reader_.source_path();
12970 }
12971
12974 {
12976
12977 if (negative_offset_)
12978 {
12980
12981 // an entry negative offset of 1 just means "replay the current head"
12982 if (!negative_offset_)
12983 return head_;
12984
12985 // otherwise step back into the history buffer
12986 else
12987 return history_.buffer
12988 + ((history_.first + history_.count - negative_offset_) % history_buffer_size);
12989 }
12990 else
12991 {
12992 // first character read from stream
12993 if TOML_UNLIKELY(!history_.count && !head_)
12994 head_ = reader_.read_next();
12995
12996 // subsequent characters and not eof
12997 else if (head_)
12998 {
13000 history_.buffer[history_.count++] = *head_;
13001 else
13003
13004 head_ = reader_.read_next();
13005 }
13006
13007 return head_;
13008 }
13009 }
13010
13012 const utf8_codepoint* step_back(size_t count) noexcept
13013 {
13015
13018
13020
13021 return negative_offset_
13022 ? history_.buffer + ((history_.first + history_.count - negative_offset_) % history_buffer_size)
13023 : head_;
13024 }
13025
13028 {
13029 return reader_.peek_eof();
13030 }
13031
13032#if !TOML_EXCEPTIONS
13033
13035 optional<parse_error>&& error() noexcept
13036 {
13037 return reader_.error();
13038 }
13039
13040#endif
13041 };
13042}
13044
13045#if TOML_EXCEPTIONS
13046#define TOML_RETURNS_BY_THROWING [[noreturn]]
13047#else
13048#define TOML_RETURNS_BY_THROWING
13049#endif
13050
13052{
13053 template <typename... T>
13056 constexpr bool is_match(char32_t codepoint, T... vals) noexcept
13057 {
13058 static_assert((std::is_same_v<char32_t, T> && ...));
13059 return ((codepoint == vals) || ...);
13060 }
13061
13062 template <uint64_t>
13063 struct parse_integer_traits;
13064 template <>
13065 struct parse_integer_traits<2>
13066 {
13067 static constexpr auto scope_qualifier = "binary integer"sv;
13068 static constexpr auto is_digit = impl::is_binary_digit;
13069 static constexpr auto is_signed = false;
13070 static constexpr auto max_digits = 63;
13071 static constexpr auto prefix_codepoint = U'b';
13072 static constexpr auto prefix = "b"sv;
13073 static constexpr auto full_prefix = "0b"sv;
13074 };
13075 template <>
13076 struct parse_integer_traits<8>
13077 {
13078 static constexpr auto scope_qualifier = "octal integer"sv;
13079 static constexpr auto is_digit = impl::is_octal_digit;
13080 static constexpr auto is_signed = false;
13081 static constexpr auto max_digits = 21; // strlen("777777777777777777777")
13082 static constexpr auto prefix_codepoint = U'o';
13083 static constexpr auto prefix = "o"sv;
13084 static constexpr auto full_prefix = "0o"sv;
13085 };
13086 template <>
13087 struct parse_integer_traits<10>
13088 {
13089 static constexpr auto scope_qualifier = "decimal integer"sv;
13090 static constexpr auto is_digit = impl::is_decimal_digit;
13091 static constexpr auto is_signed = true;
13092 static constexpr auto max_digits = 19; // strlen("9223372036854775807")
13093 static constexpr auto full_prefix = ""sv;
13094 };
13095 template <>
13096 struct parse_integer_traits<16>
13097 {
13098 static constexpr auto scope_qualifier = "hexadecimal integer"sv;
13099 static constexpr auto is_digit = impl::is_hexadecimal_digit;
13100 static constexpr auto is_signed = false;
13101 static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
13102 static constexpr auto prefix_codepoint = U'x';
13103 static constexpr auto prefix = "x"sv;
13104 static constexpr auto full_prefix = "0x"sv;
13105 };
13106
13109 std::string_view to_sv(node_type val) noexcept
13110 {
13111 return impl::node_type_friendly_names[impl::unwrap_enum(val)];
13112 }
13113
13116 std::string_view to_sv(const std::string& str) noexcept
13117 {
13118 return std::string_view{ str };
13119 }
13120
13123 std::string_view to_sv(bool val) noexcept
13124 {
13125 using namespace std::string_view_literals;
13126
13127 return val ? "true"sv : "false"sv;
13128 }
13129
13132 std::string_view to_sv(const utf8_codepoint& cp) noexcept
13133 {
13134 if (cp.value <= U'\x1F')
13135 return impl::control_char_escapes[cp.value];
13136 else if (cp.value == U'\x7F')
13137 return "\\u007F"sv;
13138 else
13139 return std::string_view{ cp.bytes, cp.count };
13140 }
13141
13144 std::string_view to_sv(const utf8_codepoint* cp) noexcept
13145 {
13146 if (cp)
13147 return to_sv(*cp);
13148 return ""sv;
13149 }
13150
13152 {
13154 };
13155
13156 template <typename T>
13157 TOML_ATTR(nonnull)
13159 void concatenate(char*& write_pos, char* const buf_end, const T& arg) noexcept
13160 {
13161 if TOML_UNLIKELY(write_pos >= buf_end)
13162 return;
13163
13164 using arg_type = impl::remove_cvref<T>;
13165
13166 // string views
13167 if constexpr (std::is_same_v<arg_type, std::string_view>)
13168 {
13169 const auto max_chars = static_cast<size_t>(buf_end - write_pos);
13170 const auto len = max_chars < arg.length() ? max_chars : arg.length();
13171 std::memcpy(write_pos, arg.data(), len);
13172 write_pos += len;
13173 }
13174
13175 // doubles
13176 else if constexpr (std::is_same_v<arg_type, double>)
13177 {
13178#if TOML_FLOAT_CHARCONV
13179 const auto result = std::to_chars(write_pos, buf_end, arg);
13180 write_pos = result.ptr;
13181#else
13182 std::ostringstream ss;
13183 ss.imbue(std::locale::classic());
13184 ss.precision(std::numeric_limits<arg_type>::max_digits10);
13185 ss << arg;
13186 concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
13187#endif
13188 }
13189
13190 // 64-bit integers
13191 else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>)
13192 {
13193#if TOML_INT_CHARCONV
13194 const auto result = std::to_chars(write_pos, buf_end, arg);
13195 write_pos = result.ptr;
13196#else
13197 std::ostringstream ss;
13198 ss.imbue(std::locale::classic());
13199 using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
13200 ss << static_cast<cast_type>(arg);
13201 concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
13202#endif
13203 }
13204
13205 // escaped_codepoint
13206 else if constexpr (std::is_same_v<arg_type, escaped_codepoint>)
13207 {
13208 if (arg.cp.value <= U'\x7F')
13209 concatenate(write_pos, buf_end, to_sv(arg.cp));
13210 else
13211 {
13212 auto val = static_cast<uint_least32_t>(arg.cp.value);
13213 const auto digits = val > 0xFFFFu ? 8u : 4u;
13214 constexpr auto mask = uint_least32_t{ 0xFu };
13215 char buf[10] = { '\\', digits > 4 ? 'U' : 'u' };
13216 for (auto i = 2u + digits; i-- > 2u;)
13217 {
13218 const auto hexdig = val & mask;
13219 buf[i] = static_cast<char>(hexdig >= 0xAu ? ('A' + (hexdig - 0xAu)) : ('0' + hexdig));
13220 val >>= 4;
13221 }
13222 concatenate(write_pos, buf_end, std::string_view{ buf, digits + 2u });
13223 }
13224 }
13225
13226 // all other floats (fallback - coerce to double)
13227 else if constexpr (std::is_floating_point_v<arg_type>)
13228 concatenate(write_pos, buf_end, static_cast<double>(arg));
13229
13230 // all other integers (fallback - coerce to (u)int64_t)
13231 else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>)
13232 {
13233 using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
13234 concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
13235 }
13236
13237 else
13238 {
13239 static_assert(
13240 impl::always_false<T>,
13241 "concatenate() inputs are limited to std::string_views, integers, floats, and escaped_codepoint");
13242 }
13243 }
13244
13246 {
13247 static constexpr std::size_t buf_size = 512;
13250 char* const max_write_pos = buf + (buf_size - std::size_t{ 1 }); // allow for null terminator
13251
13253 error_builder(std::string_view scope) noexcept
13254 {
13255 concatenate(write_pos, max_write_pos, "Error while parsing "sv);
13258 }
13259
13260 template <typename T>
13261 void append(const T& arg) noexcept
13262 {
13264 }
13265
13267 auto finish(const source_position& pos, const source_path_ptr& source_path) const
13268 {
13269 *write_pos = '\0';
13270
13271#if TOML_EXCEPTIONS
13272 throw parse_error{ buf, pos, source_path };
13273#else
13274 return parse_error{ std::string(buf, static_cast<size_t>(write_pos - buf)), pos, source_path };
13275#endif
13276 }
13277
13279 };
13280
13282 {
13283 std::string_view& storage_;
13284 std::string_view parent_;
13285
13287 explicit parse_scope(std::string_view& current_scope, std::string_view new_scope) noexcept
13288 : storage_{ current_scope },
13289 parent_{ current_scope }
13290 {
13291 storage_ = new_scope;
13292 }
13293
13294 ~parse_scope() noexcept
13295 {
13296 storage_ = parent_;
13297 }
13298
13300 };
13301#define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
13302#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
13303#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
13304
13306 {
13307 std::string buffer;
13308 std::vector<std::pair<size_t, size_t>> segments;
13309 std::vector<source_position> starts;
13310 std::vector<source_position> ends;
13311
13312 void clear() noexcept
13313 {
13314 buffer.clear();
13315 segments.clear();
13316 starts.clear();
13317 ends.clear();
13318 }
13319
13320 void push_back(std::string_view segment, source_position b, source_position e)
13321 {
13322 segments.push_back({ buffer.length(), segment.length() });
13323 buffer.append(segment);
13324 starts.push_back(b);
13325 ends.push_back(e);
13326 }
13327
13329 std::string_view operator[](size_t i) const noexcept
13330 {
13331 return std::string_view{ buffer.c_str() + segments[i].first, segments[i].second };
13332 }
13333
13335 std::string_view back() const noexcept
13336 {
13337 return (*this)[segments.size() - 1u];
13338 }
13339
13341 bool empty() const noexcept
13342 {
13343 return segments.empty();
13344 }
13345
13347 size_t size() const noexcept
13348 {
13349 return segments.size();
13350 }
13351 };
13352
13354 {
13355 size_t& depth_;
13356
13358 explicit depth_counter_scope(size_t& depth) noexcept //
13359 : depth_{ depth }
13360 {
13361 depth_++;
13362 }
13363
13365 {
13366 depth_--;
13367 }
13368
13370 };
13371
13373 {
13374 std::string_view value;
13376 };
13377
13379 {
13380 std::vector<table*>& tables;
13381
13383 explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
13384 : tables{ tables_ }
13385 {
13386 tables.push_back(&tbl);
13387 }
13388
13390 {
13391 tables.pop_back();
13392 }
13393
13395 };
13396}
13398
13399#if 1 // parser helper macros
13400
13401// Q: "what the fuck is this? MACROS????"
13402// A: The parser needs to work in exceptionless mode (returning error objects directly)
13403// and exception mode (reporting parse failures by throwing). Two totally different control flows.
13404// These macros encapsulate the differences between the two modes so I can write code code
13405// as though I was only targeting one mode and not want yeet myself into the sun.
13406// They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
13407// of toml++.
13408
13409#define is_eof() !cp
13410#define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
13411#define return_if_eof(...) \
13412 do \
13413 { \
13414 if TOML_UNLIKELY(is_eof()) \
13415 return __VA_ARGS__; \
13416 } \
13417 while (false)
13418
13419#if TOML_EXCEPTIONS
13420#define is_error() false
13421#define return_after_error(...) TOML_UNREACHABLE
13422#define assert_not_error() static_assert(true)
13423#define return_if_error(...) static_assert(true)
13424#define return_if_error_or_eof(...) return_if_eof(__VA_ARGS__)
13425#else
13426#define is_error() !!err
13427#define return_after_error(...) return __VA_ARGS__
13428#define assert_not_error() TOML_ASSERT(!is_error())
13429#define return_if_error(...) \
13430 do \
13431 { \
13432 if TOML_UNLIKELY(is_error()) \
13433 return __VA_ARGS__; \
13434 } \
13435 while (false)
13436#define return_if_error_or_eof(...) \
13437 do \
13438 { \
13439 if TOML_UNLIKELY(is_eof() || is_error()) \
13440 return __VA_ARGS__; \
13441 } \
13442 while (false)
13443#endif
13444
13445#if defined(TOML_BREAK_AT_PARSE_ERRORS) && TOML_BREAK_AT_PARSE_ERRORS
13446#if defined(__has_builtin)
13447#if __has_builtin(__builtin_debugtrap)
13448#define parse_error_break() __builtin_debugtrap()
13449#elif __has_builtin(__debugbreak)
13450#define parse_error_break() __debugbreak()
13451#endif
13452#endif
13453#ifndef parse_error_break
13454#if TOML_MSVC || TOML_ICC
13455#define parse_error_break() __debugbreak()
13456#else
13457#define parse_error_break() TOML_ASSERT(false)
13458#endif
13459#endif
13460#else
13461#define parse_error_break() static_assert(true)
13462#endif
13463
13464#define set_error_and_return(ret, ...) \
13465 do \
13466 { \
13467 if (!is_error()) \
13468 set_error(__VA_ARGS__); \
13469 return_after_error(ret); \
13470 } \
13471 while (false)
13472
13473#define set_error_and_return_default(...) set_error_and_return({}, __VA_ARGS__)
13474
13475#define set_error_and_return_if_eof(...) \
13476 do \
13477 { \
13478 if TOML_UNLIKELY(is_eof()) \
13479 set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \
13480 } \
13481 while (false)
13482
13483#define advance_and_return_if_error(...) \
13484 do \
13485 { \
13486 assert_not_eof(); \
13487 advance(); \
13488 return_if_error(__VA_ARGS__); \
13489 } \
13490 while (false)
13491
13492#define advance_and_return_if_error_or_eof(...) \
13493 do \
13494 { \
13495 assert_not_eof(); \
13496 advance(); \
13497 return_if_error(__VA_ARGS__); \
13498 set_error_and_return_if_eof(__VA_ARGS__); \
13499 } \
13500 while (false)
13501
13502#endif // parser helper macros
13503
13505{
13506 TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
13507
13509 {
13510 private:
13512
13516 const utf8_codepoint* cp = {};
13517 std::vector<table*> implicit_tables;
13518 std::vector<table*> dotted_key_tables;
13519 std::vector<table*> open_inline_tables;
13520 std::vector<array*> table_arrays;
13522 std::string string_buffer;
13523 std::string recording_buffer; // for diagnostics
13524 bool recording = false, recording_whitespace = true;
13525 std::string_view current_scope;
13526 size_t nested_values = {};
13527#if !TOML_EXCEPTIONS
13528 mutable optional<parse_error> err;
13529#endif
13530
13532 source_position current_position(source_index fallback_offset = 0) const noexcept
13533 {
13534 if (!is_eof())
13535 return cp->position;
13536 return { prev_pos.line, static_cast<source_index>(prev_pos.column + fallback_offset) };
13537 }
13538
13539 template <typename... T>
13542 void set_error_at(source_position pos, const T&... reason) const
13543 {
13544 static_assert(sizeof...(T) > 0);
13546
13547 error_builder builder{ current_scope };
13548 (builder.append(reason), ...);
13549
13551
13552#if TOML_EXCEPTIONS
13553 builder.finish(pos, reader.source_path());
13554#else
13555 err.emplace(builder.finish(pos, reader.source_path()));
13556#endif
13557 }
13558
13559 template <typename... T>
13561 void set_error(const T&... reason) const
13562 {
13563 set_error_at(current_position(1), reason...);
13564 }
13565
13566 void go_back(size_t count = 1) noexcept
13567 {
13570
13571 cp = reader.step_back(count);
13572 prev_pos = cp->position;
13573 }
13574
13575 void advance()
13576 {
13579
13580 prev_pos = cp->position;
13581 cp = reader.read_next();
13582
13583#if !TOML_EXCEPTIONS
13584 if (reader.error())
13585 {
13586 err = std::move(reader.error());
13587 return;
13588 }
13589#endif
13590
13591 if (recording && !is_eof())
13592 {
13593 if (recording_whitespace || !is_whitespace(*cp))
13594 recording_buffer.append(cp->bytes, cp->count);
13595 }
13596 }
13597
13598 void start_recording(bool include_current = true) noexcept
13599 {
13601
13602 recording = true;
13603 recording_whitespace = true;
13604 recording_buffer.clear();
13605 if (include_current && !is_eof())
13606 recording_buffer.append(cp->bytes, cp->count);
13607 }
13608
13609 void stop_recording(size_t pop_bytes = 0) noexcept
13610 {
13612
13613 recording = false;
13614 if (pop_bytes)
13615 {
13616 if (pop_bytes >= recording_buffer.length())
13617 recording_buffer.clear();
13618 else if (pop_bytes == 1u)
13619 recording_buffer.pop_back();
13620 else
13622 + static_cast<ptrdiff_t>(recording_buffer.length() - pop_bytes),
13623 recording_buffer.end());
13624 }
13625 }
13626
13628 {
13630
13631 bool consumed = false;
13632 while (!is_eof() && is_horizontal_whitespace(*cp))
13633 {
13634 if TOML_UNLIKELY(!is_ascii_horizontal_whitespace(*cp))
13635 set_error_and_return_default("expected space or tab, saw '"sv, escaped_codepoint{ *cp }, "'"sv);
13636
13637 consumed = true;
13639 }
13640 return consumed;
13641 }
13642
13644 {
13646
13647 if TOML_UNLIKELY(is_match(*cp, U'\v', U'\f'))
13649 R"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);
13650
13651 if (*cp == U'\r')
13652 {
13653 advance_and_return_if_error({}); // skip \r
13654
13655 if TOML_UNLIKELY(is_eof())
13656 set_error_and_return_default("expected '\\n' after '\\r', saw EOF"sv);
13657
13658 if TOML_UNLIKELY(*cp != U'\n')
13659 set_error_and_return_default("expected '\\n' after '\\r', saw '"sv,
13661 "'"sv);
13662 }
13663 else if (*cp != U'\n')
13664 return false;
13665
13666 advance_and_return_if_error({}); // skip \n
13667 return true;
13668 }
13669
13671 {
13673
13674 do
13675 {
13676 if (is_ascii_vertical_whitespace(*cp))
13677 return consume_line_break();
13678 else
13679 advance();
13680 return_if_error({});
13681 }
13682 while (!is_eof());
13683
13684 return true;
13685 }
13686
13688 {
13690
13691 if (*cp != U'#')
13692 return false;
13693
13694 push_parse_scope("comment"sv);
13695
13696 advance_and_return_if_error({}); // skip the '#'
13697
13698 while (!is_eof())
13699 {
13700 if (consume_line_break())
13701 return true;
13702 return_if_error({});
13703
13704#if TOML_LANG_AT_LEAST(1, 0, 0)
13705
13706 // toml/issues/567 (disallow non-TAB control characters in comments)
13707 if TOML_UNLIKELY(is_nontab_control_character(*cp))
13709 "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv);
13710
13711 // toml/pull/720 (disallow surrogates in comments)
13712 else if TOML_UNLIKELY(is_unicode_surrogate(*cp))
13714 "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
13715#endif
13716
13718 }
13719
13720 return true;
13721 }
13722
13724 bool consume_expected_sequence(std::u32string_view seq)
13725 {
13726 return_if_error({});
13727 TOML_ASSERT(!seq.empty());
13728
13729 for (auto c : seq)
13730 {
13732 if (*cp != c)
13733 return false;
13735 }
13736 return true;
13737 }
13738
13739 template <typename T>
13741 bool consume_digit_sequence(T* digits, size_t len)
13742 {
13743 return_if_error({});
13744 TOML_ASSERT_ASSUME(digits);
13745 TOML_ASSERT_ASSUME(len);
13746
13747 for (size_t i = 0; i < len; i++)
13748 {
13750 if (!is_decimal_digit(*cp))
13751 return false;
13752
13753 digits[i] = static_cast<T>(*cp - U'0');
13755 }
13756 return true;
13757 }
13758
13759 template <typename T>
13761 size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len)
13762 {
13763 return_if_error({});
13764 TOML_ASSERT_ASSUME(buffer);
13765 TOML_ASSERT_ASSUME(max_len);
13766
13767 size_t i = {};
13768 for (; i < max_len; i++)
13769 {
13770 if (is_eof() || !is_decimal_digit(*cp))
13771 break;
13772
13773 buffer[i] = static_cast<T>(*cp - U'0');
13775 }
13776 return i;
13777 }
13778
13781 std::string_view parse_basic_string(bool multi_line)
13782 {
13783 return_if_error({});
13785 TOML_ASSERT_ASSUME(*cp == U'"');
13786 push_parse_scope("string"sv);
13787
13788 // skip the '"'
13790
13791 // multi-line strings ignore a single line ending right at the beginning
13792 if (multi_line)
13793 {
13795 return_if_error({});
13797 }
13798
13799 auto& str = string_buffer;
13800 str.clear();
13801 bool escaped = false;
13802 bool skipping_whitespace = false;
13803 do
13804 {
13805 if (escaped)
13806 {
13807 escaped = false;
13808
13809 // handle 'line ending slashes' in multi-line mode
13810 if (multi_line && is_whitespace(*cp))
13811 {
13813
13816 "line-ending backslashes must be the last non-whitespace character on the line"sv);
13817
13818 skipping_whitespace = true;
13819 return_if_error({});
13820 continue;
13821 }
13822
13823 bool skip_escaped_codepoint = true;
13825 switch (const auto escaped_codepoint = *cp)
13826 {
13827 // 'regular' escape codes
13828 case U'b': str += '\b'; break;
13829 case U'f': str += '\f'; break;
13830 case U'n': str += '\n'; break;
13831 case U'r': str += '\r'; break;
13832 case U't': str += '\t'; break;
13833 case U'"': str += '"'; break;
13834 case U'\\': str += '\\'; break;
13835
13836#if TOML_LANG_UNRELEASED // toml/pull/790 (\e shorthand for \x1B)
13837 case U'e': str += '\x1B'; break;
13838#else
13839 case U'e':
13841 "escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
13842#endif
13843
13844#if TOML_LANG_UNRELEASED // toml/pull/796 (\xHH unicode scalar sequences)
13845 case U'x': [[fallthrough]];
13846#else
13847 case U'x':
13849 "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
13850#endif
13851
13852 // unicode scalar sequences
13853 case U'u': [[fallthrough]];
13854 case U'U':
13855 {
13856 push_parse_scope("unicode scalar sequence"sv);
13858 skip_escaped_codepoint = false;
13859
13860 uint32_t place_value =
13861 escaped_codepoint == U'U' ? 0x10000000u : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
13862 uint32_t sequence_value{};
13863 while (place_value)
13864 {
13866
13867 if TOML_UNLIKELY(!is_hexadecimal_digit(*cp))
13868 set_error_and_return_default("expected hex digit, saw '"sv, to_sv(*cp), "'"sv);
13869
13870 sequence_value += place_value * hex_to_dec(*cp);
13871 place_value /= 16u;
13873 }
13874
13875 if TOML_UNLIKELY(is_unicode_surrogate(sequence_value))
13877 "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
13878 else if TOML_UNLIKELY(sequence_value > 0x10FFFFu)
13879 set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
13880
13881 if (sequence_value < 0x80)
13882 {
13883 str += static_cast<char>(sequence_value);
13884 }
13885 else if (sequence_value < 0x800u)
13886 {
13887 str += static_cast<char>((sequence_value >> 6) | 0xC0u);
13888 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
13889 }
13890 else if (sequence_value < 0x10000u)
13891 {
13892 str += static_cast<char>((sequence_value >> 12) | 0xE0u);
13893 str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
13894 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
13895 }
13896 else if (sequence_value < 0x110000u)
13897 {
13898 str += static_cast<char>((sequence_value >> 18) | 0xF0u);
13899 str += static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
13900 str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
13901 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
13902 }
13903 break;
13904 }
13905
13906 // ???
13908 default: set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
13909 }
13910
13911 if (skip_escaped_codepoint)
13913 }
13914 else
13915 {
13916 // handle closing delimiters
13917 if (*cp == U'"')
13918 {
13919 if (multi_line)
13920 {
13921 size_t lookaheads = {};
13922 size_t consecutive_delimiters = 1;
13923 do
13924 {
13926 lookaheads++;
13927 if (!is_eof() && *cp == U'"')
13928 consecutive_delimiters++;
13929 else
13930 break;
13931 }
13932 while (lookaheads < 4u);
13933
13934 switch (consecutive_delimiters)
13935 {
13936 // """ " (one quote somewhere in a ML string)
13937 case 1:
13938 str += '"';
13939 skipping_whitespace = false;
13940 continue;
13941
13942 // """ "" (two quotes somewhere in a ML string)
13943 case 2:
13944 str.append("\"\""sv);
13945 skipping_whitespace = false;
13946 continue;
13947
13948 // """ """ (the end of the string)
13949 case 3: return str;
13950
13951 // """ """" (one at the end of the string)
13952 case 4: str += '"'; return str;
13953
13954 // """ """"" (two quotes at the end of the string)
13955 case 5:
13956 str.append("\"\""sv);
13957 advance_and_return_if_error({}); // skip the last '"'
13958 return str;
13959
13960 default: TOML_UNREACHABLE;
13961 }
13962 }
13963 else
13964 {
13965 advance_and_return_if_error({}); // skip the closing delimiter
13966 return str;
13967 }
13968 }
13969
13970 // handle escapes
13971 else if (*cp == U'\\')
13972 {
13973 advance_and_return_if_error_or_eof({}); // skip the '\'
13974 skipping_whitespace = false;
13975 escaped = true;
13976 continue;
13977 }
13978
13979 // handle line endings in multi-line mode
13980 if (multi_line && is_ascii_vertical_whitespace(*cp))
13981 {
13983 return_if_error({});
13984 if (!skipping_whitespace)
13985 str += '\n';
13986 continue;
13987 }
13988
13989 // handle control characters
13990 if TOML_UNLIKELY(is_nontab_control_character(*cp))
13992 "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv);
13993
13994#if TOML_LANG_AT_LEAST(1, 0, 0)
13995
13996 // handle surrogates in strings
13997 if TOML_UNLIKELY(is_unicode_surrogate(*cp))
13999 "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
14000#endif
14001
14002 if (multi_line)
14003 {
14004 if (!skipping_whitespace || !is_horizontal_whitespace(*cp))
14005 {
14006 skipping_whitespace = false;
14007 str.append(cp->bytes, cp->count);
14008 }
14009 }
14010 else
14011 str.append(cp->bytes, cp->count);
14012
14014 }
14015 }
14016 while (!is_eof());
14017
14018 set_error_and_return_default("encountered end-of-file"sv);
14019 }
14020
14023 std::string_view parse_literal_string(bool multi_line)
14024 {
14025 return_if_error({});
14027 TOML_ASSERT_ASSUME(*cp == U'\'');
14028 push_parse_scope("literal string"sv);
14029
14030 // skip the delimiter
14032
14033 // multi-line strings ignore a single line ending right at the beginning
14034 if (multi_line)
14035 {
14037 return_if_error({});
14039 }
14040
14041 auto& str = string_buffer;
14042 str.clear();
14043 do
14044 {
14045 return_if_error({});
14046
14047 // handle closing delimiters
14048 if (*cp == U'\'')
14049 {
14050 if (multi_line)
14051 {
14052 size_t lookaheads = {};
14053 size_t consecutive_delimiters = 1;
14054 do
14055 {
14057 lookaheads++;
14058 if (!is_eof() && *cp == U'\'')
14059 consecutive_delimiters++;
14060 else
14061 break;
14062 }
14063 while (lookaheads < 4u);
14064
14065 switch (consecutive_delimiters)
14066 {
14067 // ''' ' (one quote somewhere in a ML string)
14068 case 1: str += '\''; continue;
14069
14070 // ''' '' (two quotes somewhere in a ML string)
14071 case 2: str.append("''"sv); continue;
14072
14073 // ''' ''' (the end of the string)
14074 case 3: return str;
14075
14076 // ''' '''' (one at the end of the string)
14077 case 4: str += '\''; return str;
14078
14079 // ''' ''''' (two quotes at the end of the string)
14080 case 5:
14081 str.append("''"sv);
14082 advance_and_return_if_error({}); // skip the last '
14083 return str;
14084
14085 default: TOML_UNREACHABLE;
14086 }
14087 }
14088 else
14089 {
14090 advance_and_return_if_error({}); // skip the closing delimiter
14091 return str;
14092 }
14093 }
14094
14095 // handle line endings in multi-line mode
14096 if (multi_line && is_ascii_vertical_whitespace(*cp))
14097 {
14099 return_if_error({});
14100 str += '\n';
14101 continue;
14102 }
14103
14104 // handle control characters
14105 if TOML_UNLIKELY(is_nontab_control_character(*cp))
14107 "control characters other than TAB (U+0009) are explicitly prohibited"sv);
14108
14109#if TOML_LANG_AT_LEAST(1, 0, 0)
14110
14111 // handle surrogates in strings
14112 if TOML_UNLIKELY(is_unicode_surrogate(*cp))
14113 set_error_and_return_default("unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
14114#endif
14115
14116 str.append(cp->bytes, cp->count);
14118 }
14119 while (!is_eof());
14120
14121 set_error_and_return_default("encountered end-of-file"sv);
14122 }
14123
14127 {
14128 return_if_error({});
14130 TOML_ASSERT_ASSUME(is_string_delimiter(*cp));
14131 push_parse_scope("string"sv);
14132
14133 // get the first three characters to determine the string type
14134 const auto first = cp->value;
14136 const auto second = cp->value;
14138 const auto third = cp ? cp->value : U'\0';
14139
14140 // if we were eof at the third character then first and second need to be
14141 // the same string character (otherwise it's an unterminated string)
14142 if (is_eof())
14143 {
14144 if (second == first)
14145 return {};
14146
14147 set_error_and_return_default("encountered end-of-file"sv);
14148 }
14149
14150 // if the first three characters are all the same string delimiter then
14151 // it's a multi-line string.
14152 else if (first == second && first == third)
14153 {
14154 return { first == U'\'' ? parse_literal_string(true) : parse_basic_string(true), true };
14155 }
14156
14157 // otherwise it's just a regular string.
14158 else
14159 {
14160 // step back two characters so that the current
14161 // character is the string delimiter
14162 go_back(2u);
14163
14164 return { first == U'\'' ? parse_literal_string(false) : parse_basic_string(false), false };
14165 }
14166 }
14167
14170 std::string_view parse_bare_key_segment()
14171 {
14172 return_if_error({});
14174 TOML_ASSERT_ASSUME(is_bare_key_character(*cp));
14175
14176 string_buffer.clear();
14177
14178 while (!is_eof())
14179 {
14180 if (!is_bare_key_character(*cp))
14181 break;
14182
14183 string_buffer.append(cp->bytes, cp->count);
14185 }
14186
14187 return string_buffer;
14188 }
14189
14193 {
14194 return_if_error({});
14196 TOML_ASSERT_ASSUME(is_match(*cp, U't', U'f', U'T', U'F'));
14197 push_parse_scope("boolean"sv);
14198
14199 start_recording(true);
14200 auto result = is_match(*cp, U't', U'T');
14201 if (!consume_expected_sequence(result ? U"true"sv : U"false"sv))
14202 set_error_and_return_default("expected '"sv,
14203 to_sv(result),
14204 "', saw '"sv,
14206 "'"sv);
14208
14209 if (cp && !is_value_terminator(*cp))
14210 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14211
14212 return result;
14213 }
14214
14218 {
14219 return_if_error({});
14221 TOML_ASSERT_ASSUME(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
14222 push_parse_scope("floating-point"sv);
14223
14224 start_recording(true);
14225 const bool negative = *cp == U'-';
14226 if (negative || *cp == U'+')
14228
14229 const bool inf = is_match(*cp, U'i', U'I');
14230 if (!consume_expected_sequence(inf ? U"inf"sv : U"nan"sv))
14231 set_error_and_return_default("expected '"sv,
14232 inf ? "inf"sv : "nan"sv,
14233 "', saw '"sv,
14235 "'"sv);
14237
14238 if (cp && !is_value_terminator(*cp))
14239 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14240
14241 return inf ? (negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity())
14242 : std::numeric_limits<double>::quiet_NaN();
14243 }
14244
14248 {
14249 return_if_error({});
14251 TOML_ASSERT_ASSUME(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
14252 push_parse_scope("floating-point"sv);
14253
14254 // sign
14255 const int sign = *cp == U'-' ? -1 : 1;
14256 if (is_match(*cp, U'+', U'-'))
14258
14259 // consume value chars
14261 size_t length = {};
14262 const utf8_codepoint* prev = {};
14263 bool seen_decimal = false, seen_exponent = false;
14264 char first_integer_part = '\0';
14265 while (!is_eof() && !is_value_terminator(*cp))
14266 {
14267 if (*cp == U'_')
14268 {
14269 if (!prev || !is_decimal_digit(*prev))
14270 set_error_and_return_default("underscores may only follow digits"sv);
14271
14272 prev = cp;
14274 continue;
14275 }
14276 else if TOML_UNLIKELY(prev && *prev == U'_' && !is_decimal_digit(*cp))
14277 set_error_and_return_default("underscores must be followed by digits"sv);
14278 else if TOML_UNLIKELY(length == sizeof(chars))
14279 set_error_and_return_default("exceeds length limit of "sv,
14280 sizeof(chars),
14281 " digits"sv,
14282 (seen_exponent ? ""sv : " (consider using exponent notation)"sv));
14283 else if (*cp == U'.')
14284 {
14285 // .1
14286 // -.1
14287 // +.1 (no integer part)
14288 if (!first_integer_part)
14289 set_error_and_return_default("expected decimal digit, saw '.'"sv);
14290
14291 // 1.0e+.10 (exponent cannot have '.')
14292 else if (seen_exponent)
14293 set_error_and_return_default("expected exponent decimal digit or sign, saw '.'"sv);
14294
14295 // 1.0.e+.10
14296 // 1..0
14297 // (multiple '.')
14298 else if (seen_decimal)
14299 set_error_and_return_default("expected decimal digit or exponent, saw '.'"sv);
14300
14301 seen_decimal = true;
14302 }
14303 else if (is_match(*cp, U'e', U'E'))
14304 {
14305 if (prev && !is_decimal_digit(*prev))
14306 set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14307
14308 // 1.0ee+10 (multiple 'e')
14309 else if (seen_exponent)
14310 set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14311
14312 seen_decimal = true; // implied
14313 seen_exponent = true;
14314 }
14315 else if (is_match(*cp, U'+', U'-'))
14316 {
14317 // 1.-0 (sign in mantissa)
14318 if (!seen_exponent)
14319 set_error_and_return_default("expected decimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14320
14321 // 1.0e1-0 (misplaced exponent sign)
14322 else if (!is_match(*prev, U'e', U'E'))
14323 set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
14324 }
14325 else if (is_decimal_digit(*cp))
14326 {
14327 if (!seen_decimal)
14328 {
14329 if (!first_integer_part)
14330 first_integer_part = static_cast<char>(cp->bytes[0]);
14331 else if (first_integer_part == '0')
14332 set_error_and_return_default("leading zeroes are prohibited"sv);
14333 }
14334 }
14335 else
14336 set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14337
14338 chars[length++] = static_cast<char>(cp->bytes[0]);
14339 prev = cp;
14341 }
14342
14343 // sanity-check ending state
14344 if (prev)
14345 {
14346 if (*prev == U'_')
14347 {
14349 set_error_and_return_default("underscores must be followed by digits"sv);
14350 }
14351 else if (is_match(*prev, U'e', U'E', U'+', U'-', U'.'))
14352 {
14354 set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14355 }
14356 }
14357
14358 // convert to double
14359 double result;
14360#if TOML_FLOAT_CHARCONV
14361 {
14362 auto fc_result = std::from_chars(chars, chars + length, result);
14363 switch (fc_result.ec)
14364 {
14366 case std::errc{}: // ok
14367 return result * sign;
14368
14369 case std::errc::invalid_argument:
14371 std::string_view{ chars, length },
14372 "' could not be interpreted as a value"sv);
14373 break;
14374
14375 case std::errc::result_out_of_range:
14377 std::string_view{ chars, length },
14378 "' is not representable in 64 bits"sv);
14379 break;
14380
14381 default: //??
14382 set_error_and_return_default("an unspecified error occurred while trying to interpret '"sv,
14383 std::string_view{ chars, length },
14384 "' as a value"sv);
14385 }
14386 }
14387#else
14388 {
14389 std::stringstream ss;
14390 ss.imbue(std::locale::classic());
14391 ss.write(chars, static_cast<std::streamsize>(length));
14392 if ((ss >> result))
14393 return result * sign;
14394 else
14396 std::string_view{ chars, length },
14397 "' could not be interpreted as a value"sv);
14398 }
14399#endif
14400 }
14401
14405 {
14406 return_if_error({});
14408 TOML_ASSERT_ASSUME(is_match(*cp, U'0', U'+', U'-'));
14409 push_parse_scope("hexadecimal floating-point"sv);
14410
14411#if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
14412
14413 // sign
14414 const int sign = *cp == U'-' ? -1 : 1;
14415 if (is_match(*cp, U'+', U'-'))
14417
14418 // '0'
14419 if (*cp != U'0')
14420 set_error_and_return_default(" expected '0', saw '"sv, to_sv(*cp), "'"sv);
14422
14423 // 'x' or 'X'
14424 if (!is_match(*cp, U'x', U'X'))
14425 set_error_and_return_default("expected 'x' or 'X', saw '"sv, to_sv(*cp), "'"sv);
14427
14428 // <HEX DIGITS> ([.]<HEX DIGITS>)? [pP] [+-]? <DEC DIGITS>
14429
14430 // consume value fragments
14431 struct fragment
14432 {
14433 char chars[24];
14434 size_t length;
14435 double value;
14436 };
14437 fragment fragments[] = {
14438 {}, // mantissa, whole part
14439 {}, // mantissa, fractional part
14440 {} // exponent
14441 };
14442 fragment* current_fragment = fragments;
14443 const utf8_codepoint* prev = {};
14444 int exponent_sign = 1;
14445 while (!is_eof() && !is_value_terminator(*cp))
14446 {
14447 if (*cp == U'_')
14448 {
14449 if (!prev || !is_hexadecimal_digit(*prev))
14450 set_error_and_return_default("underscores may only follow digits"sv);
14451
14452 prev = cp;
14454 continue;
14455 }
14456 else if (prev && *prev == U'_' && !is_hexadecimal_digit(*cp))
14457 set_error_and_return_default("underscores must be followed by digits"sv);
14458 else if (*cp == U'.')
14459 {
14460 // 0x10.0p-.0 (exponent cannot have '.')
14461 if (current_fragment == fragments + 2)
14462 set_error_and_return_default("expected exponent digit or sign, saw '.'"sv);
14463
14464 // 0x10.0.p-0 (multiple '.')
14465 else if (current_fragment == fragments + 1)
14466 set_error_and_return_default("expected hexadecimal digit or exponent, saw '.'"sv);
14467
14468 else
14469 current_fragment++;
14470 }
14471 else if (is_match(*cp, U'p', U'P'))
14472 {
14473 // 0x10.0pp-0 (multiple 'p')
14474 if (current_fragment == fragments + 2)
14475 set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
14476
14477 // 0x.p-0 (mantissa is just '.')
14478 else if (fragments[0].length == 0u && fragments[1].length == 0u)
14479 set_error_and_return_default("expected hexadecimal digit, saw '"sv, to_sv(*cp), "'"sv);
14480
14481 else
14482 current_fragment = fragments + 2;
14483 }
14484 else if (is_match(*cp, U'+', U'-'))
14485 {
14486 // 0x-10.0p-0 (sign in mantissa)
14487 if (current_fragment != fragments + 2)
14488 set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14489
14490 // 0x10.0p0- (misplaced exponent sign)
14491 else if (!is_match(*prev, U'p', U'P'))
14492 set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
14493
14494 else
14495 exponent_sign = *cp == U'-' ? -1 : 1;
14496 }
14497 else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*cp))
14498 set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14499 else if (current_fragment == fragments + 2 && !is_decimal_digit(*cp))
14500 set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
14501 else if (current_fragment->length == sizeof(fragment::chars))
14502 set_error_and_return_default("fragment exceeeds maximum length of "sv,
14503 sizeof(fragment::chars),
14504 " characters"sv);
14505 else
14506 current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
14507
14508 prev = cp;
14510 }
14511
14512 // sanity-check ending state
14513 if (current_fragment != fragments + 2 || current_fragment->length == 0u)
14514 {
14516 set_error_and_return_default("missing exponent"sv);
14517 }
14518 else if (prev && *prev == U'_')
14519 {
14521 set_error_and_return_default("underscores must be followed by digits"sv);
14522 }
14523
14524 // calculate values for the three fragments
14525 for (int fragment_idx = 0; fragment_idx < 3; fragment_idx++)
14526 {
14527 auto& f = fragments[fragment_idx];
14528 const uint32_t base = fragment_idx == 2 ? 10u : 16u;
14529
14530 // left-trim zeroes
14531 const char* c = f.chars;
14532 size_t sig = {};
14533 while (f.length && *c == '0')
14534 {
14535 f.length--;
14536 c++;
14537 sig++;
14538 }
14539 if (!f.length)
14540 continue;
14541
14542 // calculate value
14543 auto place = 1u;
14544 for (size_t i = 0; i < f.length - 1u; i++)
14545 place *= base;
14546 uint32_t val{};
14547 while (place)
14548 {
14549 if (base == 16)
14550 val += place * hex_to_dec(*c);
14551 else
14552 val += place * static_cast<uint32_t>(*c - '0');
14553 if (fragment_idx == 1)
14554 sig++;
14555 c++;
14556 place /= base;
14557 }
14558 f.value = static_cast<double>(val);
14559
14560 // shift the fractional part
14561 if (fragment_idx == 1)
14562 {
14563 while (sig--)
14564 f.value /= base;
14565 }
14566 }
14567
14568 return (fragments[0].value + fragments[1].value) * pow(2.0, fragments[2].value * exponent_sign) * sign;
14569
14570#else // !TOML_LANG_UNRELEASED
14571
14572 set_error_and_return_default("hexadecimal floating-point values are not supported "
14573 "in TOML 1.0.0 and earlier"sv);
14574
14575#endif // !TOML_LANG_UNRELEASED
14576 }
14577
14578 template <uint64_t base>
14582 {
14583 return_if_error({});
14585 using traits = parse_integer_traits<base>;
14586 push_parse_scope(traits::scope_qualifier);
14587
14588 [[maybe_unused]] int64_t sign = 1;
14589 if constexpr (traits::is_signed)
14590 {
14591 sign = *cp == U'-' ? -1 : 1;
14592 if (is_match(*cp, U'+', U'-'))
14594 }
14595
14596 if constexpr (base == 10)
14597 {
14598 if (!traits::is_digit(*cp))
14599 set_error_and_return_default("expected expected digit or sign, saw '"sv, to_sv(*cp), "'"sv);
14600 }
14601 else
14602 {
14603 // '0'
14604 if (*cp != U'0')
14605 set_error_and_return_default("expected '0', saw '"sv, to_sv(*cp), "'"sv);
14607
14608 // 'b', 'o', 'x'
14609 if (*cp != traits::prefix_codepoint)
14610 set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
14612
14613 if (!traits::is_digit(*cp))
14614 set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
14615 }
14616
14617 // consume digits
14619 size_t length = {};
14620 const utf8_codepoint* prev = {};
14621 while (!is_eof() && !is_value_terminator(*cp))
14622 {
14623 if (*cp == U'_')
14624 {
14625 if (!prev || !traits::is_digit(*prev))
14626 set_error_and_return_default("underscores may only follow digits"sv);
14627
14628 prev = cp;
14630 continue;
14631 }
14632 else if TOML_UNLIKELY(prev && *prev == U'_' && !traits::is_digit(*cp))
14633 set_error_and_return_default("underscores must be followed by digits"sv);
14634 else if TOML_UNLIKELY(!traits::is_digit(*cp))
14635 set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
14636 else if TOML_UNLIKELY(length == sizeof(digits))
14637 set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
14638 else
14639 digits[length++] = static_cast<char>(cp->bytes[0]);
14640
14641 prev = cp;
14643 }
14644
14645 // sanity check ending state
14646 if (prev && *prev == U'_')
14647 {
14649 set_error_and_return_default("underscores must be followed by digits"sv);
14650 }
14651
14652 // single digits can be converted trivially
14653 if (length == 1u)
14654 {
14655 int64_t result;
14656
14657 if constexpr (base == 16)
14658 result = static_cast<int64_t>(hex_to_dec(digits[0]));
14659 else
14660 result = static_cast<int64_t>(digits[0] - '0');
14661
14662 if constexpr (traits::is_signed)
14663 result *= sign;
14664
14665 return result;
14666 }
14667
14668 // bin, oct and hex allow leading zeroes so trim them first
14669 const char* end = digits + length;
14670 const char* msd = digits;
14671 if constexpr (base != 10)
14672 {
14673 while (msd < end && *msd == '0')
14674 msd++;
14675 if (msd == end)
14676 return 0ll;
14677 }
14678
14679 // decimal integers do not allow leading zeroes
14680 else
14681 {
14682 if TOML_UNLIKELY(digits[0] == '0')
14683 set_error_and_return_default("leading zeroes are prohibited"sv);
14684 }
14685
14686 // range check
14687 if TOML_UNLIKELY(static_cast<size_t>(end - msd) > traits::max_digits)
14689 traits::full_prefix,
14690 std::string_view{ digits, length },
14691 "' is not representable in 64 bits"sv);
14692
14693 // do the thing
14694 {
14695 uint64_t result = {};
14696 {
14697 uint64_t power = 1;
14698 while (--end >= msd)
14699 {
14700 if constexpr (base == 16)
14701 result += power * hex_to_dec(*end);
14702 else
14703 result += power * static_cast<uint64_t>(*end - '0');
14704
14705 power *= base;
14706 }
14707 }
14708
14709 // range check
14710 static constexpr auto i64_max = static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
14711 if TOML_UNLIKELY(result > i64_max + (sign < 0 ? 1u : 0u))
14713 traits::full_prefix,
14714 std::string_view{ digits, length },
14715 "' is not representable in 64 bits"sv);
14716
14717 if constexpr (traits::is_signed)
14718 {
14719 // avoid signed multiply UB when parsing INT64_MIN
14720 if TOML_UNLIKELY(sign < 0 && result == i64_max + 1u)
14721 return (std::numeric_limits<int64_t>::min)();
14722
14723 return static_cast<int64_t>(result) * sign;
14724 }
14725 else
14726 return static_cast<int64_t>(result);
14727 }
14728 }
14729
14732 date parse_date(bool part_of_datetime = false)
14733 {
14734 return_if_error({});
14736 TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
14737 push_parse_scope("date"sv);
14738
14739 // "YYYY"
14740 uint32_t digits[4];
14741 if (!consume_digit_sequence(digits, 4u))
14742 set_error_and_return_default("expected 4-digit year, saw '"sv, to_sv(cp), "'"sv);
14743 const auto year = digits[3] + digits[2] * 10u + digits[1] * 100u + digits[0] * 1000u;
14744 const auto is_leap_year = (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
14746
14747 // '-'
14748 if (*cp != U'-')
14749 set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
14751
14752 // "MM"
14753 if (!consume_digit_sequence(digits, 2u))
14754 set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
14755 const auto month = digits[1] + digits[0] * 10u;
14756 if (month == 0u || month > 12u)
14757 set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv, month);
14758 const auto max_days_in_month = month == 2u
14759 ? (is_leap_year ? 29u : 28u)
14760 : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
14762
14763 // '-'
14764 if (*cp != U'-')
14765 set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
14767
14768 // "DD"
14769 if (!consume_digit_sequence(digits, 2u))
14770 set_error_and_return_default("expected 2-digit day, saw '"sv, to_sv(cp), "'"sv);
14771 const auto day = digits[1] + digits[0] * 10u;
14772 if (day == 0u || day > max_days_in_month)
14773 set_error_and_return_default("expected day between 1 and "sv,
14774 max_days_in_month,
14775 " (inclusive), saw "sv,
14776 day);
14777
14778 if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
14779 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14780
14781 return { year, month, day };
14782 }
14783
14786 time parse_time(bool part_of_datetime = false)
14787 {
14788 return_if_error({});
14790 TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
14791 push_parse_scope("time"sv);
14792
14793 static constexpr size_t max_digits = 64; // far more than necessary but needed to allow fractional
14794 // millisecond truncation per the spec
14795 uint32_t digits[max_digits];
14796
14797 // "HH"
14798 if (!consume_digit_sequence(digits, 2u))
14799 set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
14800 const auto hour = digits[1] + digits[0] * 10u;
14801 if (hour > 23u)
14802 set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv, hour);
14804
14805 // ':'
14806 if (*cp != U':')
14807 set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
14809
14810 // "MM"
14811 if (!consume_digit_sequence(digits, 2u))
14812 set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
14813 const auto minute = digits[1] + digits[0] * 10u;
14814 if (minute > 59u)
14815 set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
14816 auto time = toml::time{ hour, minute };
14817
14818 // ':'
14819 if constexpr (TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
14820 {
14821 if (is_eof() || is_value_terminator(*cp) || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
14822 return time;
14823 }
14824 else
14826 if (*cp != U':')
14827 set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
14829
14830 // "SS"
14831 if (!consume_digit_sequence(digits, 2u))
14832 set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
14833 const auto second = digits[1] + digits[0] * 10u;
14834 if (second > 59u)
14835 set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv, second);
14836 time.second = static_cast<decltype(time.second)>(second);
14837
14838 // '.' (early-exiting is allowed; fractional is optional)
14839 if (is_eof() || is_value_terminator(*cp) || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
14840 return time;
14841 if (*cp != U'.')
14842 set_error_and_return_default("expected '.', saw '"sv, to_sv(*cp), "'"sv);
14844
14845 // "FFFFFFFFF"
14846 size_t digit_count = consume_variable_length_digit_sequence(digits, max_digits);
14847 if (!digit_count)
14848 {
14850 set_error_and_return_default("expected fractional digits, saw '"sv, to_sv(*cp), "'"sv);
14851 }
14852 else if (!is_eof())
14853 {
14854 if (digit_count == max_digits && is_decimal_digit(*cp))
14855 set_error_and_return_default("fractional component exceeds maximum precision of "sv, max_digits);
14856 else if (!part_of_datetime && !is_value_terminator(*cp))
14857 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14858 }
14859 uint32_t value = 0u;
14860 uint32_t place = 1u;
14861 for (auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;)
14862 {
14863 value += digits[i] * place;
14864 place *= 10u;
14865 }
14866 for (auto i = digit_count; i < 9u; i++) // implicit zeros
14867 value *= 10u;
14869 return time;
14870 }
14871
14875 {
14876 return_if_error({});
14878 TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
14879 push_parse_scope("date-time"sv);
14880
14881 // "YYYY-MM-DD"
14882 auto date = parse_date(true);
14884
14885 // ' ', 'T' or 't'
14886 if (!is_match(*cp, U' ', U'T', U't'))
14887 set_error_and_return_default("expected space, 'T' or 't', saw '"sv, to_sv(*cp), "'"sv);
14889
14890 // "HH:MM:SS.FFFFFFFFF"
14891 auto time = parse_time(true);
14892 return_if_error({});
14893
14894 // no offset
14895 if (is_eof() || is_value_terminator(*cp))
14896 return { date, time };
14897
14898 // zero offset ('Z' or 'z')
14899 time_offset offset{};
14900 if (is_match(*cp, U'Z', U'z'))
14902
14903 // explicit offset ("+/-HH:MM")
14904 else if (is_match(*cp, U'+', U'-'))
14905 {
14906 push_parse_scope("date-time offset"sv);
14907
14908 // sign
14909 int sign = *cp == U'-' ? -1 : 1;
14911
14912 // "HH"
14913 int digits[2];
14914 if (!consume_digit_sequence(digits, 2u))
14915 set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
14916 const auto hour = digits[1] + digits[0] * 10;
14917 if (hour > 23)
14918 set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv, hour);
14920
14921 // ':'
14922 if (*cp != U':')
14923 set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
14925
14926 // "MM"
14927 if (!consume_digit_sequence(digits, 2u))
14928 set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
14929 const auto minute = digits[1] + digits[0] * 10;
14930 if (minute > 59)
14931 set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
14932 offset.minutes = static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
14933 }
14934
14935 if (!is_eof() && !is_value_terminator(*cp))
14936 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14937
14938 return { date, time, offset };
14939 }
14940
14942 node_ptr parse_array();
14943
14945 node_ptr parse_inline_table();
14946
14949 {
14950 return_if_error({});
14952 TOML_ASSERT_ASSUME(!is_control_character(*cp));
14953 TOML_ASSERT_ASSUME(*cp != U'_');
14954
14955 switch (cp->value)
14956 {
14957 // arrays
14958 case U'[': return parse_array();
14959
14960 // inline tables
14961 case U'{': return parse_inline_table();
14962
14963 // floats beginning with '.'
14964 case U'.': return node_ptr{ new value{ parse_float() } };
14965
14966 // strings
14967 case U'"': [[fallthrough]];
14968 case U'\'': return node_ptr{ new value{ parse_string().value } };
14969
14970 default:
14971 {
14972 const auto cp_upper = static_cast<uint_least32_t>(cp->value) & ~0x20u;
14973
14974 // bools
14975 if (cp_upper == 70u || cp_upper == 84u) // F or T
14976 return node_ptr{ new value{ parse_boolean() } };
14977
14978 // inf/nan
14979 else if (cp_upper == 73u || cp_upper == 78u) // I or N
14980 return node_ptr{ new value{ parse_inf_or_nan() } };
14981
14982 else
14983 return nullptr;
14984 }
14985 }
14987 }
14988
14990 node_ptr parse_value()
14991 {
14992 return_if_error({});
14994 TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
14995 push_parse_scope("value"sv);
14996
14997 const depth_counter_scope depth_counter{ nested_values };
14999 set_error_and_return_default("exceeded maximum nested value depth of "sv,
15001 " (TOML_MAX_NESTED_VALUES)"sv);
15002
15003 // check if it begins with some control character
15004 // (note that this will also fail for whitespace but we're assuming we've
15005 // called consume_leading_whitespace() before calling parse_value())
15006 if TOML_UNLIKELY(is_control_character(*cp))
15007 set_error_and_return_default("unexpected control character"sv);
15008
15009 // underscores at the beginning
15010 else if (*cp == U'_')
15011 set_error_and_return_default("values may not begin with underscores"sv);
15012
15013 const auto begin_pos = cp->position;
15014 node_ptr val;
15015
15016 do
15017 {
15018 TOML_ASSERT_ASSUME(!is_control_character(*cp));
15019 TOML_ASSERT_ASSUME(*cp != U'_');
15020
15021 // detect the value type and parse accordingly,
15022 // starting with value types that can be detected
15023 // unambiguously from just one character.
15024
15026 return_if_error({});
15027 if (val)
15028 break;
15029
15030 // value types from here down require more than one character to unambiguously identify
15031 // so scan ahead and collect a set of value 'traits'.
15033 {
15034 has_nothing = 0,
15035 has_digits = 1,
15036 has_b = 1 << 1, // as second char only (0b)
15037 has_e = 1 << 2, // only float exponents
15038 has_o = 1 << 3, // as second char only (0o)
15039 has_p = 1 << 4, // only hexfloat exponents
15040 has_t = 1 << 5,
15041 has_x = 1 << 6, // as second or third char only (0x, -0x, +0x)
15042 has_z = 1 << 7,
15043 has_colon = 1 << 8,
15044 has_plus = 1 << 9,
15045 has_minus = 1 << 10,
15046 has_dot = 1 << 11,
15047 begins_sign = 1 << 12,
15048 begins_digit = 1 << 13,
15049 begins_zero = 1 << 14,
15050 signs_msk = has_plus | has_minus,
15051 bdigit_msk = has_digits | begins_digit,
15052 bzero_msk = bdigit_msk | begins_zero,
15053 };
15054 value_traits traits = has_nothing;
15055 const auto has_any = [&](auto t) noexcept { return (traits & t) != has_nothing; };
15056 const auto has_none = [&](auto t) noexcept { return (traits & t) == has_nothing; };
15057 const auto add_trait = [&](auto t) noexcept { traits = static_cast<value_traits>(traits | t); };
15058
15059 // examine the first character to get the 'begins with' traits
15060 // (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
15061 if (is_decimal_digit(*cp))
15062 {
15063 add_trait(begins_digit);
15064 if (*cp == U'0')
15065 add_trait(begins_zero);
15066 }
15067 else if (is_match(*cp, U'+', U'-'))
15068 add_trait(begins_sign);
15069 else
15070 break;
15071
15072 // scan the rest of the value to determine the remaining traits
15074 size_t char_count = {}, advance_count = {};
15075 bool eof_while_scanning = false;
15076 const auto scan = [&]() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
15077 {
15078 if (is_eof())
15079 return;
15080 TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
15081
15082 do
15083 {
15084 if (const auto c = **cp; c != U'_')
15085 {
15086 chars[char_count++] = c;
15087
15088 if (is_decimal_digit(c))
15089 add_trait(has_digits);
15090 else if (is_ascii_letter(c))
15091 {
15092 TOML_ASSERT_ASSUME((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
15093 switch (static_cast<char32_t>(c | 32u))
15094 {
15095 case U'b':
15096 if (char_count == 2u && has_any(begins_zero))
15097 add_trait(has_b);
15098 break;
15099
15100 case U'e':
15101 if (char_count > 1u
15102 && has_none(has_b | has_o | has_p | has_t | has_x | has_z | has_colon)
15103 && (has_none(has_plus | has_minus) || has_any(begins_sign)))
15104 add_trait(has_e);
15105 break;
15106
15107 case U'o':
15108 if (char_count == 2u && has_any(begins_zero))
15109 add_trait(has_o);
15110 break;
15111
15112 case U'p':
15113 if (has_any(has_x))
15114 add_trait(has_p);
15115 break;
15116
15117 case U'x':
15118 if ((char_count == 2u && has_any(begins_zero))
15119 || (char_count == 3u && has_any(begins_sign) && chars[1] == U'0'))
15120 add_trait(has_x);
15121 break;
15122
15123 case U't': add_trait(has_t); break;
15124 case U'z': add_trait(has_z); break;
15125 }
15126 }
15127 else if (c <= U':')
15128 {
15129 TOML_ASSERT_ASSUME(c < U'0' || c > U'9');
15130 switch (c)
15131 {
15132 case U'+': add_trait(has_plus); break;
15133 case U'-': add_trait(has_minus); break;
15134 case U'.': add_trait(has_dot); break;
15135 case U':': add_trait(has_colon); break;
15136 }
15137 }
15138 }
15139
15141 advance_count++;
15142 eof_while_scanning = is_eof();
15143 }
15144 while (advance_count < (utf8_buffered_reader::max_history_length - 1u) && !is_eof()
15145 && !is_value_terminator(*cp));
15146 };
15147 scan();
15148 return_if_error({});
15149
15150 // force further scanning if this could have been a date-time with a space instead of a T
15151 if (char_count == 10u //
15152 && (traits | begins_zero) == (bzero_msk | has_minus) //
15153 && chars[4] == U'-' //
15154 && chars[7] == U'-' //
15155 && !is_eof() //
15156 && *cp == U' ')
15157 {
15158 const auto pre_advance_count = advance_count;
15159 const auto pre_scan_traits = traits;
15160 chars[char_count++] = *cp;
15161 add_trait(has_t);
15162
15163 const auto backpedal = [&]() noexcept
15164 {
15165 go_back(advance_count - pre_advance_count);
15166 advance_count = pre_advance_count;
15167 traits = pre_scan_traits;
15168 char_count = 10u;
15169 };
15170
15172 advance_count++;
15173
15174 if (is_eof() || !is_decimal_digit(*cp))
15175 backpedal();
15176 else
15177 {
15178 chars[char_count++] = *cp;
15179
15181 advance_count++;
15182
15183 scan();
15184 return_if_error({});
15185
15186 if (char_count == 12u)
15187 backpedal();
15188 }
15189 }
15190
15191 // set the reader back to where we started
15192 go_back(advance_count);
15193
15194 // if after scanning ahead we still only have one value character,
15195 // the only valid value type is an integer.
15196 if (char_count == 1u)
15197 {
15198 if (has_any(begins_digit))
15199 {
15200 val.reset(new value{ static_cast<int64_t>(chars[0] - U'0') });
15201 advance(); // skip the digit
15202 break;
15203 }
15204
15205 // anything else would be ambiguous.
15206 else
15207 set_error_and_return_default(eof_while_scanning ? "encountered end-of-file"sv
15208 : "could not determine value type"sv);
15209 }
15210
15211 // now things that can be identified from two or more characters
15212 return_if_error({});
15213 TOML_ASSERT_ASSUME(char_count >= 2u);
15214
15215 // do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
15216 // typed parse functions to take over and show better diagnostics if there's an issue
15217 // (as opposed to the fallback "could not determine type" message)
15218 if (has_any(has_p))
15219 val.reset(new value{ parse_hex_float() });
15220 else if (has_any(has_x | has_o | has_b))
15221 {
15222 int64_t i;
15223 value_flags flags;
15224 if (has_any(has_x))
15225 {
15226 i = parse_integer<16>();
15227 flags = value_flags::format_as_hexadecimal;
15228 }
15229 else if (has_any(has_o))
15230 {
15231 i = parse_integer<8>();
15232 flags = value_flags::format_as_octal;
15233 }
15234 else // has_b
15235 {
15236 i = parse_integer<2>();
15237 flags = value_flags::format_as_binary;
15238 }
15239 return_if_error({});
15240
15241 val.reset(new value{ i });
15242 val->ref_cast<int64_t>().flags(flags);
15243 }
15244 else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
15245 val.reset(new value{ parse_float() });
15246 else if (has_any(begins_sign))
15247 {
15248 // single-digit signed integers
15249 if (char_count == 2u && has_any(has_digits))
15250 {
15251 val.reset(new value{ static_cast<int64_t>(chars[1] - U'0') * (chars[0] == U'-' ? -1LL : 1LL) });
15252 advance(); // skip the sign
15253 advance(); // skip the digit
15254 break;
15255 }
15256
15257 // simple signed floats (e.g. +1.0)
15258 if (is_decimal_digit(chars[1]) && chars[2] == U'.')
15259 val.reset(new value{ parse_float() });
15260
15261 // signed infinity or nan
15262 else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
15263 val.reset(new value{ parse_inf_or_nan() });
15264 }
15265
15266 return_if_error({});
15267 if (val)
15268 break;
15269
15270 // match trait masks against what they can match exclusively.
15271 // all correct value parses will come out of this list, so doing this as a switch is likely to
15272 // be a better friend to the optimizer on the success path (failure path can be slow but that
15273 // doesn't matter much).
15274 switch (unwrap_enum(traits))
15275 {
15276 // binary integers
15277 // 0b10
15278 case bzero_msk | has_b:
15279 val.reset(new value{ parse_integer<2>() });
15280 val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
15281 break;
15282
15283 // octal integers
15284 // 0o10
15285 case bzero_msk | has_o:
15286 val.reset(new value{ parse_integer<8>() });
15287 val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
15288 break;
15289
15290 // decimal integers
15291 // 00
15292 // 10
15293 // +10
15294 // -10
15295 case bzero_msk: [[fallthrough]];
15296 case bdigit_msk: [[fallthrough]];
15297 case begins_sign | has_digits | has_minus: [[fallthrough]];
15298 case begins_sign | has_digits | has_plus:
15299 {
15300 // if the value was so long we exhausted the history buffer it's reasonable to assume
15301 // there was more and the value's actual type is impossible to identify without making the
15302 // buffer bigger (since it could have actually been a float), so emit an error.
15303 //
15304 // (this will likely only come up during fuzzing and similar scenarios)
15305 static constexpr size_t max_numeric_value_length =
15307 if TOML_UNLIKELY(!eof_while_scanning && advance_count > max_numeric_value_length)
15308 set_error_and_return_default("numeric value too long to identify type - cannot exceed "sv,
15309 max_numeric_value_length,
15310 " characters"sv);
15311
15312 val.reset(new value{ parse_integer<10>() });
15313 break;
15314 }
15315
15316 // hexadecimal integers
15317 // 0x10
15318 case bzero_msk | has_x:
15319 val.reset(new value{ parse_integer<16>() });
15320 val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
15321 break;
15322
15323 // decimal floats
15324 // 0e1
15325 // 0e-1
15326 // 0e+1
15327 // 0.0
15328 // 0.0e1
15329 // 0.0e-1
15330 // 0.0e+1
15331 case bzero_msk | has_e: [[fallthrough]];
15332 case bzero_msk | has_e | has_minus: [[fallthrough]];
15333 case bzero_msk | has_e | has_plus: [[fallthrough]];
15334 case bzero_msk | has_dot: [[fallthrough]];
15335 case bzero_msk | has_dot | has_e: [[fallthrough]];
15336 case bzero_msk | has_dot | has_e | has_minus: [[fallthrough]];
15337 case bzero_msk | has_dot | has_e | has_plus: [[fallthrough]];
15338 // 1e1
15339 // 1e-1
15340 // 1e+1
15341 // 1.0
15342 // 1.0e1
15343 // 1.0e-1
15344 // 1.0e+1
15345 case bdigit_msk | has_e: [[fallthrough]];
15346 case bdigit_msk | has_e | has_minus: [[fallthrough]];
15347 case bdigit_msk | has_e | has_plus: [[fallthrough]];
15348 case bdigit_msk | has_dot: [[fallthrough]];
15349 case bdigit_msk | has_dot | has_e: [[fallthrough]];
15350 case bdigit_msk | has_dot | has_e | has_minus: [[fallthrough]];
15351 case bdigit_msk | has_dot | has_e | has_plus: [[fallthrough]];
15352 // +1e1
15353 // +1.0
15354 // +1.0e1
15355 // +1.0e+1
15356 // +1.0e-1
15357 // -1.0e+1
15358 case begins_sign | has_digits | has_e | has_plus: [[fallthrough]];
15359 case begins_sign | has_digits | has_dot | has_plus: [[fallthrough]];
15360 case begins_sign | has_digits | has_dot | has_e | has_plus: [[fallthrough]];
15361 case begins_sign | has_digits | has_dot | has_e | signs_msk: [[fallthrough]];
15362 // -1e1
15363 // -1e+1
15364 // +1e-1
15365 // -1.0
15366 // -1.0e1
15367 // -1.0e-1
15368 case begins_sign | has_digits | has_e | has_minus: [[fallthrough]];
15369 case begins_sign | has_digits | has_e | signs_msk: [[fallthrough]];
15370 case begins_sign | has_digits | has_dot | has_minus: [[fallthrough]];
15371 case begins_sign | has_digits | has_dot | has_e | has_minus:
15372 val.reset(new value{ parse_float() });
15373 break;
15374
15375 // hexadecimal floats
15376 // 0x10p0
15377 // 0x10p-0
15378 // 0x10p+0
15379 case bzero_msk | has_x | has_p: [[fallthrough]];
15380 case bzero_msk | has_x | has_p | has_minus: [[fallthrough]];
15381 case bzero_msk | has_x | has_p | has_plus: [[fallthrough]];
15382 // -0x10p0
15383 // -0x10p-0
15384 // +0x10p0
15385 // +0x10p+0
15386 // -0x10p+0
15387 // +0x10p-0
15388 case begins_sign | has_digits | has_x | has_p | has_minus: [[fallthrough]];
15389 case begins_sign | has_digits | has_x | has_p | has_plus: [[fallthrough]];
15390 case begins_sign | has_digits | has_x | has_p | signs_msk: [[fallthrough]];
15391 // 0x10.1p0
15392 // 0x10.1p-0
15393 // 0x10.1p+0
15394 case bzero_msk | has_x | has_dot | has_p: [[fallthrough]];
15395 case bzero_msk | has_x | has_dot | has_p | has_minus: [[fallthrough]];
15396 case bzero_msk | has_x | has_dot | has_p | has_plus: [[fallthrough]];
15397 // -0x10.1p0
15398 // -0x10.1p-0
15399 // +0x10.1p0
15400 // +0x10.1p+0
15401 // -0x10.1p+0
15402 // +0x10.1p-0
15403 case begins_sign | has_digits | has_x | has_dot | has_p | has_minus: [[fallthrough]];
15404 case begins_sign | has_digits | has_x | has_dot | has_p | has_plus: [[fallthrough]];
15405 case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
15406 val.reset(new value{ parse_hex_float() });
15407 break;
15408
15409 // times
15410 // HH:MM
15411 // HH:MM:SS
15412 // HH:MM:SS.FFFFFF
15413 case bzero_msk | has_colon: [[fallthrough]];
15414 case bzero_msk | has_colon | has_dot: [[fallthrough]];
15415 case bdigit_msk | has_colon: [[fallthrough]];
15416 case bdigit_msk | has_colon | has_dot: val.reset(new value{ parse_time() }); break;
15417
15418 // local dates
15419 // YYYY-MM-DD
15420 case bzero_msk | has_minus: [[fallthrough]];
15421 case bdigit_msk | has_minus: val.reset(new value{ parse_date() }); break;
15422
15423 // date-times
15424 // YYYY-MM-DDTHH:MM
15425 // YYYY-MM-DDTHH:MM-HH:MM
15426 // YYYY-MM-DDTHH:MM+HH:MM
15427 // YYYY-MM-DD HH:MM
15428 // YYYY-MM-DD HH:MM-HH:MM
15429 // YYYY-MM-DD HH:MM+HH:MM
15430 // YYYY-MM-DDTHH:MM:SS
15431 // YYYY-MM-DDTHH:MM:SS-HH:MM
15432 // YYYY-MM-DDTHH:MM:SS+HH:MM
15433 // YYYY-MM-DD HH:MM:SS
15434 // YYYY-MM-DD HH:MM:SS-HH:MM
15435 // YYYY-MM-DD HH:MM:SS+HH:MM
15436 case bzero_msk | has_minus | has_colon | has_t: [[fallthrough]];
15437 case bzero_msk | signs_msk | has_colon | has_t: [[fallthrough]];
15438 case bdigit_msk | has_minus | has_colon | has_t: [[fallthrough]];
15439 case bdigit_msk | signs_msk | has_colon | has_t: [[fallthrough]];
15440 // YYYY-MM-DDTHH:MM:SS.FFFFFF
15441 // YYYY-MM-DDTHH:MM:SS.FFFFFF-HH:MM
15442 // YYYY-MM-DDTHH:MM:SS.FFFFFF+HH:MM
15443 // YYYY-MM-DD HH:MM:SS.FFFFFF
15444 // YYYY-MM-DD HH:MM:SS.FFFFFF-HH:MM
15445 // YYYY-MM-DD HH:MM:SS.FFFFFF+HH:MM
15446 case bzero_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
15447 case bzero_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
15448 case bdigit_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
15449 case bdigit_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
15450 // YYYY-MM-DDTHH:MMZ
15451 // YYYY-MM-DD HH:MMZ
15452 // YYYY-MM-DDTHH:MM:SSZ
15453 // YYYY-MM-DD HH:MM:SSZ
15454 // YYYY-MM-DDTHH:MM:SS.FFFFFFZ
15455 // YYYY-MM-DD HH:MM:SS.FFFFFFZ
15456 case bzero_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
15457 case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t: [[fallthrough]];
15458 case bdigit_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
15459 case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
15460 val.reset(new value{ parse_date_time() });
15461 break;
15462 }
15463 }
15464 while (false);
15465
15466 if (!val)
15467 {
15468 set_error_at(begin_pos, "could not determine value type"sv);
15470 }
15471
15472 val->source_ = { begin_pos, current_position(1), reader.source_path() };
15473 return val;
15474 }
15475
15478 {
15479 return_if_error({});
15481 TOML_ASSERT_ASSUME(is_bare_key_character(*cp) || is_string_delimiter(*cp));
15482 push_parse_scope("key"sv);
15483
15484 key_buffer.clear();
15485 recording_whitespace = false;
15486
15487 while (!is_error())
15488 {
15489 std::string_view key_segment;
15490 const auto key_begin = current_position();
15491
15492 // bare_key_segment
15493 if (is_bare_key_character(*cp))
15494 key_segment = parse_bare_key_segment();
15495
15496 // "quoted key segment"
15497 else if (is_string_delimiter(*cp))
15498 {
15499 const auto begin_pos = cp->position;
15500
15501 recording_whitespace = true;
15503 recording_whitespace = false;
15504 return_if_error({});
15505
15506 if (str.was_multi_line)
15507 {
15508 set_error_at(begin_pos,
15509 "multi-line strings are prohibited in "sv,
15510 key_buffer.empty() ? ""sv : "dotted "sv,
15511 "keys"sv);
15513 }
15514 else
15515 key_segment = str.value;
15516 }
15517
15518 // ???
15519 else
15520 set_error_and_return_default("expected bare key starting character or string delimiter, saw '"sv,
15521 to_sv(*cp),
15522 "'"sv);
15523
15524 const auto key_end = current_position();
15525
15526 // whitespace following the key segment
15528
15529 // store segment
15530 key_buffer.push_back(key_segment, key_begin, key_end);
15531
15532 // eof or no more key to come
15533 if (is_eof() || *cp != U'.')
15534 break;
15535
15536 // was a dotted key - go around again
15540 }
15541 return_if_error({});
15542
15543 return true;
15544 }
15545
15547 key make_key(size_t segment_index) const
15548 {
15549 TOML_ASSERT(key_buffer.size() > segment_index);
15550
15551 return key{
15552 key_buffer[segment_index],
15553 source_region{ key_buffer.starts[segment_index], key_buffer.ends[segment_index], root.source().path }
15554 };
15555 }
15556
15560 {
15561 return_if_error({});
15563 TOML_ASSERT_ASSUME(*cp == U'[');
15564 push_parse_scope("table header"sv);
15565
15566 const source_position header_begin_pos = cp->position;
15567 source_position header_end_pos;
15568 bool is_arr = false;
15569
15570 // parse header
15571 {
15572 // skip first '['
15574
15575 // skip past any whitespace that followed the '['
15576 const bool had_leading_whitespace = consume_leading_whitespace();
15578
15579 // skip second '[' (if present)
15580 if (*cp == U'[')
15581 {
15582 if (had_leading_whitespace)
15584 "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv);
15585
15586 is_arr = true;
15588
15589 // skip past any whitespace that followed the '['
15592 }
15593
15594 // check for a premature closing ']'
15595 if (*cp == U']')
15596 set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
15597
15598 // get the actual key
15600 parse_key();
15601 stop_recording(1u);
15602 return_if_error({});
15603
15604 // skip past any whitespace that followed the key
15606 return_if_error({});
15608
15609 // consume the closing ']'
15610 if (*cp != U']')
15611 set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
15612 if (is_arr)
15613 {
15615 if (*cp != U']')
15616 set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
15617 }
15619 header_end_pos = current_position(1);
15620
15621 // handle the rest of the line after the header
15623 if (!is_eof() && !consume_comment() && !consume_line_break())
15624 set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
15625 }
15626 TOML_ASSERT(!key_buffer.empty());
15627
15628 // check if each parent is a table/table array, or can be created implicitly as a table.
15629 table* parent = &root;
15630 for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++)
15631 {
15632 const std::string_view segment = key_buffer[i];
15633 auto pit = parent->lower_bound(segment);
15634
15635 // parent already existed
15636 if (pit != parent->end() && pit->first == segment)
15637 {
15638 node& p = pit->second;
15639
15640 if (auto tbl = p.as_table())
15641 {
15642 // adding to closed inline tables is illegal
15643 if (tbl->is_inline() && !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
15644 set_error_and_return_default("cannot insert '"sv,
15646 "' into existing inline table"sv);
15647
15648 parent = tbl;
15649 }
15650 else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
15651 {
15652 // table arrays are a special case;
15653 // the spec dictates we select the most recently declared element in the array.
15654 TOML_ASSERT(!arr->empty());
15655 TOML_ASSERT(arr->back().is_table());
15656 parent = &arr->back().ref_cast<table>();
15657 }
15658 else
15659 {
15660 if (!is_arr && p.type() == node_type::table)
15661 set_error_and_return_default("cannot redefine existing table '"sv,
15663 "'"sv);
15664 else
15665 set_error_and_return_default("cannot redefine existing "sv,
15666 to_sv(p.type()),
15667 " '"sv,
15669 "' as "sv,
15670 is_arr ? "array-of-tables"sv : "table"sv);
15671 }
15672 }
15673
15674 // need to create a new implicit table
15675 else
15676 {
15677 pit = parent->emplace_hint<table>(pit, make_key(i));
15678 table& p = pit->second.ref_cast<table>();
15679 p.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15680
15681 implicit_tables.push_back(&p);
15682 parent = &p;
15683 }
15684 }
15685
15686 const auto last_segment = key_buffer.back();
15687 auto it = parent->lower_bound(last_segment);
15688
15689 // if there was already a matching node some sanity checking is necessary;
15690 // this is ok if we're making an array and the existing element is already an array (new element)
15691 // or if we're making a table and the existing element is an implicitly-created table (promote it),
15692 // otherwise this is a redefinition error.
15693 if (it != parent->end() && it->first == last_segment)
15694 {
15695 node& matching_node = it->second;
15696 if (auto arr = matching_node.as_array();
15697 is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
15698 {
15699 table& tbl = arr->emplace_back<table>();
15700 tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15701 return &tbl;
15702 }
15703
15704 else if (auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty())
15705 {
15706 if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl); found)
15707 {
15708 bool ok = true;
15709 if (!tbl->empty())
15710 {
15711 for (auto& [_, child] : *tbl)
15712 {
15713 if (!child.is_table() && !child.is_array_of_tables())
15714 {
15715 ok = false;
15716 break;
15717 }
15718 }
15719 }
15720
15721 if (ok)
15722 {
15723 implicit_tables.erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
15724 tbl->source_.begin = header_begin_pos;
15725 tbl->source_.end = header_end_pos;
15726 return tbl;
15727 }
15728 }
15729 }
15730
15731 // if we get here it's a redefinition error.
15732 if (!is_arr && matching_node.type() == node_type::table)
15733 {
15734 set_error_at(header_begin_pos,
15735 "cannot redefine existing table '"sv,
15737 "'"sv);
15739 }
15740 else
15741 {
15742 set_error_at(header_begin_pos,
15743 "cannot redefine existing "sv,
15744 to_sv(matching_node.type()),
15745 " '"sv,
15747 "' as "sv,
15748 is_arr ? "array-of-tables"sv : "table"sv);
15750 }
15751 }
15752
15753 // there was no matching node, sweet - we can freely instantiate a new table/table array.
15754 else
15755 {
15756 auto last_key = make_key(key_buffer.size() - 1u);
15757
15758 // if it's an array we need to make the array and it's first table element,
15759 // set the starting regions, and return the table element
15760 if (is_arr)
15761 {
15762 it = parent->emplace_hint<array>(it, std::move(last_key));
15763 array& tbl_arr = it->second.ref_cast<array>();
15764 table_arrays.push_back(&tbl_arr);
15765 tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15766
15767 table& tbl = tbl_arr.emplace_back<table>();
15768 tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15769 return &tbl;
15770 }
15771
15772 // otherwise we're just making a table
15773 else
15774 {
15775 it = parent->emplace_hint<table>(it, std::move(last_key));
15776 table& tbl = it->second.ref_cast<table>();
15777 tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15778 return &tbl;
15779 }
15780 }
15781 }
15782
15785 {
15786 return_if_error({});
15788 TOML_ASSERT_ASSUME(is_string_delimiter(*cp) || is_bare_key_character(*cp));
15789 push_parse_scope("key-value pair"sv);
15790
15791 // read the key into the key buffer
15793 parse_key();
15794 stop_recording(1u);
15795 return_if_error({});
15796 TOML_ASSERT(key_buffer.size() >= 1u);
15797
15798 // skip past any whitespace that followed the key
15801
15802 // '='
15803 if (*cp != U'=')
15804 set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv);
15806
15807 // skip past any whitespace that followed the '='
15809 return_if_error({});
15811
15812 // check that the next character could actually be a value
15813 if (is_value_terminator(*cp))
15814 set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
15815
15816 // if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
15817 // and set the target table to the second-to-last one in the chain
15818 if (key_buffer.size() > 1u)
15819 {
15820 for (size_t i = 0; i < key_buffer.size() - 1u; i++)
15821 {
15822 const std::string_view segment = key_buffer[i];
15823 auto pit = tbl->lower_bound(segment);
15824
15825 // parent already existed
15826 if (pit != tbl->end() && pit->first == segment)
15827 {
15828 table* p = pit->second.as_table();
15829
15830 // redefinition
15831 if TOML_UNLIKELY(!p
15832 || !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
15833 || impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
15834 {
15835 set_error_at(key_buffer.starts[i],
15836 "cannot redefine existing "sv,
15837 to_sv(pit->second.type()),
15838 " as dotted key-value pair"sv);
15840 }
15841
15842 tbl = p;
15843 }
15844
15845 // need to create a new implicit table
15846 else
15847 {
15848 pit = tbl->emplace_hint<table>(pit, make_key(i));
15849 table& p = pit->second.ref_cast<table>();
15850 p.source_ = pit->first.source();
15851
15852 dotted_key_tables.push_back(&p);
15853 tbl = &p;
15854 }
15855 }
15856 }
15857
15858 // ensure this isn't a redefinition
15859 const std::string_view last_segment = key_buffer.back();
15860 auto it = tbl->lower_bound(last_segment);
15861 if (it != tbl->end() && it->first == last_segment)
15862 {
15863 set_error("cannot redefine existing "sv,
15864 to_sv(it->second.type()),
15865 " '"sv,
15867 "'"sv);
15869 }
15870
15871 // create the key first since the key buffer will likely get overwritten during value parsing (inline
15872 // tables)
15873 auto last_key = make_key(key_buffer.size() - 1u);
15874
15875 // now we can actually parse the value
15876 node_ptr val = parse_value();
15877 return_if_error({});
15878
15879 tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
15880 return true;
15881 }
15882
15884 {
15887 push_parse_scope("root table"sv);
15888
15889 table* current_table = &root;
15890
15891 do
15892 {
15894
15895 // leading whitespace, line endings, comments
15897 continue;
15899
15900 // [tables]
15901 // [[table array]]
15902 if (*cp == U'[')
15903 current_table = parse_table_header();
15904
15905 // bare_keys
15906 // dotted.keys
15907 // "quoted keys"
15908 else if (is_bare_key_character(*cp) || is_string_delimiter(*cp))
15909 {
15910 push_parse_scope("key-value pair"sv);
15911
15912 parse_key_value_pair_and_insert(current_table);
15913
15914 // handle the rest of the line after the kvp
15915 // (this is not done in parse_key_value_pair() because that is also used for inline tables)
15918 if (!is_eof() && !consume_comment() && !consume_line_break())
15919 set_error("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
15920 }
15921
15922 else // ??
15923 set_error("expected keys, tables, whitespace or comments, saw '"sv, to_sv(cp), "'"sv);
15924 }
15925 while (!is_eof());
15926
15927 auto eof_pos = current_position(1);
15928 root.source_.end = eof_pos;
15929 if (current_table && current_table != &root && current_table->source_.end <= current_table->source_.begin)
15930 current_table->source_.end = eof_pos;
15931 }
15932
15933 static void update_region_ends(node& nde) noexcept
15934 {
15935 const auto type = nde.type();
15936 if (type > node_type::array)
15937 return;
15938
15939 if (type == node_type::table)
15940 {
15941 auto& tbl = nde.ref_cast<table>();
15942 if (tbl.is_inline()) // inline tables (and all their inline descendants) are already correctly
15943 // terminated
15944 return;
15945
15946 auto end = nde.source_.end;
15947 for (auto&& [k, v] : tbl)
15948 {
15949 TOML_UNUSED(k);
15951 if (end < v.source_.end)
15952 end = v.source_.end;
15953 }
15954 }
15955 else // arrays
15956 {
15957 auto& arr = nde.ref_cast<array>();
15958 auto end = nde.source_.end;
15959 for (auto&& v : arr)
15960 {
15962 if (end < v.source_.end)
15963 end = v.source_.end;
15964 }
15965 nde.source_.end = end;
15966 }
15967 }
15968
15969 public:
15971 : reader{ reader_ }
15972 {
15973 root.source_ = { prev_pos, prev_pos, reader.source_path() };
15974
15975 if (!reader.peek_eof())
15976 {
15977 cp = reader.read_next();
15978
15979#if !TOML_EXCEPTIONS
15980 if (reader.error())
15981 {
15982 err = std::move(reader.error());
15983 return;
15984 }
15985#endif
15986
15987 if (cp)
15989 }
15990
15992 }
15993
15995 operator parse_result() && noexcept
15996 {
15997#if TOML_EXCEPTIONS
15998
15999 return { std::move(root) };
16000
16001#else
16002
16003 if (err)
16004 return parse_result{ *std::move(err) };
16005 else
16006 return parse_result{ std::move(root) };
16007
16008#endif
16009 }
16010 };
16011
16014 {
16015 return_if_error({});
16017 TOML_ASSERT_ASSUME(*cp == U'[');
16018 push_parse_scope("array"sv);
16019
16020 // skip opening '['
16022
16023 node_ptr arr_ptr{ new array{} };
16024 array& arr = arr_ptr->ref_cast<array>();
16025 enum class TOML_CLOSED_ENUM parse_type : int
16026 {
16027 none,
16028 comma,
16029 val
16030 };
16031 parse_type prev = parse_type::none;
16032
16033 while (!is_error())
16034 {
16036 continue;
16038
16039 // commas - only legal after a value
16040 if (*cp == U',')
16041 {
16042 if (prev == parse_type::val)
16043 {
16044 prev = parse_type::comma;
16046 continue;
16047 }
16048 set_error_and_return_default("expected value or closing ']', saw comma"sv);
16049 }
16050
16051 // closing ']'
16052 else if (*cp == U']')
16053 {
16055 break;
16056 }
16057
16058 // must be a value
16059 else
16060 {
16061 if (prev == parse_type::val)
16062 {
16063 set_error_and_return_default("expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
16064 continue;
16065 }
16066 prev = parse_type::val;
16067
16068 auto val = parse_value();
16069 return_if_error({});
16070
16071 if (!arr.capacity())
16072 arr.reserve(4u);
16073 arr.emplace_back<node_ptr>(std::move(val));
16074 }
16075 }
16076
16077 return_if_error({});
16078 return arr_ptr;
16079 }
16080
16083 {
16084 return_if_error({});
16086 TOML_ASSERT_ASSUME(*cp == U'{');
16087 push_parse_scope("inline table"sv);
16088
16089 // skip opening '{'
16091
16092 node_ptr tbl_ptr{ new table{} };
16093 table& tbl = tbl_ptr->ref_cast<table>();
16094 tbl.is_inline(true);
16095 table_vector_scope table_scope{ open_inline_tables, tbl };
16096
16097 enum class TOML_CLOSED_ENUM parse_type : int
16098 {
16099 none,
16100 comma,
16101 kvp
16102 };
16103 parse_type prev = parse_type::none;
16104 while (!is_error())
16105 {
16106 if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
16107 {
16109 continue;
16110 }
16111 else
16112 {
16114 continue;
16115 }
16116 return_if_error({});
16118
16119 // commas - only legal after a key-value pair
16120 if (*cp == U',')
16121 {
16122 if (prev == parse_type::kvp)
16123 {
16124 prev = parse_type::comma;
16126 }
16127 else
16128 set_error_and_return_default("expected key-value pair or closing '}', saw comma"sv);
16129 }
16130
16131 // closing '}'
16132 else if (*cp == U'}')
16133 {
16134 if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
16135 {
16136 if (prev == parse_type::comma)
16137 {
16138 set_error_and_return_default("expected key-value pair, saw closing '}' (dangling comma)"sv);
16139 continue;
16140 }
16141 }
16143 break;
16144 }
16145
16146 // key-value pair
16147 else if (is_string_delimiter(*cp) || is_bare_key_character(*cp))
16148 {
16149 if (prev == parse_type::kvp)
16150 set_error_and_return_default("expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
16151 else
16152 {
16153 prev = parse_type::kvp;
16155 }
16156 }
16157
16158 else
16159 set_error_and_return_default("expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
16160 }
16161
16162 return_if_error({});
16163 return tbl_ptr;
16164 }
16165
16166 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
16167}
16169
16170#undef TOML_RETURNS_BY_THROWING
16171#undef advance_and_return_if_error
16172#undef advance_and_return_if_error_or_eof
16173#undef assert_not_eof
16174#undef assert_not_error
16175#undef is_eof
16176#undef is_error
16177#undef parse_error_break
16178#undef push_parse_scope
16179#undef push_parse_scope_1
16180#undef push_parse_scope_2
16181#undef return_after_error
16182#undef return_if_eof
16183#undef return_if_error
16184#undef return_if_error_or_eof
16185#undef set_error_and_return
16186#undef set_error_and_return_default
16187#undef set_error_and_return_if_eof
16188#undef utf8_buffered_reader_error_check
16189#undef utf8_reader_error
16190#undef utf8_reader_error_check
16191#undef utf8_reader_return_after_error
16192
16194{
16197 parse_result do_parse(utf8_reader_interface && reader)
16198 {
16199 return impl::parser{ std::move(reader) };
16200 }
16201
16204 parse_result do_parse_file(std::string_view file_path)
16205 {
16206#if TOML_EXCEPTIONS
16207#define TOML_PARSE_FILE_ERROR(msg, path) \
16208 throw parse_error{ msg, source_position{}, std::make_shared<const std::string>(std::move(path)) }
16209#else
16210#define TOML_PARSE_FILE_ERROR(msg, path) \
16211 return parse_result \
16212 { \
16213 parse_error \
16214 { \
16215 msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
16216 } \
16217 }
16218#endif
16219
16220 std::string file_path_str(file_path);
16221
16222 // open file with a custom-sized stack buffer
16223 std::ifstream file;
16224 TOML_OVERALIGNED char file_buffer[sizeof(void*) * 1024u];
16225 file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
16226#if TOML_WINDOWS
16227 file.open(impl::widen(file_path_str).c_str(), std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
16228#else
16229 file.open(file_path_str, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
16230#endif
16231 if (!file.is_open())
16232 TOML_PARSE_FILE_ERROR("File could not be opened for reading", file_path_str);
16233
16234 // get size
16235 const auto file_size = file.tellg();
16236 if (file_size == -1)
16237 TOML_PARSE_FILE_ERROR("Could not determine file size", file_path_str);
16238 file.seekg(0, std::ifstream::beg);
16239
16240 // read the whole file into memory first if the file isn't too large
16241 constexpr auto large_file_threshold = 1024 * 1024 * 2; // 2 MB
16242 if (file_size <= large_file_threshold)
16243 {
16244 std::vector<char> file_data;
16245 file_data.resize(static_cast<size_t>(file_size));
16246 file.read(file_data.data(), static_cast<std::streamsize>(file_size));
16247 return parse(std::string_view{ file_data.data(), file_data.size() }, std::move(file_path_str));
16248 }
16249
16250 // otherwise parse it using the streams
16251 else
16252 return parse(file, std::move(file_path_str));
16253
16254#undef TOML_PARSE_FILE_ERROR
16255 }
16256}
16258
16260{
16262
16264 parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path)
16265 {
16266 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
16267 }
16268
16270 parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path)
16271 {
16272 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
16273 }
16274
16276 parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path)
16277 {
16278 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
16279 }
16280
16282 parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path)
16283 {
16284 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
16285 }
16286
16288 parse_result TOML_CALLCONV parse_file(std::string_view file_path)
16289 {
16290 return TOML_ANON_NAMESPACE::do_parse_file(file_path);
16291 }
16292
16293#if TOML_HAS_CHAR8
16294
16296 parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path)
16297 {
16298 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
16299 }
16300
16302 parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path)
16303 {
16304 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
16305 }
16306
16308 parse_result TOML_CALLCONV parse_file(std::u8string_view file_path)
16309 {
16310 std::string file_path_str;
16311 file_path_str.resize(file_path.length());
16312 memcpy(file_path_str.data(), file_path.data(), file_path.length());
16313 return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
16314 }
16315
16316#endif // TOML_HAS_CHAR8
16317
16318#if TOML_ENABLE_WINDOWS_COMPAT
16319
16321 parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path)
16322 {
16323 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
16324 }
16325
16327 parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path)
16328 {
16329 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
16330 }
16331
16333 parse_result TOML_CALLCONV parse_file(std::wstring_view file_path)
16334 {
16335 return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
16336 }
16337
16338#endif // TOML_ENABLE_WINDOWS_COMPAT
16339
16340#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
16341
16343 parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path)
16344 {
16345 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
16346 }
16347
16348#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
16349
16350 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
16351}
16353
16354#undef TOML_OVERALIGNED
16355
16356#ifdef _MSC_VER
16357#pragma pop_macro("min")
16358#pragma pop_macro("max")
16359#ifndef __clang__
16360#pragma inline_recursion(off)
16361#endif
16362#endif
16364
16365#endif // TOML_ENABLE_PARSER
16366
16367//******** impl/formatter.inl ****************************************************************************************
16368
16369#if TOML_ENABLE_FORMATTERS
16370
16372#ifdef _MSC_VER
16373#ifndef __clang__
16374#pragma inline_recursion(on)
16375#endif
16376#pragma push_macro("min")
16377#pragma push_macro("max")
16378#undef min
16379#undef max
16380#endif
16381
16383{
16384 enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
16385 {
16386 none,
16387 line_breaks = 1u << 0, // \n
16388 tabs = 1u << 1, // \t
16389 control_chars = 1u << 2, // also includes non-ascii vertical whitespace
16390 single_quotes = 1u << 3,
16391 non_bare = 1u << 4, // anything not satisfying "is bare key character"
16392 non_ascii = 1u << 5, // any codepoint >= 128
16393
16394 all = (non_ascii << 1u) - 1u
16395 };
16396 TOML_MAKE_FLAGS(formatted_string_traits);
16397
16399 formatter::formatter(const node* source_node,
16400 const parse_result* source_pr,
16401 const formatter_constants& constants,
16402 const formatter_config& config) noexcept //
16403#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
16404 : source_{ source_pr && *source_pr ? &source_pr->table() : source_node },
16405 result_{ source_pr },
16406#else
16407 : source_{ source_pr ? source_pr : source_node },
16408#endif
16409 constants_{ &constants },
16410 config_{ config }
16411 {
16412 TOML_ASSERT_ASSUME(source_);
16413
16414 config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
16415
16416 indent_columns_ = {};
16417 for (auto c : config_.indent)
16418 indent_columns_ += c == '\t' ? 4u : 1u;
16419
16420 int_format_mask_ = config_.flags
16421 & (format_flags::allow_binary_integers | format_flags::allow_octal_integers
16422 | format_flags::allow_hexadecimal_integers);
16423 }
16424
16426 void formatter::attach(std::ostream & stream) noexcept
16427 {
16428 indent_ = {};
16429 naked_newline_ = true;
16430 stream_ = &stream;
16431 }
16432
16434 void formatter::detach() noexcept
16435 {
16436 stream_ = nullptr;
16437 }
16438
16441 {
16442 if (!naked_newline_ || force)
16443 {
16444 print_to_stream(*stream_, '\n');
16445 naked_newline_ = true;
16446 }
16447 }
16448
16451 {
16452 for (int i = 0; i < indent_; i++)
16453 {
16455 naked_newline_ = false;
16456 }
16457 }
16458
16461 {
16463 naked_newline_ = false;
16464 }
16465
16467 void formatter::print_unformatted(std::string_view str)
16468 {
16469 print_to_stream(*stream_, str);
16470 naked_newline_ = false;
16471 }
16472
16474 void formatter::print_string(std::string_view str,
16475 bool allow_multi_line,
16476 bool allow_bare,
16477 bool allow_literal_whitespace)
16478 {
16479 if (str.empty())
16480 {
16481 print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
16482 return;
16483 }
16484
16485 // pre-scan the string to determine how we should output it
16486 formatted_string_traits traits = {};
16487
16488 if (!allow_bare)
16489 traits |= formatted_string_traits::non_bare;
16490 bool unicode_allowed = unicode_strings_allowed();
16491
16492 // ascii fast path
16493 if (is_ascii(str.data(), str.length()))
16494 {
16495 for (auto c : str)
16496 {
16497 switch (c)
16498 {
16499 case '\n': traits |= formatted_string_traits::line_breaks; break;
16500 case '\t': traits |= formatted_string_traits::tabs; break;
16501 case '\'': traits |= formatted_string_traits::single_quotes; break;
16502 default:
16503 {
16504 if TOML_UNLIKELY(is_control_character(c))
16505 traits |= formatted_string_traits::control_chars;
16506
16507 if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
16508 traits |= formatted_string_traits::non_bare;
16509 break;
16510 }
16511 }
16512
16513 static constexpr auto all_ascii_traits =
16514 formatted_string_traits::all & ~formatted_string_traits::non_ascii;
16515 if (traits == all_ascii_traits)
16516 break;
16517 }
16518 }
16519
16520 // unicode slow path
16521 else
16522 {
16523 traits |= formatted_string_traits::non_ascii;
16524 utf8_decoder decoder;
16525
16526 // if the unicode is malformed just treat the string as a single-line non-literal and
16527 // escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
16528 const auto bad_unicode = [&]() noexcept
16529 {
16530 traits &= ~formatted_string_traits::line_breaks;
16531 traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
16532 unicode_allowed = false;
16533 };
16534
16535 for (auto c : str)
16536 {
16537 decoder(c);
16538
16539 if TOML_UNLIKELY(decoder.error())
16540 {
16541 bad_unicode();
16542 break;
16543 }
16544
16545 if (!decoder.has_code_point())
16546 continue;
16547
16548 switch (decoder.codepoint)
16549 {
16550 case U'\n': traits |= formatted_string_traits::line_breaks; break;
16551 case U'\t': traits |= formatted_string_traits::tabs; break;
16552 case U'\'': traits |= formatted_string_traits::single_quotes; break;
16553 default:
16554 {
16555 if TOML_UNLIKELY(is_control_character(decoder.codepoint)
16556 || is_non_ascii_vertical_whitespace(decoder.codepoint))
16557 traits |= formatted_string_traits::control_chars;
16558
16559 if (!is_bare_key_character(decoder.codepoint))
16560 traits |= formatted_string_traits::non_bare;
16561 break;
16562 }
16563 }
16564 }
16565
16566 if (decoder.needs_more_input())
16567 bad_unicode();
16568 }
16569
16570 // strings with line breaks, tabs, and single-quotes can't be bare
16571 if (!!(traits
16572 & (formatted_string_traits::line_breaks | formatted_string_traits::tabs
16573 | formatted_string_traits::single_quotes)))
16574 traits |= formatted_string_traits::non_bare;
16575
16576 // if the string meets the requirements of being 'bare' we can emit a bare string
16577 // (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
16578 if (!(traits & formatted_string_traits::non_bare)
16579 && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed))
16580 {
16581 print_unformatted(str);
16582 return;
16583 }
16584 const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
16585
16586 // determine if this should be a multi-line string (triple-quotes)
16587 const auto multi_line = allow_literal_whitespace //
16588 && allow_multi_line //
16590 && !!(traits & formatted_string_traits::line_breaks);
16591
16592 // determine if this should be a literal string (single-quotes with no escaping)
16593 const auto literal = literal_strings_allowed() //
16594 && !(traits & formatted_string_traits::control_chars) //
16595 && (!(traits & formatted_string_traits::single_quotes) || multi_line) //
16596 && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed) //
16597 && (!(traits & formatted_string_traits::line_breaks) || multi_line) //
16598 && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
16599
16600 // literal strings (single quotes, no escape codes)
16601 if (literal)
16602 {
16603 const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
16604 print_unformatted(quot);
16605 print_unformatted(str);
16606 print_unformatted(quot);
16607 return;
16608 }
16609
16610 // anything from here down is a non-literal string, so requires iteration and escaping.
16611 print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
16612
16613 // ascii fast path
16614 if (!(traits & formatted_string_traits::non_ascii))
16615 {
16616 for (auto c : str)
16617 {
16618 switch (c)
16619 {
16620 case '"': print_to_stream(*stream_, R"(\")"sv); break;
16621 case '\\': print_to_stream(*stream_, R"(\\)"sv); break;
16622 case '\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
16623 case '\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
16624 case '\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
16625 default:
16626 {
16627 // control characters from lookup table
16628 if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
16630
16631 // regular characters
16632 else
16634 }
16635 }
16636 }
16637 }
16638
16639 // unicode slow path
16640 else
16641 {
16642 utf8_decoder decoder;
16643 const char* cp_start = str.data();
16644 const char* cp_end = cp_start;
16645 for (auto c : str)
16646 {
16647 decoder(c);
16648 cp_end++;
16649
16650 // if the decoder encounters malformed unicode just emit raw bytes and
16651 if (decoder.error())
16652 {
16653 while (cp_start != cp_end)
16654 {
16655 print_to_stream(*stream_, R"(\u00)"sv);
16657 static_cast<uint8_t>(*cp_start),
16658 value_flags::format_as_hexadecimal,
16659 2);
16660 cp_start++;
16661 }
16662 decoder.reset();
16663 continue;
16664 }
16665
16666 if (!decoder.has_code_point())
16667 continue;
16668
16669 switch (decoder.codepoint)
16670 {
16671 case U'"': print_to_stream(*stream_, R"(\")"sv); break;
16672 case U'\\': print_to_stream(*stream_, R"(\\)"sv); break;
16673 case U'\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
16674 case U'\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
16675 case U'\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
16676 default:
16677 {
16678 // control characters from lookup table
16679 if TOML_UNLIKELY(decoder.codepoint <= U'\x1F')
16681 control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);
16682
16683 // escaped unicode characters
16684 else if (decoder.codepoint > U'\x7F'
16685 && (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint)))
16686 {
16687 if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu)
16688 {
16689 print_to_stream(*stream_, R"(\U)"sv);
16691 static_cast<uint_least32_t>(decoder.codepoint),
16692 value_flags::format_as_hexadecimal,
16693 8);
16694 }
16695 else
16696 {
16697 print_to_stream(*stream_, R"(\u)"sv);
16699 static_cast<uint_least32_t>(decoder.codepoint),
16700 value_flags::format_as_hexadecimal,
16701 4);
16702 }
16703 }
16704
16705 // regular characters
16706 else
16707 print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
16708 }
16709 }
16710
16711 cp_start = cp_end;
16712 }
16713 }
16714
16715 print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
16716 }
16717
16720 {
16721 print_string(val.get());
16722 }
16723
16726 {
16727 naked_newline_ = false;
16728
16729 if (*val >= 0 && !!int_format_mask_)
16730 {
16731 static constexpr auto value_flags_mask =
16732 value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
16733
16734 const auto fmt = val.flags() & value_flags_mask;
16735 switch (fmt)
16736 {
16737 case value_flags::format_as_binary:
16738 if (!!(int_format_mask_ & format_flags::allow_binary_integers))
16739 {
16740 print_to_stream(*stream_, "0b"sv);
16741 print_to_stream(*stream_, *val, fmt);
16742 return;
16743 }
16744 break;
16745
16746 case value_flags::format_as_octal:
16747 if (!!(int_format_mask_ & format_flags::allow_octal_integers))
16748 {
16749 print_to_stream(*stream_, "0o"sv);
16750 print_to_stream(*stream_, *val, fmt);
16751 return;
16752 }
16753 break;
16754
16755 case value_flags::format_as_hexadecimal:
16756 if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers))
16757 {
16758 print_to_stream(*stream_, "0x"sv);
16759 print_to_stream(*stream_, *val, fmt);
16760 return;
16761 }
16762 break;
16763
16764 default: break;
16765 }
16766 }
16767
16768 // fallback to decimal
16769 print_to_stream(*stream_, *val);
16770 }
16771
16774 {
16775 const std::string_view* inf_nan = nullptr;
16776 switch (fpclassify(*val))
16777 {
16778 case fp_class::neg_inf: inf_nan = &constants_->float_neg_inf; break;
16779 case fp_class::pos_inf: inf_nan = &constants_->float_pos_inf; break;
16780 case fp_class::nan: inf_nan = &constants_->float_nan; break;
16781 case fp_class::ok:
16783 *val,
16784 value_flags::none,
16785 !!(config_.flags & format_flags::relaxed_float_precision));
16786 break;
16787 default: TOML_UNREACHABLE;
16788 }
16789
16790 if (inf_nan)
16791 {
16792 if (!!(config_.flags & format_flags::quote_infinities_and_nans))
16793 print_to_stream_bookended(*stream_, *inf_nan, '"');
16794 else
16795 print_to_stream(*stream_, *inf_nan);
16796 }
16797
16798 naked_newline_ = false;
16799 }
16800
16803 {
16804 print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
16805 }
16806
16809 {
16810 if (!!(config_.flags & format_flags::quote_dates_and_times))
16812 else
16813 print_to_stream(*stream_, *val);
16814 naked_newline_ = false;
16815 }
16816
16819 {
16820 if (!!(config_.flags & format_flags::quote_dates_and_times))
16822 else
16823 print_to_stream(*stream_, *val);
16824 naked_newline_ = false;
16825 }
16826
16829 {
16830 if (!!(config_.flags & format_flags::quote_dates_and_times))
16832 else
16833 print_to_stream(*stream_, *val);
16834 naked_newline_ = false;
16835 }
16836
16838 void formatter::print_value(const node& val_node, node_type type)
16839 {
16840 TOML_ASSUME(type > node_type::array);
16841 switch (type)
16842 {
16843 case node_type::string: print(*reinterpret_cast<const value<std::string>*>(&val_node)); break;
16844 case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
16845 case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
16846 case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
16847 case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
16848 case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
16849 case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
16850 default: TOML_UNREACHABLE;
16851 }
16852 }
16853
16854#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
16855
16858 {
16859 if (result_ && !(*result_))
16860 {
16861 stream() << result_->error();
16862 return true;
16863 }
16864 return false;
16865 }
16866
16867#else
16868
16870 TOML_ATTR(const)
16871 bool formatter::dump_failed_parse_result()
16872 {
16873 return false;
16874 }
16875
16876#endif
16877}
16879
16880#ifdef _MSC_VER
16881#pragma pop_macro("min")
16882#pragma pop_macro("max")
16883#ifndef __clang__
16884#pragma inline_recursion(off)
16885#endif
16886#endif
16888
16889#endif // TOML_ENABLE_FORMATTERS
16890
16891//******** impl/toml_formatter.inl ***********************************************************************************
16892
16893#if TOML_ENABLE_FORMATTERS
16894
16896#ifdef _MSC_VER
16897#ifndef __clang__
16898#pragma inline_recursion(on)
16899#endif
16900#pragma push_macro("min")
16901#pragma push_macro("max")
16902#undef min
16903#undef max
16904#endif
16905
16907
16909{
16911 size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept
16912 {
16913 switch (node.type())
16914 {
16915 case node_type::table:
16916 {
16917 auto& tbl = *reinterpret_cast<const table*>(&node);
16918 if (tbl.empty())
16919 return 2u; // "{}"
16920 size_t weight = 3u; // "{ }"
16921 for (auto&& [k, v] : tbl)
16922 {
16923 weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // + ", "
16924 if (weight >= line_wrap_cols)
16925 break;
16926 }
16927 return weight;
16928 }
16929
16930 case node_type::array:
16931 {
16932 auto& arr = *reinterpret_cast<const array*>(&node);
16933 if (arr.empty())
16934 return 2u; // "[]"
16935 size_t weight = 3u; // "[ ]"
16936 for (auto& elem : arr)
16937 {
16938 weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // + ", "
16939 if (weight >= line_wrap_cols)
16940 break;
16941 }
16942 return weight;
16943 }
16944
16945 case node_type::string:
16946 {
16947 // todo: proper utf8 decoding?
16948 // todo: tab awareness?
16949 auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
16950 return str.length() + 2u; // + ""
16951 }
16952
16953 case node_type::integer:
16954 {
16955 auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
16956 if (!val)
16957 return 1u;
16958 size_t weight = {};
16959 if (val < 0)
16960 {
16961 weight += 1u;
16962 val *= -1;
16963 }
16964 return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
16965 }
16966
16967 case node_type::floating_point:
16968 {
16969 auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
16970 if (val == 0.0)
16971 return 3u; // "0.0"
16972 size_t weight = 2u; // ".0"
16973 if (val < 0.0)
16974 {
16975 weight += 1u;
16976 val *= -1.0;
16977 }
16978 return weight + static_cast<size_t>(log10(val)) + 1u;
16979 break;
16980 }
16981
16982 case node_type::boolean: return 5u;
16983 case node_type::date: [[fallthrough]];
16984 case node_type::time: return 10u;
16985 case node_type::date_time: return 30u;
16986 case node_type::none: TOML_UNREACHABLE;
16987 default: TOML_UNREACHABLE;
16988 }
16989
16991 }
16992
16994 bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept
16995 {
16996 return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols;
16997 }
16998}
17000
17002{
17004 void toml_formatter::print_pending_table_separator()
17005 {
17006 if (pending_table_separator_)
17007 {
17008 print_newline(true);
17009 print_newline(true);
17010 pending_table_separator_ = false;
17011 }
17012 }
17013
17015 void toml_formatter::print(const key& k)
17016 {
17017 print_string(k.str(), false, true, false);
17018 }
17019
17021 void toml_formatter::print_inline(const table& tbl)
17022 {
17023 if (tbl.empty())
17024 {
17025 print_unformatted("{}"sv);
17026 return;
17027 }
17028
17029 print_unformatted("{ "sv);
17030
17031 bool first = false;
17032 for (auto&& [k, v] : tbl)
17033 {
17034 if (first)
17035 print_unformatted(", "sv);
17036 first = true;
17037
17038 print(k);
17039 if (terse_kvps())
17040 print_unformatted("="sv);
17041 else
17042 print_unformatted(" = "sv);
17043
17044 const auto type = v.type();
17045 TOML_ASSUME(type != node_type::none);
17046 switch (type)
17047 {
17048 case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
17049 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17050 default: print_value(v, type);
17051 }
17052 }
17053
17054 print_unformatted(" }"sv);
17055 }
17056
17058 void toml_formatter::print(const array& arr)
17059 {
17060 if (arr.empty())
17061 {
17062 print_unformatted("[]"sv);
17063 return;
17064 }
17065
17066 const auto original_indent = indent();
17067 const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
17068 arr,
17069 120u,
17070 indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
17071
17072 print_unformatted("["sv);
17073
17074 if (multiline)
17075 {
17076 if (original_indent < 0)
17077 indent(0);
17079 increase_indent();
17080 }
17081 else
17082 print_unformatted(' ');
17083
17084 for (size_t i = 0; i < arr.size(); i++)
17085 {
17086 if (i > 0u)
17087 {
17088 print_unformatted(',');
17089 if (!multiline)
17090 print_unformatted(' ');
17091 }
17092
17093 if (multiline)
17094 {
17095 print_newline(true);
17096 print_indent();
17097 }
17098
17099 auto& v = arr[i];
17100 const auto type = v.type();
17101 TOML_ASSUME(type != node_type::none);
17102 switch (type)
17103 {
17104 case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
17105 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17106 default: print_value(v, type);
17107 }
17108 }
17109 if (multiline)
17110 {
17111 indent(original_indent);
17112 print_newline(true);
17113 print_indent();
17114 }
17115 else
17116 print_unformatted(' ');
17117
17118 print_unformatted("]"sv);
17119 }
17120
17122 void toml_formatter::print(const table& tbl)
17123 {
17124 static constexpr auto is_non_inline_array_of_tables = [](const node& n) noexcept
17125 {
17126 const auto arr = n.as_array();
17127 if (!arr || !arr->is_array_of_tables())
17128 return false;
17129
17130 return !reinterpret_cast<const table*>(&(*arr)[0])->is_inline();
17131 };
17132
17133 // values, arrays, and inline tables/table arrays
17134 for (auto&& [k, v] : tbl)
17135 {
17136 const auto type = v.type();
17137 if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
17138 || (type == node_type::array && is_non_inline_array_of_tables(v)))
17139 continue;
17140
17141 pending_table_separator_ = true;
17142 print_newline();
17143 print_indent();
17144 print(k);
17145 if (terse_kvps())
17146 print_unformatted("="sv);
17147 else
17148 print_unformatted(" = "sv);
17149 TOML_ASSUME(type != node_type::none);
17150 switch (type)
17151 {
17152 case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
17153 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17154 default: print_value(v, type);
17155 }
17156 }
17157
17158 const auto print_key_path = [&]()
17159 {
17160 size_t i{};
17161 for (const auto k : key_path_)
17162 {
17163 if (i++)
17164 print_unformatted('.');
17165 print(*k);
17166 }
17167 };
17168
17169 // non-inline tables
17170 for (auto&& [k, v] : tbl)
17171 {
17172 const auto type = v.type();
17173 if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
17174 continue;
17175 auto& child_tbl = *reinterpret_cast<const table*>(&v);
17176
17177 // we can skip indenting and emitting the headers for tables that only contain other tables
17178 // (so we don't over-nest)
17179 size_t child_value_count{}; // includes inline tables and non-table arrays
17180 size_t child_table_count{};
17181 size_t child_table_array_count{};
17182 for (auto&& [child_k, child_v] : child_tbl)
17183 {
17184 TOML_UNUSED(child_k);
17185 const auto child_type = child_v.type();
17186 TOML_ASSUME(child_type != node_type::none);
17187 switch (child_type)
17188 {
17189 case node_type::table:
17190 if (reinterpret_cast<const table*>(&child_v)->is_inline())
17191 child_value_count++;
17192 else
17193 child_table_count++;
17194 break;
17195
17196 case node_type::array:
17197 if (is_non_inline_array_of_tables(child_v))
17198 child_table_array_count++;
17199 else
17200 child_value_count++;
17201 break;
17202
17203 default: child_value_count++;
17204 }
17205 }
17206 bool skip_self = false;
17207 if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u))
17208 skip_self = true;
17209
17210 key_path_.push_back(&k);
17211
17212 if (!skip_self)
17213 {
17214 print_pending_table_separator();
17215 if (indent_sub_tables())
17216 increase_indent();
17217 print_indent();
17218 print_unformatted("["sv);
17219 print_key_path();
17220 print_unformatted("]"sv);
17221 pending_table_separator_ = true;
17222 }
17223
17224 print(child_tbl);
17225
17226 key_path_.pop_back();
17227 if (!skip_self && indent_sub_tables())
17228 decrease_indent();
17229 }
17230
17231 // table arrays
17232 for (auto&& [k, v] : tbl)
17233 {
17234 if (!is_non_inline_array_of_tables(v))
17235 continue;
17236 auto& arr = *reinterpret_cast<const array*>(&v);
17237
17238 if (indent_sub_tables())
17239 increase_indent();
17240 key_path_.push_back(&k);
17241
17242 for (size_t i = 0; i < arr.size(); i++)
17243 {
17244 print_pending_table_separator();
17245 print_indent();
17246 print_unformatted("[["sv);
17247 print_key_path();
17248 print_unformatted("]]"sv);
17249 pending_table_separator_ = true;
17250 print(*reinterpret_cast<const table*>(&arr[i]));
17251 }
17252
17253 key_path_.pop_back();
17254 if (indent_sub_tables())
17255 decrease_indent();
17256 }
17257 }
17258
17260 void toml_formatter::print()
17261 {
17262 if (dump_failed_parse_result())
17263 return;
17264
17265 switch (auto source_type = source().type())
17266 {
17267 case node_type::table:
17268 {
17269 auto& tbl = *reinterpret_cast<const table*>(&source());
17270 if (tbl.is_inline())
17271 print_inline(tbl);
17272 else
17273 {
17274 decrease_indent(); // so root kvps and tables have the same indent
17275 print(tbl);
17276 }
17277 break;
17278 }
17279
17280 case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
17281
17282 default: print_value(source(), source_type);
17283 }
17284 }
17285}
17287
17288#ifdef _MSC_VER
17289#pragma pop_macro("min")
17290#pragma pop_macro("max")
17291#ifndef __clang__
17292#pragma inline_recursion(off)
17293#endif
17294#endif
17296
17297#endif // TOML_ENABLE_FORMATTERS
17298
17299//******** impl/json_formatter.inl ***********************************************************************************
17300
17301#if TOML_ENABLE_FORMATTERS
17302
17304#ifdef _MSC_VER
17305#ifndef __clang__
17306#pragma inline_recursion(on)
17307#endif
17308#pragma push_macro("min")
17309#pragma push_macro("max")
17310#undef min
17311#undef max
17312#endif
17313
17315{
17317 void json_formatter::print(const toml::table& tbl)
17318 {
17319 if (tbl.empty())
17320 {
17321 print_unformatted("{}"sv);
17322 return;
17323 }
17324
17325 print_unformatted('{');
17326
17327 if (indent_sub_tables())
17328 increase_indent();
17329 bool first = false;
17330 for (auto&& [k, v] : tbl)
17331 {
17332 if (first)
17333 print_unformatted(',');
17334 first = true;
17335 print_newline(true);
17336 print_indent();
17337
17338 print_string(k.str(), false);
17339 if (terse_kvps())
17340 print_unformatted(":"sv);
17341 else
17342 print_unformatted(" : "sv);
17343
17344 const auto type = v.type();
17345 TOML_ASSUME(type != node_type::none);
17346 switch (type)
17347 {
17348 case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
17349 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17350 default: print_value(v, type);
17351 }
17352 }
17353 if (indent_sub_tables())
17354 decrease_indent();
17355 print_newline(true);
17356 print_indent();
17357
17358 print_unformatted('}');
17359 }
17360
17362 void json_formatter::print(const toml::array& arr)
17363 {
17364 if (arr.empty())
17365 {
17366 print_unformatted("[]"sv);
17367 return;
17368 }
17369
17370 print_unformatted('[');
17372 increase_indent();
17373 for (size_t i = 0; i < arr.size(); i++)
17374 {
17375 if (i > 0u)
17376 print_unformatted(',');
17377 print_newline(true);
17378 print_indent();
17379
17380 auto& v = arr[i];
17381 const auto type = v.type();
17382 TOML_ASSUME(type != node_type::none);
17383 switch (type)
17384 {
17385 case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
17386 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17387 default: print_value(v, type);
17388 }
17389 }
17391 decrease_indent();
17392 print_newline(true);
17393 print_indent();
17394 print_unformatted(']');
17395 }
17396
17398 void json_formatter::print()
17399 {
17400 if (dump_failed_parse_result())
17401 return;
17402
17403 switch (auto source_type = source().type())
17404 {
17405 case node_type::table: print(*reinterpret_cast<const table*>(&source())); break;
17406 case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
17407 default: print_value(source(), source_type);
17408 }
17409 }
17410}
17412
17413#ifdef _MSC_VER
17414#pragma pop_macro("min")
17415#pragma pop_macro("max")
17416#ifndef __clang__
17417#pragma inline_recursion(off)
17418#endif
17419#endif
17421
17422#endif // TOML_ENABLE_FORMATTERS
17423
17424//******** impl/yaml_formatter.inl ***********************************************************************************
17425
17426#if TOML_ENABLE_FORMATTERS
17427
17429#ifdef _MSC_VER
17430#ifndef __clang__
17431#pragma inline_recursion(on)
17432#endif
17433#pragma push_macro("min")
17434#pragma push_macro("max")
17435#undef min
17436#undef max
17437#endif
17438
17440{
17442 void yaml_formatter::print_yaml_string(const value<std::string>& str)
17443 {
17444 if (str->empty())
17445 {
17446 base::print(str);
17447 return;
17448 }
17449
17450 bool contains_newline = false;
17451 for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
17452 contains_newline = *c == '\n';
17453
17454 if (contains_newline)
17455 {
17456 print_unformatted("|-"sv);
17457
17458 increase_indent();
17459
17460 auto line_end = str->c_str() - 1u;
17461 const auto end = str->c_str() + str->length();
17462 while (line_end != end)
17463 {
17464 auto line_start = line_end + 1u;
17465 line_end = line_start;
17466 for (; line_end != end && *line_end != '\n'; line_end++)
17467 ;
17468
17469 if TOML_LIKELY(line_start != line_end || line_end != end)
17470 {
17471 print_newline();
17472 print_indent();
17473 print_unformatted(std::string_view{ line_start, static_cast<size_t>(line_end - line_start) });
17474 }
17475 }
17476
17477 decrease_indent();
17478 }
17479 else
17480 print_string(*str, false, true);
17481 }
17482
17484 void yaml_formatter::print(const toml::table& tbl, bool parent_is_array)
17485 {
17486 if (tbl.empty())
17487 {
17488 print_unformatted("{}"sv);
17489 return;
17490 }
17491
17492 increase_indent();
17493
17494 for (auto&& [k, v] : tbl)
17495 {
17496 if (!parent_is_array)
17497 {
17498 print_newline();
17499 print_indent();
17500 }
17501 parent_is_array = false;
17502
17503 print_string(k.str(), false, true);
17504 if (terse_kvps())
17505 print_unformatted(":"sv);
17506 else
17507 print_unformatted(": "sv);
17508
17509 const auto type = v.type();
17510 TOML_ASSUME(type != node_type::none);
17511 switch (type)
17512 {
17513 case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
17514 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17515 case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
17516 default: print_value(v, type);
17517 }
17518 }
17519
17520 decrease_indent();
17521 }
17522
17524 void yaml_formatter::print(const toml::array& arr, bool parent_is_array)
17525 {
17526 if (arr.empty())
17527 {
17528 print_unformatted("[]"sv);
17529 return;
17530 }
17531
17532 increase_indent();
17533
17534 for (auto&& v : arr)
17535 {
17536 if (!parent_is_array)
17537 {
17538 print_newline();
17539 print_indent();
17540 }
17541 parent_is_array = false;
17542
17543 print_unformatted("- "sv);
17544
17545 const auto type = v.type();
17546 TOML_ASSUME(type != node_type::none);
17547 switch (type)
17548 {
17549 case node_type::table: print(*reinterpret_cast<const table*>(&v), true); break;
17550 case node_type::array: print(*reinterpret_cast<const array*>(&v), true); break;
17551 case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
17552 default: print_value(v, type);
17553 }
17554 }
17555
17556 decrease_indent();
17557 }
17558
17560 void yaml_formatter::print()
17561 {
17562 if (dump_failed_parse_result())
17563 return;
17564
17565 switch (auto source_type = source().type())
17566 {
17567 case node_type::table:
17568 decrease_indent(); // so root kvps and tables have the same indent
17569 print(*reinterpret_cast<const table*>(&source()));
17570 break;
17571
17572 case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
17573
17574 case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&source())); break;
17575
17576 default: print_value(source(), source_type);
17577 }
17578 }
17579}
17581
17582#ifdef _MSC_VER
17583#pragma pop_macro("min")
17584#pragma pop_macro("max")
17585#ifndef __clang__
17586#pragma inline_recursion(off)
17587#endif
17588#endif
17590
17591#endif // TOML_ENABLE_FORMATTERS
17592
17593#endif // TOML_IMPLEMENTATION
17594
17596
17597// macro hygiene
17598#if TOML_UNDEF_MACROS
17599#undef TOML_ABI_NAMESPACE_BOOL
17600#undef TOML_ABI_NAMESPACE_END
17601#undef TOML_ABI_NAMESPACE_START
17602#undef TOML_ABI_NAMESPACES
17603#undef TOML_ABSTRACT_INTERFACE
17604#undef TOML_ALWAYS_INLINE
17605#undef TOML_ANON_NAMESPACE
17606#undef TOML_ANON_NAMESPACE_END
17607#undef TOML_ANON_NAMESPACE_START
17608#undef TOML_ARCH_AMD64
17609#undef TOML_ARCH_ARM
17610#undef TOML_ARCH_ARM32
17611#undef TOML_ARCH_ARM64
17612#undef TOML_ARCH_BITNESS
17613#undef TOML_ARCH_ITANIUM
17614#undef TOML_ARCH_X64
17615#undef TOML_ARCH_X86
17616#undef TOML_ASSERT
17617#undef TOML_ASSERT_ASSUME
17618#undef TOML_ASSUME
17619#undef TOML_ASYMMETRICAL_EQUALITY_OPS
17620#undef TOML_ATTR
17621#undef TOML_CLANG
17622#undef TOML_CLANG_VERSION
17623#undef TOML_CLOSED_ENUM
17624#undef TOML_CLOSED_FLAGS_ENUM
17625#undef TOML_COMPILER_HAS_EXCEPTIONS
17626#undef TOML_COMPILER_HAS_RTTI
17627#undef TOML_CONST
17628#undef TOML_CONST_GETTER
17629#undef TOML_CONST_INLINE_GETTER
17630#undef TOML_CONSTRAINED_TEMPLATE
17631#undef TOML_CPP
17632#undef TOML_DECLSPEC
17633#undef TOML_DELETE_DEFAULTS
17634#undef TOML_DISABLE_ARITHMETIC_WARNINGS
17635#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
17636#undef TOML_DISABLE_SPAM_WARNINGS
17637#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
17638#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_11
17639#undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
17640#undef TOML_DISABLE_SWITCH_WARNINGS
17641#undef TOML_DISABLE_WARNINGS
17642#undef TOML_DOXYGEN
17643#undef TOML_EMPTY_BASES
17644#undef TOML_ENABLE_IF
17645#undef TOML_ENABLE_WARNINGS
17646#undef TOML_EVAL_BOOL_0
17647#undef TOML_EVAL_BOOL_1
17648#undef TOML_EXTERNAL_LINKAGE
17649#undef TOML_FLAGS_ENUM
17650#undef TOML_FLOAT_CHARCONV
17651#undef TOML_FLOAT128
17652#undef TOML_FLOAT16_DIG
17653#undef TOML_FLOAT16_LIMITS_SET
17654#undef TOML_FLOAT16_MANT_DIG
17655#undef TOML_FLOAT16_MAX_10_EXP
17656#undef TOML_FLOAT16_MAX_EXP
17657#undef TOML_FLOAT16_MIN_10_EXP
17658#undef TOML_FLOAT16_MIN_EXP
17659#undef TOML_GCC
17660#undef TOML_GCC_LIKE
17661#undef TOML_HAS_ATTR
17662#undef TOML_HAS_BUILTIN
17663#undef TOML_HAS_CHAR8
17664#undef TOML_HAS_CPP_ATTR
17665#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
17666#undef TOML_HAS_FEATURE
17667#undef TOML_HAS_INCLUDE
17668#undef TOML_HAS_SSE2
17669#undef TOML_HAS_SSE4_1
17670#undef TOML_HIDDEN_CONSTRAINT
17671#undef TOML_ICC
17672#undef TOML_ICC_CL
17673#undef TOML_IMPL_NAMESPACE_END
17674#undef TOML_IMPL_NAMESPACE_START
17675#undef TOML_IMPLEMENTATION
17676#undef TOML_INCLUDE_WINDOWS_H
17677#undef TOML_INLINE_GETTER
17678#undef TOML_INT_CHARCONV
17679#undef TOML_INT128
17680#undef TOML_INTELLISENSE
17681#undef TOML_INTERNAL_LINKAGE
17682#undef TOML_LANG_AT_LEAST
17683#undef TOML_LANG_EFFECTIVE_VERSION
17684#undef TOML_LANG_HIGHER_THAN
17685#undef TOML_LANG_UNRELEASED
17686#undef TOML_LAUNDER
17687#undef TOML_LIFETIME_HOOKS
17688#undef TOML_LIKELY
17689#undef TOML_LIKELY_CASE
17690#undef TOML_LINUX
17691#undef TOML_MAKE_FLAGS
17692#undef TOML_MAKE_FLAGS_
17693#undef TOML_MAKE_FLAGS_1
17694#undef TOML_MAKE_FLAGS_2
17695#undef TOML_MAKE_STRING
17696#undef TOML_MAKE_STRING_1
17697#undef TOML_MAKE_VERSION
17698#undef TOML_MSVC
17699#undef TOML_MSVC_LIKE
17700#undef TOML_NAMESPACE
17701#undef TOML_NEVER_INLINE
17702#undef TOML_NODISCARD
17703#undef TOML_NODISCARD_CTOR
17704#undef TOML_OPEN_ENUM
17705#undef TOML_OPEN_FLAGS_ENUM
17706#undef TOML_PARSER_TYPENAME
17707#undef TOML_POP_WARNINGS
17708#undef TOML_PRAGMA_CLANG
17709#undef TOML_PRAGMA_CLANG_GE_10
17710#undef TOML_PRAGMA_CLANG_GE_11
17711#undef TOML_PRAGMA_CLANG_GE_8
17712#undef TOML_PRAGMA_CLANG_GE_9
17713#undef TOML_PRAGMA_GCC
17714#undef TOML_PRAGMA_ICC
17715#undef TOML_PRAGMA_MSVC
17716#undef TOML_PURE
17717#undef TOML_PURE_GETTER
17718#undef TOML_PURE_INLINE_GETTER
17719#undef TOML_PUSH_WARNINGS
17720#undef TOML_REQUIRES
17721#undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
17722#undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
17723#undef TOML_SA_LIST_BEG
17724#undef TOML_SA_LIST_END
17725#undef TOML_SA_LIST_NEW
17726#undef TOML_SA_LIST_NXT
17727#undef TOML_SA_LIST_SEP
17728#undef TOML_SA_NATIVE_VALUE_TYPE_LIST
17729#undef TOML_SA_NEWLINE
17730#undef TOML_SA_NODE_TYPE_LIST
17731#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
17732#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
17733#undef TOML_SA_VALUE_FUNC_MESSAGE
17734#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
17735#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
17736#undef TOML_SA_VALUE_MESSAGE_WSTRING
17737#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
17738#undef TOML_TRIVIAL_ABI
17739#undef TOML_UINT128
17740#undef TOML_UNIX
17741#undef TOML_UNLIKELY
17742#undef TOML_UNLIKELY_CASE
17743#undef TOML_UNREACHABLE
17744#undef TOML_UNUSED
17745#undef TOML_WINDOWS
17746#endif
17747
17748#endif // TOMLPLUSPLUS_HPP
uint8_t byte
Minimal Arduino.h stub for native unit tests.
Definition Arduino.h:16
#define min(a, b)
Definition Arduino.h:42
#define max(a, b)
Definition Arduino.h:43
static route_t * find(uint16_t pin)
Definition board_exti.c:20
TOML_NODISCARD_CTOR parse_error(std::string &&desc, source_region &&src) noexcept
Definition toml.hpp:9103
TOML_NODISCARD_CTOR parse_error(std::string &&desc, const source_region &src) noexcept
Definition toml.hpp:9109
friend std::ostream & operator<<(std::ostream &lhs, const parse_error &rhs)
Definition toml.hpp:9136
std::string description_
Definition toml.hpp:9074
TOML_NODISCARD const source_region & source() const noexcept
Definition toml.hpp:9131
TOML_NODISCARD_CTOR parse_error(std::string &&desc, const source_position &position, const source_path_ptr &path={}) noexcept
Definition toml.hpp:9114
TOML_NODISCARD std::string_view description() const noexcept
Definition toml.hpp:9121
source_region source_
Definition toml.hpp:9076
TOML_NODISCARD iterator begin() noexcept
Definition toml.hpp:6616
TOML_CONST_INLINE_GETTER table * as_table() noexcept final
Definition toml.hpp:6429
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION array(const impl::array_init_elem *, const impl::array_init_elem *)
TOML_PURE_INLINE_GETTER node * get(size_t index) noexcept
Definition toml.hpp:6537
const node & const_reference
Definition toml.hpp:6294
TOML_PURE_GETTER bool is_homogeneous() const noexcept
Definition toml.hpp:6347
TOML_EXPORTED_MEMBER_FUNCTION void reserve(size_t new_capacity)
TOML_NODISCARD friend bool operator==(const array &lhs, const std::initializer_list< T > &rhs) noexcept
Definition toml.hpp:7138
TOML_CONST_INLINE_GETTER bool is_boolean() const noexcept final
Definition toml.hpp:6405
std::disjunction< can_for_each< Func, Array, table >, can_for_each< Func, Array, array >, can_for_each< Func, Array, std::string >, can_for_each< Func, Array, int64_t >, can_for_each< Func, Array, double >, can_for_each< Func, Array, bool >, can_for_each< Func, Array, date >, can_for_each< Func, Array, time >, can_for_each< Func, Array, date_time > > can_for_each_any
Definition toml.hpp:6677
TOML_CONST_INLINE_GETTER bool is_array() const noexcept final
Definition toml.hpp:6363
TOML_CONST_INLINE_GETTER bool is_date_time() const noexcept final
Definition toml.hpp:6423
TOML_NODISCARD friend bool operator==(const array &lhs, const std::vector< T > &rhs) noexcept
Definition toml.hpp:7146
TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0||!std::is_same_v< impl::remove_cvref< ElemType >, array >), typename ElemType, typename... ElemTypes) TOML_NODISCARD_CTOR explicit array(ElemType &&val
TOML_EXPORTED_MEMBER_FUNCTION ~array() noexcept
TOML_EXPORTED_MEMBER_FUNCTION array & operator=(array &&rhs) noexcept
TOML_CONST_INLINE_GETTER toml::value< double > * as_floating_point() noexcept final
Definition toml.hpp:6453
TOML_CONST_INLINE_GETTER const toml::value< bool > * as_boolean() const noexcept final
Definition toml.hpp:6513
TOML_NODISCARD iterator end() noexcept
Definition toml.hpp:6634
const array & for_each(Func &&visitor) const &noexcept(for_each_is_nothrow< Func &&, const array & >::value)
Definition toml.hpp:6843
TOML_CONST_INLINE_GETTER bool is_string() const noexcept final
Definition toml.hpp:6381
std::vector< impl::node_ptr > vector_type
Definition toml.hpp:6248
std::conditional_t< std::is_invocable_v< Func, for_each_elem_ref< T, Array >, size_t >, std::is_nothrow_invocable< Func, for_each_elem_ref< T, Array >, size_t >, std::conditional_t< std::is_invocable_v< Func, size_t, for_each_elem_ref< T, Array > >, std::is_nothrow_invocable< Func, size_t, for_each_elem_ref< T, Array > >, std::conditional_t< std::is_invocable_v< Func, for_each_elem_ref< T, Array > >, std::is_nothrow_invocable< Func, for_each_elem_ref< T, Array > >, std::false_type > > > can_for_each_nothrow
Definition toml.hpp:6662
TOML_NODISCARD const_iterator cbegin() const noexcept
Definition toml.hpp:6628
TOML_CONST_INLINE_GETTER toml::value< std::string > * as_string() noexcept final
Definition toml.hpp:6441
TOML_NODISCARD_CTOR array(std::false_type, std::initializer_list< impl::array_init_elem > elems)
Definition toml.hpp:6258
void emplace_back_if_not_empty_view(T &&val, value_flags flags)
Definition toml.hpp:6272
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, const node *&first_nonmatch) const noexcept final
TOML_EXPORTED_MEMBER_FUNCTION void insert_at_back(impl::node_ptr &&)
vector_type elems_
Definition toml.hpp:6251
TOML_NODISCARD node & back() noexcept
Definition toml.hpp:6600
array && prune(bool recursive=true) &&noexcept
Definition toml.hpp:6924
TOML_NODISCARD size_t capacity() const noexcept
Definition toml.hpp:6877
iterator insert(const_iterator pos, size_t count, ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:6948
TOML_NODISCARD friend bool operator!=(const array &lhs, const array &rhs) noexcept
Definition toml.hpp:7131
TOML_CONST_INLINE_GETTER bool is_floating_point() const noexcept final
Definition toml.hpp:6393
TOML_CONST_INLINE_GETTER toml::value< bool > * as_boolean() noexcept final
Definition toml.hpp:6459
TOML_PURE_INLINE_GETTER const node * get(size_t index) const noexcept
Definition toml.hpp:6543
TOML_EXPORTED_MEMBER_FUNCTION iterator erase(const_iterator pos) noexcept
TOML_ASYMMETRICAL_EQUALITY_OPS(const array &, const std::vector< T > &, template< typename T >)
static TOML_NODISCARD bool equal_to_container(const array &lhs, const T &rhs) noexcept
Definition toml.hpp:7100
node & reference
Definition toml.hpp:6293
array && for_each(Func &&visitor) &&noexcept(for_each_is_nothrow< Func &&, array && >::value)
Definition toml.hpp:6835
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION size_t total_leaf_count() const noexcept
decltype(auto) emplace_back(Args &&... args)
Definition toml.hpp:7060
TOML_ASYMMETRICAL_EQUALITY_OPS(const array &, const std::initializer_list< T > &, template< typename T >)
TOML_NODISCARD const node & operator[](size_t index) const noexcept
Definition toml.hpp:6572
TOML_NODISCARD const_iterator cend() const noexcept
Definition toml.hpp:6646
std::disjunction< std::is_invocable< Func, for_each_elem_ref< T, Array >, size_t >, std::is_invocable< Func, size_t, for_each_elem_ref< T, Array > >, std::is_invocable< Func, for_each_elem_ref< T, Array > > > can_for_each
Definition toml.hpp:6657
TOML_EXPORTED_MEMBER_FUNCTION void pop_back() noexcept
TOML_CONST_INLINE_GETTER const toml::value< time > * as_time() const noexcept final
Definition toml.hpp:6525
TOML_CONST_INLINE_GETTER bool is_time() const noexcept final
Definition toml.hpp:6417
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION node & at(size_t index)
TOML_CONST_INLINE_GETTER const toml::value< date_time > * as_date_time() const noexcept final
Definition toml.hpp:6531
TOML_CONST_INLINE_GETTER bool is_integer() const noexcept final
Definition toml.hpp:6387
TOML_EXPORTED_MEMBER_FUNCTION void flatten_child(array &&child, size_t &dest_index) noexcept
TOML_EXPORTED_MEMBER_FUNCTION array & prune(bool recursive=true) &noexcept
array && flatten() &&
Definition toml.hpp:6916
TOML_EXPORTED_MEMBER_FUNCTION void clear() noexcept
TOML_CONST_INLINE_GETTER toml::value< int64_t > * as_integer() noexcept final
Definition toml.hpp:6447
TOML_PURE_GETTER bool is_array_of_tables() const noexcept final
Definition toml.hpp:6369
TOML_NODISCARD const_iterator begin() const noexcept
Definition toml.hpp:6622
TOML_NODISCARD const_iterator end() const noexcept
Definition toml.hpp:6640
TOML_CONST_INLINE_GETTER const array * as_array() const noexcept final
Definition toml.hpp:6489
std::disjunction< std::negation< can_for_each< Func, Array, T > >, can_for_each_nothrow< Func, Array, T > > for_each_is_nothrow_one
Definition toml.hpp:6688
iterator insert(const_iterator pos, std::initializer_list< ElemType > ilist, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7014
const array && for_each(Func &&visitor) const &&noexcept(for_each_is_nothrow< Func &&, const array && >::value)
Definition toml.hpp:6851
TOML_EXPORTED_MEMBER_FUNCTION iterator erase(const_iterator first, const_iterator last) noexcept
static void do_for_each(Func &&visitor, Array &&arr) noexcept(for_each_is_nothrow< Func &&, Array && >::value)
Definition toml.hpp:6703
TOML_EXPORTED_MEMBER_FUNCTION void truncate(size_t new_size)
TOML_NODISCARD static TOML_EXPORTED_STATIC_FUNCTION bool TOML_CALLCONV equal(const array &, const array &) noexcept
std::conjunction< for_each_is_nothrow_one< Func, Array, table >, for_each_is_nothrow_one< Func, Array, array >, for_each_is_nothrow_one< Func, Array, std::string >, for_each_is_nothrow_one< Func, Array, int64_t >, for_each_is_nothrow_one< Func, Array, double >, for_each_is_nothrow_one< Func, Array, bool >, for_each_is_nothrow_one< Func, Array, date >, for_each_is_nothrow_one< Func, Array, time >, for_each_is_nothrow_one< Func, Array, date_time > > for_each_is_nothrow
Definition toml.hpp:6692
TOML_NODISCARD friend bool operator==(const array &lhs, const array &rhs) noexcept
Definition toml.hpp:7125
TOML_CONST_INLINE_GETTER toml::value< date_time > * as_date_time() noexcept final
Definition toml.hpp:6477
TOML_CONST_INLINE_GETTER node_type type() const noexcept final
Definition toml.hpp:6328
TOML_CONST_INLINE_GETTER const table * as_table() const noexcept final
Definition toml.hpp:6483
TOML_EXPORTED_MEMBER_FUNCTION void preinsertion_resize(size_t idx, size_t count)
array & for_each(Func &&visitor) &noexcept(for_each_is_nothrow< Func &&, array & >::value)
Definition toml.hpp:6827
TOML_CONST_INLINE_GETTER bool is_value() const noexcept final
Definition toml.hpp:6375
TOML_NODISCARD node & operator[](size_t index) noexcept
Definition toml.hpp:6566
TOML_NODISCARD bool empty() const noexcept
Definition toml.hpp:6859
TOML_NODISCARD size_t max_size() const noexcept
Definition toml.hpp:6871
size_t size_type
Definition toml.hpp:6291
TOML_CONST_INLINE_GETTER const toml::value< double > * as_floating_point() const noexcept final
Definition toml.hpp:6507
TOML_CONST_INLINE_GETTER const toml::value< int64_t > * as_integer() const noexcept final
Definition toml.hpp:6501
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype) const noexcept final
TOML_CONST_INLINE_GETTER const toml::value< std::string > * as_string() const noexcept final
Definition toml.hpp:6495
TOML_CONST_INLINE_GETTER toml::value< time > * as_time() noexcept final
Definition toml.hpp:6471
ptrdiff_t difference_type
Definition toml.hpp:6292
TOML_NODISCARD const node & at(size_t index) const
Definition toml.hpp:6582
void resize(size_t new_size, ElemType &&default_init_val, value_flags default_init_flags=preserve_source_value_flags)
Definition toml.hpp:6892
TOML_NODISCARD node & front() noexcept
Definition toml.hpp:6588
TOML_EXPORTED_MEMBER_FUNCTION array & flatten() &
ElemTypes && vals
Definition toml.hpp:6316
iterator replace(const_iterator pos, ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7038
typename vector_type::const_iterator const_vector_iterator
Definition toml.hpp:6250
TOML_CONST_INLINE_GETTER const toml::value< date > * as_date() const noexcept final
Definition toml.hpp:6519
TOML_CONST_INLINE_GETTER toml::value< date > * as_date() noexcept final
Definition toml.hpp:6465
friend std::ostream & operator<<(std::ostream &lhs, const array &rhs)
Definition toml.hpp:7154
array_iterator iterator
Definition toml.hpp:6611
TOML_CONST_INLINE_GETTER bool is_number() const noexcept final
Definition toml.hpp:6399
impl::copy_cvref< impl::wrap_node< impl::remove_cvref< impl::unwrap_node< T > > >, Array > for_each_elem_ref
Definition toml.hpp:6654
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final
const_array_iterator const_iterator
Definition toml.hpp:6613
iterator emplace(const_iterator pos, Args &&... args)
Definition toml.hpp:7022
iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:6977
TOML_CONST_INLINE_GETTER array * as_array() noexcept final
Definition toml.hpp:6435
TOML_NODISCARD impl::wrap_node< ElemType > * get_as(size_t index) noexcept
Definition toml.hpp:6550
TOML_EXPORTED_MEMBER_FUNCTION void shrink_to_fit()
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION array() noexcept
TOML_NODISCARD const node & front() const noexcept
Definition toml.hpp:6594
TOML_NODISCARD const node & back() const noexcept
Definition toml.hpp:6606
TOML_NODISCARD size_t size() const noexcept
Definition toml.hpp:6865
iterator insert(const_iterator pos, ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:6936
node value_type
Definition toml.hpp:6290
TOML_CONST_INLINE_GETTER bool is_table() const noexcept final
Definition toml.hpp:6357
TOML_NODISCARD const impl::wrap_node< ElemType > * get_as(size_t index) const noexcept
Definition toml.hpp:6559
typename vector_type::iterator vector_iterator
Definition toml.hpp:6249
TOML_CONST_INLINE_GETTER bool is_date() const noexcept final
Definition toml.hpp:6411
void push_back(ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7054
TOML_EXPORTED_MEMBER_FUNCTION vector_iterator insert_at(const_vector_iterator, impl::node_ptr &&)
TOML_EXPORTED_MEMBER_FUNCTION void print_string(std::string_view str, bool allow_multi_line=true, bool allow_bare=false, bool allow_literal_whitespace=true)
Definition toml.hpp:16474
int indent_
Definition toml.hpp:9681
const parse_result * result_
Definition toml.hpp:9674
TOML_EXPORTED_MEMBER_FUNCTION void print_indent()
Definition toml.hpp:16450
TOML_PURE_INLINE_GETTER bool multi_line_strings_allowed() const noexcept
Definition toml.hpp:9743
TOML_PURE_INLINE_GETTER size_t indent_columns() const noexcept
Definition toml.hpp:9719
bool naked_newline_
Definition toml.hpp:9682
void indent(int level) noexcept
Definition toml.hpp:9703
void decrease_indent() noexcept
Definition toml.hpp:9713
const formatter_constants * constants_
Definition toml.hpp:9676
TOML_PURE_INLINE_GETTER std::ostream & stream() const noexcept
Definition toml.hpp:9692
TOML_PURE_INLINE_GETTER const node & source() const noexcept
Definition toml.hpp:9686
TOML_EXPORTED_MEMBER_FUNCTION void print_unformatted(char)
Definition toml.hpp:16460
TOML_PURE_INLINE_GETTER bool real_tabs_in_strings_allowed() const noexcept
Definition toml.hpp:9749
TOML_PURE_INLINE_GETTER bool indent_sub_tables() const noexcept
Definition toml.hpp:9731
TOML_EXPORTED_MEMBER_FUNCTION void detach() noexcept
Definition toml.hpp:16434
TOML_EXPORTED_MEMBER_FUNCTION void print_value(const node &, node_type)
Definition toml.hpp:16838
std::ostream * stream_
Definition toml.hpp:9680
TOML_PURE_INLINE_GETTER bool terse_kvps() const noexcept
Definition toml.hpp:9761
TOML_PURE_INLINE_GETTER bool indent_array_elements() const noexcept
Definition toml.hpp:9725
TOML_PURE_INLINE_GETTER bool unicode_strings_allowed() const noexcept
Definition toml.hpp:9755
TOML_EXPORTED_MEMBER_FUNCTION void attach(std::ostream &stream) noexcept
Definition toml.hpp:16426
TOML_PURE_INLINE_GETTER int indent() const noexcept
Definition toml.hpp:9698
TOML_EXPORTED_MEMBER_FUNCTION void print(const value< std::string > &)
Definition toml.hpp:16719
TOML_PURE_INLINE_GETTER bool literal_strings_allowed() const noexcept
Definition toml.hpp:9737
format_flags int_format_mask_
Definition toml.hpp:9679
size_t indent_columns_
Definition toml.hpp:9678
formatter_config config_
Definition toml.hpp:9677
TOML_EXPORTED_MEMBER_FUNCTION void print_newline(bool force=false)
Definition toml.hpp:16440
void increase_indent() noexcept
Definition toml.hpp:9708
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool dump_failed_parse_result()
Definition toml.hpp:16857
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION formatter(const node *, const parse_result *, const formatter_constants &, const formatter_config &) noexcept
Definition toml.hpp:16399
const node * source_
Definition toml.hpp:9672
TOML_NODISCARD toml::table && table() &&noexcept
Definition toml.hpp:9299
TOML_NODISCARD toml::table & table() &noexcept
Definition toml.hpp:9292
TOML_NODISCARD node_view< const node > operator[](const toml::path &path) const noexcept
Definition toml.hpp:9456
TOML_NODISCARD node_view< node > at_path(std::string_view path) noexcept
Definition toml.hpp:9410
TOML_NODISCARD node_view< node > at_path(const toml::path &path) noexcept
Definition toml.hpp:9422
TOML_NODISCARD const toml::table & table() const &noexcept
Definition toml.hpp:9306
TOML_NODISCARD const_table_iterator begin() const noexcept
Definition toml.hpp:9380
TOML_NODISCARD bool failed() const noexcept
Definition toml.hpp:9280
friend std::ostream & operator<<(std::ostream &os, const parse_result &result)
Definition toml.hpp:9491
TOML_NODISCARD_CTOR parse_result(parse_result &&res) noexcept
Definition toml.hpp:9238
TOML_NODISCARD node_view< const node > at_path(const toml::path &path) const noexcept
Definition toml.hpp:9428
TOML_NODISCARD table_iterator end() noexcept
Definition toml.hpp:9392
~parse_result() noexcept
Definition toml.hpp:9268
TOML_NODISCARD_CTOR parse_result(toml::table &&tbl) noexcept
Definition toml.hpp:9224
table_iterator iterator
Definition toml.hpp:9369
TOML_NODISCARD table_iterator begin() noexcept
Definition toml.hpp:9374
const_table_iterator const_iterator
Definition toml.hpp:9371
parse_result & operator=(parse_result &&rhs) noexcept
Definition toml.hpp:9247
TOML_NODISCARD_CTOR parse_result() noexcept
Definition toml.hpp:9217
TOML_NODISCARD node_view< node > operator[](std::string_view key) noexcept
Definition toml.hpp:9462
TOML_NODISCARD const_table_iterator end() const noexcept
Definition toml.hpp:9398
TOML_NODISCARD node_view< const node > operator[](std::string_view key) const noexcept
Definition toml.hpp:9468
TOML_NODISCARD static TOML_ALWAYS_INLINE Type * get_as(storage_t &s) noexcept
Definition toml.hpp:9201
TOML_NODISCARD_CTOR parse_result(parse_error &&err) noexcept
Definition toml.hpp:9231
void destroy() noexcept
Definition toml.hpp:9206
TOML_NODISCARD const_table_iterator cend() const noexcept
Definition toml.hpp:9404
TOML_NODISCARD node_view< node > operator[](const toml::path &path) noexcept
Definition toml.hpp:9450
TOML_NODISCARD parse_error && error() &&noexcept
Definition toml.hpp:9338
TOML_NODISCARD const parse_error & error() const &noexcept
Definition toml.hpp:9345
TOML_NODISCARD node_view< const node > at_path(std::string_view path) const noexcept
Definition toml.hpp:9416
TOML_NODISCARD bool succeeded() const noexcept
Definition toml.hpp:9274
TOML_NODISCARD parse_error & error() &noexcept
Definition toml.hpp:9331
storage_t storage_
Definition toml.hpp:9195
TOML_NODISCARD const_table_iterator cbegin() const noexcept
Definition toml.hpp:9386
std::vector< table * > implicit_tables
Definition toml.hpp:13517
TOML_NODISCARD key make_key(size_t segment_index) const
Definition toml.hpp:15547
optional< parse_error > err
Definition toml.hpp:13528
TOML_NODISCARD node_ptr parse_value_known_prefixes()
Definition toml.hpp:14948
TOML_NODISCARD TOML_NEVER_INLINE date parse_date(bool part_of_datetime=false)
Definition toml.hpp:14732
utf8_buffered_reader reader
Definition toml.hpp:13513
table root
Definition toml.hpp:13514
parser(utf8_reader_interface &&reader_)
Definition toml.hpp:15970
TOML_NODISCARD TOML_NEVER_INLINE bool parse_boolean()
Definition toml.hpp:14192
TOML_NODISCARD TOML_NEVER_INLINE date_time parse_date_time()
Definition toml.hpp:14874
TOML_RETURNS_BY_THROWING void set_error(const T &... reason) const
Definition toml.hpp:13561
size_t nested_values
Definition toml.hpp:13526
TOML_NODISCARD node_ptr parse_value()
Definition toml.hpp:14990
TOML_NODISCARD node_ptr parse_inline_table()
Definition toml.hpp:16082
parse_key_buffer key_buffer
Definition toml.hpp:13521
std::string_view current_scope
Definition toml.hpp:13525
std::string string_buffer
Definition toml.hpp:13522
bool consume_leading_whitespace()
Definition toml.hpp:13627
bool consume_rest_of_line()
Definition toml.hpp:13670
std::string recording_buffer
Definition toml.hpp:13523
void advance()
Definition toml.hpp:13575
TOML_NODISCARD node_ptr parse_array()
Definition toml.hpp:16013
TOML_NODISCARD TOML_NEVER_INLINE double parse_float()
Definition toml.hpp:14247
TOML_NODISCARD TOML_NEVER_INLINE int64_t parse_integer()
Definition toml.hpp:14581
TOML_NODISCARD size_t consume_variable_length_digit_sequence(T *buffer, size_t max_len)
Definition toml.hpp:13761
void go_back(size_t count=1) noexcept
Definition toml.hpp:13566
TOML_NODISCARD bool consume_digit_sequence(T *digits, size_t len)
Definition toml.hpp:13741
TOML_NODISCARD bool consume_expected_sequence(std::u32string_view seq)
Definition toml.hpp:13724
bool recording_whitespace
Definition toml.hpp:13524
source_position prev_pos
Definition toml.hpp:13515
TOML_NEVER_INLINE bool parse_key_value_pair_and_insert(table *tbl)
Definition toml.hpp:15784
void parse_document()
Definition toml.hpp:15883
TOML_NODISCARD TOML_NEVER_INLINE std::string_view parse_basic_string(bool multi_line)
Definition toml.hpp:13781
std::vector< array * > table_arrays
Definition toml.hpp:13520
bool recording
Definition toml.hpp:13524
std::vector< table * > open_inline_tables
Definition toml.hpp:13519
TOML_NODISCARD source_position current_position(source_index fallback_offset=0) const noexcept
Definition toml.hpp:13532
TOML_NODISCARD TOML_NEVER_INLINE time parse_time(bool part_of_datetime=false)
Definition toml.hpp:14786
TOML_NODISCARD TOML_NEVER_INLINE table * parse_table_header()
Definition toml.hpp:15559
static constexpr size_t max_nested_values
Definition toml.hpp:13511
const utf8_codepoint * cp
Definition toml.hpp:13516
TOML_NODISCARD TOML_NEVER_INLINE double parse_inf_or_nan()
Definition toml.hpp:14217
static void update_region_ends(node &nde) noexcept
Definition toml.hpp:15933
TOML_NEVER_INLINE bool parse_key()
Definition toml.hpp:15477
void stop_recording(size_t pop_bytes=0) noexcept
Definition toml.hpp:13609
TOML_NODISCARD TOML_NEVER_INLINE std::string_view parse_literal_string(bool multi_line)
Definition toml.hpp:14023
TOML_RETURNS_BY_THROWING TOML_NEVER_INLINE void set_error_at(source_position pos, const T &... reason) const
Definition toml.hpp:13542
TOML_NODISCARD TOML_NEVER_INLINE parsed_string parse_string()
Definition toml.hpp:14126
bool consume_comment()
Definition toml.hpp:13687
TOML_NODISCARD TOML_NEVER_INLINE std::string_view parse_bare_key_segment()
Definition toml.hpp:14170
TOML_NODISCARD TOML_NEVER_INLINE double parse_hex_float()
Definition toml.hpp:14404
bool consume_line_break()
Definition toml.hpp:13643
void start_recording(bool include_current=true) noexcept
Definition toml.hpp:13598
std::vector< table * > dotted_key_tables
Definition toml.hpp:13518
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component()
static void store_index(size_t index, storage_t &storage_) noexcept
Definition toml.hpp:3057
TOML_NODISCARD size_t & index_ref() noexcept
Definition toml.hpp:3069
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(const path_component &rhs)
void destroy() noexcept
Definition toml.hpp:3062
TOML_NODISCARD std::string & key_ref() noexcept
Definition toml.hpp:3076
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component(const path_component &pc)
TOML_PURE_GETTER const std::string & key() const noexcept
Definition toml.hpp:3150
TOML_PURE_INLINE_GETTER friend bool operator==(const path_component &lhs, const path_component &rhs) noexcept
Definition toml.hpp:3169
~path_component() noexcept
Definition toml.hpp:3131
TOML_PURE_INLINE_GETTER friend bool operator!=(const path_component &lhs, const path_component &rhs) noexcept
Definition toml.hpp:3175
path_component_type type_
Definition toml.hpp:3039
static void store_key(std::string_view key, storage_t &storage_)
Definition toml.hpp:3052
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(std::string_view new_key)
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(size_t new_index) noexcept
storage_t value_storage_
Definition toml.hpp:3037
TOML_PURE_GETTER size_t index() const noexcept
Definition toml.hpp:3137
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component(size_t index) noexcept
TOML_PURE_GETTER static TOML_EXPORTED_STATIC_FUNCTION bool TOML_CALLCONV equal(const path_component &, const path_component &) noexcept
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component(std::string_view key)
TOML_PURE_INLINE_GETTER path_component_type type() const noexcept
Definition toml.hpp:3163
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component(path_component &&pc) noexcept
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(path_component &&rhs) noexcept
static TOML_PURE_INLINE_GETTER Type * get_as(storage_t &s) noexcept
Definition toml.hpp:3047
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator!=(std::string_view lhs, const path &rhs)
Definition toml.hpp:3465
TOML_EXPORTED_MEMBER_FUNCTION void clear() noexcept
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path parent() const
TOML_EXPORTED_MEMBER_FUNCTION path & truncate(size_t n)
TOML_PURE_INLINE_GETTER friend bool operator!=(const path &lhs, const path &rhs) noexcept
Definition toml.hpp:3437
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator!=(const path &lhs, std::string_view rhs)
Definition toml.hpp:3458
std::vector< path_component >::const_iterator const_iterator
Definition toml.hpp:3504
TOML_PURE_INLINE_GETTER friend bool operator==(const path &lhs, const path &rhs) noexcept
Definition toml.hpp:3431
TOML_PURE_INLINE_GETTER const path_component & operator[](size_t index) const noexcept
Definition toml.hpp:3245
TOML_ALWAYS_INLINE friend std::ostream & operator<<(std::ostream &os, const path &rhs)
Definition toml.hpp:3398
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path truncated(size_t n) const
TOML_PURE_INLINE_GETTER iterator end() noexcept
Definition toml.hpp:3513
TOML_ALWAYS_INLINE path & append(std::string_view str)
Definition toml.hpp:3322
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(path &&)
std::vector< path_component >::iterator iterator
Definition toml.hpp:3502
TOML_NODISCARD friend path operator+(const path &lhs, std::string_view rhs)
Definition toml.hpp:3362
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition toml.hpp:3220
TOML_NODISCARD friend path operator+(std::string_view lhs, const path &rhs)
Definition toml.hpp:3370
TOML_EXPORTED_MEMBER_FUNCTION void print_to(std::ostream &) const
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION std::string str() const
TOML_EXPORTED_MEMBER_FUNCTION path & operator+=(path &&)
TOML_NODISCARD_CTOR path() noexcept=default
TOML_PURE_INLINE_GETTER iterator begin() noexcept
Definition toml.hpp:3507
TOML_PURE_GETTER static TOML_EXPORTED_STATIC_FUNCTION bool TOML_CALLCONV equal(const path &, const path &) noexcept
TOML_PURE_INLINE_GETTER const_iterator begin() const noexcept
Definition toml.hpp:3519
path & operator=(path &&) noexcept=default
TOML_PURE_INLINE_GETTER path_component & operator[](size_t index) noexcept
Definition toml.hpp:3238
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(std::string_view)
TOML_ALWAYS_INLINE path & append(const path &p)
Definition toml.hpp:3310
std::vector< path_component > components_
Definition toml.hpp:3185
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(const path &)
TOML_PURE_INLINE_GETTER const_iterator end() const noexcept
Definition toml.hpp:3525
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator==(std::string_view lhs, const path &rhs)
Definition toml.hpp:3451
TOML_PURE_INLINE_GETTER const_iterator cbegin() const noexcept
Definition toml.hpp:3531
TOML_EXPORTED_MEMBER_FUNCTION path & operator+=(const path &)
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition toml.hpp:3232
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path leaf(size_t n=1) const
TOML_ALWAYS_INLINE path & assign(const path &p)
Definition toml.hpp:3266
TOML_PURE_INLINE_GETTER const_iterator cend() const noexcept
Definition toml.hpp:3537
TOML_NODISCARD friend path operator+(const path &lhs, const path &rhs)
Definition toml.hpp:3354
TOML_EXPORTED_MEMBER_FUNCTION path & operator+=(std::string_view)
TOML_ALWAYS_INLINE path & assign(path &&p) noexcept
Definition toml.hpp:3272
TOML_ALWAYS_INLINE path & append(path &&p)
Definition toml.hpp:3316
path & operator=(const path &)=default
TOML_ALWAYS_INLINE path & assign(std::string_view str)
Definition toml.hpp:3278
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path subpath(const_iterator start, const_iterator end) const
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator==(const path &lhs, std::string_view rhs)
Definition toml.hpp:3444
~path() noexcept=default
table_iterator & operator=(const table_iterator &rhs) noexcept
Definition toml.hpp:7523
table_iterator & operator--() noexcept
Definition toml.hpp:7551
TOML_NODISCARD proxy_type * get_proxy() const noexcept
Definition toml.hpp:7485
map_iterator iter_
Definition toml.hpp:7480
table_proxy_pair< IsConst > value_type
Definition toml.hpp:7530
bool proxy_instantiated_
Definition toml.hpp:7482
TOML_NODISCARD_CTOR table_iterator(const table_iterator &other) noexcept
Definition toml.hpp:7519
typename std::iterator_traits< map_iterator >::iterator_category iterator_category
Definition toml.hpp:7534
table_iterator & operator++() noexcept
Definition toml.hpp:7536
std::map< toml::key, node_ptr, std::less<> >::const_iterator const_map_iterator
Definition toml.hpp:7477
TOML_NODISCARD_CTOR table_iterator(const table_iterator< false > &other) noexcept
Definition toml.hpp:7514
table_proxy_pair< IsConst > proxy_type
Definition toml.hpp:7475
TOML_PURE_INLINE_GETTER friend bool operator==(const table_iterator &lhs, const table_iterator &rhs) noexcept
Definition toml.hpp:7592
TOML_NODISCARD_CTOR table_iterator() noexcept=default
value_type * pointer
Definition toml.hpp:7532
table_iterator operator++(int) noexcept
Definition toml.hpp:7543
std::conditional_t< IsConst, const_map_iterator, mutable_map_iterator > map_iterator
Definition toml.hpp:7478
unsigned char proxy_[sizeof(proxy_type)]
Definition toml.hpp:7481
typename std::iterator_traits< map_iterator >::difference_type difference_type
Definition toml.hpp:7533
table_iterator operator--(int) noexcept
Definition toml.hpp:7558
TOML_PURE_INLINE_GETTER pointer operator->() const noexcept
Definition toml.hpp:7573
TOML_NODISCARD_CTOR table_iterator(const_map_iterator iter) noexcept
Definition toml.hpp:7508
TOML_PURE_INLINE_GETTER friend bool operator!=(const table_iterator &lhs, const table_iterator &rhs) noexcept
Definition toml.hpp:7598
TOML_PURE_INLINE_GETTER reference operator*() const noexcept
Definition toml.hpp:7567
value_type & reference
Definition toml.hpp:7531
friend class table_iterator
Definition toml.hpp:7473
std::map< toml::key, node_ptr, std::less<> >::iterator mutable_map_iterator
Definition toml.hpp:7476
TOML_PURE_INLINE_GETTER const_iterator begin() const noexcept
Definition toml.hpp:7992
std:: conditional_t< std::is_void_v< raw_value_type >, impl::emplaced_type_of< ValueArgs &&... >, raw_value_type > value_type
Definition toml.hpp:8365
void insert(Iter begin, Iter end, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:8462
TOML_EXPORTED_MEMBER_FUNCTION table & prune(bool recursive=true) &noexcept
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final
KeyType && key
Definition toml.hpp:8358
typename map_type::const_iterator const_map_iterator
Definition toml.hpp:7632
TOML_CONST_INLINE_GETTER bool is_date_time() const noexcept final
Definition toml.hpp:7766
TOML_NODISCARD const node & at(std::string_view key) const
Definition toml.hpp:7960
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION node & at(std::string_view key)
std::disjunction< can_for_each< Func, Table, table >, can_for_each< Func, Table, array >, can_for_each< Func, Table, std::string >, can_for_each< Func, Table, int64_t >, can_for_each< Func, Table, double >, can_for_each< Func, Table, bool >, can_for_each< Func, Table, date >, can_for_each< Func, Table, time >, can_for_each< Func, Table, date_time > > can_for_each_any
Definition toml.hpp:8042
TOML_CONST_INLINE_GETTER bool is_string() const noexcept final
Definition toml.hpp:7724
TOML_PURE_INLINE_GETTER const node * get(std::string_view key) const noexcept
Definition toml.hpp:7895
TOML_CONST_INLINE_GETTER const toml::value< std::string > * as_string() const noexcept final
Definition toml.hpp:7838
impl::remove_cvref< impl::unwrap_node< value_type > > unwrapped_type
Definition toml.hpp:8383
TOML_CONST_INLINE_GETTER bool is_number() const noexcept final
Definition toml.hpp:7742
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION table() noexcept
iterator erase(const_iterator pos) noexcept
Definition toml.hpp:8311
std::disjunction< std::is_invocable< Func, const key &, for_each_value_ref< T, Table > >, std::is_invocable< Func, for_each_value_ref< T, Table > > > can_for_each
Definition toml.hpp:8027
std::conjunction< for_each_is_nothrow_one< Func, Table, table >, for_each_is_nothrow_one< Func, Table, array >, for_each_is_nothrow_one< Func, Table, std::string >, for_each_is_nothrow_one< Func, Table, int64_t >, for_each_is_nothrow_one< Func, Table, double >, for_each_is_nothrow_one< Func, Table, bool >, for_each_is_nothrow_one< Func, Table, date >, for_each_is_nothrow_one< Func, Table, time >, for_each_is_nothrow_one< Func, Table, date_time > > for_each_is_nothrow
Definition toml.hpp:8057
table && for_each(Func &&visitor) &&noexcept(for_each_is_nothrow< Func &&, table && >::value)
Definition toml.hpp:8180
TOML_CONST_INLINE_GETTER const toml::value< double > * as_floating_point() const noexcept final
Definition toml.hpp:7850
TOML_CONST_INLINE_GETTER toml::value< bool > * as_boolean() noexcept final
Definition toml.hpp:7802
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION node * get(std::string_view key) noexcept
TOML_CONST_INLINE_GETTER const toml::value< int64_t > * as_integer() const noexcept final
Definition toml.hpp:7844
table & for_each(Func &&visitor) &noexcept(for_each_is_nothrow< Func &&, table & >::value)
Definition toml.hpp:8172
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition toml.hpp:8204
TOML_CONST_INLINE_GETTER const toml::value< time > * as_time() const noexcept final
Definition toml.hpp:7868
TOML_PURE_GETTER bool contains(std::string_view key) const noexcept
Definition toml.hpp:8266
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION table(const impl::table_init_pair *, const impl::table_init_pair *)
const table && for_each(Func &&visitor) const &&noexcept(for_each_is_nothrow< Func &&, const table && >::value)
Definition toml.hpp:8196
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION map_iterator get_lower_bound(std::string_view) noexcept
TOML_CONST_INLINE_GETTER bool is_array() const noexcept final
Definition toml.hpp:7706
TOML_CONST_INLINE_GETTER node_type type() const noexcept final
Definition toml.hpp:7671
TOML_CONST_INLINE_GETTER array * as_array() noexcept final
Definition toml.hpp:7778
TOML_EXPORTED_MEMBER_FUNCTION map_iterator insert_with_hint(const_iterator, key &&, impl::node_ptr &&)
iterator erase(const_iterator begin, const_iterator end) noexcept
Definition toml.hpp:8316
TOML_PURE_GETTER bool is_homogeneous() const noexcept
Definition toml.hpp:7690
toml::const_table_iterator const_iterator
Definition toml.hpp:7983
TOML_EXPORTED_MEMBER_FUNCTION table & operator=(table &&rhs) noexcept
map_iterator ipos
Definition toml.hpp:8391
TOML_EXPORTED_MEMBER_FUNCTION size_t erase(std::string_view key) noexcept
TOML_PURE_GETTER impl::wrap_node< T > * get_as(std::string_view key) noexcept
Definition toml.hpp:7921
TOML_EXPORTED_MEMBER_FUNCTION map_iterator erase(const_map_iterator) noexcept
TOML_EXPORTED_MEMBER_FUNCTION void clear() noexcept
bool inline_
Definition toml.hpp:7635
toml::table_iterator iterator
Definition toml.hpp:7981
TOML_NODISCARD node_view< node > operator[](std::string_view key) noexcept
Definition toml.hpp:8568
impl::remove_cvref< ValueType > raw_value_type
Definition toml.hpp:8364
impl::copy_cvref< impl::wrap_node< impl::remove_cvref< impl::unwrap_node< T > > >, Table > for_each_value_ref
Definition toml.hpp:8024
TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible< KeyType && >||impl::is_wide_string< KeyType >), typename ValueType=void, typename KeyType, typename... ValueArgs) std
Definition toml.hpp:8521
TOML_PURE_GETTER const_iterator lower_bound(std::string_view key) const noexcept
Definition toml.hpp:8230
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype) const noexcept final
TOML_CONST_INLINE_GETTER table * as_table() noexcept final
Definition toml.hpp:7772
TOML_EXPORTED_MEMBER_FUNCTION table & operator=(const table &)
TOML_CONST_INLINE_GETTER toml::value< time > * as_time() noexcept final
Definition toml.hpp:7814
TOML_PURE_INLINE_GETTER const_iterator end() const noexcept
Definition toml.hpp:8010
TOML_CONST_INLINE_GETTER const toml::value< date_time > * as_date_time() const noexcept final
Definition toml.hpp:7874
TOML_PURE_INLINE_GETTER iterator begin() noexcept
Definition toml.hpp:7986
TOML_NODISCARD node_view< const node > operator[](std::string_view key) const noexcept
Definition toml.hpp:8574
TOML_CONST_INLINE_GETTER bool is_table() const noexcept final
Definition toml.hpp:7700
TOML_EXPORTED_MEMBER_FUNCTION ~table() noexcept
TOML_CONST_INLINE_GETTER bool is_value() const noexcept final
Definition toml.hpp:7718
TOML_NODISCARD friend bool operator==(const table &lhs, const table &rhs) noexcept
Definition toml.hpp:8604
TOML_CONST_INLINE_GETTER const table * as_table() const noexcept final
Definition toml.hpp:7826
friend std::ostream & operator<<(std::ostream &lhs, const table &rhs)
Definition toml.hpp:8617
TOML_CONST_INLINE_GETTER bool is_boolean() const noexcept final
Definition toml.hpp:7748
TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible< KeyType && >||impl::is_wide_string< KeyType >), typename KeyType, typename ValueType) std
Definition toml.hpp:8421
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION const_iterator find(std::string_view key) const noexcept
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION iterator find(std::string_view key) noexcept
TOML_CONST_INLINE_GETTER toml::value< int64_t > * as_integer() noexcept final
Definition toml.hpp:7790
const table & for_each(Func &&visitor) const &noexcept(for_each_is_nothrow< Func &&, const table & >::value)
Definition toml.hpp:8188
table && prune(bool recursive=true) &&noexcept
Definition toml.hpp:8339
TOML_CONST_INLINE_GETTER bool is_floating_point() const noexcept final
Definition toml.hpp:7736
TOML_PURE_INLINE_GETTER const_iterator cbegin() const noexcept
Definition toml.hpp:7998
TOML_CONST_INLINE_GETTER bool is_date() const noexcept final
Definition toml.hpp:7754
TOML_EXPORTED_MEMBER_FUNCTION map_iterator erase(const_map_iterator, const_map_iterator) noexcept
TOML_PURE_INLINE_GETTER iterator end() noexcept
Definition toml.hpp:8004
TOML_CONST_INLINE_GETTER toml::value< date > * as_date() noexcept final
Definition toml.hpp:7808
std::map< toml::key, impl::node_ptr, std::less<> > map_type
Definition toml.hpp:7629
TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible< KeyType && >||impl::is_wide_string< KeyType >), typename ValueType=void, typename KeyType, typename... ValueArgs) iterator emplace_hint(const_iterator hint
TOML_PURE_INLINE_GETTER bool is_inline() const noexcept
Definition toml.hpp:7880
TOML_CONST_INLINE_GETTER const array * as_array() const noexcept final
Definition toml.hpp:7832
TOML_PURE_GETTER const impl::wrap_node< T > * get_as(std::string_view key) const noexcept
Definition toml.hpp:7929
typename map_type::iterator map_iterator
Definition toml.hpp:7631
KeyType ValueArgs && args
Definition toml.hpp:8359
TOML_NODISCARD friend bool operator!=(const table &lhs, const table &rhs) noexcept
Definition toml.hpp:8610
static void do_for_each(Func &&visitor, Table &&tbl) noexcept(for_each_is_nothrow< Func &&, Table && >::value)
Definition toml.hpp:8068
TOML_CONST_INLINE_GETTER const toml::value< date > * as_date() const noexcept final
Definition toml.hpp:7862
TOML_CONST_INLINE_GETTER toml::value< double > * as_floating_point() noexcept final
Definition toml.hpp:7796
TOML_PURE_GETTER iterator lower_bound(std::string_view key) noexcept
Definition toml.hpp:8224
TOML_CONST_INLINE_GETTER toml::value< date_time > * as_date_time() noexcept final
Definition toml.hpp:7820
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, const node *&first_nonmatch) const noexcept final
TOML_PURE_GETTER bool is_array_of_tables() const noexcept final
Definition toml.hpp:7712
TOML_CONST_INLINE_GETTER bool is_integer() const noexcept final
Definition toml.hpp:7730
TOML_CONST_INLINE_GETTER const toml::value< bool > * as_boolean() const noexcept final
Definition toml.hpp:7856
TOML_PURE_GETTER static TOML_EXPORTED_STATIC_FUNCTION bool TOML_CALLCONV equal(const table &, const table &) noexcept
std::conditional_t< std::is_invocable_v< Func, const key &, for_each_value_ref< T, Table > >, std::is_nothrow_invocable< Func, const key &, for_each_value_ref< T, Table > >, std::conditional_t< std::is_invocable_v< Func, for_each_value_ref< T, Table > >, std::is_nothrow_invocable< Func, for_each_value_ref< T, Table > >, std::false_type > > can_for_each_nothrow
Definition toml.hpp:8031
void is_inline(bool val) noexcept
Definition toml.hpp:7885
std::pair< const toml::key, impl::node_ptr > map_pair
Definition toml.hpp:7630
map_type map_
Definition toml.hpp:7633
TOML_PURE_INLINE_GETTER const_iterator cend() const noexcept
Definition toml.hpp:8016
TOML_CONST_INLINE_GETTER bool is_time() const noexcept final
Definition toml.hpp:7760
TOML_CONST_INLINE_GETTER toml::value< std::string > * as_string() noexcept final
Definition toml.hpp:7784
iterator erase(iterator pos) noexcept
Definition toml.hpp:8306
std::disjunction< std::negation< can_for_each< Func, Table, T > >, can_for_each_nothrow< Func, Table, T > > for_each_is_nothrow_one
Definition toml.hpp:8053
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition toml.hpp:8210
static constexpr size_t history_buffer_size
Definition toml.hpp:12950
struct utf8_buffered_reader::@061365031327232150223023347207336074216106371060 history_
utf8_reader_interface & reader_
Definition toml.hpp:12951
utf8_codepoint buffer[history_buffer_size]
Definition toml.hpp:12954
TOML_PURE_INLINE_GETTER const source_path_ptr & source_path() const noexcept
Definition toml.hpp:12967
TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:12973
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:13027
const utf8_codepoint * head_
Definition toml.hpp:12957
TOML_NODISCARD const utf8_codepoint * step_back(size_t count) noexcept
Definition toml.hpp:13012
TOML_NODISCARD optional< parse_error > && error() noexcept
Definition toml.hpp:13035
static constexpr size_t max_history_length
Definition toml.hpp:12947
TOML_NODISCARD_CTOR utf8_buffered_reader(utf8_reader_interface &reader) noexcept
Definition toml.hpp:12962
TOML_PURE_INLINE_GETTER constexpr bool peek_eof() const noexcept
Definition toml.hpp:12538
TOML_NODISCARD_CTOR constexpr utf8_byte_stream(std::basic_string_view< Char > sv) noexcept
Definition toml.hpp:12511
TOML_CONST_INLINE_GETTER constexpr bool error() const noexcept
Definition toml.hpp:12520
TOML_PURE_INLINE_GETTER constexpr bool eof() const noexcept
Definition toml.hpp:12526
std::basic_string_view< Char > source_
Definition toml.hpp:12506
TOML_PURE_INLINE_GETTER bool eof() const noexcept
Definition toml.hpp:12587
TOML_NODISCARD_CTOR utf8_byte_stream(std::istream &stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:12564
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:12599
TOML_PURE_INLINE_GETTER bool error() const noexcept
Definition toml.hpp:12581
TOML_NODISCARD_CTOR utf8_reader(U &&source, String &&source_path={}) noexcept(std::is_nothrow_constructible_v< utf8_byte_stream< T >, U && >)
Definition toml.hpp:12867
struct utf8_reader::currently_decoding_t currently_decoding_
utf8_byte_stream< T > stream_
Definition toml.hpp:12686
source_position next_pos_
Definition toml.hpp:12687
source_path_ptr source_path_
Definition toml.hpp:12703
optional< parse_error > err_
Definition toml.hpp:12706
impl::utf8_decoder decoder_
Definition toml.hpp:12689
TOML_NODISCARD optional< parse_error > && error() noexcept final
Definition toml.hpp:12914
TOML_PURE_INLINE_GETTER const source_path_ptr & source_path() const noexcept final
Definition toml.hpp:12881
bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:12709
static constexpr size_t block_capacity
Definition toml.hpp:12685
struct utf8_reader::codepoints_t codepoints_
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
Definition toml.hpp:12906
TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
Definition toml.hpp:12887
uint8_t value
static emmc_status_t format(emmc_log_t *log)
Definition emmc_log.c:324
static ActuatorControllerState state
Definition main.cpp:57
static bool ok
Definition flight_e2e.c:435
int32_t p
Definition flight_e2e.c:78
static void start(gnss_frame_parser_t *p, uint8_t byte)
Definition gnss_frame.c:45
static const idle_config_t config
Definition idle_task.c:17
typename Container::iterator iterator
Definition json.hpp:19038
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
Definition json.hpp:13878
*brief append another JSON pointer at the end of this JSON pointer *sa ptr reference_tokens begin()
typename Container::const_iterator const_iterator
Definition json.hpp:19039
*brief create JSON pointer *sa reference_tokens const string_t & a
Definition json.hpp:13877
std::pair< iterator, bool > insert(value_type &&value)
Definition json.hpp:19328
*brief compares two JSON pointer for less than friend bool operator<(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
Definition json.hpp:14786
json_pointer res
Definition json.hpp:13957
size_type count(const key_type &key) const
Definition json.hpp:19264
*brief remove last reference token *sa JSON pointer has no parent
Definition json.hpp:13968
bool contains(const BasicJsonType *ptr) const
Definition json.hpp:14383
*brief create JSON pointer *sa reference_tokens end()
typename Container::value_type value_type
Definition json.hpp:19041
*brief compares two JSON pointers for inequality *sa RefStringTypeRhs friend bool operator!=(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
static BasicJsonType::size_type array_index(const string_t &s)
Definition json.hpp:14019
*brief write string representation of the JSON pointer to stream *sa const json_pointer & ptr
Definition json.hpp:13895
std::pair< iterator, bool > emplace(const key_type &key, T &&t)
Definition json.hpp:19058
T & operator[](const key_type &key)
Definition json.hpp:19086
T & at(const key_type &key)
Definition json.hpp:19110
*brief compares two JSON pointers for equality *sa RefStringTypeRhs friend bool operator==(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
*brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer *sa const json_pointer & rhs
Definition json.hpp:13930
json_pointer result
Definition json.hpp:14064
size_type erase(const key_type &key)
Definition json.hpp:19166
static void flatten(const string_t &reference_string, const BasicJsonType &value, BasicJsonType &result)
Definition json.hpp:14540
const uint8_t * get()
@ error
throw a parse_error exception in case of a tag
Definition json.hpp:9186
@ string
string value
Definition json.hpp:2877
@ array
array (ordered collection of values)
Definition json.hpp:2876
List[Optional[float]] out(Iterable[float] values, Optional[int] digits=None)
Definition ladder.py:67
np.ndarray arr(Optional[Iterable[Any]] values, Optional[int] n=None)
Definition ladder.py:51
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474
float B
Definition lqr_motor.py:17
float T
Definition lqr_motor.py:40
STL namespace.
*brief exchanges the values of two JSON objects *sa nlohmann::NLOHMANN_BASIC_JSON_TPL &j2 noexcept(is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
Definition json.hpp:24537
Table2D table(fn, x=(0.0, 1.0, 5), y=(0.0, 2.0, 4))
dict[str, object] node(str nid, str ctype, str label, **object data)
Definition test_pid.py:57
node_ptr value
Definition toml.hpp:6227
TOML_NODISCARD_CTOR array_init_elem(T &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:6231
std::add_const_t< Dest > type
Definition toml.hpp:1718
std::add_cv_t< Dest > type
Definition toml.hpp:1730
std::add_volatile_t< Dest > type
Definition toml.hpp:1724
Dest type
Definition toml.hpp:1712
std::add_lvalue_reference_t< Dest > type
Definition toml.hpp:1695
std::add_rvalue_reference_t< Dest > type
Definition toml.hpp:1701
Dest type
Definition toml.hpp:1689
TOML_NODISCARD_CTOR constexpr date_time(const toml::date &d) noexcept
Definition toml.hpp:2867
toml::date date
Definition toml.hpp:2850
TOML_PURE_INLINE_GETTER friend constexpr bool operator>(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:2928
TOML_PURE_INLINE_GETTER friend constexpr bool operator!=(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:2902
TOML_PURE_GETTER friend constexpr bool operator==(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:2894
toml::time time
Definition toml.hpp:2852
TOML_PURE_GETTER friend constexpr bool operator<(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:2908
TOML_PURE_GETTER friend constexpr bool operator<=(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:2918
TOML_NODISCARD_CTOR date_time() noexcept=default
TOML_PURE_INLINE_GETTER constexpr bool is_local() const noexcept
Definition toml.hpp:2888
TOML_PURE_INLINE_GETTER friend constexpr bool operator>=(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:2934
friend std::ostream & operator<<(std::ostream &lhs, const date_time &rhs)
Definition toml.hpp:2939
TOML_NODISCARD_CTOR constexpr date_time(const toml::date &d, const toml::time &t, const toml::time_offset &off) noexcept
Definition toml.hpp:2881
optional< toml::time_offset > offset
Definition toml.hpp:2854
TOML_NODISCARD_CTOR constexpr date_time(const toml::time &t) noexcept
Definition toml.hpp:2874
static constexpr auto type
Definition toml.hpp:1767
static constexpr bool can_represent_native
Definition toml.hpp:1765
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1764
static constexpr bool can_partially_represent_native
Definition toml.hpp:1766
static constexpr bool is_native
Definition toml.hpp:1763
~depth_counter_scope() noexcept
Definition toml.hpp:13364
TOML_DELETE_DEFAULTS(depth_counter_scope)
TOML_NODISCARD_CTOR depth_counter_scope(size_t &depth) noexcept
Definition toml.hpp:13358
std::conditional_t< is_one_of< T, node, node_view< node >, node_view< const node > >, void, typename inserted_type_of_< T >::type > type
Definition toml.hpp:5983
typename emplaced_type_of_< remove_cvref< T > >::type type
Definition toml.hpp:5991
void append(const T &arg) noexcept
Definition toml.hpp:13261
char buf[buf_size]
Definition toml.hpp:13248
static constexpr std::size_t buf_size
Definition toml.hpp:13247
TOML_NODISCARD_CTOR error_builder(std::string_view scope) noexcept
Definition toml.hpp:13253
TOML_DELETE_DEFAULTS(error_builder)
TOML_RETURNS_BY_THROWING auto finish(const source_position &pos, const source_path_ptr &source_path) const
Definition toml.hpp:13267
char *const max_write_pos
Definition toml.hpp:13250
char * write_pos
Definition toml.hpp:13249
const utf8_codepoint & cp
Definition toml.hpp:13153
static constexpr int bits
Definition toml.hpp:1920
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1924
double native_type
Definition toml.hpp:1916
static constexpr bool can_represent_native
Definition toml.hpp:1928
static constexpr bool is_signed
Definition toml.hpp:1918
static constexpr int digits10
Definition toml.hpp:1922
static constexpr auto type
Definition toml.hpp:1915
static constexpr bool is_native
Definition toml.hpp:1917
static constexpr int digits
Definition toml.hpp:1921
static constexpr bool can_partially_represent_native
Definition toml.hpp:1931
std::string_view indent
Definition toml.hpp:9666
format_flags flags
Definition toml.hpp:9665
typename inserted_type_of_< remove_cvref< T > >::type type
Definition toml.hpp:5958
static constexpr T max
Definition toml.hpp:1812
static constexpr T min
Definition toml.hpp:1811
static constexpr auto type
Definition toml.hpp:1820
static constexpr bool is_signed
Definition toml.hpp:1819
static constexpr bool is_native
Definition toml.hpp:1818
int64_t native_type
Definition toml.hpp:1817
static constexpr bool can_partially_represent_native
Definition toml.hpp:1821
TOML_NODISCARD static TOML_ALWAYS_INLINE U && make(U &&val) noexcept
Definition toml.hpp:4838
static constexpr bool is_native
Definition toml.hpp:2067
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:2068
static constexpr bool can_partially_represent_native
Definition toml.hpp:2070
static constexpr auto type
Definition toml.hpp:2071
static constexpr bool can_represent_native
Definition toml.hpp:2069
static constexpr auto value
Definition toml.hpp:2201
static constexpr auto value
Definition toml.hpp:2196
static constexpr auto value
Definition toml.hpp:2206
static constexpr auto value
Definition toml.hpp:2191
std::add_const_t< T > type
Definition toml.hpp:2173
std::add_volatile_t< std::add_const_t< T > > type
Definition toml.hpp:2183
std::add_volatile_t< T > type
Definition toml.hpp:2178
value< bool > type
Definition toml.hpp:2139
std::add_const_t< typename node_wrapper< T >::type > type
Definition toml.hpp:2109
std::add_const_t< std::add_volatile_t< typename node_wrapper< T >::type > > type
Definition toml.hpp:2119
value< date > type
Definition toml.hpp:2144
value< date_time > type
Definition toml.hpp:2154
value< double > type
Definition toml.hpp:2134
value< int64_t > type
Definition toml.hpp:2129
value< std::string > type
Definition toml.hpp:2124
value< time > type
Definition toml.hpp:2149
std::add_volatile_t< typename node_wrapper< T >::type > type
Definition toml.hpp:2114
static constexpr auto full_prefix
Definition toml.hpp:13093
static constexpr auto scope_qualifier
Definition toml.hpp:13089
static constexpr auto is_signed
Definition toml.hpp:13091
static constexpr auto is_digit
Definition toml.hpp:13090
static constexpr auto max_digits
Definition toml.hpp:13092
static constexpr auto max_digits
Definition toml.hpp:13101
static constexpr auto is_signed
Definition toml.hpp:13100
static constexpr auto full_prefix
Definition toml.hpp:13104
static constexpr auto scope_qualifier
Definition toml.hpp:13098
static constexpr auto prefix
Definition toml.hpp:13103
static constexpr auto is_digit
Definition toml.hpp:13099
static constexpr auto prefix_codepoint
Definition toml.hpp:13102
static constexpr auto prefix
Definition toml.hpp:13072
static constexpr auto full_prefix
Definition toml.hpp:13073
static constexpr auto is_digit
Definition toml.hpp:13068
static constexpr auto prefix_codepoint
Definition toml.hpp:13071
static constexpr auto is_signed
Definition toml.hpp:13069
static constexpr auto scope_qualifier
Definition toml.hpp:13067
static constexpr auto max_digits
Definition toml.hpp:13070
static constexpr auto max_digits
Definition toml.hpp:13081
static constexpr auto prefix_codepoint
Definition toml.hpp:13082
static constexpr auto is_signed
Definition toml.hpp:13080
static constexpr auto prefix
Definition toml.hpp:13083
static constexpr auto is_digit
Definition toml.hpp:13079
static constexpr auto scope_qualifier
Definition toml.hpp:13078
static constexpr auto full_prefix
Definition toml.hpp:13084
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition toml.hpp:13347
std::vector< std::pair< size_t, size_t > > segments
Definition toml.hpp:13308
std::vector< source_position > starts
Definition toml.hpp:13309
std::vector< source_position > ends
Definition toml.hpp:13310
TOML_PURE_INLINE_GETTER std::string_view back() const noexcept
Definition toml.hpp:13335
void clear() noexcept
Definition toml.hpp:13312
void push_back(std::string_view segment, source_position b, source_position e)
Definition toml.hpp:13320
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition toml.hpp:13341
std::string buffer
Definition toml.hpp:13307
TOML_PURE_INLINE_GETTER std::string_view operator[](size_t i) const noexcept
Definition toml.hpp:13329
unsigned char bytes[size]
Definition toml.hpp:9192
static constexpr size_t align
Definition toml.hpp:9189
static constexpr size_t size
Definition toml.hpp:9187
TOML_DELETE_DEFAULTS(parse_scope)
std::string_view parent_
Definition toml.hpp:13284
~parse_scope() noexcept
Definition toml.hpp:13294
TOML_NODISCARD_CTOR parse_scope(std::string_view &current_scope, std::string_view new_scope) noexcept
Definition toml.hpp:13287
std::string_view & storage_
Definition toml.hpp:13283
std::string_view value
Definition toml.hpp:13374
bool was_multi_line
Definition toml.hpp:13375
unsigned char bytes[size]
Definition toml.hpp:3035
static constexpr size_t align
Definition toml.hpp:3032
static constexpr size_t size
Definition toml.hpp:3030
static constexpr bool can_represent_native
Definition toml.hpp:1837
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1834
TOML_PURE_GETTER friend constexpr bool operator>=(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2565
TOML_PURE_INLINE_GETTER friend constexpr bool operator!=(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2531
source_index line
Definition toml.hpp:2512
source_index column
Definition toml.hpp:2514
TOML_PURE_GETTER friend constexpr bool operator==(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2524
static TOML_PURE_GETTER constexpr uint64_t pack(const source_position &pos) noexcept
Definition toml.hpp:2539
TOML_PURE_GETTER friend constexpr bool operator>(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2559
TOML_PURE_GETTER friend constexpr bool operator<(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2547
TOML_PURE_GETTER friend constexpr bool operator<=(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2553
friend std::ostream & operator<<(std::ostream &lhs, const source_position &rhs)
Definition toml.hpp:2570
source_path_ptr path
Definition toml.hpp:2583
friend std::ostream & operator<<(std::ostream &lhs, const source_region &rhs)
Definition toml.hpp:2597
source_position end
Definition toml.hpp:2581
source_position begin
Definition toml.hpp:2579
static constexpr auto type
Definition toml.hpp:1987
static constexpr bool is_native
Definition toml.hpp:1982
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1983
static constexpr bool can_partially_represent_native
Definition toml.hpp:1986
std::string native_type
Definition toml.hpp:1981
static constexpr bool can_represent_native
Definition toml.hpp:1984
node_ptr value
Definition toml.hpp:7607
TOML_NODISCARD_CTOR table_init_pair(K &&k, V &&v, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7611
toml::key key
Definition toml.hpp:7606
std::vector< table * > & tables
Definition toml.hpp:13380
~table_vector_scope() noexcept
Definition toml.hpp:13389
TOML_DELETE_DEFAULTS(table_vector_scope)
TOML_NODISCARD_CTOR table_vector_scope(std::vector< table * > &tables_, table &tbl)
Definition toml.hpp:13383
TOML_PURE_INLINE_GETTER friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2822
friend std::ostream & operator<<(std::ostream &lhs, const time_offset &rhs)
Definition toml.hpp:2839
TOML_PURE_INLINE_GETTER friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2828
TOML_PURE_INLINE_GETTER friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2816
TOML_PURE_INLINE_GETTER friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2834
int16_t minutes
Definition toml.hpp:2790
TOML_PURE_INLINE_GETTER friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2804
TOML_PURE_INLINE_GETTER friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2810
TOML_NODISCARD_CTOR time_offset() noexcept=default
uint8_t minute
Definition toml.hpp:2709
TOML_CONSTRAINED_TEMPLATE((impl::all_integral< H, M, S, NS >), typename H, typename M, typename S=uint8_t, typename NS=uint32_t) TOML_NODISCARD_CTOR const expr time(H h
M S s
Definition toml.hpp:2724
M m
Definition toml.hpp:2724
uint32_t nanosecond
Definition toml.hpp:2713
uint8_t hour
Definition toml.hpp:2707
uint8_t second
Definition toml.hpp:2711
TOML_NODISCARD_CTOR time() noexcept=default
std::underlying_type_t< T > type
Definition toml.hpp:1748
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1826
static constexpr bool can_represent_native
Definition toml.hpp:1828
TOML_PURE_INLINE_GETTER constexpr const char32_t & operator*() const noexcept
Definition toml.hpp:12629
source_position position
Definition toml.hpp:12620
char32_t value
Definition toml.hpp:12617
char bytes[4]
Definition toml.hpp:12618
TOML_OVERALIGNED utf8_codepoint buffer[block_capacity]
Definition toml.hpp:12698
virtual TOML_NODISCARD optional< parse_error > && error() noexcept=0
virtual TOML_NODISCARD const source_path_ptr & source_path() const noexcept=0
virtual ~utf8_reader_interface() noexcept=default
virtual TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)=0
virtual TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)=0
value_traits< underlying_type< T > > type
Definition toml.hpp:1785
default_value_traits type
Definition toml.hpp:1778
static boot_report_t r
static void make(uint8_t *out, uint64_t ts, uint8_t type, uint16_t sensor, float ref)
static bool has_error(const Config &c, const std::string &needle)
Definition test_t7.cpp:39
enum TOML_OPEN_FLAGS_ENUM format_as_hexadecimal
Definition toml.hpp:1609
typename underlying_type_< T >::type underlying_type
Definition toml.hpp:1756
#define TOML_ANON_NAMESPACE_END
Definition toml.hpp:1209
#define TOML_PARSER_TYPENAME
Definition toml.hpp:1558
#define TOML_UNUSED(...)
Definition toml.hpp:628
#define TOML_NODISCARD_CTOR
Definition toml.hpp:471
toml_formatter default_formatter
Definition toml.hpp:1648
constexpr bool is_constructible_or_convertible
Definition toml.hpp:2212
constexpr bool is_native
Definition toml.hpp:2090
enum TOML_OPEN_FLAGS_ENUM value_flags
Definition toml.hpp:1604
constexpr size_t charconv_buffer_length< int16_t >
Definition toml.hpp:10269
#define TOML_TRIVIAL_ABI
Definition toml.hpp:455
#define TOML_DISABLE_ARITHMETIC_WARNINGS
Definition toml.hpp:888
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE
Definition toml.hpp:1036
constexpr size_t charconv_buffer_length< uint8_t >
Definition toml.hpp:10278
#define TOML_LIFETIME_HOOKS
Definition toml.hpp:1081
#define POXY_IMPLEMENTATION_DETAIL(...)
Definition toml.hpp:658
constexpr bool value_retrieval_is_nothrow
Definition toml.hpp:1674
#define TOML_UNLIKELY(...)
Definition toml.hpp:563
#define TOML_ABI_NAMESPACE_BOOL(cond, T, F)
Definition toml.hpp:1195
#define TOML_SA_LIST_BEG
Definition toml.hpp:1240
#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST
Definition toml.hpp:1269
constexpr bool is_number
Definition toml.hpp:2244
#define TOML_EMPTY_BASES
Definition toml.hpp:449
#define TOML_RETURNS_BY_THROWING
Definition toml.hpp:13048
#define TOML_LIKELY(...)
Definition toml.hpp:550
enum TOML_OPEN_FLAGS_ENUM format_as_octal
Definition toml.hpp:1608
enum TOML_CLOSED_FLAGS_ENUM allow_multi_line_strings
Definition toml.hpp:1622
enum TOML_CLOSED_FLAGS_ENUM quote_dates_and_times
Definition toml.hpp:1619
#define TOML_PUSH_WARNINGS
Definition toml.hpp:873
#define TOML_CONSTRAINED_TEMPLATE(condition,...)
Definition toml.hpp:1135
#define TOML_SA_NODE_TYPE_LIST
Definition toml.hpp:1257
#define TOML_CALLCONV
Definition toml.hpp:1055
TOML_PURE_GETTER fp_class fpclassify(const double &val) noexcept
Definition toml.hpp:2301
constexpr node_type node_type_of
Definition toml.hpp:2209
#define TOML_ABI_NAMESPACE_END
Definition toml.hpp:1196
enum TOML_CLOSED_FLAGS_ENUM allow_unicode_strings
Definition toml.hpp:1624
#define TOML_NEVER_INLINE
Definition toml.hpp:444
#define TOML_INTERNAL_LINKAGE
Definition toml.hpp:1212
TOML_PURE_GETTER auto find(Iterator start, Iterator end, const T &needle) noexcept -> decltype(&(*start))
Definition toml.hpp:2324
typename value_traits< T >::native_type native_type_of
Definition toml.hpp:2088
#define set_error_and_return_if_eof(...)
Definition toml.hpp:13475
constexpr size_t charconv_buffer_length< int64_t >
Definition toml.hpp:10275
std::common_type_t< std::make_signed_t< T >... > common_signed_type
Definition toml.hpp:1658
#define TOML_CLOSED_ENUM
Definition toml.hpp:582
#define TOML_EXPORTED_CLASS
Definition toml.hpp:967
constexpr bool is_boolean
Definition toml.hpp:2247
enum TOML_CLOSED_FLAGS_ENUM allow_real_tabs_in_strings
Definition toml.hpp:1623
TOML_EXPORTED_FREE_FUNCTION void TOML_CALLCONV print_to_stream(std::ostream &, std::string_view)
#define TOML_UNLIKELY_CASE
Definition toml.hpp:566
constexpr bool is_floating_point
Definition toml.hpp:2239
constexpr bool is_date
Definition toml.hpp:2252
constexpr bool can_partially_represent_native
Definition toml.hpp:2094
constexpr bool is_key
Definition toml.hpp:7420
#define TOML_EXTERNAL_LINKAGE
Definition toml.hpp:1211
TOML_NODISCARD node_ptr make_node(T &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:5969
#define TOML_UNREACHABLE
Definition toml.hpp:540
typename node_wrapper< std::remove_reference_t< T > >::type wrap_node
Definition toml.hpp:2157
#define set_error_and_return_default(...)
Definition toml.hpp:13473
#define TOML_DISABLE_WARNINGS
Definition toml.hpp:894
TOML_NODISCARD TOML_EXPORTED_FREE_FUNCTION parse_result TOML_CALLCONV parse_file(std::string_view file_path)
Definition toml.hpp:16288
#define TOML_NODISCARD
Definition toml.hpp:464
enum TOML_CLOSED_FLAGS_ENUM allow_octal_integers
Definition toml.hpp:1626
#define TOML_ANON_NAMESPACE_START
Definition toml.hpp:1208
#define TOML_LAUNDER(x)
Definition toml.hpp:1310
#define TOML_DISABLE_SWITCH_WARNINGS
Definition toml.hpp:879
TOML_PURE_GETTER bool is_ascii(const char *str, size_t len) noexcept
typename copy_cv_< Dest, Src >::type copy_cv
Definition toml.hpp:1707
enum TOML_CLOSED_FLAGS_ENUM allow_binary_integers
Definition toml.hpp:1625
constexpr bool is_string
Definition toml.hpp:2229
#define return_if_error_or_eof(...)
Definition toml.hpp:13436
#define is_error()
Definition toml.hpp:13426
#define TOML_CONST_GETTER
Definition toml.hpp:510
#define TOML_LANG_UNRELEASED
Definition toml.hpp:1180
#define TOML_SA_LIST_END
Definition toml.hpp:1241
#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS
Definition toml.hpp:882
constexpr std::string_view control_char_escapes[]
Definition toml.hpp:1500
TOML_NODISCARD TOML_EXPORTED_FREE_FUNCTION parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path={})
Definition toml.hpp:16264
TOML_INTERNAL_LINKAGE void print_floating_point_to_stream(std::ostream &stream, T val, value_flags format, bool relaxed_precision)
Definition toml.hpp:10384
#define TOML_COMPILER_HAS_EXCEPTIONS
Definition toml.hpp:359
constexpr bool is_array
Definition toml.hpp:2223
constexpr bool first_is_same
Definition toml.hpp:1741
#define TOML_ENV_MESSAGE
Definition toml.hpp:1408
constexpr size_t charconv_buffer_length< uint16_t >
Definition toml.hpp:10281
#define TOML_OVERALIGNED
Definition toml.hpp:12678
constexpr bool all_integral
Definition toml.hpp:1664
#define utf8_reader_error(...)
Definition toml.hpp:12663
utf8_reader(std::basic_string_view< Char >, std::string_view) -> utf8_reader< std::basic_string_view< Char > >
TOML_PURE_GETTER TOML_INTERNAL_LINKAGE std::string_view to_sv(node_type val) noexcept
Definition toml.hpp:13109
enum TOML_CLOSED_FLAGS_ENUM quote_infinities_and_nans
Definition toml.hpp:1620
constexpr bool is_chronological
Definition toml.hpp:2267
constexpr bool is_date_time
Definition toml.hpp:2262
enum TOML_CLOSED_FLAGS_ENUM allow_hexadecimal_integers
Definition toml.hpp:1627
#define TOML_PARSE_FILE_ERROR(msg, path)
constexpr bool is_one_of
Definition toml.hpp:1661
constexpr size_t charconv_buffer_length< int8_t >
Definition toml.hpp:10266
typename emplaced_type_of_< remove_cvref< T >... >::type emplaced_type_of
Definition toml.hpp:5995
#define TOML_EXPORTED_STATIC_FUNCTION
Definition toml.hpp:973
#define TOML_POP_WARNINGS
Definition toml.hpp:891
#define return_if_error(...)
Definition toml.hpp:13429
enum TOML_CLOSED_FLAGS_ENUM allow_literal_strings
Definition toml.hpp:1621
TOML_NODISCARD bool TOML_CALLCONV parse_path(std::string_view, void *, parse_path_callback< std::string_view >, parse_path_callback< size_t >)
constexpr bool is_integer
Definition toml.hpp:2234
#define TOML_ASSERT(expr)
Definition toml.hpp:1094
TOML_CONST_GETTER optional< T > node_integer_cast(int64_t val) noexcept
Definition toml.hpp:4908
constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:2096
#define return_after_error(...)
Definition toml.hpp:13427
TOML_NODISCARD TOML_EXPORTED_FREE_FUNCTION node_view< const node > TOML_CALLCONV at_path(const node &root, std::string_view path) noexcept
std::shared_ptr< const std::string > source_path_ptr
Definition toml.hpp:2508
constexpr bool always_false
Definition toml.hpp:1738
#define TOML_EXCEPTIONS
Definition toml.hpp:1050
#define TOML_PURE_GETTER
Definition toml.hpp:499
enum TOML_CLOSED_FLAGS_ENUM terse_key_value_pairs
Definition toml.hpp:1632
#define TOML_ENABLE_WINDOWS_COMPAT
Definition toml.hpp:1020
constexpr bool is_natively_one_of
Definition toml.hpp:2098
#define TOML_ABI_NAMESPACE_START(name)
Definition toml.hpp:1194
#define TOML_LIKELY_CASE
Definition toml.hpp:553
#define push_parse_scope(scope)
Definition toml.hpp:13303
constexpr bool is_cvref
Definition toml.hpp:1667
#define utf8_reader_error_check(...)
Definition toml.hpp:12665
constexpr size_t charconv_buffer_length< uint32_t >
Definition toml.hpp:10284
#define TOML_ASSERT_ASSUME(expr)
Definition toml.hpp:1099
#define TOML_NAMESPACE_START
Definition toml.hpp:1191
#define TOML_MAX_NESTED_VALUES
Definition toml.hpp:1063
#define assert_not_error()
Definition toml.hpp:13428
constexpr size_t charconv_buffer_length< int32_t >
Definition toml.hpp:10272
POXY_IMPLEMENTATION_DETAIL(impl::table_iterator< true >) const_table_iterator
Definition toml.hpp:7623
#define TOML_OPEN_FLAGS_ENUM
Definition toml.hpp:586
#define advance_and_return_if_error_or_eof(...)
Definition toml.hpp:13492
constexpr bool is_container
Definition toml.hpp:2226
constexpr size_t charconv_buffer_length< uint64_t >
Definition toml.hpp:10287
#define TOML_PRAGMA_CLANG(decl)
Definition toml.hpp:384
#define TOML_NAMESPACE_END
Definition toml.hpp:1192
#define TOML_SA_LIST_NEW
Definition toml.hpp:1242
#define TOML_SA_LIST_NXT
Definition toml.hpp:1243
#define TOML_CLOSED_FLAGS_ENUM
Definition toml.hpp:587
constexpr value_flags preserve_source_value_flags
Definition toml.hpp:1613
#define TOML_HIDDEN_CONSTRAINT(condition,...)
Definition toml.hpp:1138
#define TOML_ATTR(...)
Definition toml.hpp:341
enum TOML_CLOSED_FLAGS_ENUM relaxed_float_precision
Definition toml.hpp:1631
#define TOML_PURE_INLINE_GETTER
Definition toml.hpp:504
enum TOML_OPEN_FLAGS_ENUM format_as_binary
Definition toml.hpp:1607
#define TOML_ALWAYS_INLINE
Definition toml.hpp:430
#define TOML_IMPL_NAMESPACE_END
Definition toml.hpp:1206
constexpr bool is_node_view
Definition toml.hpp:2277
#define TOML_DISABLE_SPAM_WARNINGS
Definition toml.hpp:885
enum TOML_CLOSED_FLAGS_ENUM format_flags
Definition toml.hpp:1616
#define TOML_EXPORTED_FREE_FUNCTION
Definition toml.hpp:976
#define parse_error_break()
Definition toml.hpp:13461
#define utf8_buffered_reader_error_check(...)
Definition toml.hpp:12934
node_view(const T &) -> node_view< const node >
#define TOML_IMPL_NAMESPACE_START
Definition toml.hpp:1205
#define is_eof()
Definition toml.hpp:13409
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS,...)
Definition toml.hpp:636
#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg)
Definition toml.hpp:4791
#define advance_and_return_if_error(...)
Definition toml.hpp:13483
constexpr size_t charconv_buffer_length< double >
Definition toml.hpp:10293
#define assert_not_eof()
Definition toml.hpp:13410
#define TOML_CONST_INLINE_GETTER
Definition toml.hpp:515
#define TOML_ENABLE_WARNINGS
Definition toml.hpp:897
constexpr bool can_represent_native
Definition toml.hpp:2092
constexpr bool is_node
Definition toml.hpp:2273
TOML_INTERNAL_LINKAGE constexpr auto utf8_byte_order_mark
Definition toml.hpp:12498
value(T) -> value< impl::native_type_of< impl::remove_cvref< T > > >
constexpr size_t charconv_buffer_length< float >
Definition toml.hpp:10290
std::basic_ostream< Char > & operator<<(std::basic_ostream< Char > &lhs, node_type rhs)
Definition toml.hpp:1589
#define TOML_EXPORTED_MEMBER_FUNCTION
Definition toml.hpp:970
TOML_INTERNAL_LINKAGE void print_integer_to_stream(std::ostream &stream, T val, value_flags format={}, size_t min_digits=0)
Definition toml.hpp:10297
enum TOML_CLOSED_FLAGS_ENUM indent_sub_tables
Definition toml.hpp:1628
copy_ref< copy_ref< copy_cv< std::remove_reference_t< Dest >, std::remove_reference_t< Src > >, Dest >, Src > copy_cvref
Definition toml.hpp:1734
POXY_IMPLEMENTATION_DETAIL(impl::array_iterator< true >) const_array_iterator
Definition toml.hpp:6242
#define TOML_SA_NATIVE_VALUE_TYPE_LIST
Definition toml.hpp:1247
constexpr bool is_time
Definition toml.hpp:2257
typename node_unwrapper< std::remove_reference_t< T > >::type unwrap_node
Definition toml.hpp:2186
enum TOML_CLOSED_FLAGS_ENUM indentation
Definition toml.hpp:1630
inserter(T &&) -> inserter< T && >
constexpr bool is_key_or_convertible
Definition toml.hpp:7423
#define TOML_MAKE_FLAGS(T)
Definition toml.hpp:626
#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg)
Definition toml.hpp:4772
enum TOML_CLOSED_FLAGS_ENUM indent_array_elements
Definition toml.hpp:1629
#define TOML_SA_LIST_SEP
Definition toml.hpp:1239
TOML_INTERNAL_LINKAGE void concatenate(char *&write_pos, char *const buf_end, const T &arg) noexcept
Definition toml.hpp:13159
constexpr std::string_view node_type_friendly_names[]
Definition toml.hpp:1536
constexpr bool is_wide_string
Definition toml.hpp:1670
#define utf8_reader_return_after_error(...)
Definition toml.hpp:12664
#define TOML_ASSUME(expr)
Definition toml.hpp:531
constexpr bool is_value
Definition toml.hpp:2270
typename copy_ref_< Dest, Src >::type copy_ref
Definition toml.hpp:1684
void print_to_stream_bookended(std::ostream &stream, const T &val, const U &bookend)
Definition toml.hpp:2473
#define TOML_ABSTRACT_INTERFACE
Definition toml.hpp:448