ESBMC
Efficient SMT-based Context-Bounded Model Checker
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) \
100 (((major)*10000) + ((minor)*100) + ((patch)))
101#endif
102
103#ifndef TOML_INTELLISENSE
104# ifdef __INTELLISENSE__
105# define TOML_INTELLISENSE 1
106# else
107# define TOML_INTELLISENSE 0
108# endif
109#endif
110
111#ifndef TOML_DOXYGEN
112# if defined(DOXYGEN) || defined(__DOXYGEN) || defined(__DOXYGEN__) || \
113 defined(__doxygen__) || defined(__POXY__) || defined(__poxy__)
114# define TOML_DOXYGEN 1
115# else
116# define TOML_DOXYGEN 0
117# endif
118#endif
119
120#ifndef TOML_CLANG
121# ifdef __clang__
122# define TOML_CLANG __clang_major__
123# else
124# define TOML_CLANG 0
125# endif
126
127// special handling for apple clang; see:
128// - https://github.com/marzer/tomlplusplus/issues/189
129// - https://en.wikipedia.org/wiki/Xcode
130// -
131// https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time
132# if TOML_CLANG && defined(__apple_build_version__)
133# undef TOML_CLANG
134# define TOML_CLANG_VERSION \
135 TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
136# if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0)
137# define TOML_CLANG 16
138# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0)
139# define TOML_CLANG 15
140# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0)
141# define TOML_CLANG 14
142# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6)
143# define TOML_CLANG 13
144# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0)
145# define TOML_CLANG 12
146# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5)
147# define TOML_CLANG 11
148# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0)
149# define TOML_CLANG 10
150# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3)
151# define TOML_CLANG 9
152# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0)
153# define TOML_CLANG 8
154# elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1)
155# define TOML_CLANG 7
156# else
157# define TOML_CLANG 6 // not strictly correct but doesn't matter below this
158# endif
159# undef TOML_CLANG_VERSION
160# endif
161#endif
162
163#ifndef TOML_ICC
164# ifdef __INTEL_COMPILER
165# define TOML_ICC __INTEL_COMPILER
166# ifdef __ICL
167# define TOML_ICC_CL TOML_ICC
168# else
169# define TOML_ICC_CL 0
170# endif
171# else
172# define TOML_ICC 0
173# define TOML_ICC_CL 0
174# endif
175#endif
176
177#ifndef TOML_MSVC_LIKE
178# ifdef _MSC_VER
179# define TOML_MSVC_LIKE _MSC_VER
180# else
181# define TOML_MSVC_LIKE 0
182# endif
183#endif
184
185#ifndef TOML_MSVC
186# if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC
187# define TOML_MSVC TOML_MSVC_LIKE
188# else
189# define TOML_MSVC 0
190# endif
191#endif
192
193#ifndef TOML_GCC_LIKE
194# ifdef __GNUC__
195# define TOML_GCC_LIKE __GNUC__
196# else
197# define TOML_GCC_LIKE 0
198# endif
199#endif
200
201#ifndef TOML_GCC
202# if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC
203# define TOML_GCC TOML_GCC_LIKE
204# else
205# define TOML_GCC 0
206# endif
207#endif
208
209#ifndef TOML_CUDA
210# if defined(__CUDACC__) || defined(__CUDA_ARCH__) || \
211 defined(__CUDA_LIBDEVICE__)
212# define TOML_CUDA 1
213# else
214# define TOML_CUDA 0
215# endif
216#endif
217
218#ifndef TOML_NVCC
219# ifdef __NVCOMPILER_MAJOR__
220# define TOML_NVCC __NVCOMPILER_MAJOR__
221# else
222# define TOML_NVCC 0
223# endif
224#endif
225
226#ifndef TOML_ARCH_ITANIUM
227# if defined(__ia64__) || defined(__ia64) || defined(_IA64) || \
228 defined(__IA64__) || defined(_M_IA64)
229# define TOML_ARCH_ITANIUM 1
230# define TOML_ARCH_BITNESS 64
231# else
232# define TOML_ARCH_ITANIUM 0
233# endif
234#endif
235
236#ifndef TOML_ARCH_AMD64
237# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || \
238 defined(__x86_64) || defined(_M_AMD64)
239# define TOML_ARCH_AMD64 1
240# define TOML_ARCH_BITNESS 64
241# else
242# define TOML_ARCH_AMD64 0
243# endif
244#endif
245
246#ifndef TOML_ARCH_X86
247# if defined(__i386__) || defined(_M_IX86)
248# define TOML_ARCH_X86 1
249# define TOML_ARCH_BITNESS 32
250# else
251# define TOML_ARCH_X86 0
252# endif
253#endif
254
255#ifndef TOML_ARCH_ARM
256# if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || \
257 defined(_M_ARM64) || defined(__ARM_64BIT_STATE) || defined(_M_ARM64EC)
258# define TOML_ARCH_ARM32 0
259# define TOML_ARCH_ARM64 1
260# define TOML_ARCH_ARM 1
261# define TOML_ARCH_BITNESS 64
262# elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE)
263# define TOML_ARCH_ARM32 1
264# define TOML_ARCH_ARM64 0
265# define TOML_ARCH_ARM 1
266# define TOML_ARCH_BITNESS 32
267# else
268# define TOML_ARCH_ARM32 0
269# define TOML_ARCH_ARM64 0
270# define TOML_ARCH_ARM 0
271# endif
272#endif
273
274#ifndef TOML_ARCH_BITNESS
275# define TOML_ARCH_BITNESS 0
276#endif
277
278#ifndef TOML_ARCH_X64
279# if TOML_ARCH_BITNESS == 64
280# define TOML_ARCH_X64 1
281# else
282# define TOML_ARCH_X64 0
283# endif
284#endif
285
286#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
287 defined(__NT__) || defined(__CYGWIN__)
288# define TOML_WINDOWS 1
289#else
290# define TOML_WINDOWS 0
291#endif
292
293#ifdef __unix__
294# define TOML_UNIX 1
295#else
296# define TOML_UNIX 0
297#endif
298
299#ifdef __linux__
300# define TOML_LINUX 1
301#else
302# define TOML_LINUX 0
303#endif
304
305// TOML_HAS_INCLUDE
306#ifndef TOML_HAS_INCLUDE
307# ifdef __has_include
308# define TOML_HAS_INCLUDE(header) __has_include(header)
309# else
310# define TOML_HAS_INCLUDE(header) 0
311# endif
312#endif
313
314// TOML_HAS_BUILTIN
315#ifndef TOML_HAS_BUILTIN
316# ifdef __has_builtin
317# define TOML_HAS_BUILTIN(name) __has_builtin(name)
318# else
319# define TOML_HAS_BUILTIN(name) 0
320# endif
321#endif
322
323// TOML_HAS_FEATURE
324#ifndef TOML_HAS_FEATURE
325# ifdef __has_feature
326# define TOML_HAS_FEATURE(name) __has_feature(name)
327# else
328# define TOML_HAS_FEATURE(name) 0
329# endif
330#endif
331
332// TOML_HAS_ATTR
333#ifndef TOML_HAS_ATTR
334# ifdef __has_attribute
335# define TOML_HAS_ATTR(attr) __has_attribute(attr)
336# else
337# define TOML_HAS_ATTR(attr) 0
338# endif
339#endif
340
341// TOML_HAS_CPP_ATTR
342#ifndef TOML_HAS_CPP_ATTR
343# ifdef __has_cpp_attribute
344# define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr)
345# else
346# define TOML_HAS_CPP_ATTR(attr) 0
347# endif
348#endif
349
350// TOML_ATTR (gnu attributes)
351#ifndef TOML_ATTR
352# if TOML_CLANG || TOML_GCC_LIKE
353# define TOML_ATTR(...) __attribute__((__VA_ARGS__))
354# else
355# define TOML_ATTR(...)
356# endif
357#endif
358
359// TOML_DECLSPEC (msvc attributes)
360#ifndef TOML_DECLSPEC
361# if TOML_MSVC_LIKE
362# define TOML_DECLSPEC(...) __declspec(__VA_ARGS__)
363# else
364# define TOML_DECLSPEC(...)
365# endif
366#endif
367
368// TOML_COMPILER_HAS_EXCEPTIONS
369#ifndef TOML_COMPILER_HAS_EXCEPTIONS
370# if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions)
371# define TOML_COMPILER_HAS_EXCEPTIONS 1
372# else
373# define TOML_COMPILER_HAS_EXCEPTIONS 0
374# endif
375#endif
376
377// TOML_COMPILER_HAS_RTTI
378#ifndef TOML_COMPILER_HAS_RTTI
379# if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti)
380# define TOML_COMPILER_HAS_RTTI 1
381# else
382# define TOML_COMPILER_HAS_RTTI 0
383# endif
384#endif
385
386// TOML_CONCAT
387#define TOML_CONCAT_1(x, y) x##y
388#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)
389
390// TOML_MAKE_STRING
391#define TOML_MAKE_STRING_1(s) #s
392#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s)
393
394// TOML_PRAGMA_XXXX (compiler-specific pragmas)
395#if TOML_CLANG
396# define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl))
397#else
398# define TOML_PRAGMA_CLANG(decl)
399#endif
400#if TOML_CLANG >= 8
401# define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl)
402#else
403# define TOML_PRAGMA_CLANG_GE_8(decl)
404#endif
405#if TOML_CLANG >= 9
406# define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl)
407#else
408# define TOML_PRAGMA_CLANG_GE_9(decl)
409#endif
410#if TOML_CLANG >= 10
411# define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl)
412#else
413# define TOML_PRAGMA_CLANG_GE_10(decl)
414#endif
415#if TOML_CLANG >= 11
416# define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl)
417#else
418# define TOML_PRAGMA_CLANG_GE_11(decl)
419#endif
420#if TOML_GCC
421# define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl))
422#else
423# define TOML_PRAGMA_GCC(decl)
424#endif
425#if TOML_MSVC
426# define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__)
427#else
428# define TOML_PRAGMA_MSVC(...)
429#endif
430#if TOML_ICC
431# define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__)
432#else
433# define TOML_PRAGMA_ICC(...)
434#endif
435
436// TOML_ALWAYS_INLINE
437#ifndef TOML_ALWAYS_INLINE
438# ifdef _MSC_VER
439# define TOML_ALWAYS_INLINE __forceinline
440# elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__)
441# define TOML_ALWAYS_INLINE \
442 TOML_ATTR(__always_inline__) \
443 inline
444# else
445# define TOML_ALWAYS_INLINE inline
446# endif
447#endif
448
449// TOML_NEVER_INLINE
450#ifndef TOML_NEVER_INLINE
451# ifdef _MSC_VER
452# define TOML_NEVER_INLINE TOML_DECLSPEC(noinline)
453# elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555
454# define TOML_NEVER_INLINE TOML_ATTR(noinline)
455# else
456# if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__)
457# define TOML_NEVER_INLINE TOML_ATTR(__noinline__)
458# endif
459# endif
460# ifndef TOML_NEVER_INLINE
461# define TOML_NEVER_INLINE
462# endif
463#endif
464
465// MSVC attributes
466#ifndef TOML_ABSTRACT_INTERFACE
467# define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable)
468#endif
469#ifndef TOML_EMPTY_BASES
470# define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases)
471#endif
472
473// TOML_TRIVIAL_ABI
474#ifndef TOML_TRIVIAL_ABI
475# if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__)
476# define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__)
477# else
478# define TOML_TRIVIAL_ABI
479# endif
480#endif
481
482// TOML_NODISCARD
483#ifndef TOML_NODISCARD
484# if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603
485# define TOML_NODISCARD [[nodiscard]]
486# elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__)
487# define TOML_NODISCARD TOML_ATTR(__warn_unused_result__)
488# else
489# define TOML_NODISCARD
490# endif
491#endif
492
493// TOML_NODISCARD_CTOR
494#ifndef TOML_NODISCARD_CTOR
495# if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907
496# define TOML_NODISCARD_CTOR [[nodiscard]]
497# else
498# define TOML_NODISCARD_CTOR
499# endif
500#endif
501
502// pure + const
503#ifndef TOML_PURE
504# ifdef NDEBUG
505# define TOML_PURE \
506 TOML_DECLSPEC(noalias) \
507 TOML_ATTR(pure)
508# else
509# define TOML_PURE
510# endif
511#endif
512#ifndef TOML_CONST
513# ifdef NDEBUG
514# define TOML_CONST \
515 TOML_DECLSPEC(noalias) \
516 TOML_ATTR(const)
517# else
518# define TOML_CONST
519# endif
520#endif
521#ifndef TOML_INLINE_GETTER
522# define TOML_INLINE_GETTER \
523 TOML_NODISCARD \
524 TOML_ALWAYS_INLINE
525#endif
526#ifndef TOML_PURE_GETTER
527# define TOML_PURE_GETTER \
528 TOML_NODISCARD \
529 TOML_PURE
530#endif
531#ifndef TOML_PURE_INLINE_GETTER
532# define TOML_PURE_INLINE_GETTER \
533 TOML_NODISCARD \
534 TOML_ALWAYS_INLINE \
535 TOML_PURE
536#endif
537#ifndef TOML_CONST_GETTER
538# define TOML_CONST_GETTER \
539 TOML_NODISCARD \
540 TOML_CONST
541#endif
542#ifndef TOML_CONST_INLINE_GETTER
543# define TOML_CONST_INLINE_GETTER \
544 TOML_NODISCARD \
545 TOML_ALWAYS_INLINE \
546 TOML_CONST
547#endif
548
549// TOML_ASSUME
550#ifndef TOML_ASSUME
551# ifdef _MSC_VER
552# define TOML_ASSUME(expr) __assume(expr)
553# elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume)
554# define TOML_ASSUME(expr) __builtin_assume(expr)
555# elif TOML_HAS_CPP_ATTR(assume) >= 202207
556# define TOML_ASSUME(expr) [[assume(expr)]]
557# elif TOML_HAS_ATTR(__assume__)
558# define TOML_ASSUME(expr) __attribute__((__assume__(expr)))
559# else
560# define TOML_ASSUME(expr) static_cast<void>(0)
561# endif
562#endif
563
564// TOML_UNREACHABLE
565#ifndef TOML_UNREACHABLE
566# ifdef _MSC_VER
567# define TOML_UNREACHABLE __assume(0)
568# elif TOML_ICC || TOML_CLANG || TOML_GCC || \
569 TOML_HAS_BUILTIN(__builtin_unreachable)
570# define TOML_UNREACHABLE __builtin_unreachable()
571# else
572# define TOML_UNREACHABLE static_cast<void>(0)
573# endif
574#endif
575
576// TOML_LIKELY
577#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803
578# define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
579# define TOML_LIKELY_CASE [[likely]]
580#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
581# define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1))
582#else
583# define TOML_LIKELY(...) (__VA_ARGS__)
584#endif
585#ifndef TOML_LIKELY_CASE
586# define TOML_LIKELY_CASE
587#endif
588
589// TOML_UNLIKELY
590#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803
591# define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
592# define TOML_UNLIKELY_CASE [[unlikely]]
593#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
594# define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0))
595#else
596# define TOML_UNLIKELY(...) (__VA_ARGS__)
597#endif
598#ifndef TOML_UNLIKELY_CASE
599# define TOML_UNLIKELY_CASE
600#endif
601
602// TOML_FLAGS_ENUM
603#if TOML_CLANG || TOML_HAS_ATTR(flag_enum)
604# define TOML_FLAGS_ENUM __attribute__((flag_enum))
605#else
606# define TOML_FLAGS_ENUM
607#endif
608
609// TOML_OPEN_ENUM + TOML_CLOSED_ENUM
610#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility)
611# define TOML_OPEN_ENUM __attribute__((enum_extensibility(open)))
612# define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed)))
613#else
614# define TOML_OPEN_ENUM
615# define TOML_CLOSED_ENUM
616#endif
617
618// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM
619#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM
620#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM
621
622// TOML_MAKE_FLAGS
623#define TOML_MAKE_FLAGS_2(T, op, linkage) \
624 TOML_CONST_INLINE_GETTER \
625 linkage constexpr T operator op(T lhs, T rhs) noexcept \
626 { \
627 using under = std::underlying_type_t<T>; \
628 return static_cast<T>(static_cast<under>(lhs) op static_cast<under>(rhs)); \
629 } \
630 \
631 linkage constexpr T &operator TOML_CONCAT(op, =)(T &lhs, T rhs) noexcept \
632 { \
633 return lhs = (lhs op rhs); \
634 } \
635 \
636 static_assert(true)
637#define TOML_MAKE_FLAGS_1(T, linkage) \
638 static_assert(std::is_enum_v<T>); \
639 \
640 TOML_MAKE_FLAGS_2(T, &, linkage); \
641 TOML_MAKE_FLAGS_2(T, |, linkage); \
642 TOML_MAKE_FLAGS_2(T, ^, linkage); \
643 \
644 TOML_CONST_INLINE_GETTER \
645 linkage constexpr T operator~(T val) noexcept \
646 { \
647 using under = std::underlying_type_t<T>; \
648 return static_cast<T>(~static_cast<under>(val)); \
649 } \
650 \
651 TOML_CONST_INLINE_GETTER \
652 linkage constexpr bool operator!(T val) noexcept \
653 { \
654 using under = std::underlying_type_t<T>; \
655 return !static_cast<under>(val); \
656 } \
657 \
658 static_assert(true)
659#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, )
660
661#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
662
663#define TOML_DELETE_DEFAULTS(T) \
664 T(const T &) = delete; \
665 T(T &&) = delete; \
666 T &operator=(const T &) = delete; \
667 T &operator=(T &&) = delete
668
669#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
670 __VA_ARGS__ TOML_NODISCARD friend bool operator==(RHS rhs, LHS lhs) noexcept \
671 { \
672 return lhs == rhs; \
673 } \
674 __VA_ARGS__ TOML_NODISCARD friend bool operator!=(LHS lhs, RHS rhs) noexcept \
675 { \
676 return !(lhs == rhs); \
677 } \
678 __VA_ARGS__ TOML_NODISCARD friend bool operator!=(RHS rhs, LHS lhs) noexcept \
679 { \
680 return !(lhs == rhs); \
681 } \
682 static_assert(true)
683
684#define TOML_EVAL_BOOL_1(T, F) T
685#define TOML_EVAL_BOOL_0(T, F) F
686
687#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL)
688# define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__
689#endif
690
691// COMPILER-SPECIFIC WARNING MANAGEMENT
692
693#if TOML_CLANG
694
695# define TOML_PUSH_WARNINGS \
696 TOML_PRAGMA_CLANG(diagnostic push) \
697 TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option") \
698 static_assert(true)
699
700# define TOML_DISABLE_SWITCH_WARNINGS \
701 TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch") \
702 static_assert(true)
703
704# define TOML_DISABLE_ARITHMETIC_WARNINGS \
705 TOML_PRAGMA_CLANG_GE_10(diagnostic ignored \
706 "-Wimplicit-int-float-conversion") \
707 TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal") \
708 TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \
709 TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \
710 TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow") \
711 static_assert(true)
712
713# define TOML_DISABLE_SPAM_WARNINGS \
714 TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted") \
715 TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported") \
716 TOML_PRAGMA_CLANG_GE_10(diagnostic ignored \
717 "-Wzero-as-null-pointer-constant") \
718 TOML_PRAGMA_CLANG_GE_11(diagnostic ignored \
719 "-Wsuggest-destructor-override") \
720 TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") \
721 TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables") \
722 TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \
723 TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \
724 TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers") \
725 TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded") \
726 static_assert(true)
727
728# define TOML_POP_WARNINGS \
729 TOML_PRAGMA_CLANG(diagnostic pop) \
730 static_assert(true)
731
732# define TOML_DISABLE_WARNINGS \
733 TOML_PRAGMA_CLANG(diagnostic push) \
734 TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything") \
735 static_assert(true, "")
736
737# define TOML_ENABLE_WARNINGS \
738 TOML_PRAGMA_CLANG(diagnostic pop) \
739 static_assert(true)
740
741# define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1
742
743#elif TOML_MSVC
744
745# define TOML_PUSH_WARNINGS __pragma(warning(push)) static_assert(true)
746
747# if TOML_HAS_INCLUDE(<CodeAnalysis / Warnings.h>)
748# pragma warning(push, 0)
749# include <CodeAnalysis/Warnings.h>
750# pragma warning(pop)
751# define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \
752 __pragma(warning(disable \
753 : ALL_CODE_ANALYSIS_WARNINGS)) static_assert(true)
754# else
755# define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
756# endif
757
758# define TOML_DISABLE_SWITCH_WARNINGS \
759 __pragma(warning(disable : 4061)) __pragma(warning(disable : 4062)) \
760 __pragma(warning(disable : 4063)) __pragma(warning( \
761 disable : 5262)) /* switch-case implicit fallthrough (false-positive) */ \
762 __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */ \
763 static_assert(true)
764
765# define TOML_DISABLE_SPAM_WARNINGS \
766 __pragma(warning(disable : 4127)) /* conditional expr is constant */ \
767 __pragma(warning( \
768 disable : 4324)) /* structure was padded due to alignment specifier */ \
769 __pragma(warning(disable : 4348)) __pragma( \
770 warning(disable : 4464)) /* relative include path contains '..' */ \
771 __pragma( \
772 warning(disable : 4505)) /* unreferenced local function removed */ \
773 __pragma(warning( \
774 disable : 4514)) /* unreferenced inline function has been removed */ \
775 __pragma( \
776 warning(disable : 4582)) /* constructor is not implicitly called */ \
777 __pragma( \
778 warning(disable : 4619)) /* there is no warning number 'XXXX' */ \
779 __pragma(warning( \
780 disable : 4623)) /* default constructor was implicitly defined as deleted */ \
781 __pragma(warning( \
782 disable : 4625)) /* copy constructor was implicitly defined as deleted */ \
783 __pragma(warning( \
784 disable : 4626)) /* assignment operator was implicitly defined as deleted */ \
785 __pragma(warning(disable : 4710)) /* function not inlined */ \
786 __pragma(warning( \
787 disable : 4711)) /* function selected for automatic expansion */ \
788 __pragma(warning(disable : 4820)) /* N bytes padding added */ \
789 __pragma(warning( \
790 disable : 4946)) /* reinterpret_cast used between related classes */ \
791 __pragma(warning( \
792 disable : 5026)) /* move constructor was implicitly defined as deleted */ \
793 __pragma(warning( \
794 disable : 5027)) /* move assignment operator was implicitly defined as deleted */ \
795 __pragma(warning( \
796 disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */ \
797 __pragma( \
798 warning(disable : 5045)) /* Compiler will insert Spectre mitigation */ \
799 __pragma(warning( \
800 disable : 5264)) /* const variable is not used (false-positive) */ \
801 __pragma(warning(disable : 26451)) __pragma(warning(disable : 26490)) \
802 __pragma(warning(disable : 26495)) __pragma(warning(disable : 26812)) \
803 __pragma(warning(disable : 26819)) static_assert(true)
804
805# define TOML_DISABLE_ARITHMETIC_WARNINGS \
806 __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */ \
807 __pragma( \
808 warning(disable : 4738)) /* storing 32-bit float result in memory */ \
809 __pragma(warning( \
810 disable : 5219)) /* implicit conversion from integral to float */ \
811 static_assert(true)
812
813# define TOML_POP_WARNINGS __pragma(warning(pop)) static_assert(true)
814
815# define TOML_DISABLE_WARNINGS \
816 __pragma(warning(push, 0)) __pragma(warning(disable : 4348)) \
817 __pragma(warning(disable : 4668)) __pragma(warning(disable : 5105)) \
818 __pragma(warning(disable : 5264)) TOML_DISABLE_CODE_ANALYSIS_WARNINGS; \
819 TOML_DISABLE_SWITCH_WARNINGS; \
820 TOML_DISABLE_SPAM_WARNINGS; \
821 TOML_DISABLE_ARITHMETIC_WARNINGS; \
822 static_assert(true)
823
824# define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
825
826#elif TOML_ICC
827
828# define TOML_PUSH_WARNINGS __pragma(warning(push)) static_assert(true)
829
830# define TOML_DISABLE_SPAM_WARNINGS \
831 __pragma(warning(disable : 82)) /* storage class is not first */ \
832 __pragma( \
833 warning(disable : 111)) /* statement unreachable (false-positive) */ \
834 __pragma(warning(disable : 869)) /* unreferenced parameter */ \
835 __pragma(warning(disable : 1011)) /* missing return (false-positive) */ \
836 __pragma( \
837 warning(disable : 2261)) /* assume expr side-effects discarded */ \
838 static_assert(true)
839
840# define TOML_POP_WARNINGS __pragma(warning(pop)) static_assert(true)
841
842# define TOML_DISABLE_WARNINGS \
843 __pragma(warning(push, 0)) TOML_DISABLE_SPAM_WARNINGS
844
845# define TOML_ENABLE_WARNINGS __pragma(warning(pop)) static_assert(true)
846
847#elif TOML_GCC
848
849# define TOML_PUSH_WARNINGS \
850 TOML_PRAGMA_GCC(diagnostic push) \
851 static_assert(true)
852
853# define TOML_DISABLE_SWITCH_WARNINGS \
854 TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch") \
855 TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum") \
856 TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default") \
857 static_assert(true)
858
859# define TOML_DISABLE_ARITHMETIC_WARNINGS \
860 TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal") \
861 TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion") \
862 TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \
863 static_assert(true)
864
865# define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \
866 TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const") \
867 TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure") \
868 static_assert(true)
869
870# define TOML_DISABLE_SPAM_WARNINGS \
871 TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded") \
872 TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align") \
873 TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment") \
874 TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits") \
875 TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast") \
876 TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \
877 TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage") \
878 TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers") \
879 TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized") \
880 TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept") \
881 TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference") \
882 TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches") \
883 static_assert(true)
884
885# define TOML_POP_WARNINGS \
886 TOML_PRAGMA_GCC(diagnostic pop) \
887 static_assert(true)
888
889# define TOML_DISABLE_WARNINGS \
890 TOML_PRAGMA_GCC(diagnostic push) \
891 TOML_PRAGMA_GCC(diagnostic ignored "-Wall") \
892 TOML_PRAGMA_GCC(diagnostic ignored "-Wextra") \
893 TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic") \
894 TOML_DISABLE_SWITCH_WARNINGS; \
895 TOML_DISABLE_ARITHMETIC_WARNINGS; \
896 TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \
897 TOML_DISABLE_SPAM_WARNINGS; \
898 static_assert(true)
899
900# define TOML_ENABLE_WARNINGS \
901 TOML_PRAGMA_GCC(diagnostic pop) \
902 static_assert(true)
903
904#endif
905
906#ifndef TOML_PUSH_WARNINGS
907# define TOML_PUSH_WARNINGS static_assert(true)
908#endif
909#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
910# define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
911#endif
912#ifndef TOML_DISABLE_SWITCH_WARNINGS
913# define TOML_DISABLE_SWITCH_WARNINGS static_assert(true)
914#endif
915#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
916# define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true)
917#endif
918#ifndef TOML_DISABLE_SPAM_WARNINGS
919# define TOML_DISABLE_SPAM_WARNINGS static_assert(true)
920#endif
921#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
922# define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true)
923#endif
924#ifndef TOML_POP_WARNINGS
925# define TOML_POP_WARNINGS static_assert(true)
926#endif
927#ifndef TOML_DISABLE_WARNINGS
928# define TOML_DISABLE_WARNINGS static_assert(true)
929#endif
930#ifndef TOML_ENABLE_WARNINGS
931# define TOML_ENABLE_WARNINGS static_assert(true)
932#endif
933#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
934# define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0
935#endif
936
937#ifdef TOML_CONFIG_HEADER
938# include TOML_CONFIG_HEADER
939#endif
940
941// is the library being built as a shared lib/dll using meson and friends?
942#ifndef TOML_SHARED_LIB
943# define TOML_SHARED_LIB 0
944#endif
945
946// header-only mode
947#if !defined(TOML_HEADER_ONLY) && \
948 defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0
949# define TOML_HEADER_ONLY TOML_ALL_INLINE
950#endif
951#if !defined(TOML_HEADER_ONLY) || \
952 (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
953# undef TOML_HEADER_ONLY
954# define TOML_HEADER_ONLY 1
955#endif
956#if TOML_DOXYGEN || TOML_SHARED_LIB
957# undef TOML_HEADER_ONLY
958# define TOML_HEADER_ONLY 0
959#endif
960
961// internal implementation switch
962#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
963# undef TOML_IMPLEMENTATION
964# define TOML_IMPLEMENTATION 1
965#else
966# define TOML_IMPLEMENTATION 0
967#endif
968
969// dll/shared lib function exports (legacy - TOML_API was the old name for this setting)
970#if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && \
971 !defined(TOML_EXPORTED_STATIC_FUNCTION) && \
972 !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && \
973 defined(TOML_API)
974# define TOML_EXPORTED_MEMBER_FUNCTION TOML_API
975# define TOML_EXPORTED_STATIC_FUNCTION TOML_API
976# define TOML_EXPORTED_FREE_FUNCTION TOML_API
977#endif
978
979// dll/shared lib exports
980#if TOML_SHARED_LIB
981# undef TOML_API
982# undef TOML_EXPORTED_CLASS
983# undef TOML_EXPORTED_MEMBER_FUNCTION
984# undef TOML_EXPORTED_STATIC_FUNCTION
985# undef TOML_EXPORTED_FREE_FUNCTION
986# if TOML_WINDOWS
987# if TOML_IMPLEMENTATION
988# define TOML_EXPORTED_CLASS __declspec(dllexport)
989# define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport)
990# else
991# define TOML_EXPORTED_CLASS __declspec(dllimport)
992# define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport)
993# endif
994# ifndef TOML_CALLCONV
995# define TOML_CALLCONV __cdecl
996# endif
997# elif defined(__GNUC__) && __GNUC__ >= 4
998# define TOML_EXPORTED_CLASS __attribute__((visibility("default")))
999# define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default")))
1000# define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default")))
1001# define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default")))
1002# endif
1003#endif
1004#ifndef TOML_EXPORTED_CLASS
1005# define TOML_EXPORTED_CLASS
1006#endif
1007#ifndef TOML_EXPORTED_MEMBER_FUNCTION
1008# define TOML_EXPORTED_MEMBER_FUNCTION
1009#endif
1010#ifndef TOML_EXPORTED_STATIC_FUNCTION
1011# define TOML_EXPORTED_STATIC_FUNCTION
1012#endif
1013#ifndef TOML_EXPORTED_FREE_FUNCTION
1014# define TOML_EXPORTED_FREE_FUNCTION
1015#endif
1016
1017// experimental language features
1018#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && \
1019 defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES
1020 // pre-3.0
1021# define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES
1022#endif
1023#if ( \
1024 defined(TOML_ENABLE_UNRELEASED_FEATURES) && \
1025 TOML_ENABLE_UNRELEASED_FEATURES) || \
1026 TOML_INTELLISENSE
1027# undef TOML_ENABLE_UNRELEASED_FEATURES
1028# define TOML_ENABLE_UNRELEASED_FEATURES 1
1029#endif
1030#ifndef TOML_ENABLE_UNRELEASED_FEATURES
1031# define TOML_ENABLE_UNRELEASED_FEATURES 0
1032#endif
1033
1034// parser
1035#if !defined(TOML_ENABLE_PARSER) && \
1036 defined(TOML_PARSER) // was TOML_PARSER pre-3.0
1037# define TOML_ENABLE_PARSER TOML_PARSER
1038#endif
1039#if !defined(TOML_ENABLE_PARSER) || \
1040 (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE
1041# undef TOML_ENABLE_PARSER
1042# define TOML_ENABLE_PARSER 1
1043#endif
1044
1045// formatters
1046#if !defined(TOML_ENABLE_FORMATTERS) || \
1047 (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || \
1048 TOML_INTELLISENSE
1049# undef TOML_ENABLE_FORMATTERS
1050# define TOML_ENABLE_FORMATTERS 1
1051#endif
1052
1053// SIMD
1054#if !defined(TOML_ENABLE_SIMD) || \
1055 (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE
1056# undef TOML_ENABLE_SIMD
1057# define TOML_ENABLE_SIMD 1
1058#endif
1059
1060// windows compat
1061#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && \
1062 defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0
1063# define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT
1064#endif
1065#if !defined(TOML_ENABLE_WINDOWS_COMPAT) || \
1066 (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) || \
1067 TOML_INTELLISENSE
1068# undef TOML_ENABLE_WINDOWS_COMPAT
1069# define TOML_ENABLE_WINDOWS_COMPAT 1
1070#endif
1071
1072#if !TOML_WINDOWS
1073# undef TOML_ENABLE_WINDOWS_COMPAT
1074# define TOML_ENABLE_WINDOWS_COMPAT 0
1075#endif
1076
1077#ifndef TOML_INCLUDE_WINDOWS_H
1078# define TOML_INCLUDE_WINDOWS_H 0
1079#endif
1080
1081// custom optional
1082#ifdef TOML_OPTIONAL_TYPE
1083# define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
1084#else
1085# define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
1086#endif
1087
1088// exceptions (library use)
1089#if TOML_COMPILER_HAS_EXCEPTIONS
1090# if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
1091# undef TOML_EXCEPTIONS
1092# define TOML_EXCEPTIONS 1
1093# endif
1094#else
1095# if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS
1096#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler.
1097# endif
1098# undef TOML_EXCEPTIONS
1099# define TOML_EXCEPTIONS 0
1100#endif
1101
1102// calling convention for static/free/friend functions
1103#ifndef TOML_CALLCONV
1104# define TOML_CALLCONV
1105#endif
1106
1107#ifndef TOML_UNDEF_MACROS
1108# define TOML_UNDEF_MACROS 1
1109#endif
1110
1111#ifndef TOML_MAX_NESTED_VALUES
1112# define TOML_MAX_NESTED_VALUES 256
1113// this refers to the depth of nested values, e.g. inline tables and arrays.
1114// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
1115#endif
1116
1117#ifdef TOML_CHAR_8_STRINGS
1118# if TOML_CHAR_8_STRINGS
1119#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly.
1120# endif
1121#endif
1122
1123#ifdef TOML_LARGE_FILES
1124# if !TOML_LARGE_FILES
1125# error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0.
1126# endif
1127#endif
1128
1129#ifndef TOML_LIFETIME_HOOKS
1130# define TOML_LIFETIME_HOOKS 0
1131#endif
1132
1133#ifdef NDEBUG
1134# undef TOML_ASSERT
1135# define TOML_ASSERT(expr) static_assert(true)
1136#endif
1137#ifndef TOML_ASSERT
1138# ifndef assert
1140# include <cassert>
1142# endif
1143# define TOML_ASSERT(expr) assert(expr)
1144#endif
1145#ifdef NDEBUG
1146# define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr)
1147#else
1148# define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr)
1149#endif
1150
1151#ifndef TOML_ENABLE_FLOAT16
1152# define TOML_ENABLE_FLOAT16 0
1153#endif
1154
1155#if !defined(TOML_FLOAT_CHARCONV) && \
1156 (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL))
1157// not supported by any version of GCC or Clang as of 26/11/2020
1158// not supported by any version of ICC on Linux as of 11/01/2021
1159# define TOML_FLOAT_CHARCONV 0
1160#endif
1161#if !defined(TOML_INT_CHARCONV) && \
1162 (defined(__EMSCRIPTEN__) || defined(__APPLE__))
1163// causes link errors on emscripten
1164// causes Mac OS SDK version errors on some versions of Apple Clang
1165# define TOML_INT_CHARCONV 0
1166#endif
1167#ifndef TOML_INT_CHARCONV
1168# define TOML_INT_CHARCONV 1
1169#endif
1170#ifndef TOML_FLOAT_CHARCONV
1171# define TOML_FLOAT_CHARCONV 1
1172#endif
1173#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE(<charconv>)
1174# undef TOML_INT_CHARCONV
1175# undef TOML_FLOAT_CHARCONV
1176# define TOML_INT_CHARCONV 0
1177# define TOML_FLOAT_CHARCONV 0
1178#endif
1179
1180#if defined(__cpp_concepts) && __cpp_concepts >= 201907
1181# define TOML_REQUIRES(...) requires(__VA_ARGS__)
1182#else
1183# define TOML_REQUIRES(...)
1184#endif
1185#define TOML_ENABLE_IF(...) \
1186 , typename std::enable_if<(__VA_ARGS__), int>::type = 0
1187#define TOML_CONSTRAINED_TEMPLATE(condition, ...) \
1188 template <__VA_ARGS__ TOML_ENABLE_IF(condition)> \
1189 TOML_REQUIRES(condition)
1190#define TOML_HIDDEN_CONSTRAINT(condition, ...) \
1191 TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__)
1192
1193#if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && \
1194 defined(__LDBL_MANT_DIG__) && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__
1195# define TOML_FLOAT128 __float128
1196#endif
1197
1198#ifdef __SIZEOF_INT128__
1199# define TOML_INT128 __int128_t
1200# define TOML_UINT128 __uint128_t
1201#endif
1202
1203// clang-format off
1204
1205//******** impl/version.hpp ******************************************************************************************
1206
1207#define TOML_LIB_MAJOR 3
1208#define TOML_LIB_MINOR 4
1209#define TOML_LIB_PATCH 0
1210
1211#define TOML_LANG_MAJOR 1
1212#define TOML_LANG_MINOR 0
1213#define TOML_LANG_PATCH 0
1214
1215//******** impl/preprocessor.hpp *************************************************************************************
1216
1217#define TOML_LIB_SINGLE_HEADER 1
1218
1219#if TOML_ENABLE_UNRELEASED_FEATURES
1220 #define TOML_LANG_EFFECTIVE_VERSION \
1221 TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
1222#else
1223 #define TOML_LANG_EFFECTIVE_VERSION \
1224 TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
1225#endif
1226
1227#define TOML_LANG_HIGHER_THAN(major, minor, patch) \
1228 (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch))
1229
1230#define TOML_LANG_AT_LEAST(major, minor, patch) \
1231 (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch))
1232
1233#define TOML_LANG_UNRELEASED \
1234 TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
1235
1236#ifndef TOML_ABI_NAMESPACES
1237 #if TOML_DOXYGEN
1238 #define TOML_ABI_NAMESPACES 0
1239 #else
1240 #define TOML_ABI_NAMESPACES 1
1241 #endif
1242#endif
1243#if TOML_ABI_NAMESPACES
1244 #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR)
1245 #define TOML_NAMESPACE_END } static_assert(true)
1246 #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR)
1247 #define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true)
1248 #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F))
1249 #define TOML_ABI_NAMESPACE_END } static_assert(true)
1250#else
1251 #define TOML_NAMESPACE_START namespace toml
1252 #define TOML_NAMESPACE_END static_assert(true)
1253 #define TOML_NAMESPACE toml
1254 #define TOML_ABI_NAMESPACE_START(...) static_assert(true)
1255 #define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true)
1256 #define TOML_ABI_NAMESPACE_END static_assert(true)
1257#endif
1258#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl
1259#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END
1260#if TOML_HEADER_ONLY
1261 #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START
1262 #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END
1263 #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl
1264 #define TOML_EXTERNAL_LINKAGE inline
1265 #define TOML_INTERNAL_LINKAGE inline
1266#else
1267 #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \
1268 using namespace toml; \
1269 namespace
1270 #define TOML_ANON_NAMESPACE_END static_assert(true)
1271 #define TOML_ANON_NAMESPACE
1272 #define TOML_EXTERNAL_LINKAGE
1273 #define TOML_INTERNAL_LINKAGE static
1274#endif
1275
1276// clang-format on
1277
1278// clang-format off
1279
1280#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES
1281
1282 #define TOML_SA_NEWLINE " "
1283 #define TOML_SA_LIST_SEP ", "
1284 #define TOML_SA_LIST_BEG " ("
1285 #define TOML_SA_LIST_END ")"
1286 #define TOML_SA_LIST_NEW " "
1287 #define TOML_SA_LIST_NXT ", "
1288
1289#else
1290
1291 #define TOML_SA_NEWLINE "\n| "
1292 #define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - "
1293 #define TOML_SA_LIST_BEG TOML_SA_LIST_SEP
1294 #define TOML_SA_LIST_END
1295 #define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE
1296 #define TOML_SA_LIST_NXT TOML_SA_LIST_NEW
1297
1298#endif
1299
1300#define TOML_SA_NATIVE_VALUE_TYPE_LIST \
1301 TOML_SA_LIST_BEG "std::string" \
1302 TOML_SA_LIST_SEP "int64_t" \
1303 TOML_SA_LIST_SEP "double" \
1304 TOML_SA_LIST_SEP "bool" \
1305 TOML_SA_LIST_SEP "toml::date" \
1306 TOML_SA_LIST_SEP "toml::time" \
1307 TOML_SA_LIST_SEP "toml::date_time" \
1308 TOML_SA_LIST_END
1309
1310#define TOML_SA_NODE_TYPE_LIST \
1311 TOML_SA_LIST_BEG "toml::table" \
1312 TOML_SA_LIST_SEP "toml::array" \
1313 TOML_SA_LIST_SEP "toml::value<std::string>" \
1314 TOML_SA_LIST_SEP "toml::value<int64_t>" \
1315 TOML_SA_LIST_SEP "toml::value<double>" \
1316 TOML_SA_LIST_SEP "toml::value<bool>" \
1317 TOML_SA_LIST_SEP "toml::value<toml::date>" \
1318 TOML_SA_LIST_SEP "toml::value<toml::time>" \
1319 TOML_SA_LIST_SEP "toml::value<toml::date_time>" \
1320 TOML_SA_LIST_END
1321
1322#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \
1323 TOML_SA_LIST_NEW "A native TOML value type" \
1324 TOML_SA_NATIVE_VALUE_TYPE_LIST \
1325 \
1326 TOML_SA_LIST_NXT "A TOML node type" \
1327 TOML_SA_NODE_TYPE_LIST
1328
1329// clang-format on
1330
1335
1336// misc warning false-positives
1337#if TOML_MSVC
1338# pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
1339# if TOML_SHARED_LIB
1340# pragma warning(disable : 4251) // dll exports for std lib types
1341# endif
1342#elif TOML_CLANG
1343TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene")
1344# if TOML_CLANG >= 12
1345TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions")
1346# endif
1347# if TOML_CLANG == 13
1348TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier")
1349# endif
1350#endif
1351
1352//******** impl/std_new.hpp ******************************************************************************************
1353
1355#include <new>
1357
1358#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || \
1359 TOML_ICC >= 1910 || TOML_MSVC >= 1914
1360# define TOML_LAUNDER(x) __builtin_launder(x)
1361#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
1362# define TOML_LAUNDER(x) std::launder(x)
1363#else
1364# define TOML_LAUNDER(x) x
1365#endif
1366
1367//******** impl/std_string.hpp ***************************************************************************************
1368
1370#include <string_view>
1371#include <string>
1373
1374#if TOML_DOXYGEN || \
1375 (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && \
1376 defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201907)
1377# define TOML_HAS_CHAR8 1
1378#else
1379# define TOML_HAS_CHAR8 0
1380#endif
1381
1382namespace toml // non-abi namespace; this is not an error
1383{
1384using namespace std::string_literals;
1385using namespace std::string_view_literals;
1386} // namespace toml
1387
1388#if TOML_ENABLE_WINDOWS_COMPAT
1389
1391{
1394 std::string narrow(std::wstring_view);
1395
1398 std::wstring widen(std::string_view);
1399
1400# if TOML_HAS_CHAR8
1401
1404 std::wstring widen(std::u8string_view);
1405
1406# endif
1407}
1409
1410#endif // TOML_ENABLE_WINDOWS_COMPAT
1411
1412//******** impl/std_optional.hpp *************************************************************************************
1413
1415#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
1416# include <optional>
1417#endif
1419
1421{
1422#if TOML_HAS_CUSTOM_OPTIONAL_TYPE
1423
1424 template <typename T>
1425 using optional = TOML_OPTIONAL_TYPE<T>;
1426
1427#else
1428
1429 template <typename T>
1430 using optional = std::optional<T>;
1431
1432#endif
1433}
1435
1436//******** impl/forward_declarations.hpp *****************************************************************************
1437
1439#include <cstdint>
1440#include <cstddef>
1441#include <cstring>
1442#include <cfloat>
1443#include <climits>
1444#include <cmath>
1445#include <limits>
1446#include <memory>
1447#include <iosfwd>
1448#include <type_traits>
1451#ifdef _MSC_VER
1452# ifndef __clang__
1453# pragma inline_recursion(on)
1454# endif
1455# pragma push_macro("min")
1456# pragma push_macro("max")
1457# undef min
1458# undef max
1459#endif
1460
1461#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS
1462# define TOML_ENV_MESSAGE \
1463 "If you're seeing this error it's because you're building toml++ for an " \
1464 "environment that doesn't conform to " \
1465 "one of the 'ground truths' assumed by the library. Essentially this " \
1466 "just means that I don't have the " \
1467 "resources to test on more platforms, but I wish I did! You can try " \
1468 "disabling the checks by defining " \
1469 "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please " \
1470 "consider filing an issue at " \
1471 "https://github.com/marzer/tomlplusplus/issues to help me improve " \
1472 "support for your target environment. " \
1473 "Thanks!"
1474
1475static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE);
1476# ifdef FLT_RADIX
1477static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE);
1478# endif
1479static_assert('A' == 65, TOML_ENV_MESSAGE);
1480static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE);
1481static_assert(std::numeric_limits<double>::is_iec559, TOML_ENV_MESSAGE);
1482static_assert(std::numeric_limits<double>::digits == 53, TOML_ENV_MESSAGE);
1483static_assert(std::numeric_limits<double>::digits10 == 15, TOML_ENV_MESSAGE);
1484static_assert(std::numeric_limits<double>::radix == 2, TOML_ENV_MESSAGE);
1485
1486# undef TOML_ENV_MESSAGE
1487#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS
1488
1489// undocumented forward declarations are hidden from doxygen because they fuck it up =/
1490
1491namespace toml // non-abi namespace; this is not an error
1492{
1493using ::std::int16_t;
1494using ::std::int32_t;
1495using ::std::int64_t;
1496using ::std::int8_t;
1497using ::std::intptr_t;
1498using ::std::nullptr_t;
1499using ::std::ptrdiff_t;
1500using ::std::size_t;
1501using ::std::uint16_t;
1502using ::std::uint32_t;
1503using ::std::uint64_t;
1504using ::std::uint8_t;
1505using ::std::uint_least32_t;
1506using ::std::uint_least64_t;
1507using ::std::uintptr_t;
1508} // namespace toml
1509
1511{
1512 struct date;
1513 struct time;
1514 struct time_offset;
1515
1517 struct date_time;
1519
1520 struct source_position;
1521 struct source_region;
1522
1523 class node;
1524 template <typename>
1526
1527 class key;
1528 class array;
1529 class table;
1530 template <typename>
1531 class value;
1532
1533 class path;
1534
1535 class toml_formatter;
1536 class json_formatter;
1537 class yaml_formatter;
1538
1540#if TOML_EXCEPTIONS
1541 using parse_result = table;
1542#else
1543 class parse_result;
1544#endif
1545 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
1546}
1548
1550{
1551 using node_ptr = std::unique_ptr<node>;
1552
1554 class parser;
1555 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
1556
1557 // clang-format off
1558
1559 inline constexpr std::string_view control_char_escapes[] =
1560 {
1561 "\\u0000"sv,
1562 "\\u0001"sv,
1563 "\\u0002"sv,
1564 "\\u0003"sv,
1565 "\\u0004"sv,
1566 "\\u0005"sv,
1567 "\\u0006"sv,
1568 "\\u0007"sv,
1569 "\\b"sv,
1570 "\\t"sv,
1571 "\\n"sv,
1572 "\\u000B"sv,
1573 "\\f"sv,
1574 "\\r"sv,
1575 "\\u000E"sv,
1576 "\\u000F"sv,
1577 "\\u0010"sv,
1578 "\\u0011"sv,
1579 "\\u0012"sv,
1580 "\\u0013"sv,
1581 "\\u0014"sv,
1582 "\\u0015"sv,
1583 "\\u0016"sv,
1584 "\\u0017"sv,
1585 "\\u0018"sv,
1586 "\\u0019"sv,
1587 "\\u001A"sv,
1588 "\\u001B"sv,
1589 "\\u001C"sv,
1590 "\\u001D"sv,
1591 "\\u001E"sv,
1592 "\\u001F"sv,
1593 };
1594
1595 inline constexpr std::string_view node_type_friendly_names[] =
1596 {
1597 "none"sv,
1598 "table"sv,
1599 "array"sv,
1600 "string"sv,
1601 "integer"sv,
1602 "floating-point"sv,
1603 "boolean"sv,
1604 "date"sv,
1605 "time"sv,
1606 "date-time"sv
1607 };
1608
1609 // clang-format on
1610}
1612
1613#if TOML_ABI_NAMESPACES
1614# if TOML_EXCEPTIONS
1615# define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser
1616# else
1617# define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser
1618# endif
1619#else
1620# define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser
1621#endif
1622
1623namespace toml
1624{
1625}
1626
1627TOML_NAMESPACE_START // abi namespace
1628{
1629 inline namespace literals
1630 {
1631 }
1632
1633 enum class TOML_CLOSED_ENUM node_type : uint8_t
1634 {
1635 none,
1636 table,
1637 array,
1638 string,
1639 integer,
1640 floating_point,
1641 boolean,
1642 date,
1643 time,
1644 date_time
1645 };
1646
1647 template <typename Char>
1648 inline std::basic_ostream<Char> &operator<<(
1649 std::basic_ostream<Char> &lhs, node_type rhs)
1650 {
1651 const auto str = impl::node_type_friendly_names
1652 [static_cast<std::underlying_type_t<node_type>>(rhs)];
1653 using str_char_t = decltype(str)::value_type;
1654 if constexpr (std::is_same_v<Char, str_char_t>)
1655 return lhs << str;
1656 else
1657 {
1658 if constexpr (sizeof(Char) == sizeof(str_char_t))
1659 return lhs << std::basic_string_view<Char>{
1660 reinterpret_cast<const Char *>(str.data()), str.length()};
1661 else
1662 return lhs << str.data();
1663 }
1664 }
1665
1666 enum class TOML_OPEN_FLAGS_ENUM
1667 value_flags : uint16_t // being an "OPEN" flags enum is not an error
1668 {
1669 none,
1673 };
1675
1678 value_flags{static_cast<std::underlying_type_t<value_flags>>(-1)});
1679
1681 {
1682 none,
1692 indent_sub_tables = (1ull << 9),
1697 };
1699
1700 template <typename T>
1702 {
1703 static_assert(std::is_reference_v<T>);
1704
1706 };
1707 template <typename T>
1709 template <typename T>
1711
1712 using default_formatter = toml_formatter;
1713}
1715
1717{
1718 template <typename T>
1719 using remove_cvref = std::remove_cv_t<std::remove_reference_t<T>>;
1720
1721 template <typename... T>
1722 using common_signed_type = std::common_type_t<std::make_signed_t<T>...>;
1723
1724 template <typename T, typename... U>
1725 inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, U>);
1726
1727 template <typename... T>
1728 inline constexpr bool all_integral = (std::is_integral_v<T> && ...);
1729
1730 template <typename T>
1731 inline constexpr bool is_cvref =
1732 std::is_reference_v<T> || std::is_const_v<T> || std::is_volatile_v<T>;
1733
1734 template <typename T>
1735 inline constexpr bool is_wide_string = is_one_of<
1736 std::decay_t<T>,
1737 const wchar_t *,
1738 wchar_t *,
1739 std::wstring_view,
1740 std::wstring>;
1741
1742 template <typename T>
1743 inline constexpr bool value_retrieval_is_nothrow =
1744 !std::is_same_v<remove_cvref<T>, std::string>
1745#if TOML_HAS_CHAR8
1746 && !std::is_same_v<remove_cvref<T>, std::u8string>
1747#endif
1748
1750
1751 template <typename, typename>
1752 struct copy_ref_;
1753 template <typename Dest, typename Src>
1755
1756 template <typename Dest, typename Src>
1758 {
1759 using type = Dest;
1760 };
1761
1762 template <typename Dest, typename Src>
1763 struct copy_ref_<Dest, Src &>
1764 {
1765 using type = std::add_lvalue_reference_t<Dest>;
1766 };
1767
1768 template <typename Dest, typename Src>
1769 struct copy_ref_<Dest, Src &&>
1770 {
1771 using type = std::add_rvalue_reference_t<Dest>;
1772 };
1773
1774 template <typename, typename>
1775 struct copy_cv_;
1776 template <typename Dest, typename Src>
1778
1779 template <typename Dest, typename Src>
1781 {
1782 using type = Dest;
1783 };
1784
1785 template <typename Dest, typename Src>
1786 struct copy_cv_<Dest, const Src>
1787 {
1788 using type = std::add_const_t<Dest>;
1789 };
1790
1791 template <typename Dest, typename Src>
1792 struct copy_cv_<Dest, volatile Src>
1793 {
1794 using type = std::add_volatile_t<Dest>;
1795 };
1796
1797 template <typename Dest, typename Src>
1798 struct copy_cv_<Dest, const volatile Src>
1799 {
1800 using type = std::add_cv_t<Dest>;
1801 };
1802
1803 template <typename Dest, typename Src>
1805 copy_ref<
1806 copy_cv<std::remove_reference_t<Dest>, std::remove_reference_t<Src>>,
1807 Dest>,
1808 Src>;
1809
1810 template <typename...>
1811 inline constexpr bool always_false = false;
1812
1813 template <typename T, typename... U>
1814 inline constexpr bool first_is_same = false;
1815 template <typename T, typename... U>
1816 inline constexpr bool first_is_same<T, T, U...> = true;
1817
1818 template <typename T, bool = std::is_enum_v<T>>
1820 {
1821 using type = std::underlying_type_t<T>;
1822 };
1823 template <typename T>
1825 {
1826 using type = T;
1827 };
1828 template <typename T>
1830
1831 // general value traits
1832 // (as they relate to their equivalent native TOML type)
1834 {
1835 using native_type = void;
1836 static constexpr bool is_native = false;
1837 static constexpr bool is_losslessly_convertible_to_native = false;
1838 static constexpr bool can_represent_native = false;
1839 static constexpr bool can_partially_represent_native = false;
1840 static constexpr auto type = node_type::none;
1841 };
1842
1843 template <typename T>
1844 struct value_traits;
1845
1846 template <typename T, bool = std::is_enum_v<T>>
1848 {
1849 static_assert(!is_cvref<T>);
1850
1852 };
1853 template <typename T>
1855 {
1856 static_assert(!is_cvref<T>);
1857
1859 };
1860
1861 template <typename T>
1865 template <typename T>
1866 struct value_traits<const T> : value_traits<T>
1867 {
1868 };
1869 template <typename T>
1870 struct value_traits<volatile T> : value_traits<T>
1871 {
1872 };
1873 template <typename T>
1874 struct value_traits<const volatile T> : value_traits<T>
1875 {
1876 };
1877 template <typename T>
1879 {
1880 };
1881 template <typename T>
1883 {
1884 };
1885
1886 // integer value_traits specializations - standard types
1887 template <typename T>
1889 {
1890 static constexpr T min =
1891 T{(std::numeric_limits<underlying_type<T>>::min)()};
1892 static constexpr T max =
1893 T{(std::numeric_limits<underlying_type<T>>::max)()};
1894 };
1895 template <typename T>
1897 {
1898 using native_type = int64_t;
1899 static constexpr bool is_native =
1900 std::is_same_v<underlying_type<T>, native_type>;
1901 static constexpr bool is_signed =
1902 static_cast<underlying_type<T>>(-1) < underlying_type<T>{};
1903 static constexpr auto type = node_type::integer;
1904 static constexpr bool can_partially_represent_native = true;
1905 };
1906 template <typename T>
1908 {
1910 integer_limits<underlying_type<T>>::max <= 9223372036854775807ULL;
1911 static constexpr bool can_represent_native = false;
1912 };
1913 template <typename T>
1915 {
1916 using native_type = int64_t;
1919 (-9223372036854775807LL - 1LL) &&
1920 integer_limits<underlying_type<T>>::max <= 9223372036854775807LL;
1921 static constexpr bool can_represent_native =
1923 (-9223372036854775807LL - 1LL) &&
1924 integer_limits<underlying_type<T>>::max >= 9223372036854775807LL;
1925 };
1926 template <typename T, bool S = integer_traits_base<T>::is_signed>
1928 {
1929 };
1930 template <typename T>
1932 {
1933 };
1934 template <>
1935 struct value_traits<signed char> : integer_traits<signed char>
1936 {
1937 };
1938 template <>
1939 struct value_traits<unsigned char> : integer_traits<unsigned char>
1940 {
1941 };
1942 template <>
1943 struct value_traits<signed short> : integer_traits<signed short>
1944 {
1945 };
1946 template <>
1947 struct value_traits<unsigned short> : integer_traits<unsigned short>
1948 {
1949 };
1950 template <>
1951 struct value_traits<signed int> : integer_traits<signed int>
1952 {
1953 };
1954 template <>
1955 struct value_traits<unsigned int> : integer_traits<unsigned int>
1956 {
1957 };
1958 template <>
1959 struct value_traits<signed long> : integer_traits<signed long>
1960 {
1961 };
1962 template <>
1963 struct value_traits<unsigned long> : integer_traits<unsigned long>
1964 {
1965 };
1966 template <>
1967 struct value_traits<signed long long> : integer_traits<signed long long>
1968 {
1969 };
1970 template <>
1971 struct value_traits<unsigned long long> : integer_traits<unsigned long long>
1972 {
1973 };
1974 static_assert(value_traits<int64_t>::is_native);
1975 static_assert(value_traits<int64_t>::is_signed);
1979
1980 // integer value_traits specializations - non-standard types
1981#ifdef TOML_INT128
1982 template <>
1983 struct integer_limits<TOML_INT128>
1984 {
1985 static constexpr TOML_INT128 max = static_cast<TOML_INT128>(
1986 (TOML_UINT128{1u} << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1);
1987 static constexpr TOML_INT128 min = -max - TOML_INT128{1};
1988 };
1989 template <>
1990 struct integer_limits<TOML_UINT128>
1991 {
1992 static constexpr TOML_UINT128 min = TOML_UINT128{};
1993 static constexpr TOML_UINT128 max =
1994 (2u * static_cast<TOML_UINT128>(integer_limits<TOML_INT128>::max)) + 1u;
1995 };
1996 template <>
1997 struct value_traits<TOML_INT128> : integer_traits<TOML_INT128>
1998 {
1999 };
2000 template <>
2001 struct value_traits<TOML_UINT128> : integer_traits<TOML_UINT128>
2002 {
2003 };
2004#endif
2005#ifdef TOML_SMALL_INT_TYPE
2006 template <>
2007 struct value_traits<TOML_SMALL_INT_TYPE>
2008 : signed_integer_traits<TOML_SMALL_INT_TYPE>
2009 {
2010 };
2011#endif
2012
2013 // floating-point traits base
2014 template <typename T, int MantissaDigits, int DecimalDigits>
2016 {
2017 static constexpr auto type = node_type::floating_point;
2018 using native_type = double;
2019 static constexpr bool is_native = std::is_same_v<T, native_type>;
2020 static constexpr bool is_signed = true;
2021
2022 static constexpr int bits = static_cast<int>(sizeof(T) * CHAR_BIT);
2023 static constexpr int digits = MantissaDigits;
2024 static constexpr int digits10 = DecimalDigits;
2025
2027 bits <= 64 //
2028 && digits <= 53 // DBL_MANT_DIG
2029 && digits10 <= 15; // DBL_DIG
2030
2031 static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG
2032 && digits10 >= 15; // DBL_DIG
2033
2034 static constexpr bool can_partially_represent_native =
2035 digits > 0 && digits10 > 0;
2036 };
2037 template <typename T>
2039 T,
2040 std::numeric_limits<T>::digits,
2041 std::numeric_limits<T>::digits10>
2042 {
2043 };
2044#if TOML_ENABLE_FLOAT16
2045 template <>
2046 struct float_traits<_Float16>
2047 : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__>
2048 {
2049 };
2050#endif
2051#ifdef TOML_FLOAT128
2052 template <>
2053 struct float_traits<TOML_FLOAT128>
2054 : float_traits_base<TOML_FLOAT128, __FLT128_MANT_DIG__, __FLT128_DIG__>
2055 {
2056 };
2057#endif
2058
2059 // floating-point traits
2060 template <>
2062 {
2063 };
2064 template <>
2065 struct value_traits<double> : float_traits<double>
2066 {
2067 };
2068 template <>
2069 struct value_traits<long double> : float_traits<long double>
2070 {
2071 };
2072#if TOML_ENABLE_FLOAT16
2073 template <>
2074 struct value_traits<_Float16> : float_traits<_Float16>
2075 {
2076 };
2077#endif
2078#ifdef TOML_FLOAT128
2079 template <>
2080 struct value_traits<TOML_FLOAT128> : float_traits<TOML_FLOAT128>
2081 {
2082 };
2083#endif
2084#ifdef TOML_SMALL_FLOAT_TYPE
2085 template <>
2086 struct value_traits<TOML_SMALL_FLOAT_TYPE>
2087 : float_traits<TOML_SMALL_FLOAT_TYPE>
2088 {
2089 };
2090#endif
2091 static_assert(value_traits<double>::is_native);
2095
2096 // string value_traits specializations - char-based strings
2097 template <typename T>
2099 {
2100 using native_type = std::string;
2101 static constexpr bool is_native = std::is_same_v<T, native_type>;
2102 static constexpr bool is_losslessly_convertible_to_native = true;
2103 static constexpr bool can_represent_native =
2104 !std::is_array_v<T> &&
2105 (!std::is_pointer_v<T> || std::is_const_v<std::remove_pointer_t<T>>);
2107 static constexpr auto type = node_type::string;
2108 };
2109 template <>
2110 struct value_traits<std::string> : string_traits<std::string>
2111 {
2112 };
2113 template <>
2114 struct value_traits<std::string_view> : string_traits<std::string_view>
2115 {
2116 };
2117 template <>
2119 {
2120 };
2121 template <size_t N>
2122 struct value_traits<const char[N]> : string_traits<const char[N]>
2123 {
2124 };
2125 template <>
2127 {
2128 };
2129 template <size_t N>
2130 struct value_traits<char[N]> : string_traits<char[N]>
2131 {
2132 };
2133
2134 // string value_traits specializations - char8_t-based strings
2135#if TOML_HAS_CHAR8
2136 template <>
2137 struct value_traits<std::u8string> : string_traits<std::u8string>
2138 {
2139 };
2140 template <>
2141 struct value_traits<std::u8string_view> : string_traits<std::u8string_view>
2142 {
2143 };
2144 template <>
2145 struct value_traits<const char8_t *> : string_traits<const char8_t *>
2146 {
2147 };
2148 template <size_t N>
2149 struct value_traits<const char8_t[N]> : string_traits<const char8_t[N]>
2150 {
2151 };
2152 template <>
2153 struct value_traits<char8_t *> : string_traits<char8_t *>
2154 {
2155 };
2156 template <size_t N>
2157 struct value_traits<char8_t[N]> : string_traits<char8_t[N]>
2158 {
2159 };
2160#endif
2161
2162 // string value_traits specializations - wchar_t-based strings on Windows
2163#if TOML_ENABLE_WINDOWS_COMPAT
2164 template <typename T>
2165 struct wstring_traits
2166 {
2167 using native_type = std::string;
2168 static constexpr bool is_native = false;
2169 static constexpr bool is_losslessly_convertible_to_native = true; // narrow
2170 static constexpr bool can_represent_native =
2171 std::is_same_v<T, std::wstring>; // widen
2173 static constexpr auto type = node_type::string;
2174 };
2175 template <>
2176 struct value_traits<std::wstring> : wstring_traits<std::wstring>
2177 {
2178 };
2179 template <>
2180 struct value_traits<std::wstring_view> : wstring_traits<std::wstring_view>
2181 {
2182 };
2183 template <>
2184 struct value_traits<const wchar_t *> : wstring_traits<const wchar_t *>
2185 {
2186 };
2187 template <size_t N>
2188 struct value_traits<const wchar_t[N]> : wstring_traits<const wchar_t[N]>
2189 {
2190 };
2191 template <>
2192 struct value_traits<wchar_t *> : wstring_traits<wchar_t *>
2193 {
2194 };
2195 template <size_t N>
2196 struct value_traits<wchar_t[N]> : wstring_traits<wchar_t[N]>
2197 {
2198 };
2199#endif
2200
2201 // other 'native' value_traits specializations
2202 template <typename T, node_type NodeType>
2204 {
2206 static constexpr bool is_native = true;
2207 static constexpr bool is_losslessly_convertible_to_native = true;
2208 static constexpr bool can_represent_native = true;
2209 static constexpr bool can_partially_represent_native = true;
2210 static constexpr auto type = NodeType;
2211 };
2212 template <>
2213 struct value_traits<bool> : native_value_traits<bool, node_type::boolean>
2214 {
2215 };
2216 template <>
2217 struct value_traits<date> : native_value_traits<date, node_type::date>
2218 {
2219 };
2220 template <>
2221 struct value_traits<time> : native_value_traits<time, node_type::time>
2222 {
2223 };
2224 template <>
2226 : native_value_traits<date_time, node_type::date_time>
2227 {
2228 };
2229
2230 // native value category queries
2231 template <typename T>
2233 template <typename T>
2234 inline constexpr bool is_native = value_traits<T>::is_native;
2235 template <typename T>
2236 inline constexpr bool can_represent_native =
2238 template <typename T>
2239 inline constexpr bool can_partially_represent_native =
2241 template <typename T>
2244 template <typename T, typename... U>
2245 inline constexpr bool is_natively_one_of = is_one_of<native_type_of<T>, U...>;
2246
2247 // native value types => nodes
2248 template <typename T>
2250 {
2251 using type = T;
2252 };
2253 template <typename T>
2254 struct node_wrapper<const T>
2255 {
2256 using type = std::add_const_t<typename node_wrapper<T>::type>;
2257 };
2258 template <typename T>
2259 struct node_wrapper<volatile T>
2260 {
2261 using type = std::add_volatile_t<typename node_wrapper<T>::type>;
2262 };
2263 template <typename T>
2264 struct node_wrapper<const volatile T>
2265 {
2266 using type =
2267 std::add_const_t<std::add_volatile_t<typename node_wrapper<T>::type>>;
2268 };
2269 template <>
2271 {
2273 };
2274 template <>
2275 struct node_wrapper<int64_t>
2276 {
2278 };
2279 template <>
2280 struct node_wrapper<double>
2281 {
2283 };
2284 template <>
2286 {
2288 };
2289 template <>
2290 struct node_wrapper<date>
2291 {
2293 };
2294 template <>
2296 {
2298 };
2299 template <>
2301 {
2303 };
2304 template <typename T>
2306
2307 // nodes => native value types
2308 template <typename T>
2310 {
2311 using type = T;
2312 };
2313 template <typename T>
2315 {
2316 using type = T;
2317 };
2318 template <typename T>
2319 struct node_unwrapper<const value<T>>
2320 {
2321 using type = std::add_const_t<T>;
2322 };
2323 template <typename T>
2324 struct node_unwrapper<volatile value<T>>
2325 {
2326 using type = std::add_volatile_t<T>;
2327 };
2328 template <typename T>
2329 struct node_unwrapper<const volatile value<T>>
2330 {
2331 using type = std::add_volatile_t<std::add_const_t<T>>;
2332 };
2333 template <typename T>
2335
2336 template <typename T>
2338 {
2339 static constexpr auto value = value_traits<T>::type;
2340 };
2341 template <>
2343 {
2344 static constexpr auto value = node_type::table;
2345 };
2346 template <>
2348 {
2349 static constexpr auto value = node_type::array;
2350 };
2351 template <>
2352 struct node_type_getter<void>
2353 {
2354 static constexpr auto value = node_type::none;
2355 };
2356 template <typename T>
2357 inline constexpr node_type node_type_of =
2359
2360 template <typename T, typename ConvertFrom>
2361 inline constexpr bool is_constructible_or_convertible =
2362 std::is_constructible_v<T, ConvertFrom> //
2363 || std::is_convertible_v<ConvertFrom, T>;
2364}
2366
2368{
2369 template <typename T>
2370 inline constexpr bool is_table = std::is_same_v<impl::remove_cvref<T>, table>;
2371
2372 template <typename T>
2373 inline constexpr bool is_array = std::is_same_v<impl::remove_cvref<T>, array>;
2374
2375 template <typename T>
2376 inline constexpr bool is_container = is_table<T> || is_array<T>;
2377
2378 template <typename T>
2379 inline constexpr bool is_string = std::is_same_v< //
2380 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2382
2383 template <typename T>
2384 inline constexpr bool is_integer = std::is_same_v< //
2385 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2387
2388 template <typename T>
2389 inline constexpr bool is_floating_point = std::is_same_v< //
2390 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2392
2393 template <typename T>
2395
2396 template <typename T>
2397 inline constexpr bool is_boolean = std::is_same_v< //
2398 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2399 value<bool>>;
2400
2401 template <typename T>
2402 inline constexpr bool is_date = std::is_same_v< //
2403 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2404 value<date>>;
2405
2406 template <typename T>
2407 inline constexpr bool is_time = std::is_same_v< //
2408 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2409 value<time>>;
2410
2411 template <typename T>
2412 inline constexpr bool is_date_time = std::is_same_v< //
2413 impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2415
2416 template <typename T>
2417 inline constexpr bool is_chronological =
2419
2420 template <typename T>
2421 inline constexpr bool is_value =
2423
2424 template <typename T>
2425 inline constexpr bool is_node =
2426 std::is_same_v<toml::node, impl::remove_cvref<T>> //
2427 || std::is_base_of_v<toml::node, impl::remove_cvref<T>>;
2428
2429 template <typename T>
2430 inline constexpr bool is_node_view = impl::
2431 is_one_of<impl::remove_cvref<T>, node_view<node>, node_view<const node>>;
2432}
2434
2436{
2437 template <typename T>
2438 TOML_CONST_INLINE_GETTER constexpr std::underlying_type_t<T> unwrap_enum(
2439 T val) noexcept
2440 {
2441 return static_cast<std::underlying_type_t<T>>(val);
2442 }
2443
2444 // Q: "why not use std::fpclassify?"
2445 // A: Because it gets broken by -ffast-math and friends
2446 enum class TOML_CLOSED_ENUM fp_class : unsigned
2447 {
2448 ok,
2449 neg_inf,
2450 pos_inf,
2451 nan
2452 };
2453
2455 inline fp_class fpclassify(const double &val) noexcept
2456 {
2457 static_assert(sizeof(uint64_t) == sizeof(double));
2458
2459 static constexpr uint64_t sign =
2460 0b1000000000000000000000000000000000000000000000000000000000000000ull;
2461 static constexpr uint64_t exponent =
2462 0b0111111111110000000000000000000000000000000000000000000000000000ull;
2463 static constexpr uint64_t mantissa =
2464 0b0000000000001111111111111111111111111111111111111111111111111111ull;
2465
2466 uint64_t val_bits;
2467 std::memcpy(&val_bits, &val, sizeof(val));
2468 if ((val_bits & exponent) != exponent)
2469 return fp_class::ok;
2470 if ((val_bits & mantissa))
2471 return fp_class::nan;
2472 return (val_bits & sign) ? fp_class::neg_inf : fp_class::pos_inf;
2473 }
2474
2475 // Q: "why not use std::find and std::min?"
2476 // A: Because <algorithm> is _huge_ and these would be the only things I used from it.
2477 // I don't want to impose such a heavy compile-time burden on users.
2478
2479 template <typename Iterator, typename T>
2481 Iterator start, Iterator end, const T &needle) noexcept //
2482 ->decltype(&(*start))
2483 {
2484 for (; start != end; start++)
2485 if (*start == needle)
2486 return &(*start);
2487 return nullptr;
2488 }
2489
2490 template <typename T>
2492 const T &a, const T &b) noexcept //
2493 {
2494 return a < b ? a : b;
2495 }
2496}
2498
2499#ifdef _MSC_VER
2500# pragma pop_macro("min")
2501# pragma pop_macro("max")
2502# ifndef __clang__
2503# pragma inline_recursion(off)
2504# endif
2505#endif
2507
2508//******** impl/print_to_stream.hpp **********************************************************************************
2509
2511#ifdef _MSC_VER
2512# ifndef __clang__
2513# pragma inline_recursion(on)
2514# endif
2515# pragma push_macro("min")
2516# pragma push_macro("max")
2517# undef min
2518# undef max
2519#endif
2520
2522{
2523 // Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
2524 // A: - I'm using <charconv> to format numerics. Faster and locale-independent.
2525 // - I can (potentially) avoid forcing users to drag in <sstream> and <iomanip>.
2526 // - Strings in C++. Honestly.
2527
2529 TOML_ATTR(nonnull)
2530 void TOML_CALLCONV print_to_stream(std::ostream &, const char *, size_t);
2531
2533 void TOML_CALLCONV print_to_stream(std::ostream &, std::string_view);
2534
2536 void TOML_CALLCONV print_to_stream(std::ostream &, const std::string &);
2537
2539 void TOML_CALLCONV print_to_stream(std::ostream &, char);
2540
2543 std::ostream &, signed char, value_flags = {}, size_t min_digits = 0);
2544
2547 std::ostream &, signed short, value_flags = {}, size_t min_digits = 0);
2548
2551 std::ostream &, signed int, value_flags = {}, size_t min_digits = 0);
2552
2555 std::ostream &, signed long, value_flags = {}, size_t min_digits = 0);
2556
2559 std::ostream &, signed long long, value_flags = {}, size_t min_digits = 0);
2560
2563 std::ostream &, unsigned char, value_flags = {}, size_t min_digits = 0);
2564
2567 std::ostream &, unsigned short, value_flags = {}, size_t min_digits = 0);
2568
2571 std::ostream &, unsigned int, value_flags = {}, size_t min_digits = 0);
2572
2575 std::ostream &, unsigned long, value_flags = {}, size_t min_digits = 0);
2576
2579 std::ostream &,
2580 unsigned long long,
2581 value_flags = {},
2582 size_t min_digits = 0);
2583
2586 std::ostream &, float, value_flags = {}, bool relaxed_precision = false);
2587
2590 std::ostream &, double, value_flags = {}, bool relaxed_precision = false);
2591
2593 void TOML_CALLCONV print_to_stream(std::ostream &, bool);
2594
2596 void TOML_CALLCONV print_to_stream(std::ostream &, const toml::date &);
2597
2599 void TOML_CALLCONV print_to_stream(std::ostream &, const toml::time &);
2600
2602 void TOML_CALLCONV print_to_stream(std::ostream &, const toml::time_offset &);
2603
2605 void TOML_CALLCONV print_to_stream(std::ostream &, const toml::date_time &);
2606
2608 void TOML_CALLCONV print_to_stream(std::ostream &, const source_position &);
2609
2611 void TOML_CALLCONV print_to_stream(std::ostream &, const source_region &);
2612
2613#if TOML_ENABLE_FORMATTERS
2614
2616 void TOML_CALLCONV print_to_stream(std::ostream &, const array &);
2617
2619 void TOML_CALLCONV print_to_stream(std::ostream &, const table &);
2620
2623 std::ostream &, const value<std::string> &);
2624
2626 void TOML_CALLCONV print_to_stream(std::ostream &, const value<int64_t> &);
2627
2629 void TOML_CALLCONV print_to_stream(std::ostream &, const value<double> &);
2630
2632 void TOML_CALLCONV print_to_stream(std::ostream &, const value<bool> &);
2633
2635 void TOML_CALLCONV print_to_stream(std::ostream &, const value<date> &);
2636
2638 void TOML_CALLCONV print_to_stream(std::ostream &, const value<time> &);
2639
2641 void TOML_CALLCONV print_to_stream(std::ostream &, const value<date_time> &);
2642
2643#endif
2644
2645 template <typename T, typename U>
2647 std::ostream & stream, const T &val, const U &bookend)
2648 {
2649 print_to_stream(stream, bookend);
2650 print_to_stream(stream, val);
2651 print_to_stream(stream, bookend);
2652 }
2653}
2655
2656#ifdef _MSC_VER
2657# pragma pop_macro("min")
2658# pragma pop_macro("max")
2659# ifndef __clang__
2660# pragma inline_recursion(off)
2661# endif
2662#endif
2664
2665//******** impl/source_region.hpp ************************************************************************************
2666
2668#ifdef _MSC_VER
2669# ifndef __clang__
2670# pragma inline_recursion(on)
2671# endif
2672# pragma push_macro("min")
2673# pragma push_macro("max")
2674# undef min
2675# undef max
2676#endif
2677
2679{
2680 using source_index = uint32_t;
2681
2682 using source_path_ptr = std::shared_ptr<const std::string>;
2683
2685 {
2686 source_index line;
2687
2688 source_index column;
2689
2691 explicit constexpr operator bool() const noexcept
2692 {
2693 return line > source_index{} //
2694 && column > source_index{};
2695 }
2696
2698 friend constexpr bool
2699 operator==(const source_position &lhs, const source_position &rhs) noexcept
2700 {
2701 return lhs.line == rhs.line //
2702 && lhs.column == rhs.column;
2703 }
2704
2706 friend constexpr bool
2707 operator!=(const source_position &lhs, const source_position &rhs) noexcept
2708 {
2709 return !(lhs == rhs);
2710 }
2711
2712 private:
2714 static constexpr uint64_t pack(const source_position &pos) noexcept
2715 {
2716 return static_cast<uint64_t>(pos.line) << 32 |
2717 static_cast<uint64_t>(pos.column);
2718 }
2719
2720 public:
2722 friend constexpr bool
2723 operator<(const source_position &lhs, const source_position &rhs) noexcept
2724 {
2725 return pack(lhs) < pack(rhs);
2726 }
2727
2729 friend constexpr bool
2730 operator<=(const source_position &lhs, const source_position &rhs) noexcept
2731 {
2732 return pack(lhs) <= pack(rhs);
2733 }
2734
2736 friend constexpr bool
2737 operator>(const source_position &lhs, const source_position &rhs) noexcept
2738 {
2739 return pack(lhs) > pack(rhs);
2740 }
2741
2743 friend constexpr bool
2744 operator>=(const source_position &lhs, const source_position &rhs) noexcept
2745 {
2746 return pack(lhs) >= pack(rhs);
2747 }
2748
2749 friend std::ostream &
2750 operator<<(std::ostream &lhs, const source_position &rhs)
2751 {
2752 impl::print_to_stream(lhs, rhs);
2753 return lhs;
2754 }
2755 };
2756
2758 {
2760
2762
2764
2765#if TOML_ENABLE_WINDOWS_COMPAT
2766
2768 optional<std::wstring> wide_path() const
2769 {
2770 if (!path || path->empty())
2771 return {};
2772 return {impl::widen(*path)};
2773 }
2774
2775#endif
2776
2777 friend std::ostream &operator<<(std::ostream &lhs, const source_region &rhs)
2778 {
2779 impl::print_to_stream(lhs, rhs);
2780 return lhs;
2781 }
2782 };
2783}
2785
2786#ifdef _MSC_VER
2787# pragma pop_macro("min")
2788# pragma pop_macro("max")
2789# ifndef __clang__
2790# pragma inline_recursion(off)
2791# endif
2792#endif
2794
2795//******** impl/date_time.hpp ****************************************************************************************
2796
2798#ifdef _MSC_VER
2799# ifndef __clang__
2800# pragma inline_recursion(on)
2801# endif
2802# pragma push_macro("min")
2803# pragma push_macro("max")
2804# undef min
2805# undef max
2806#endif
2807
2809{
2810 struct TOML_TRIVIAL_ABI date
2811 {
2812 uint16_t year;
2813
2814 uint8_t month;
2815
2816 uint8_t day;
2817
2819 date() noexcept = default;
2820
2822 (impl::all_integral<Y, M, D>),
2823 typename Y,
2824 typename M,
2825 typename D)
2827 constexpr date(Y y, M m, D d) noexcept //
2828 : year{static_cast<uint16_t>(y)},
2829 month{static_cast<uint8_t>(m)},
2830 day{static_cast<uint8_t>(d)}
2831 {
2832 }
2833
2835 friend constexpr bool operator==(const date &lhs, const date &rhs) noexcept
2836 {
2837 return lhs.year == rhs.year //
2838 && lhs.month == rhs.month //
2839 && lhs.day == rhs.day;
2840 }
2841
2843 friend constexpr bool operator!=(const date &lhs, const date &rhs) noexcept
2844 {
2845 return !(lhs == rhs);
2846 }
2847
2848 private:
2850 static constexpr uint32_t pack(const date &d) noexcept
2851 {
2852 return (static_cast<uint32_t>(d.year) << 16) |
2853 (static_cast<uint32_t>(d.month) << 8) |
2854 static_cast<uint32_t>(d.day);
2855 }
2856
2857 public:
2859 friend constexpr bool operator<(const date &lhs, const date &rhs) noexcept
2860 {
2861 return pack(lhs) < pack(rhs);
2862 }
2863
2865 friend constexpr bool operator<=(const date &lhs, const date &rhs) noexcept
2866 {
2867 return pack(lhs) <= pack(rhs);
2868 }
2869
2871 friend constexpr bool operator>(const date &lhs, const date &rhs) noexcept
2872 {
2873 return pack(lhs) > pack(rhs);
2874 }
2875
2877 friend constexpr bool operator>=(const date &lhs, const date &rhs) noexcept
2878 {
2879 return pack(lhs) >= pack(rhs);
2880 }
2881
2882 friend std::ostream &operator<<(std::ostream &lhs, const date &rhs)
2883 {
2884 impl::print_to_stream(lhs, rhs);
2885 return lhs;
2886 }
2887 };
2888
2890 {
2891 uint8_t hour;
2892
2893 uint8_t minute;
2894
2895 uint8_t second;
2896
2897 uint32_t nanosecond;
2898
2900 time() noexcept = default;
2901
2903 (impl::all_integral<H, M, S, NS>),
2904 typename H,
2905 typename M,
2906 typename S = uint8_t,
2907 typename NS = uint32_t)
2909 constexpr time(H h, M m, S s = S{}, NS ns = NS{}) noexcept //
2910 : hour{static_cast<uint8_t>(h)},
2911 minute{static_cast<uint8_t>(m)},
2912 second{static_cast<uint8_t>(s)},
2913 nanosecond{static_cast<uint32_t>(ns)}
2914 {
2915 }
2916
2918 friend constexpr bool operator==(const time &lhs, const time &rhs) noexcept
2919 {
2920 return lhs.hour == rhs.hour //
2921 && lhs.minute == rhs.minute //
2922 && lhs.second == rhs.second //
2923 && lhs.nanosecond == rhs.nanosecond;
2924 }
2925
2927 friend constexpr bool operator!=(const time &lhs, const time &rhs) noexcept
2928 {
2929 return !(lhs == rhs);
2930 }
2931
2932 private:
2934 static constexpr uint64_t pack(const time &t) noexcept
2935 {
2936 return static_cast<uint64_t>(t.hour) << 48 |
2937 static_cast<uint64_t>(t.minute) << 40 |
2938 static_cast<uint64_t>(t.second) << 32 |
2939 static_cast<uint64_t>(t.nanosecond);
2940 }
2941
2942 public:
2944 friend constexpr bool operator<(const time &lhs, const time &rhs) noexcept
2945 {
2946 return pack(lhs) < pack(rhs);
2947 }
2948
2950 friend constexpr bool operator<=(const time &lhs, const time &rhs) noexcept
2951 {
2952 return pack(lhs) <= pack(rhs);
2953 }
2954
2956 friend constexpr bool operator>(const time &lhs, const time &rhs) noexcept
2957 {
2958 return pack(lhs) > pack(rhs);
2959 }
2960
2962 friend constexpr bool operator>=(const time &lhs, const time &rhs) noexcept
2963 {
2964 return pack(lhs) >= pack(rhs);
2965 }
2966
2967 friend std::ostream &operator<<(std::ostream &lhs, const time &rhs)
2968 {
2969 impl::print_to_stream(lhs, rhs);
2970 return lhs;
2971 }
2972 };
2973
2975 {
2976 int16_t minutes;
2977
2980
2982 (impl::all_integral<H, M>),
2983 typename H,
2984 typename M)
2986 constexpr time_offset(H h, M m) noexcept //
2987 : minutes{static_cast<int16_t>(
2988 static_cast<impl::common_signed_type<H, M>>(h) *
2989 impl::common_signed_type<H, M>{60} +
2990 static_cast<impl::common_signed_type<H, M>>(m))}
2991 {
2992 }
2993
2995 friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
2996 {
2997 return lhs.minutes == rhs.minutes;
2998 }
2999
3001 friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
3002 {
3003 return lhs.minutes != rhs.minutes;
3004 }
3005
3007 friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
3008 {
3009 return lhs.minutes < rhs.minutes;
3010 }
3011
3013 friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
3014 {
3015 return lhs.minutes <= rhs.minutes;
3016 }
3017
3019 friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
3020 {
3021 return lhs.minutes > rhs.minutes;
3022 }
3023
3025 friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
3026 {
3027 return lhs.minutes >= rhs.minutes;
3028 }
3029
3030 friend std::ostream &operator<<(std::ostream &lhs, const time_offset &rhs)
3031 {
3032 impl::print_to_stream(lhs, rhs);
3033 return lhs;
3034 }
3035 };
3036
3038
3040 {
3041 toml::date date;
3042
3043 toml::time time;
3044
3045 optional<toml::time_offset> offset;
3046
3048 date_time() noexcept = default;
3049
3051 constexpr date_time(const toml::date &d, const toml::time &t) noexcept //
3052 : date{d}, time{t}, offset{} // TINAE - icc bugfix
3053 {
3054 }
3055
3057 explicit constexpr date_time(const toml::date &d) noexcept //
3058 : date{d}, time{}, offset{} // TINAE - icc bugfix
3059 {
3060 }
3061
3063 explicit constexpr date_time(const toml::time &t) noexcept //
3064 : date{}, time{t}, offset{} // TINAE - icc bugfix
3065 {
3066 }
3067
3069 constexpr date_time(
3070 const toml::date &d,
3071 const toml::time &t,
3072 const toml::time_offset &off) noexcept
3073 : date{d}, time{t}, offset{off}
3074 {
3075 }
3076
3078 constexpr bool is_local() const noexcept
3079 {
3080 return !offset.has_value();
3081 }
3082
3084 friend constexpr bool
3085 operator==(const date_time &lhs, const date_time &rhs) noexcept
3086 {
3087 return lhs.date == rhs.date //
3088 && lhs.time == rhs.time //
3089 && lhs.offset == rhs.offset;
3090 }
3091
3093 friend constexpr bool
3094 operator!=(const date_time &lhs, const date_time &rhs) noexcept
3095 {
3096 return !(lhs == rhs);
3097 }
3098
3100 friend constexpr bool
3101 operator<(const date_time &lhs, const date_time &rhs) noexcept
3102 {
3103 if (lhs.date != rhs.date)
3104 return lhs.date < rhs.date;
3105 if (lhs.time != rhs.time)
3106 return lhs.time < rhs.time;
3107 return lhs.offset < rhs.offset;
3108 }
3109
3111 friend constexpr bool
3112 operator<=(const date_time &lhs, const date_time &rhs) noexcept
3113 {
3114 if (lhs.date != rhs.date)
3115 return lhs.date < rhs.date;
3116 if (lhs.time != rhs.time)
3117 return lhs.time < rhs.time;
3118 return lhs.offset <= rhs.offset;
3119 }
3120
3122 friend constexpr bool
3123 operator>(const date_time &lhs, const date_time &rhs) noexcept
3124 {
3125 return !(lhs <= rhs);
3126 }
3127
3129 friend constexpr bool
3130 operator>=(const date_time &lhs, const date_time &rhs) noexcept
3131 {
3132 return !(lhs < rhs);
3133 }
3134
3135 friend std::ostream &operator<<(std::ostream &lhs, const date_time &rhs)
3136 {
3137 impl::print_to_stream(lhs, rhs);
3138 return lhs;
3139 }
3140 };
3141
3142 TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
3143}
3145
3146#ifdef _MSC_VER
3147# pragma pop_macro("min")
3148# pragma pop_macro("max")
3149# ifndef __clang__
3150# pragma inline_recursion(off)
3151# endif
3152#endif
3154
3155//******** impl/at_path.hpp ******************************************************************************************
3156
3158{
3159 template <typename T>
3160 using parse_path_callback = bool(TOML_CALLCONV *)(void *, T);
3161
3164 std::string_view,
3165 void *,
3166 parse_path_callback<std::string_view>,
3167 parse_path_callback<size_t>);
3168}
3170
3172{
3176 node & root, std::string_view path) noexcept;
3177
3181 const node &root, std::string_view path) noexcept;
3182
3183#if TOML_ENABLE_WINDOWS_COMPAT
3184
3187 node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path);
3188
3192 const node &root, std::wstring_view path);
3193
3194#endif
3195}
3197
3198//******** impl/std_vector.hpp ***************************************************************************************
3199
3201#include <vector>
3202#include <iterator>
3204
3205//******** impl/path.hpp *********************************************************************************************
3206
3208#ifdef _MSC_VER
3209# ifndef __clang__
3210# pragma inline_recursion(on)
3211# endif
3212# pragma push_macro("min")
3213# pragma push_macro("max")
3214# undef min
3215# undef max
3216#endif
3217
3219{
3220 enum class TOML_CLOSED_ENUM path_component_type : uint8_t
3221 {
3222 key = 0x1,
3223 array_index = 0x2
3224 };
3225
3227 {
3228 struct storage_t
3229 {
3230 static constexpr size_t size =
3231 (sizeof(size_t) < sizeof(std::string) ? sizeof(std::string)
3232 : sizeof(size_t));
3233 static constexpr size_t align =
3234 (alignof(size_t) < alignof(std::string) ? alignof(std::string)
3235 : alignof(size_t));
3236
3237 alignas(align) unsigned char bytes[size];
3238 };
3239 alignas(storage_t::align) mutable storage_t value_storage_;
3240
3241 path_component_type type_;
3242
3245 static bool TOML_CALLCONV
3246 equal(const path_component &, const path_component &) noexcept;
3247
3248 template <typename Type>
3249 TOML_PURE_INLINE_GETTER static Type *get_as(storage_t &s) noexcept
3250 {
3251 return TOML_LAUNDER(reinterpret_cast<Type *>(s.bytes));
3252 }
3253
3254 static void store_key(std::string_view key, storage_t &storage_)
3255 {
3256 ::new (static_cast<void *>(storage_.bytes)) std::string{key};
3257 }
3258
3259 static void store_index(size_t index, storage_t &storage_) noexcept
3260 {
3261 ::new (static_cast<void *>(storage_.bytes)) std::size_t{index};
3262 }
3263
3264 void destroy() noexcept
3265 {
3266 if (type_ == path_component_type::key)
3267 get_as<std::string>(value_storage_)->~basic_string();
3268 }
3269
3271 size_t &index_ref() noexcept
3272 {
3273 TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
3274 return *get_as<size_t>(value_storage_);
3275 }
3276
3278 std::string &key_ref() noexcept
3279 {
3280 TOML_ASSERT_ASSUME(type_ == path_component_type::key);
3281 return *get_as<std::string>(value_storage_);
3282 }
3283
3284 public:
3288
3291 path_component(size_t index) noexcept;
3292
3295 path_component(std::string_view key);
3296
3297#if TOML_ENABLE_WINDOWS_COMPAT
3298
3301 path_component(std::wstring_view key);
3302
3303#endif
3304
3308
3312
3315
3318
3320 path_component &operator=(size_t new_index) noexcept;
3321
3323 path_component &operator=(std::string_view new_key);
3324
3325#if TOML_ENABLE_WINDOWS_COMPAT
3326
3328 path_component &operator=(std::wstring_view new_key);
3329
3330#endif
3331
3333 {
3334 destroy();
3335 }
3336
3338 size_t index() const noexcept
3339 {
3340 TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
3341 return *get_as<const size_t>(value_storage_);
3342 }
3343
3345 explicit operator size_t() const noexcept
3346 {
3347 return index();
3348 }
3349
3351 const std::string &key() const noexcept
3352 {
3353 TOML_ASSERT_ASSUME(type_ == path_component_type::key);
3354 return *get_as<const std::string>(value_storage_);
3355 }
3356
3358 explicit operator const std::string &() const noexcept
3359 {
3360 return key();
3361 }
3362
3364 path_component_type type() const noexcept
3365 {
3366 return type_;
3367 }
3368
3370 friend bool
3371 operator==(const path_component &lhs, const path_component &rhs) noexcept
3372 {
3373 return equal(lhs, rhs);
3374 }
3375
3377 friend bool
3378 operator!=(const path_component &lhs, const path_component &rhs) noexcept
3379 {
3380 return !equal(lhs, rhs);
3381 }
3382 };
3383
3385 {
3386 private:
3387 std::vector<path_component> components_;
3388
3390 void print_to(std::ostream &) const;
3391
3394 static bool TOML_CALLCONV equal(const path &, const path &) noexcept;
3395
3396 public:
3398 path() noexcept = default;
3399
3402 explicit path(std::string_view);
3403
3404#if TOML_ENABLE_WINDOWS_COMPAT
3405
3408 explicit path(std::wstring_view);
3409
3410#endif
3411
3412 ~path() noexcept = default;
3413
3415 path(const path &) = default;
3416
3418 path(path &&) noexcept = default;
3419
3421 size_t size() const noexcept
3422 {
3423 return components_.size();
3424 }
3425
3427 explicit operator bool() const noexcept
3428 {
3429 return !components_.empty();
3430 }
3431
3433 bool empty() const noexcept
3434 {
3435 return components_.empty();
3436 }
3437
3439 path_component &operator[](size_t index) noexcept
3440 {
3441 TOML_ASSERT(index < size());
3442 return components_[index];
3443 }
3444
3446 const path_component &operator[](size_t index) const noexcept
3447 {
3448 TOML_ASSERT(index < size());
3449 return components_[index];
3450 }
3451
3452 path &operator=(const path &) = default;
3453
3454 path &operator=(path &&) noexcept = default;
3455
3457 path &operator=(std::string_view);
3458
3459#if TOML_ENABLE_WINDOWS_COMPAT
3460
3462 path &operator=(std::wstring_view);
3463
3464#endif
3465
3467 path &assign(const path &p)
3468 {
3469 return *this = p;
3470 }
3471
3473 path &assign(path &&p) noexcept
3474 {
3475 return *this = std::move(p);
3476 }
3477
3479 path &assign(std::string_view str)
3480 {
3481 return *this = str;
3482 }
3483
3484#if TOML_ENABLE_WINDOWS_COMPAT
3485
3487 path &assign(std::wstring_view str)
3488 {
3489 return *this = str;
3490 }
3491
3492#endif
3493
3496
3499
3501 path &operator+=(std::string_view);
3502
3503#if TOML_ENABLE_WINDOWS_COMPAT
3504
3506 path &operator+=(std::wstring_view);
3507
3508#endif
3509
3511 path &append(const path &p)
3512 {
3513 return *this += p;
3514 }
3515
3518 {
3519 return *this += std::move(p);
3520 }
3521
3523 path &append(std::string_view str)
3524 {
3525 return *this += str;
3526 }
3527
3528#if TOML_ENABLE_WINDOWS_COMPAT
3529
3531 path &append(std::wstring_view str)
3532 {
3533 return *this += str;
3534 }
3535
3536#endif
3537
3539 path &prepend(const path &);
3540
3543
3545 path &prepend(std::string_view);
3546
3547#if TOML_ENABLE_WINDOWS_COMPAT
3548
3550 path &prepend(std::wstring_view);
3551
3552#endif
3553
3555 friend path operator+(const path &lhs, const path &rhs)
3556 {
3557 path result = lhs;
3558 result += rhs;
3559 return result;
3560 }
3561
3563 friend path operator+(const path &lhs, std::string_view rhs)
3564 {
3565 path result = lhs;
3566 result += rhs;
3567 return result;
3568 }
3569
3571 friend path operator+(std::string_view lhs, const path &rhs)
3572 {
3573 path result = rhs;
3574 result.prepend(lhs);
3575 return result;
3576 }
3577
3578#if TOML_ENABLE_WINDOWS_COMPAT
3579
3581 friend path operator+(const path &lhs, std::wstring_view rhs)
3582 {
3583 path result = lhs;
3584 result += rhs;
3585 return result;
3586 }
3587
3589 friend path operator+(std::wstring_view lhs, const path &rhs)
3590 {
3591 path result = rhs;
3592 result.prepend(lhs);
3593 return result;
3594 }
3595
3596#endif
3597
3599 friend std::ostream &operator<<(std::ostream &os, const path &rhs)
3600 {
3601 rhs.print_to(os);
3602 return os;
3603 }
3604
3607 std::string str() const;
3608
3611 explicit operator std::string() const
3612 {
3613 return str();
3614 }
3615
3616#if TOML_ENABLE_WINDOWS_COMPAT
3617
3620 std::wstring wide_str() const;
3621
3624 explicit operator std::wstring() const
3625 {
3626 return wide_str();
3627 }
3628
3629#endif
3630
3632 friend bool operator==(const path &lhs, const path &rhs) noexcept
3633 {
3634 return equal(lhs, rhs);
3635 }
3636
3638 friend bool operator!=(const path &lhs, const path &rhs) noexcept
3639 {
3640 return !equal(lhs, rhs);
3641 }
3642
3645 friend bool operator==(const path &lhs, std::string_view rhs)
3646 {
3647 return lhs == path{rhs};
3648 }
3649
3652 friend bool operator==(std::string_view lhs, const path &rhs)
3653 {
3654 return rhs == lhs;
3655 }
3656
3659 friend bool operator!=(const path &lhs, std::string_view rhs)
3660 {
3661 return lhs != path{rhs};
3662 }
3663
3666 friend bool operator!=(std::string_view lhs, const path &rhs)
3667 {
3668 return rhs != lhs;
3669 }
3670
3671#if TOML_ENABLE_WINDOWS_COMPAT
3672
3675 friend bool operator==(const path &lhs, std::wstring_view rhs)
3676 {
3677 return lhs == path{rhs};
3678 }
3679
3682 friend bool operator==(std::wstring_view lhs, const path &rhs)
3683 {
3684 return rhs == lhs;
3685 }
3686
3689 friend bool operator!=(const path &lhs, std::wstring_view rhs)
3690 {
3691 return lhs != path{rhs};
3692 }
3693
3696 friend bool operator!=(std::wstring_view lhs, const path &rhs)
3697 {
3698 return rhs != lhs;
3699 }
3700
3701#endif // TOML_ENABLE_WINDOWS_COMPAT
3702
3703 using iterator = std::vector<path_component>::iterator;
3704
3705 using const_iterator = std::vector<path_component>::const_iterator;
3706
3708 iterator begin() noexcept
3709 {
3710 return components_.begin();
3711 }
3712
3714 iterator end() noexcept
3715 {
3716 return components_.end();
3717 }
3718
3720 const_iterator begin() const noexcept
3721 {
3722 return components_.begin();
3723 }
3724
3726 const_iterator end() const noexcept
3727 {
3728 return components_.end();
3729 }
3730
3732 const_iterator cbegin() const noexcept
3733 {
3734 return components_.begin();
3735 }
3736
3738 const_iterator cend() const noexcept
3739 {
3740 return components_.end();
3741 }
3742
3744 void clear() noexcept;
3745
3747 path &truncate(size_t n);
3748
3751 path truncated(size_t n) const;
3752
3755 path parent() const;
3756
3759 path leaf(size_t n = 1) const;
3760
3764
3767 path subpath(size_t start, size_t length) const;
3768 };
3769
3770 inline namespace literals
3771 {
3774 path operator"" _tpath(const char *str, size_t len)
3775 {
3776 return path(std::string_view{str, len});
3777 }
3778 } // namespace literals
3779
3783 node & root, const toml::path &path) noexcept;
3784
3788 const node &root, const toml::path &path) noexcept;
3789}
3791
3792#ifdef _MSC_VER
3793# pragma pop_macro("min")
3794# pragma pop_macro("max")
3795# ifndef __clang__
3796# pragma inline_recursion(off)
3797# endif
3798#endif
3800
3801//******** impl/std_utility.hpp **************************************************************************************
3802
3804#include <utility>
3806
3807//******** impl/node.hpp *********************************************************************************************
3808
3810#ifdef _MSC_VER
3811# ifndef __clang__
3812# pragma inline_recursion(on)
3813# endif
3814# pragma push_macro("min")
3815# pragma push_macro("max")
3816# undef min
3817# undef max
3818#endif
3819
3820// workaround for this: https://github.com/marzer/tomlplusplus/issues/220
3821#if TOML_NVCC
3822# define TOML_NVCC_WORKAROUND \
3823 { \
3824 return {}; \
3825 }
3826#else
3827# define TOML_NVCC_WORKAROUND = 0
3828#endif
3829
3831{
3833 {
3834 private:
3835 friend class TOML_PARSER_TYPENAME;
3836 source_region source_{};
3837
3838 template <typename T>
3839 TOML_NODISCARD decltype(auto) get_value_exact() const
3840 noexcept(impl::value_retrieval_is_nothrow<T>);
3841
3842 template <typename T, typename N>
3843 using ref_type_ = std::conditional_t< //
3844 std::is_reference_v<T>, //
3845 impl::copy_ref<
3846 impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>,
3847 T>, //
3848 impl::copy_cvref<impl::unwrap_node<T>, N> //
3849 >;
3850
3851 template <typename T, typename N>
3852 using ref_type = std::conditional_t< //
3853 std::is_reference_v<N>, //
3854 ref_type_<T, N>, //
3855 ref_type_<T, std::add_lvalue_reference_t<N>> //
3856 >;
3857
3858 template <typename T, typename N>
3859 TOML_PURE_GETTER static ref_type<T, N &&> do_ref(N &&n) noexcept
3860 {
3861 using unwrapped_type = impl::unwrap_node<T>;
3862 static_assert(
3863 toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3864 "The template type argument of node::ref() must be one "
3866
3868 n.template is<unwrapped_type>() &&
3869 "template type argument provided to toml::node::ref() didn't match the "
3870 "node's actual type");
3871
3872 using node_ref = std::remove_volatile_t<std::remove_reference_t<N>> &;
3873 using val_type = std::remove_volatile_t<unwrapped_type>;
3874 using out_ref = ref_type<T, N &&>;
3875 static_assert(std::is_reference_v<out_ref>);
3876
3877 if constexpr (toml::is_value<unwrapped_type>)
3878 return static_cast<out_ref>(
3879 const_cast<node_ref>(n).template ref_cast<val_type>().get());
3880 else
3881 return static_cast<out_ref>(
3882 const_cast<node_ref>(n).template ref_cast<val_type>());
3883 }
3884
3885 protected:
3887 node() noexcept;
3888
3890 node(const node &) noexcept;
3891
3893 node(node &&) noexcept;
3894
3896 node &operator=(const node &) noexcept;
3897
3899 node &operator=(node &&) noexcept;
3900
3901 template <typename T, typename N>
3902 using ref_cast_type_ = std::conditional_t< //
3903 std::is_reference_v<T>, //
3904 impl::copy_ref<
3905 impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>,
3906 T>, //
3907 impl::copy_cvref<impl::wrap_node<T>, N> //
3908 >;
3909
3910 template <typename T, typename N>
3911 using ref_cast_type = std::conditional_t< //
3912 std::is_reference_v<N>, //
3913 ref_cast_type_<T, N>, //
3914 ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
3915 >;
3916
3917 template <typename T>
3918 TOML_PURE_INLINE_GETTER ref_cast_type<T, node &> ref_cast() &noexcept
3919 {
3920 using out_ref = ref_cast_type<T, node &>;
3921 using out_type = std::remove_reference_t<out_ref>;
3922 return static_cast<out_ref>(*reinterpret_cast<out_type *>(this));
3923 }
3924
3925 template <typename T>
3926 TOML_PURE_INLINE_GETTER ref_cast_type<T, node &&> ref_cast() &&noexcept
3927 {
3928 using out_ref = ref_cast_type<T, node &&>;
3929 using out_type = std::remove_reference_t<out_ref>;
3930 return static_cast<out_ref>(*reinterpret_cast<out_type *>(this));
3931 }
3932
3933 template <typename T>
3934 TOML_PURE_INLINE_GETTER ref_cast_type<T, const node &>
3935 ref_cast() const &noexcept
3936 {
3937 using out_ref = ref_cast_type<T, const node &>;
3938 using out_type = std::remove_reference_t<out_ref>;
3939 return static_cast<out_ref>(*reinterpret_cast<out_type *>(this));
3940 }
3941
3942 template <typename T>
3943 TOML_PURE_INLINE_GETTER ref_cast_type<T, const node &&>
3944 ref_cast() const &&noexcept
3945 {
3946 using out_ref = ref_cast_type<T, const node &&>;
3947 using out_type = std::remove_reference_t<out_ref>;
3948 return static_cast<out_ref>(*reinterpret_cast<out_type *>(this));
3949 }
3950
3951 public:
3953 virtual ~node() noexcept;
3954
3956 virtual bool
3957 is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept = 0;
3958
3960 virtual bool is_homogeneous(node_type ntype, const node *&first_nonmatch)
3961 const noexcept = 0;
3962
3964 virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
3965
3966 template <typename ElemType = void>
3967 TOML_PURE_GETTER bool is_homogeneous() const noexcept
3968 {
3969 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
3970 static_assert(
3971 std::is_void_v<type> || toml::is_value<type> ||
3972 toml::is_container<type>,
3973 "The template type argument of node::is_homogeneous() must be void or "
3974 "one "
3976
3977 return is_homogeneous(impl::node_type_of<type>);
3978 }
3979
3981 virtual node_type type() const noexcept TOML_NVCC_WORKAROUND;
3982
3984 virtual bool is_table() const noexcept TOML_NVCC_WORKAROUND;
3985
3987 virtual bool is_array() const noexcept = 0;
3988
3990 virtual bool is_array_of_tables() const noexcept TOML_NVCC_WORKAROUND;
3991
3993 virtual bool is_value() const noexcept = 0;
3994
3996 virtual bool is_string() const noexcept = 0;
3997
3999 virtual bool is_integer() const noexcept = 0;
4000
4002 virtual bool is_floating_point() const noexcept = 0;
4003
4005 virtual bool is_number() const noexcept = 0;
4006
4008 virtual bool is_boolean() const noexcept = 0;
4009
4011 virtual bool is_date() const noexcept = 0;
4012
4014 virtual bool is_time() const noexcept = 0;
4015
4017 virtual bool is_date_time() const noexcept = 0;
4018
4019 template <typename T>
4020 TOML_PURE_INLINE_GETTER bool is() const noexcept
4021 {
4022 using type = impl::remove_cvref<impl::unwrap_node<T>>;
4023 static_assert(
4024 toml::is_value<type> || toml::is_container<type>,
4025 "The template type argument of node::is() must be one "
4027
4028 if constexpr (std::is_same_v<type, table>)
4029 return is_table();
4030 else if constexpr (std::is_same_v<type, array>)
4031 return is_array();
4032 else if constexpr (std::is_same_v<type, std::string>)
4033 return is_string();
4034 else if constexpr (std::is_same_v<type, int64_t>)
4035 return is_integer();
4036 else if constexpr (std::is_same_v<type, double>)
4037 return is_floating_point();
4038 else if constexpr (std::is_same_v<type, bool>)
4039 return is_boolean();
4040 else if constexpr (std::is_same_v<type, date>)
4041 return is_date();
4042 else if constexpr (std::is_same_v<type, time>)
4043 return is_time();
4044 else if constexpr (std::is_same_v<type, date_time>)
4045 return is_date_time();
4046
4048 }
4049
4051 virtual table *as_table() noexcept = 0;
4052
4054 virtual array *as_array() noexcept = 0;
4055
4057 virtual toml::value<std::string> *as_string() noexcept = 0;
4058
4060 virtual toml::value<int64_t> *as_integer() noexcept = 0;
4061
4063 virtual toml::value<double> *as_floating_point() noexcept = 0;
4064
4066 virtual toml::value<bool> *as_boolean() noexcept = 0;
4067
4069 virtual toml::value<date> *as_date() noexcept = 0;
4070
4072 virtual toml::value<time> *as_time() noexcept = 0;
4073
4075 virtual toml::value<date_time> *as_date_time() noexcept = 0;
4076
4078 virtual const table *as_table() const noexcept = 0;
4079
4081 virtual const array *as_array() const noexcept = 0;
4082
4084 virtual const toml::value<std::string> *as_string() const noexcept = 0;
4085
4087 virtual const toml::value<int64_t> *as_integer() const noexcept = 0;
4088
4090 virtual const toml::value<double> *as_floating_point() const noexcept = 0;
4091
4093 virtual const toml::value<bool> *as_boolean() const noexcept = 0;
4094
4096 virtual const toml::value<date> *as_date() const noexcept = 0;
4097
4099 virtual const toml::value<time> *as_time() const noexcept = 0;
4100
4102 virtual const toml::value<date_time> *as_date_time() const noexcept = 0;
4103
4104 template <typename T>
4105 TOML_PURE_INLINE_GETTER impl::wrap_node<T> *as() noexcept
4106 {
4107 using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
4108 static_assert(
4109 toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
4110 "The template type argument of node::as() must be one "
4112
4113 if constexpr (std::is_same_v<unwrapped_type, table>)
4114 return as_table();
4115 else if constexpr (std::is_same_v<unwrapped_type, array>)
4116 return as_array();
4117 else if constexpr (std::is_same_v<unwrapped_type, std::string>)
4118 return as_string();
4119 else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
4120 return as_integer();
4121 else if constexpr (std::is_same_v<unwrapped_type, double>)
4122 return as_floating_point();
4123 else if constexpr (std::is_same_v<unwrapped_type, bool>)
4124 return as_boolean();
4125 else if constexpr (std::is_same_v<unwrapped_type, date>)
4126 return as_date();
4127 else if constexpr (std::is_same_v<unwrapped_type, time>)
4128 return as_time();
4129 else if constexpr (std::is_same_v<unwrapped_type, date_time>)
4130 return as_date_time();
4131
4133 }
4134
4135 template <typename T>
4136 TOML_PURE_INLINE_GETTER const impl::wrap_node<T> *as() const noexcept
4137 {
4138 using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
4139 static_assert(
4140 toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
4141 "The template type argument of node::as() must be one "
4143
4144 if constexpr (std::is_same_v<unwrapped_type, table>)
4145 return as_table();
4146 else if constexpr (std::is_same_v<unwrapped_type, array>)
4147 return as_array();
4148 else if constexpr (std::is_same_v<unwrapped_type, std::string>)
4149 return as_string();
4150 else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
4151 return as_integer();
4152 else if constexpr (std::is_same_v<unwrapped_type, double>)
4153 return as_floating_point();
4154 else if constexpr (std::is_same_v<unwrapped_type, bool>)
4155 return as_boolean();
4156 else if constexpr (std::is_same_v<unwrapped_type, date>)
4157 return as_date();
4158 else if constexpr (std::is_same_v<unwrapped_type, time>)
4159 return as_time();
4160 else if constexpr (std::is_same_v<unwrapped_type, date_time>)
4161 return as_date_time();
4162
4164 }
4165
4166 template <typename T>
4167 TOML_NODISCARD optional<T> value_exact() const
4168 noexcept(impl::value_retrieval_is_nothrow<T>);
4169
4170 template <typename T>
4171 TOML_NODISCARD optional<T> value() const
4172 noexcept(impl::value_retrieval_is_nothrow<T>);
4173
4174 template <typename T>
4175 TOML_NODISCARD auto value_or(T &&default_value) const
4176 noexcept(impl::value_retrieval_is_nothrow<T>);
4177
4178 template <typename T>
4179 TOML_PURE_GETTER decltype(auto) ref() &noexcept
4180 {
4181 return do_ref<T>(*this);
4182 }
4183
4184 template <typename T>
4185 TOML_PURE_GETTER decltype(auto) ref() &&noexcept
4186 {
4187 return do_ref<T>(std::move(*this));
4188 }
4189
4190 template <typename T>
4191 TOML_PURE_GETTER decltype(auto) ref() const &noexcept
4192 {
4193 return do_ref<T>(*this);
4194 }
4195
4196 template <typename T>
4197 TOML_PURE_GETTER decltype(auto) ref() const &&noexcept
4198 {
4199 return do_ref<T>(std::move(*this));
4200 }
4201
4203 const source_region &source() const noexcept
4204 {
4205 return source_;
4206 }
4207
4208 private:
4209 template <typename Func, typename Node, typename T>
4210 static constexpr bool can_visit =
4211 std::is_invocable_v<Func, ref_cast_type<T, Node>>;
4212
4213 template <typename Func, typename Node, typename T>
4214 static constexpr bool can_visit_nothrow =
4215 std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>;
4216
4217 template <typename Func, typename Node>
4218 static constexpr bool can_visit_any =
4219 can_visit<Func, Node, table> //
4220 || can_visit<Func, Node, array> //
4221 || can_visit<Func, Node, std::string> //
4222 || can_visit<Func, Node, int64_t> //
4223 || can_visit<Func, Node, double> //
4224 || can_visit<Func, Node, bool> //
4225 || can_visit<Func, Node, date> //
4226 || can_visit<Func, Node, time> //
4227 || can_visit<Func, Node, date_time>;
4228
4229 // clang-format off
4230
4231 template <typename Func, typename Node>
4232 static constexpr bool can_visit_all = can_visit<Func, Node, table> //
4233 && can_visit<Func, Node, array> //
4234 && can_visit<Func, Node, std::string> //
4235 && can_visit<Func, Node, int64_t> //
4236 && can_visit<Func, Node, double> //
4237 && can_visit<Func, Node, bool> //
4238 && can_visit<Func, Node, date> //
4239 && can_visit<Func, Node, time> //
4240 && can_visit<Func, Node, date_time>;
4241
4242 template <typename Func, typename Node, typename T>
4243 static constexpr bool visit_is_nothrow_one = !can_visit<Func, Node, T> || can_visit_nothrow<Func, Node, T>;
4244
4245 template <typename Func, typename Node>
4246 static constexpr bool visit_is_nothrow = visit_is_nothrow_one<Func, Node, table> //
4247 && visit_is_nothrow_one<Func, Node, array> //
4248 && visit_is_nothrow_one<Func, Node, std::string> //
4249 && visit_is_nothrow_one<Func, Node, int64_t> //
4250 && visit_is_nothrow_one<Func, Node, double> //
4251 && visit_is_nothrow_one<Func, Node, bool> //
4252 && visit_is_nothrow_one<Func, Node, date> //
4253 && visit_is_nothrow_one<Func, Node, time> //
4254 && visit_is_nothrow_one<Func, Node, date_time>;
4255
4256 // clang-format on
4257
4258 template <
4259 typename Func,
4260 typename Node,
4261 typename T,
4262 bool = can_visit<Func, Node, T>>
4263 struct visit_return_type_
4264 {
4265 using type =
4266 decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>()));
4267 };
4268 template <typename Func, typename Node, typename T>
4269 struct visit_return_type_<Func, Node, T, false>
4270 {
4271 using type = void;
4272 };
4273
4274 template <typename Func, typename Node, typename T>
4275 using visit_return_type = typename visit_return_type_<Func, Node, T>::type;
4276
4277 template <typename A, typename B>
4278 using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
4279
4280 template <typename Func, typename Node>
4281 static decltype(auto) do_visit(Func &&visitor, Node &&n) noexcept(
4282 visit_is_nothrow<Func &&, Node &&>)
4283 {
4284 static_assert(
4285 can_visit_any<Func &&, Node &&>,
4286 "TOML node visitors must be invocable for at least one of the "
4287 "toml::node "
4288 "specializations:" TOML_SA_NODE_TYPE_LIST);
4289
4290 switch (n.type())
4291 {
4292 case node_type::table:
4293 if constexpr (can_visit<Func &&, Node &&, table>)
4294 return static_cast<Func &&>(visitor)(
4295 static_cast<Node &&>(n).template ref_cast<table>());
4296 break;
4297
4298 case node_type::array:
4299 if constexpr (can_visit<Func &&, Node &&, array>)
4300 return static_cast<Func &&>(visitor)(
4301 static_cast<Node &&>(n).template ref_cast<array>());
4302 break;
4303
4304 case node_type::string:
4305 if constexpr (can_visit<Func &&, Node &&, std::string>)
4306 return static_cast<Func &&>(visitor)(
4307 static_cast<Node &&>(n).template ref_cast<std::string>());
4308 break;
4309
4310 case node_type::integer:
4311 if constexpr (can_visit<Func &&, Node &&, int64_t>)
4312 return static_cast<Func &&>(visitor)(
4313 static_cast<Node &&>(n).template ref_cast<int64_t>());
4314 break;
4315
4316 case node_type::floating_point:
4317 if constexpr (can_visit<Func &&, Node &&, double>)
4318 return static_cast<Func &&>(visitor)(
4319 static_cast<Node &&>(n).template ref_cast<double>());
4320 break;
4321
4322 case node_type::boolean:
4323 if constexpr (can_visit<Func &&, Node &&, bool>)
4324 return static_cast<Func &&>(visitor)(
4325 static_cast<Node &&>(n).template ref_cast<bool>());
4326 break;
4327
4328 case node_type::date:
4329 if constexpr (can_visit<Func &&, Node &&, date>)
4330 return static_cast<Func &&>(visitor)(
4331 static_cast<Node &&>(n).template ref_cast<date>());
4332 break;
4333
4334 case node_type::time:
4335 if constexpr (can_visit<Func &&, Node &&, time>)
4336 return static_cast<Func &&>(visitor)(
4337 static_cast<Node &&>(n).template ref_cast<time>());
4338 break;
4339
4340 case node_type::date_time:
4341 if constexpr (can_visit<Func &&, Node &&, date_time>)
4342 return static_cast<Func &&>(visitor)(
4343 static_cast<Node &&>(n).template ref_cast<date_time>());
4344 break;
4345
4346 case node_type::none:
4348 default:
4350 }
4351
4352 if constexpr (!can_visit_all<Func &&, Node &&>)
4353 {
4354 // clang-format off
4355
4356 using return_type =
4357 nonvoid<visit_return_type<Func&&, Node&&, table>,
4358 nonvoid<visit_return_type<Func&&, Node&&, array>,
4359 nonvoid<visit_return_type<Func&&, Node&&, std::string>,
4360 nonvoid<visit_return_type<Func&&, Node&&, int64_t>,
4361 nonvoid<visit_return_type<Func&&, Node&&, double>,
4362 nonvoid<visit_return_type<Func&&, Node&&, bool>,
4363 nonvoid<visit_return_type<Func&&, Node&&, date>,
4364 nonvoid<visit_return_type<Func&&, Node&&, time>,
4365 visit_return_type<Func&&, Node&&, date_time>
4366 >>>>>>>>;
4367
4368 // clang-format on
4369
4370 if constexpr (!std::is_void_v<return_type>)
4371 {
4372 static_assert(
4373 std::is_default_constructible_v<return_type>,
4374 "Non-exhaustive visitors must return a default-constructible type, "
4375 "or void");
4376 return return_type{};
4377 }
4378 }
4379 }
4380
4381 public:
4382 template <typename Func>
4383 decltype(auto)
4384 visit(Func &&visitor) &noexcept(visit_is_nothrow<Func &&, node &>)
4385 {
4386 return do_visit(static_cast<Func &&>(visitor), *this);
4387 }
4388
4389 template <typename Func>
4390 decltype(auto)
4391 visit(Func &&visitor) &&noexcept(visit_is_nothrow<Func &&, node &&>)
4392 {
4393 return do_visit(
4394 static_cast<Func &&>(visitor), static_cast<node &&>(*this));
4395 }
4396
4397 template <typename Func>
4398 decltype(auto) visit(Func &&visitor) const &noexcept(
4399 visit_is_nothrow<Func &&, const node &>)
4400 {
4401 return do_visit(static_cast<Func &&>(visitor), *this);
4402 }
4403
4404 template <typename Func>
4405 decltype(auto) visit(Func &&visitor) const &&noexcept(
4406 visit_is_nothrow<Func &&, const node &&>)
4407 {
4408 return do_visit(
4409 static_cast<Func &&>(visitor), static_cast<const node &&>(*this));
4410 }
4411
4413 explicit operator node_view<node>() noexcept;
4414
4416 explicit operator node_view<const node>() const noexcept;
4417
4420 node_view<node> at_path(std::string_view path) noexcept;
4421
4424 node_view<const node> at_path(std::string_view path) const noexcept;
4425
4428 node_view<node> at_path(const toml::path &path) noexcept;
4429
4432 node_view<const node> at_path(const toml::path &path) const noexcept;
4433
4434#if TOML_ENABLE_WINDOWS_COMPAT
4435
4438 node_view<node> at_path(std::wstring_view path);
4439
4442 node_view<const node> at_path(std::wstring_view path) const;
4443
4444#endif // TOML_ENABLE_WINDOWS_COMPAT
4445
4448 node_view<node> operator[](const toml::path &path) noexcept;
4449
4452 node_view<const node> operator[](const toml::path &path) const noexcept;
4453 };
4454}
4456
4458{
4461 bool TOML_CALLCONV node_deep_equality(const node *, const node *) noexcept;
4462}
4464
4465#undef TOML_NVCC_WORKAROUND
4466
4467#ifdef _MSC_VER
4468# pragma pop_macro("min")
4469# pragma pop_macro("max")
4470# ifndef __clang__
4471# pragma inline_recursion(off)
4472# endif
4473#endif
4475
4476//******** impl/std_initializer_list.hpp *****************************************************************************
4477
4479#include <initializer_list>
4481
4482//******** impl/node_view.hpp ****************************************************************************************
4483
4485#ifdef _MSC_VER
4486# ifndef __clang__
4487# pragma inline_recursion(on)
4488# endif
4489# pragma push_macro("min")
4490# pragma push_macro("max")
4491# undef min
4492# undef max
4493#endif
4494
4496
4498{
4499 template <typename ViewedType>
4501 {
4502 static_assert(
4503 impl::is_one_of<ViewedType, toml::node, const toml::node>,
4504 "A toml::node_view<> must wrap toml::node or const toml::node.");
4505
4506 public:
4507 using viewed_type = ViewedType;
4508
4509 private:
4510 template <typename T>
4511 friend class node_view;
4512
4513 mutable viewed_type *node_ = nullptr;
4514
4515 public:
4517 node_view() noexcept = default;
4518
4520 explicit node_view(viewed_type *node) noexcept //
4521 : node_{node}
4522 {
4523 }
4524
4526 explicit node_view(viewed_type &node) noexcept //
4527 : node_{&node}
4528 {
4529 }
4530
4532 node_view(const node_view &) noexcept = default;
4533
4535 node_view(node_view &&) noexcept = default;
4536
4537 node_view &operator=(const node_view &) &noexcept = default;
4538
4539 node_view &operator=(node_view &&) &noexcept = default;
4540
4542 explicit operator bool() const noexcept
4543 {
4544 return node_ != nullptr;
4545 }
4546
4548 viewed_type *node() const noexcept
4549 {
4550 return node_;
4551 }
4552
4554 node_type type() const noexcept
4555 {
4556 return node_ ? node_->type() : node_type::none;
4557 }
4558
4560 bool is_table() const noexcept
4561 {
4562 return node_ && node_->is_table();
4563 }
4564
4566 bool is_array() const noexcept
4567 {
4568 return node_ && node_->is_array();
4569 }
4570
4572 bool is_value() const noexcept
4573 {
4574 return node_ && node_->is_value();
4575 }
4576
4578 bool is_string() const noexcept
4579 {
4580 return node_ && node_->is_string();
4581 }
4582
4584 bool is_integer() const noexcept
4585 {
4586 return node_ && node_->is_integer();
4587 }
4588
4590 bool is_floating_point() const noexcept
4591 {
4592 return node_ && node_->is_floating_point();
4593 }
4594
4596 bool is_number() const noexcept
4597 {
4598 return node_ && node_->is_number();
4599 }
4600
4602 bool is_boolean() const noexcept
4603 {
4604 return node_ && node_->is_boolean();
4605 }
4606
4608 bool is_date() const noexcept
4609 {
4610 return node_ && node_->is_date();
4611 }
4612
4614 bool is_time() const noexcept
4615 {
4616 return node_ && node_->is_time();
4617 }
4618
4620 bool is_date_time() const noexcept
4621 {
4622 return node_ && node_->is_date_time();
4623 }
4624
4626 bool is_array_of_tables() const noexcept
4627 {
4628 return node_ && node_->is_array_of_tables();
4629 }
4630
4631 template <typename T>
4632 TOML_PURE_GETTER bool is() const noexcept
4633 {
4634 return node_
4635 ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>()
4636 : false;
4637 }
4638
4640 bool
4641 is_homogeneous(node_type ntype, viewed_type *&first_nonmatch) const noexcept
4642 {
4643 if (!node_)
4644 {
4645 first_nonmatch = {};
4646 return false;
4647 }
4648 return node_->is_homogeneous(ntype, first_nonmatch);
4649 }
4650
4652 bool is_homogeneous(node_type ntype) const noexcept
4653 {
4654 return node_ ? node_->is_homogeneous(ntype) : false;
4655 }
4656
4657 template <typename ElemType = void>
4658 TOML_PURE_GETTER bool is_homogeneous() const noexcept
4659 {
4660 return node_ ? node_->template is_homogeneous<
4661 impl::unwrap_node<impl::remove_cvref<ElemType>>>()
4662 : false;
4663 }
4664
4665 template <typename T>
4666 TOML_PURE_GETTER auto *as() const noexcept
4667 {
4668 return node_ ? node_->template as<T>() : nullptr;
4669 }
4670
4672 auto *as_table() const noexcept
4673 {
4674 return as<table>();
4675 }
4676
4678 auto *as_array() const noexcept
4679 {
4680 return as<array>();
4681 }
4682
4684 auto *as_string() const noexcept
4685 {
4686 return as<std::string>();
4687 }
4688
4690 auto *as_integer() const noexcept
4691 {
4692 return as<int64_t>();
4693 }
4694
4696 auto *as_floating_point() const noexcept
4697 {
4698 return as<double>();
4699 }
4700
4702 auto *as_boolean() const noexcept
4703 {
4704 return as<bool>();
4705 }
4706
4708 auto *as_date() const noexcept
4709 {
4710 return as<date>();
4711 }
4712
4714 auto *as_time() const noexcept
4715 {
4716 return as<time>();
4717 }
4718
4720 auto *as_date_time() const noexcept
4721 {
4722 return as<date_time>();
4723 }
4724
4725 template <typename T>
4726 TOML_NODISCARD optional<T> value_exact() const
4727 noexcept(impl::value_retrieval_is_nothrow<T>)
4728 {
4729 if (node_)
4730 return node_->template value_exact<T>();
4731 return {};
4732 }
4733
4734 template <typename T>
4735 TOML_NODISCARD optional<T> value() const
4736 noexcept(impl::value_retrieval_is_nothrow<T>)
4737 {
4738 if (node_)
4739 return node_->template value<T>();
4740 return {};
4741 }
4742
4743 template <typename T>
4744 TOML_NODISCARD auto value_or(T &&default_value) const
4745 noexcept(impl::value_retrieval_is_nothrow<T>)
4746 {
4747 using namespace ::toml::impl;
4748
4749 static_assert(
4751 "Retrieving values as wide-character strings is only "
4752 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
4753
4754 if constexpr (is_wide_string<T>)
4755 {
4756#if TOML_ENABLE_WINDOWS_COMPAT
4757
4758 if (node_)
4759 return node_->value_or(static_cast<T &&>(default_value));
4760 return std::wstring{static_cast<T &&>(default_value)};
4761
4762#else
4763
4764 static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
4765
4766#endif
4767 }
4768 else
4769 {
4770 using value_type = std::conditional_t<
4771 std::is_pointer_v<std::decay_t<T>>,
4772 std::add_pointer_t<
4773 std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
4774 std::decay_t<T>>;
4775
4776 if (node_)
4777 return node_->value_or(static_cast<T &&>(default_value));
4778 if constexpr (std::is_pointer_v<value_type>)
4779 return value_type{default_value};
4780 else
4781 return static_cast<T &&>(default_value);
4782 }
4783 }
4784
4785 template <typename T>
4786 TOML_PURE_INLINE_GETTER decltype(auto) ref() const noexcept
4787 {
4789 node_ &&
4790 "toml::node_view::ref() called on a node_view that did not reference a "
4791 "node");
4792 return node_->template ref<T>();
4793 }
4794
4795 private:
4796 template <typename Func>
4797 static constexpr bool visit_is_nothrow =
4798 noexcept(std::declval<viewed_type *>()->visit(std::declval<Func>()));
4799
4800 public:
4801 template <typename Func>
4802 decltype(auto) visit(Func &&visitor) const
4803 noexcept(visit_is_nothrow<Func &&>)
4804 {
4805 using return_type = decltype(node_->visit(static_cast<Func &&>(visitor)));
4806 if (node_)
4807 return node_->visit(static_cast<Func &&>(visitor));
4808 if constexpr (!std::is_void_v<return_type>)
4809 return return_type{};
4810 }
4811
4812 public:
4813 template <typename T>
4814 TOML_PURE_GETTER friend bool
4815 operator==(const node_view &lhs, const node_view<T> &rhs) noexcept
4816 {
4817 return impl::node_deep_equality(lhs.node_, rhs.node_);
4818 }
4819
4820 template <typename T>
4821 TOML_PURE_GETTER friend bool
4822 operator!=(const node_view &lhs, const node_view<T> &rhs) noexcept
4823 {
4824 return !impl::node_deep_equality(lhs.node_, rhs.node_);
4825 }
4826
4828 friend bool operator==(const node_view &lhs, const table &rhs) noexcept
4829 {
4830 if (lhs.node_ == &rhs)
4831 return true;
4832 const auto tbl = lhs.as<table>();
4833 return tbl && *tbl == rhs;
4834 }
4836
4838 friend bool operator==(const node_view &lhs, const array &rhs) noexcept
4839 {
4840 if (lhs.node_ == &rhs)
4841 return true;
4842 const auto arr = lhs.as<array>();
4843 return arr && *arr == rhs;
4844 }
4846
4847 template <typename T>
4848 TOML_NODISCARD friend bool
4849 operator==(const node_view &lhs, const toml::value<T> &rhs) noexcept
4850 {
4851 if (lhs.node_ == &rhs)
4852 return true;
4853 const auto val = lhs.as<T>();
4854 return val && *val == rhs;
4855 }
4857 const node_view &,
4858 const toml::value<T> &,
4859 template <typename T>
4860 );
4861
4863 impl::is_losslessly_convertible_to_native<T>,
4864 typename T)
4866 friend bool operator==(const node_view &lhs, const T &rhs) noexcept(
4867 !impl::is_wide_string<T>)
4868 {
4869 static_assert(
4870 !impl::is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
4871 "Comparison with wide-character strings is only "
4872 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
4873
4874 if constexpr (impl::is_wide_string<T>)
4875 {
4876#if TOML_ENABLE_WINDOWS_COMPAT
4877 return lhs == impl::narrow(rhs);
4878#else
4879 static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
4880#endif
4881 }
4882 else
4883 {
4884 const auto val = lhs.as<impl::native_type_of<T>>();
4885 return val && *val == rhs;
4886 }
4887 }
4889 const node_view &,
4890 const T &,
4892 impl::is_losslessly_convertible_to_native<T>,
4893 typename T));
4894
4895 template <typename T>
4896 TOML_NODISCARD friend bool operator==(
4897 const node_view &lhs,
4898 const std::initializer_list<T> &rhs) noexcept(!impl::is_wide_string<T>)
4899 {
4900 const auto arr = lhs.as<array>();
4901 return arr && *arr == rhs;
4902 }
4904 const node_view &,
4905 const std::initializer_list<T> &,
4906 template <typename T>
4907 );
4908
4909 template <typename T>
4910 TOML_NODISCARD friend bool operator==(
4911 const node_view &lhs,
4912 const std::vector<T> &rhs) noexcept(!impl::is_wide_string<T>)
4913 {
4914 const auto arr = lhs.as<array>();
4915 return arr && *arr == rhs;
4916 }
4918 const node_view &,
4919 const std::vector<T> &,
4920 template <typename T>
4921 );
4922
4924 node_view operator[](std::string_view key) const noexcept
4925 {
4926 if (auto tbl = this->as_table())
4927 return node_view{tbl->get(key)};
4928 return {};
4929 }
4930
4932 node_view operator[](const toml::path &path) const noexcept
4933 {
4934 return node_ ? node_->at_path(path) : node_view{};
4935 }
4936
4938 node_view at_path(std::string_view path) const noexcept
4939 {
4940 return node_ ? node_->at_path(path) : node_view{};
4941 }
4942
4944 node_view at_path(const toml::path &path) const noexcept
4945 {
4946 return node_ ? node_->at_path(path) : node_view{};
4947 }
4948
4949#if TOML_ENABLE_WINDOWS_COMPAT
4950
4952 node_view operator[](std::wstring_view key) const
4953 {
4954 if (auto tbl = this->as_table())
4955 return node_view{tbl->get(key)};
4956 return {};
4957 }
4958
4960 node_view at_path(std::wstring_view path) const
4961 {
4962 return node_ ? node_->at_path(path) : node_view{};
4963 }
4964
4965#endif // TOML_ENABLE_WINDOWS_COMPAT
4966
4968 node_view operator[](size_t index) const noexcept
4969 {
4970 if (auto arr = this->as_array())
4971 return node_view{arr->get(index)};
4972 return {};
4973 }
4974
4975#if TOML_ENABLE_FORMATTERS
4976
4977 friend std::ostream &operator<<(std::ostream &os, const node_view &nv)
4978 {
4979 if (nv.node_)
4980 nv.node_->visit([&os](const auto &n) { os << n; });
4981 return os;
4982 }
4983
4984#endif
4985 };
4986
4987 template <typename T>
4989
4990 template <typename T>
4992
4993 template <typename T>
4995
4996 template <typename T>
4998}
5000
5002{
5003 inline node::operator node_view<node>() noexcept
5004 {
5005 return node_view<node>{this};
5006 }
5007
5008 inline node::operator node_view<const node>() const noexcept
5009 {
5010 return node_view<const node>{this};
5011 }
5012}
5014
5015#ifdef _MSC_VER
5016# pragma pop_macro("min")
5017# pragma pop_macro("max")
5018# ifndef __clang__
5019# pragma inline_recursion(off)
5020# endif
5021#endif
5023
5024//******** impl/value.hpp ********************************************************************************************
5025
5027#ifdef _MSC_VER
5028# ifndef __clang__
5029# pragma inline_recursion(on)
5030# endif
5031# pragma push_macro("min")
5032# pragma push_macro("max")
5033# undef min
5034# undef max
5035#endif
5036
5038
5039// clang-format off
5040
5041#if TOML_ENABLE_WINDOWS_COMPAT
5042 #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
5043#else
5044 #define TOML_SA_VALUE_MESSAGE_WSTRING
5045#endif
5046#if TOML_HAS_CHAR8
5047 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
5048 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
5049#else
5050 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
5051 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
5052#endif
5053
5054#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
5055 "The " type_arg " must be one of:" \
5056 TOML_SA_LIST_NEW "A native TOML value type" \
5057 TOML_SA_NATIVE_VALUE_TYPE_LIST \
5058 \
5059 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
5060 TOML_SA_LIST_BEG "std::string" \
5061 TOML_SA_VALUE_MESSAGE_WSTRING \
5062 TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
5063 TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
5064 TOML_SA_LIST_END \
5065 \
5066 TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
5067 TOML_SA_LIST_BEG "std::string_view" \
5068 TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
5069 TOML_SA_LIST_SEP "const char*" \
5070 TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
5071 TOML_SA_LIST_END
5072
5073#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
5074 "The " type_arg " must be one of:" \
5075 TOML_SA_LIST_NEW "A native TOML value type" \
5076 TOML_SA_NATIVE_VALUE_TYPE_LIST \
5077 \
5078 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
5079 TOML_SA_LIST_BEG "std::string" \
5080 TOML_SA_VALUE_MESSAGE_WSTRING \
5081 TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
5082 TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
5083 TOML_SA_LIST_END \
5084 \
5085 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
5086 TOML_SA_LIST_BEG "any other integral type" \
5087 TOML_SA_LIST_SEP "any floating-point type" \
5088 TOML_SA_LIST_END \
5089 \
5090 TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
5091 TOML_SA_LIST_BEG "std::string_view" \
5092 TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
5093 TOML_SA_LIST_SEP "const char*" \
5094 TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
5095 TOML_SA_LIST_END
5096
5097// clang-format on
5099{
5100 template <typename T, typename...>
5101 struct native_value_maker
5102 {
5103 template <typename... Args>
5104 TOML_NODISCARD static T make(Args &&...args) noexcept(
5105 std::is_nothrow_constructible_v<T, Args &&...>)
5106 {
5107 if constexpr (std::is_aggregate_v<T>)
5108 return T{static_cast<Args &&>(args)...};
5109 else
5110 return T(static_cast<Args &&>(args)...);
5111 }
5112 };
5113
5114 template <typename T>
5115 struct native_value_maker<T, T>
5116 {
5117 template <typename U>
5118 TOML_NODISCARD TOML_ALWAYS_INLINE static U &&make(U &&val) noexcept
5119 {
5120 return static_cast<U &&>(val);
5121 }
5122 };
5123
5124#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
5125
5126 struct string_maker
5127 {
5128 template <typename T>
5129 TOML_NODISCARD static std::string make(T &&arg)
5130 {
5131 using arg_type = std::decay_t<T>;
5132# if TOML_HAS_CHAR8
5134 {
5135 return std::string(
5136 reinterpret_cast<const char *>(static_cast<const char8_t *>(arg)));
5137 }
5139 {
5140 return std::string(
5141 reinterpret_cast<const char *>(
5142 static_cast<const char8_t *>(arg.data())),
5143 arg.length());
5144 }
5145# endif
5146
5147# if TOML_ENABLE_WINDOWS_COMPAT
5148 if constexpr (is_wide_string<arg_type>)
5149 {
5150 return narrow(static_cast<T &&>(arg));
5151 }
5152# endif
5153 }
5154 };
5155
5156# if TOML_HAS_CHAR8
5157 template <>
5158 struct native_value_maker<std::string, char8_t *> : string_maker
5159 {
5160 };
5161 template <>
5162 struct native_value_maker<std::string, const char8_t *> : string_maker
5163 {
5164 };
5165 template <>
5166 struct native_value_maker<std::string, std::u8string> : string_maker
5167 {
5168 };
5169 template <>
5170 struct native_value_maker<std::string, std::u8string_view> : string_maker
5171 {
5172 };
5173# endif // TOML_HAS_CHAR8
5174
5175# if TOML_ENABLE_WINDOWS_COMPAT
5176 template <>
5177 struct native_value_maker<std::string, wchar_t *> : string_maker
5178 {
5179 };
5180 template <>
5181 struct native_value_maker<std::string, const wchar_t *> : string_maker
5182 {
5183 };
5184 template <>
5185 struct native_value_maker<std::string, std::wstring> : string_maker
5186 {
5187 };
5188 template <>
5189 struct native_value_maker<std::string, std::wstring_view> : string_maker
5190 {
5191 };
5192# endif // TOML_ENABLE_WINDOWS_COMPAT
5193
5194#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
5195
5196 template <typename T>
5197 TOML_CONST_GETTER inline optional<T> node_integer_cast(int64_t val) noexcept
5198 {
5199 static_assert(node_type_of<T> == node_type::integer);
5200 static_assert(!is_cvref<T>);
5201
5202 using traits = value_traits<T>;
5203 if constexpr (!traits::is_signed)
5204 {
5205 if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
5206 {
5207 using common_t = decltype(int64_t{} + T{});
5208 if (
5209 val < int64_t{} ||
5210 static_cast<common_t>(val) > static_cast<common_t>(traits::max))
5211 return {};
5212 }
5213 else
5214 {
5215 if (val < int64_t{})
5216 return {};
5217 }
5218 }
5219 else
5220 {
5221 if (val < traits::min || val > traits::max)
5222 return {};
5223 }
5224 return {static_cast<T>(val)};
5225 }
5226
5227 template <typename...>
5228 struct value_variadic_ctor_allowed : std::true_type
5229 {
5230 };
5231
5232 template <typename T, typename... Args>
5234 : std::false_type
5235 {
5236 };
5237}
5239
5241{
5242 template <typename ValueType>
5243 class value : public node
5244 {
5245 static_assert(
5246 impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
5247 "A toml::value<> must model one of the native TOML value "
5249
5250 private:
5251 friend class TOML_PARSER_TYPENAME;
5252
5253 template <typename T, typename U>
5254 TOML_CONST_INLINE_GETTER static auto
5255 as_value([[maybe_unused]] U *ptr) noexcept
5256 {
5257 if constexpr (std::is_same_v<value_type, T>)
5258 return ptr;
5259 else
5260 return nullptr;
5261 }
5262
5263 ValueType val_;
5264 value_flags flags_ = value_flags::none;
5265
5266 public:
5267 using value_type = ValueType;
5268
5269 using value_arg = POXY_IMPLEMENTATION_DETAIL(
5270 std::conditional_t<
5271 std::is_same_v<value_type, std::string>,
5272 std::string_view,
5273 std::conditional_t<
5274 impl::is_one_of<value_type, double, int64_t, bool>,
5275 value_type,
5276 const value_type &>>);
5277
5279 (impl::value_variadic_ctor_allowed<
5281 impl::remove_cvref<Args>...>::value),
5282 typename... Args)
5284 explicit value(Args &&...args) noexcept(noexcept(value_type(
5285 impl::native_value_maker<value_type, std::decay_t<Args>...>::make(
5286 static_cast<Args &&>(args)...))))
5287 : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(
5288 static_cast<Args &&>(args)...))
5289 {
5290#if TOML_LIFETIME_HOOKS
5291 TOML_VALUE_CREATED;
5292#endif
5293 }
5294
5296 value(const value &other) noexcept //
5297 : node(other), val_{other.val_}, flags_{other.flags_}
5298 {
5299#if TOML_LIFETIME_HOOKS
5300 TOML_VALUE_CREATED;
5301#endif
5302 }
5303
5305 value(const value &other, value_flags flags) noexcept //
5306 : node(other),
5307 val_{other.val_},
5308 flags_{flags == preserve_source_value_flags ? other.flags_ : flags}
5309 {
5310#if TOML_LIFETIME_HOOKS
5311 TOML_VALUE_CREATED;
5312#endif
5313 }
5314
5316 value(value &&other) noexcept //
5317 : node(std::move(other)),
5318 val_{std::move(other.val_)},
5319 flags_{std::exchange(other.flags_, value_flags{})}
5320 {
5321#if TOML_LIFETIME_HOOKS
5322 TOML_VALUE_CREATED;
5323#endif
5324 }
5325
5327 value(value &&other, value_flags flags) noexcept //
5328 : node(std::move(other)),
5329 val_{std::move(other.val_)},
5330 flags_{flags == preserve_source_value_flags ? other.flags_ : flags}
5331 {
5332#if TOML_LIFETIME_HOOKS
5333 TOML_VALUE_CREATED;
5334#endif
5335 other.flags_ = {};
5336 }
5337
5338 value &operator=(const value &rhs) noexcept
5339 {
5340 node::operator=(rhs);
5341 val_ = rhs.val_;
5342 flags_ = rhs.flags_;
5343 return *this;
5344 }
5345
5346 value &operator=(value &&rhs) noexcept
5347 {
5348 if (&rhs != this)
5349 {
5350 node::operator=(std::move(rhs));
5351 val_ = std::move(rhs.val_);
5352 flags_ = std::exchange(rhs.flags_, value_flags{});
5353 }
5354 return *this;
5355 }
5356
5357#if TOML_LIFETIME_HOOKS
5358 ~value() noexcept
5359 {
5360 TOML_VALUE_DESTROYED;
5361 }
5362#endif
5363
5365 node_type type() const noexcept final
5366 {
5367 return impl::node_type_of<value_type>;
5368 }
5369
5371 bool is_homogeneous(node_type ntype) const noexcept final
5372 {
5373 return ntype == node_type::none ||
5374 ntype == impl::node_type_of<value_type>;
5375 }
5376
5378 bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final
5379 {
5380 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
5381 {
5382 first_nonmatch = this;
5383 return false;
5384 }
5385 return true;
5386 }
5387
5389 bool is_homogeneous(node_type ntype, const node *&first_nonmatch)
5390 const noexcept final
5391 {
5392 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
5393 {
5394 first_nonmatch = this;
5395 return false;
5396 }
5397 return true;
5398 }
5399
5400 template <typename ElemType = void>
5401 TOML_PURE_GETTER bool is_homogeneous() const noexcept
5402 {
5403 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
5404 static_assert(
5405 std::is_void_v<type> || toml::is_value<type> ||
5406 toml::is_container<type>,
5407 "The template type argument of value::is_homogeneous() must be void or "
5408 "one "
5410
5411 if constexpr (std::is_void_v<type>)
5412 return true;
5413 else
5414 return impl::node_type_of<type> == impl::node_type_of<value_type>;
5415 }
5417 bool is_table() const noexcept final
5418 {
5419 return false;
5420 }
5421
5423 bool is_array() const noexcept final
5424 {
5425 return false;
5426 }
5427
5429 bool is_array_of_tables() const noexcept final
5430 {
5431 return false;
5432 }
5433
5435 bool is_value() const noexcept final
5436 {
5437 return true;
5438 }
5439
5441 bool is_string() const noexcept final
5442 {
5443 return std::is_same_v<value_type, std::string>;
5444 }
5445
5447 bool is_integer() const noexcept final
5448 {
5449 return std::is_same_v<value_type, int64_t>;
5450 }
5451
5453 bool is_floating_point() const noexcept final
5454 {
5455 return std::is_same_v<value_type, double>;
5456 }
5457
5459 bool is_number() const noexcept final
5460 {
5461 return impl::is_one_of<value_type, int64_t, double>;
5462 }
5463
5465 bool is_boolean() const noexcept final
5466 {
5467 return std::is_same_v<value_type, bool>;
5468 }
5469
5471 bool is_date() const noexcept final
5472 {
5473 return std::is_same_v<value_type, date>;
5474 }
5475
5477 bool is_time() const noexcept final
5478 {
5479 return std::is_same_v<value_type, time>;
5480 }
5481
5483 bool is_date_time() const noexcept final
5484 {
5485 return std::is_same_v<value_type, date_time>;
5486 }
5487
5489 table *as_table() noexcept final
5490 {
5491 return nullptr;
5492 }
5493
5495 array *as_array() noexcept final
5496 {
5497 return nullptr;
5498 }
5499
5501 value<std::string> *as_string() noexcept final
5502 {
5503 return as_value<std::string>(this);
5504 }
5505
5507 value<int64_t> *as_integer() noexcept final
5508 {
5509 return as_value<int64_t>(this);
5510 }
5511
5513 value<double> *as_floating_point() noexcept final
5514 {
5515 return as_value<double>(this);
5516 }
5517
5519 value<bool> *as_boolean() noexcept final
5520 {
5521 return as_value<bool>(this);
5522 }
5523
5525 value<date> *as_date() noexcept final
5526 {
5527 return as_value<date>(this);
5528 }
5529
5531 value<time> *as_time() noexcept final
5532 {
5533 return as_value<time>(this);
5534 }
5535
5537 value<date_time> *as_date_time() noexcept final
5538 {
5539 return as_value<date_time>(this);
5540 }
5541
5543 const table *as_table() const noexcept final
5544 {
5545 return nullptr;
5546 }
5547
5549 const array *as_array() const noexcept final
5550 {
5551 return nullptr;
5552 }
5553
5555 const value<std::string> *as_string() const noexcept final
5556 {
5557 return as_value<std::string>(this);
5558 }
5559
5561 const value<int64_t> *as_integer() const noexcept final
5562 {
5563 return as_value<int64_t>(this);
5564 }
5565
5567 const value<double> *as_floating_point() const noexcept final
5568 {
5569 return as_value<double>(this);
5570 }
5571
5573 const value<bool> *as_boolean() const noexcept final
5574 {
5575 return as_value<bool>(this);
5576 }
5577
5579 const value<date> *as_date() const noexcept final
5580 {
5581 return as_value<date>(this);
5582 }
5583
5585 const value<time> *as_time() const noexcept final
5586 {
5587 return as_value<time>(this);
5588 }
5589
5591 const value<date_time> *as_date_time() const noexcept final
5592 {
5593 return as_value<date_time>(this);
5594 }
5595
5597 value_type &get() &noexcept
5598 {
5599 return val_;
5600 }
5601
5603 value_type &&get() &&noexcept
5604 {
5605 return static_cast<value_type &&>(val_);
5606 }
5607
5609 const value_type &get() const &noexcept
5610 {
5611 return val_;
5612 }
5613
5615 const value_type &&get() const &&noexcept
5616 {
5617 return static_cast<const value_type &&>(val_);
5618 }
5619
5621 value_type &operator*() &noexcept
5622 {
5623 return val_;
5624 }
5625
5627 value_type &&operator*() &&noexcept
5628 {
5629 return static_cast<value_type &&>(val_);
5630 }
5631
5633 const value_type &operator*() const &noexcept
5634 {
5635 return val_;
5636 }
5637
5639 const value_type &&operator*() const &&noexcept
5640 {
5641 return static_cast<const value_type &&>(val_);
5642 }
5643
5645 explicit operator value_type &() &noexcept
5646 {
5647 return val_;
5648 }
5649
5651 explicit operator value_type &&() &&noexcept
5652 {
5653 return static_cast<value_type &&>(val_);
5654 }
5655
5657 explicit operator const value_type &() const &noexcept
5658 {
5659 return val_;
5660 }
5661
5663 explicit operator const value_type &&() &&noexcept
5664 {
5665 return static_cast<const value_type &&>(val_);
5666 }
5667
5668 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
5670 value_type *operator->() noexcept
5671 {
5672 return &val_;
5673 }
5674
5675 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
5677 const value_type *operator->() const noexcept
5678 {
5679 return &val_;
5680 }
5681
5683 value_flags flags() const noexcept
5684 {
5685 return flags_;
5686 }
5687
5688 value &flags(value_flags new_flags) noexcept
5689 {
5690 flags_ = new_flags;
5691 return *this;
5692 }
5693
5694 value &operator=(value_arg rhs) noexcept
5695 {
5696 if constexpr (std::is_same_v<value_type, std::string>)
5697 val_.assign(rhs);
5698 else
5699 val_ = rhs;
5700 return *this;
5701 }
5702
5704 (std::is_same_v<T, std::string>),
5705 typename T = value_type)
5706 value &operator=(std::string &&rhs) noexcept
5707 {
5708 val_ = std::move(rhs);
5709 return *this;
5710 }
5711
5713 friend bool operator==(const value &lhs, value_arg rhs) noexcept
5714 {
5715 if constexpr (std::is_same_v<value_type, double>)
5716 {
5717 const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan;
5718 const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan;
5719 if (lhs_nan != rhs_nan)
5720 return false;
5721 if (lhs_nan)
5722 return true;
5723 }
5724 return lhs.val_ == rhs;
5725 }
5726 TOML_ASYMMETRICAL_EQUALITY_OPS(const value &, value_arg, );
5727
5729 friend bool operator<(const value &lhs, value_arg rhs) noexcept
5730 {
5731 return lhs.val_ < rhs;
5732 }
5733
5735 friend bool operator<(value_arg lhs, const value &rhs) noexcept
5736 {
5737 return lhs < rhs.val_;
5738 }
5739
5741 friend bool operator<=(const value &lhs, value_arg rhs) noexcept
5742 {
5743 return lhs.val_ <= rhs;
5744 }
5745
5747 friend bool operator<=(value_arg lhs, const value &rhs) noexcept
5748 {
5749 return lhs <= rhs.val_;
5750 }
5751
5753 friend bool operator>(const value &lhs, value_arg rhs) noexcept
5754 {
5755 return lhs.val_ > rhs;
5756 }
5757
5759 friend bool operator>(value_arg lhs, const value &rhs) noexcept
5760 {
5761 return lhs > rhs.val_;
5762 }
5763
5765 friend bool operator>=(const value &lhs, value_arg rhs) noexcept
5766 {
5767 return lhs.val_ >= rhs;
5768 }
5769
5771 friend bool operator>=(value_arg lhs, const value &rhs) noexcept
5772 {
5773 return lhs >= rhs.val_;
5774 }
5775
5776 template <typename T>
5777 TOML_PURE_GETTER friend bool
5778 operator==(const value &lhs, const value<T> &rhs) noexcept
5779 {
5780 if constexpr (std::is_same_v<value_type, T>)
5781 return lhs ==
5782 rhs
5783 .val_; // calls asymmetrical value-equality operator defined above
5784 else
5785 return false;
5786 }
5787
5788 template <typename T>
5789 TOML_PURE_INLINE_GETTER friend bool
5790 operator!=(const value &lhs, const value<T> &rhs) noexcept
5791 {
5792 return !(lhs == rhs);
5793 }
5794
5795 template <typename T>
5796 TOML_PURE_GETTER friend bool
5797 operator<(const value &lhs, const value<T> &rhs) noexcept
5798 {
5799 if constexpr (std::is_same_v<value_type, T>)
5800 return lhs.val_ < rhs.val_;
5801 else
5802 return impl::node_type_of<value_type> < impl::node_type_of<T>;
5803 }
5804
5805 template <typename T>
5806 TOML_PURE_GETTER friend bool
5807 operator<=(const value &lhs, const value<T> &rhs) noexcept
5808 {
5809 if constexpr (std::is_same_v<value_type, T>)
5810 return lhs.val_ <= rhs.val_;
5811 else
5812 return impl::node_type_of<value_type> <= impl::node_type_of<T>;
5813 }
5814
5815 template <typename T>
5816 TOML_PURE_GETTER friend bool
5817 operator>(const value &lhs, const value<T> &rhs) noexcept
5818 {
5819 if constexpr (std::is_same_v<value_type, T>)
5820 return lhs.val_ > rhs.val_;
5821 else
5822 return impl::node_type_of<value_type> > impl::node_type_of<T>;
5823 }
5824
5825 template <typename T>
5826 TOML_PURE_GETTER friend bool
5827 operator>=(const value &lhs, const value<T> &rhs) noexcept
5828 {
5829 if constexpr (std::is_same_v<value_type, T>)
5830 return lhs.val_ >= rhs.val_;
5831 else
5832 return impl::node_type_of<value_type> >= impl::node_type_of<T>;
5833 }
5834
5835#if TOML_ENABLE_FORMATTERS
5836
5837 friend std::ostream &operator<<(std::ostream &lhs, const value &rhs)
5838 {
5839 impl::print_to_stream(lhs, rhs);
5840 return lhs;
5841 }
5842
5843#endif
5844 };
5845
5846 template <typename T>
5848 template <typename T>
5850
5851 template <typename T>
5852 TOML_NODISCARD inline decltype(auto) node::get_value_exact()
5853 const noexcept(impl::value_retrieval_is_nothrow<T>)
5854 {
5855 using namespace impl;
5856
5857 static_assert(node_type_of<T> != node_type::none);
5858 static_assert(node_type_of<T> != node_type::table);
5859 static_assert(node_type_of<T> != node_type::array);
5860 static_assert(is_native<T> || can_represent_native<T>);
5861 static_assert(!is_cvref<T>);
5862 TOML_ASSERT(this->type() == node_type_of<T>);
5863
5864 if constexpr (node_type_of<T> == node_type::string)
5865 {
5866 const auto &str = *ref_cast<std::string>();
5867 if constexpr (std::is_same_v<T, std::string>)
5868 return str;
5869 else if constexpr (std::is_same_v<T, std::string_view>)
5870 return T{str};
5871 else if constexpr (std::is_same_v<T, const char *>)
5872 return str.c_str();
5873
5874 else if constexpr (std::is_same_v<T, std::wstring>)
5875 {
5876#if TOML_ENABLE_WINDOWS_COMPAT
5877 return widen(str);
5878#else
5879 static_assert(always_false<T>, "Evaluated unreachable branch!");
5880#endif
5881 }
5882
5883#if TOML_HAS_CHAR8
5884
5885 // char -> char8_t (potentially unsafe - the feature is 'experimental'!)
5887 return T(reinterpret_cast<const char8_t *>(str.c_str()), str.length());
5888 else if constexpr (std::is_same_v<T, const char8_t *>)
5889 return reinterpret_cast<const char8_t *>(str.c_str());
5890 else
5891 static_assert(always_false<T>, "Evaluated unreachable branch!");
5892
5893#endif
5894 }
5895 else
5896 return static_cast<T>(*ref_cast<native_type_of<T>>());
5897 }
5898
5899 template <typename T>
5900 TOML_NODISCARD inline optional<T> node::value_exact()
5901 const noexcept(impl::value_retrieval_is_nothrow<T>)
5902 {
5903 using namespace impl;
5904
5905 static_assert(
5907 "Retrieving values as wide-character strings with node::value_exact() is "
5908 "only "
5909 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5910
5911 static_assert(
5913 TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()"));
5914
5915 // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
5917 {
5918 if (type() == node_type_of<T>)
5919 return {this->get_value_exact<T>()};
5920 else
5921 return {};
5922 }
5923 }
5924
5925 template <typename T>
5926 TOML_NODISCARD inline optional<T> node::value()
5927 const noexcept(impl::value_retrieval_is_nothrow<T>)
5928 {
5929 using namespace impl;
5930
5931 static_assert(
5933 "Retrieving values as wide-character strings with node::value() is only "
5934 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5935 static_assert(
5938 TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
5939
5940 // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
5941 // semantics to be mindful of so the exact retrieval is enough.
5943 {
5944 if (type() == node_type_of<T>)
5945 return {this->get_value_exact<T>()};
5946 else
5947 return {};
5948 }
5949
5950 // everything else requires a bit of logicking.
5951 else
5952 {
5953 switch (type())
5954 {
5955 // int -> *
5956 case node_type::integer:
5957 {
5958 // int -> int
5959 if constexpr (is_natively_one_of<T, int64_t>)
5960 {
5961 if constexpr (is_native<T> || can_represent_native<T>)
5962 return static_cast<T>(*ref_cast<int64_t>());
5963 else
5964 return node_integer_cast<T>(*ref_cast<int64_t>());
5965 }
5966
5967 // int -> float
5968 else if constexpr (is_natively_one_of<T, double>)
5969 {
5970 const int64_t val = *ref_cast<int64_t>();
5971 if constexpr (std::numeric_limits<T>::digits < 64)
5972 {
5973 constexpr auto largest_whole_float =
5974 (int64_t{1} << std::numeric_limits<T>::digits);
5975 if (val < -largest_whole_float || val > largest_whole_float)
5976 return {};
5977 }
5978 return static_cast<T>(val);
5979 }
5980
5981 // int -> bool
5982 else if constexpr (is_natively_one_of<T, bool>)
5983 return static_cast<bool>(*ref_cast<int64_t>());
5984
5985 // int -> anything else
5986 else
5987 return {};
5988 }
5989
5990 // float -> *
5991 case node_type::floating_point:
5992 {
5993 // float -> float
5994 if constexpr (is_natively_one_of<T, double>)
5995 {
5996 if constexpr (is_native<T> || can_represent_native<T>)
5997 return {static_cast<T>(*ref_cast<double>())};
5998 else
5999 {
6000 const double val = *ref_cast<double>();
6001 if (
6002 impl::fpclassify(val) == fp_class::ok &&
6003 (val < (std::numeric_limits<T>::lowest)() ||
6004 val > (std::numeric_limits<T>::max)()))
6005 return {};
6006 return {static_cast<T>(val)};
6007 }
6008 }
6009
6010 // float -> int
6011 else if constexpr (is_natively_one_of<T, int64_t>)
6012 {
6013 const double val = *ref_cast<double>();
6014 if (
6015 impl::fpclassify(val) == fp_class::ok &&
6016 static_cast<double>(static_cast<int64_t>(val)) == val)
6017 return node_integer_cast<T>(static_cast<int64_t>(val));
6018 else
6019 return {};
6020 }
6021
6022 // float -> anything else
6023 else
6024 return {};
6025 }
6026
6027 // bool -> *
6028 case node_type::boolean:
6029 {
6030 // bool -> bool
6031 if constexpr (is_natively_one_of<T, bool>)
6032 return {*ref_cast<bool>()};
6033
6034 // bool -> int
6035 else if constexpr (is_natively_one_of<T, int64_t>)
6036 return {static_cast<T>(*ref_cast<bool>())};
6037
6038 // bool -> anything else
6039 else
6040 return {};
6041 }
6042 }
6043
6044 // non-values, or 'exact' types covered above
6045 return {};
6046 }
6047 }
6048
6049 template <typename T>
6050 TOML_NODISCARD inline auto node::value_or(T && default_value)
6051 const noexcept(impl::value_retrieval_is_nothrow<T>)
6052 {
6053 using namespace impl;
6054
6055 static_assert(
6057 "Retrieving values as wide-character strings with node::value_or() is "
6058 "only "
6059 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
6060
6061 if constexpr (is_wide_string<T>)
6062 {
6063#if TOML_ENABLE_WINDOWS_COMPAT
6064
6065 if (type() == node_type::string)
6066 return widen(*ref_cast<std::string>());
6067 return std::wstring{static_cast<T &&>(default_value)};
6068
6069#else
6070
6071 static_assert(always_false<T>, "Evaluated unreachable branch!");
6072
6073#endif
6074 }
6075 else
6076 {
6077 using value_type = std::conditional_t<
6078 std::is_pointer_v<std::decay_t<T>>,
6079 std::add_pointer_t<
6080 std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
6081 std::decay_t<T>>;
6082 using traits = value_traits<value_type>;
6083
6084 // clang-format off
6085
6086 static_assert(
6087 traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
6088 "The default value type of node::value_or() must be one of:"
6089 TOML_SA_LIST_NEW "A native TOML value type"
6091
6092 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
6093 TOML_SA_LIST_BEG "std::string"
6094 #if TOML_ENABLE_WINDOWS_COMPAT
6095 TOML_SA_LIST_SEP "std::wstring"
6096 #endif
6097 TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
6098 TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
6100
6101 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
6102 TOML_SA_LIST_BEG "any other integral type"
6103 TOML_SA_LIST_SEP "any floating-point type"
6105
6106 TOML_SA_LIST_NXT "A compatible view type"
6107 TOML_SA_LIST_BEG "std::string_view"
6108 #if TOML_HAS_CHAR8
6109 TOML_SA_LIST_SEP "std::u8string_view"
6110 #endif
6111 #if TOML_ENABLE_WINDOWS_COMPAT
6112 TOML_SA_LIST_SEP "std::wstring_view"
6113 #endif
6114 TOML_SA_LIST_SEP "const char*"
6115 #if TOML_HAS_CHAR8
6116 TOML_SA_LIST_SEP "const char8_t*"
6117 #endif
6118 #if TOML_ENABLE_WINDOWS_COMPAT
6119 TOML_SA_LIST_SEP "const wchar_t*"
6120 #endif
6122 );
6123
6124 // clang-format on
6125
6126 // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
6127 if constexpr (
6128 traits::is_native || traits::can_represent_native ||
6129 traits::can_partially_represent_native)
6130 {
6131 if constexpr (traits::is_native)
6132 {
6134 return *ref_cast<typename traits::native_type>();
6135 }
6136 if (auto val = this->value<value_type>())
6137 return *val;
6138 if constexpr (std::is_pointer_v<value_type>)
6139 return value_type{default_value};
6140 else
6141 return static_cast<T &&>(default_value);
6142 }
6143 }
6144 }
6145}
6147
6148#ifdef _MSC_VER
6149# pragma pop_macro("min")
6150# pragma pop_macro("max")
6151# ifndef __clang__
6152# pragma inline_recursion(off)
6153# endif
6154#endif
6156
6157//******** impl/make_node.hpp ****************************************************************************************
6158
6160#ifdef _MSC_VER
6161# ifndef __clang__
6162# pragma inline_recursion(on)
6163# endif
6164# pragma push_macro("min")
6165# pragma push_macro("max")
6166# undef min
6167# undef max
6168#endif
6169
6171{
6172 template <typename T>
6173 TOML_NODISCARD TOML_ATTR(returns_nonnull) auto *make_node_impl_specialized(
6174 T && val, [[maybe_unused]] value_flags flags)
6175 {
6176 using unwrapped_type = unwrap_node<remove_cvref<T>>;
6177 static_assert(!std::is_same_v<unwrapped_type, node>);
6178 static_assert(!is_node_view<unwrapped_type>);
6179
6180 // arrays + tables - invoke copy/move ctor
6182 {
6183 return new unwrapped_type(static_cast<T &&>(val));
6184 }
6185
6186 // values
6187 else
6188 {
6189 using native_type = native_type_of<unwrapped_type>;
6190 using value_type = value<native_type>;
6191
6192 value_type *out;
6193
6194 // copy/move ctor
6195 if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
6196 {
6197 out = new value_type{static_cast<T &&>(val), flags};
6198 }
6199
6200 // creating from raw value
6201 else
6202 {
6203 static_assert(
6205 "Instantiating values from wide-character strings is only "
6206 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
6207
6209 {
6210 if constexpr (std::is_same_v<native_type, int64_t>)
6211 static_assert(
6213 "Integral value initializers must be losslessly convertible to "
6214 "int64_t");
6215 else if constexpr (std::is_same_v<native_type, double>)
6216 static_assert(
6218 "Floating-point value initializers must be losslessly "
6219 "convertible to double");
6220 else
6221 static_assert(
6223 "Value initializers must be losslessly convertible to one of the "
6224 "TOML value types");
6225 }
6226
6227 if constexpr (is_wide_string<T>)
6228 {
6229#if TOML_ENABLE_WINDOWS_COMPAT
6230 out = new value_type{narrow(static_cast<T &&>(val))};
6231#else
6232 static_assert(always_false<T>, "Evaluated unreachable branch!");
6233#endif
6234 }
6235 else
6236 out = new value_type{static_cast<T &&>(val)};
6237
6238 if (flags != preserve_source_value_flags)
6239 out->flags(flags);
6240 }
6241
6242 return out;
6243 }
6244 }
6245
6246 template <typename T>
6247 TOML_NODISCARD auto *make_node_impl(
6249 {
6250 using unwrapped_type = unwrap_node<remove_cvref<T>>;
6251 if constexpr (
6252 std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>)
6253 {
6254 if constexpr (is_node_view<unwrapped_type>)
6255 {
6256 if (!val)
6257 return static_cast<toml::node *>(nullptr);
6258 }
6259
6260 return static_cast<T &&>(val).visit(
6261 [flags](auto &&concrete)
6262 {
6263 return static_cast<toml::node *>(make_node_impl_specialized(
6264 static_cast<decltype(concrete) &&>(concrete), flags));
6265 });
6266 }
6267 else
6268 return make_node_impl_specialized(static_cast<T &&>(val), flags);
6269 }
6270
6271 template <typename T>
6272 TOML_NODISCARD auto *make_node_impl(
6274 {
6275 return make_node_impl(static_cast<T &&>(val.value), flags);
6276 }
6277
6278 template <
6279 typename T,
6280 bool =
6283 struct inserted_type_of_
6284 {
6285 using type =
6286 std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
6287 };
6288
6289 template <typename T>
6290 struct inserted_type_of_<inserter<T>, false>
6291 {
6292 using type = typename inserted_type_of_<remove_cvref<T>>::type;
6293 };
6294
6295 template <typename T>
6296 struct inserted_type_of_<T, false>
6297 {
6298 using type = void;
6299 };
6300
6301 template <typename T>
6304 {
6305 return node_ptr{make_node_impl(static_cast<T &&>(val), flags)};
6306 }
6307
6308 template <typename... T>
6310 {
6311 using type = void;
6312 };
6313
6314 template <typename T>
6316 {
6317 using type = std::conditional_t<
6319 void,
6320 typename inserted_type_of_<T>::type>;
6321 };
6322
6323 template <typename T>
6328
6329 template <typename... T>
6331}
6333
6335{
6336 template <typename T>
6337 using inserted_type_of = POXY_IMPLEMENTATION_DETAIL(
6338 typename impl::inserted_type_of_<impl::remove_cvref<T>>::type);
6339}
6341
6342#ifdef _MSC_VER
6343# pragma pop_macro("min")
6344# pragma pop_macro("max")
6345# ifndef __clang__
6346# pragma inline_recursion(off)
6347# endif
6348#endif
6350
6351//******** impl/array.hpp ********************************************************************************************
6352
6354#ifdef _MSC_VER
6355# ifndef __clang__
6356# pragma inline_recursion(on)
6357# endif
6358# pragma push_macro("min")
6359# pragma push_macro("max")
6360# undef min
6361# undef max
6362#endif
6363
6364#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
6365# if TOML_GCC && TOML_GCC <= 7
6366# define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1
6367# else
6368# define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0
6369# endif
6370#endif
6371
6372#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && \
6373 !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
6374# define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE \
6375 "If you're seeing this error it's because you're using one of toml++'s " \
6376 "for_each() functions on a compiler with " \
6377 "known bugs in that area (e.g. GCC 7). On these compilers returning a " \
6378 "bool (or bool-convertible) value from the " \
6379 "for_each() callable causes spurious compilation failures, while " \
6380 "returning nothing (void) works fine. " \
6381 "If you believe this message is incorrect for your compiler, you can try " \
6382 "your luck by #defining " \
6383 "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it " \
6384 "works, great! Let me know at " \
6385 "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you " \
6386 "don't have any need for early-exiting from " \
6387 "for_each(), you can suppress this error by #defining " \
6388 "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED " \
6389 "and moving on with your life."
6390#endif
6391
6393{
6394 template <bool IsConst>
6395 class TOML_TRIVIAL_ABI array_iterator
6396 {
6397 private:
6398 template <bool>
6399 friend class array_iterator;
6400
6401 using mutable_vector_iterator = std::vector<node_ptr>::iterator;
6402 using const_vector_iterator = std::vector<node_ptr>::const_iterator;
6403 using vector_iterator = std::
6404 conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
6405
6406 mutable vector_iterator iter_;
6407
6408 public:
6409 using value_type = std::conditional_t<IsConst, const node, node>;
6410 using reference = value_type &;
6411 using pointer = value_type *;
6412 using difference_type = ptrdiff_t;
6413 using iterator_category =
6414 typename std::iterator_traits<vector_iterator>::iterator_category;
6415
6417 array_iterator() noexcept = default;
6418
6420 explicit array_iterator(mutable_vector_iterator iter) noexcept //
6421 : iter_{iter}
6422 {
6423 }
6424
6425 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
6427 explicit array_iterator(const_vector_iterator iter) noexcept //
6428 : iter_{iter}
6429 {
6430 }
6431
6432 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
6434 array_iterator(const array_iterator<false> &other) noexcept //
6435 : iter_{other.iter_}
6436 {
6437 }
6438
6440 array_iterator(const array_iterator &) noexcept = default;
6441
6442 array_iterator &operator=(const array_iterator &) noexcept = default;
6443
6444 array_iterator &operator++() noexcept // ++pre
6445 {
6446 ++iter_;
6447 return *this;
6448 }
6449
6450 array_iterator operator++(int) noexcept // post++
6451 {
6452 array_iterator out{iter_};
6453 ++iter_;
6454 return out;
6455 }
6456
6457 array_iterator &operator--() noexcept // --pre
6458 {
6459 --iter_;
6460 return *this;
6461 }
6462
6463 array_iterator operator--(int) noexcept // post--
6464 {
6465 array_iterator out{iter_};
6466 --iter_;
6467 return out;
6468 }
6469
6471 reference operator*() const noexcept
6472 {
6473 return *iter_->get();
6474 }
6475
6477 pointer operator->() const noexcept
6478 {
6479 return iter_->get();
6480 }
6481
6483 explicit operator const vector_iterator &() const noexcept
6484 {
6485 return iter_;
6486 }
6487
6488 TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
6490 explicit operator const const_vector_iterator() const noexcept
6491 {
6492 return iter_;
6493 }
6494
6495 array_iterator &operator+=(ptrdiff_t rhs) noexcept
6496 {
6497 iter_ += rhs;
6498 return *this;
6499 }
6500
6501 array_iterator &operator-=(ptrdiff_t rhs) noexcept
6502 {
6503 iter_ -= rhs;
6504 return *this;
6505 }
6506
6508 friend array_iterator
6509 operator+(const array_iterator &lhs, ptrdiff_t rhs) noexcept
6510 {
6511 return array_iterator{lhs.iter_ + rhs};
6512 }
6513
6515 friend array_iterator
6516 operator+(ptrdiff_t lhs, const array_iterator &rhs) noexcept
6517 {
6518 return array_iterator{rhs.iter_ + lhs};
6519 }
6520
6522 friend array_iterator
6523 operator-(const array_iterator &lhs, ptrdiff_t rhs) noexcept
6524 {
6525 return array_iterator{lhs.iter_ - rhs};
6526 }
6527
6529 friend ptrdiff_t
6530 operator-(const array_iterator &lhs, const array_iterator &rhs) noexcept
6531 {
6532 return lhs.iter_ - rhs.iter_;
6533 }
6534
6536 friend bool
6537 operator==(const array_iterator &lhs, const array_iterator &rhs) noexcept
6538 {
6539 return lhs.iter_ == rhs.iter_;
6540 }
6541
6543 friend bool
6544 operator!=(const array_iterator &lhs, const array_iterator &rhs) noexcept
6545 {
6546 return lhs.iter_ != rhs.iter_;
6547 }
6548
6550 friend bool
6551 operator<(const array_iterator &lhs, const array_iterator &rhs) noexcept
6552 {
6553 return lhs.iter_ < rhs.iter_;
6554 }
6555
6557 friend bool
6558 operator<=(const array_iterator &lhs, const array_iterator &rhs) noexcept
6559 {
6560 return lhs.iter_ <= rhs.iter_;
6561 }
6562
6564 friend bool
6565 operator>(const array_iterator &lhs, const array_iterator &rhs) noexcept
6566 {
6567 return lhs.iter_ > rhs.iter_;
6568 }
6569
6571 friend bool
6572 operator>=(const array_iterator &lhs, const array_iterator &rhs) noexcept
6573 {
6574 return lhs.iter_ >= rhs.iter_;
6575 }
6576
6578 reference operator[](ptrdiff_t idx) const noexcept
6579 {
6580 return *(iter_ + idx)->get();
6581 }
6582 };
6583
6585 {
6586 mutable node_ptr value;
6587
6588 template <typename T>
6591 : value{make_node(static_cast<T &&>(val), flags)}
6592 {
6593 }
6594 };
6595}
6597
6599{
6600 using array_iterator =
6601 POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);
6602
6604 POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);
6605
6606 class TOML_EXPORTED_CLASS array : public node
6607 {
6608 private:
6609 using vector_type = std::vector<impl::node_ptr>;
6610 using vector_iterator = typename vector_type::iterator;
6611 using const_vector_iterator = typename vector_type::const_iterator;
6612 vector_type elems_;
6613
6616 array(const impl::array_init_elem *, const impl::array_init_elem *);
6617
6619 array(
6620 std::false_type,
6621 std::initializer_list<impl::array_init_elem> elems) //
6622 : array{elems.begin(), elems.end()}
6623 {
6624 }
6625
6627 void preinsertion_resize(size_t idx, size_t count);
6628
6630 void insert_at_back(impl::node_ptr &&);
6631
6633 vector_iterator insert_at(const_vector_iterator, impl::node_ptr &&);
6634
6635 template <typename T>
6636 void emplace_back_if_not_empty_view(T &&val, value_flags flags)
6637 {
6638 if constexpr (is_node_view<T>)
6639 {
6640 if (!val)
6641 return;
6642 }
6643 insert_at_back(impl::make_node(static_cast<T &&>(val), flags));
6644 }
6645
6648 size_t total_leaf_count() const noexcept;
6649
6651 void flatten_child(array &&child, size_t &dest_index) noexcept;
6652
6653 public:
6654 using value_type = node;
6657 using reference = node &;
6658 using const_reference = const node &;
6659
6662 array() noexcept;
6663
6665 ~array() noexcept;
6666
6669 array(const array &);
6670
6673 array(array &&other) noexcept;
6674
6676 (sizeof...(ElemTypes) > 0 ||
6677 !std::is_same_v<impl::remove_cvref<ElemType>, array>),
6678 typename ElemType,
6679 typename... ElemTypes)
6681 explicit array(ElemType &&val, ElemTypes &&...vals)
6682 : array{
6683 std::false_type{},
6684 std::initializer_list<impl::array_init_elem>{
6685 static_cast<ElemType &&>(val),
6686 static_cast<ElemTypes &&>(vals)...}}
6687 {
6688 }
6689
6691 array &operator=(const array &);
6692
6694 array &operator=(array &&rhs) noexcept;
6695
6697 node_type type() const noexcept final
6698 {
6699 return node_type::array;
6700 }
6701
6704 bool is_homogeneous(node_type ntype) const noexcept final;
6705
6708 bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final;
6709
6712 bool is_homogeneous(node_type ntype, const node *&first_nonmatch)
6713 const noexcept final;
6714
6715 template <typename ElemType = void>
6716 TOML_PURE_GETTER bool is_homogeneous() const noexcept
6717 {
6718 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
6719 static_assert(
6720 std::is_void_v<type> || toml::is_value<type> ||
6721 toml::is_container<type>,
6722 "The template type argument of array::is_homogeneous() must be void or "
6723 "one "
6725
6726 return is_homogeneous(impl::node_type_of<type>);
6727 }
6729 bool is_table() const noexcept final
6730 {
6731 return false;
6732 }
6733
6735 bool is_array() const noexcept final
6736 {
6737 return true;
6738 }
6739
6741 bool is_array_of_tables() const noexcept final
6742 {
6743 return is_homogeneous(node_type::table);
6744 }
6745
6747 bool is_value() const noexcept final
6748 {
6749 return false;
6750 }
6751
6753 bool is_string() const noexcept final
6754 {
6755 return false;
6756 }
6757
6759 bool is_integer() const noexcept final
6760 {
6761 return false;
6762 }
6763
6765 bool is_floating_point() const noexcept final
6766 {
6767 return false;
6768 }
6769
6771 bool is_number() const noexcept final
6772 {
6773 return false;
6774 }
6775
6777 bool is_boolean() const noexcept final
6778 {
6779 return false;
6780 }
6781
6783 bool is_date() const noexcept final
6784 {
6785 return false;
6786 }
6787
6789 bool is_time() const noexcept final
6790 {
6791 return false;
6792 }
6793
6795 bool is_date_time() const noexcept final
6796 {
6797 return false;
6798 }
6799
6801 table *as_table() noexcept final
6802 {
6803 return nullptr;
6804 }
6805
6807 array *as_array() noexcept final
6808 {
6809 return this;
6810 }
6811
6813 toml::value<std::string> *as_string() noexcept final
6814 {
6815 return nullptr;
6816 }
6817
6819 toml::value<int64_t> *as_integer() noexcept final
6820 {
6821 return nullptr;
6822 }
6823
6825 toml::value<double> *as_floating_point() noexcept final
6826 {
6827 return nullptr;
6828 }
6829
6831 toml::value<bool> *as_boolean() noexcept final
6832 {
6833 return nullptr;
6834 }
6835
6837 toml::value<date> *as_date() noexcept final
6838 {
6839 return nullptr;
6840 }
6841
6843 toml::value<time> *as_time() noexcept final
6844 {
6845 return nullptr;
6846 }
6847
6849 toml::value<date_time> *as_date_time() noexcept final
6850 {
6851 return nullptr;
6852 }
6853
6855 const table *as_table() const noexcept final
6856 {
6857 return nullptr;
6858 }
6859
6861 const array *as_array() const noexcept final
6862 {
6863 return this;
6864 }
6865
6867 const toml::value<std::string> *as_string() const noexcept final
6868 {
6869 return nullptr;
6870 }
6871
6873 const toml::value<int64_t> *as_integer() const noexcept final
6874 {
6875 return nullptr;
6876 }
6877
6879 const toml::value<double> *as_floating_point() const noexcept final
6880 {
6881 return nullptr;
6882 }
6883
6885 const toml::value<bool> *as_boolean() const noexcept final
6886 {
6887 return nullptr;
6888 }
6889
6891 const toml::value<date> *as_date() const noexcept final
6892 {
6893 return nullptr;
6894 }
6895
6897 const toml::value<time> *as_time() const noexcept final
6898 {
6899 return nullptr;
6900 }
6901
6903 const toml::value<date_time> *as_date_time() const noexcept final
6904 {
6905 return nullptr;
6906 }
6907
6909 node *get(size_t index) noexcept
6910 {
6911 return index < elems_.size() ? elems_[index].get() : nullptr;
6912 }
6913
6915 const node *get(size_t index) const noexcept
6916 {
6917 return const_cast<array &>(*this).get(index);
6918 }
6919
6920 template <typename ElemType>
6921 TOML_NODISCARD impl::wrap_node<ElemType> *get_as(size_t index) noexcept
6922 {
6923 if (auto val = get(index))
6924 return val->template as<ElemType>();
6925 return nullptr;
6926 }
6927
6928 template <typename ElemType>
6929 TOML_NODISCARD const impl::wrap_node<ElemType> *
6930 get_as(size_t index) const noexcept
6931 {
6932 return const_cast<array &>(*this).template get_as<ElemType>(index);
6933 }
6934
6935 using node::operator[]; // inherit operator[toml::path]
6937 node &operator[](size_t index) noexcept
6938 {
6939 return *elems_[index];
6940 }
6941
6943 const node &operator[](size_t index) const noexcept
6944 {
6945 return *elems_[index];
6946 }
6947
6950 node &at(size_t index);
6951
6953 const node &at(size_t index) const
6954 {
6955 return const_cast<array &>(*this).at(index);
6956 }
6957
6959 node &front() noexcept
6960 {
6961 return *elems_.front();
6962 }
6963
6965 const node &front() const noexcept
6966 {
6967 return *elems_.front();
6968 }
6969
6971 node &back() noexcept
6972 {
6973 return *elems_.back();
6974 }
6975
6977 const node &back() const noexcept
6978 {
6979 return *elems_.back();
6980 }
6981
6982 using iterator = array_iterator;
6983
6985
6987 iterator begin() noexcept
6988 {
6989 return iterator{elems_.begin()};
6990 }
6991
6993 const_iterator begin() const noexcept
6994 {
6995 return const_iterator{elems_.cbegin()};
6996 }
6997
6999 const_iterator cbegin() const noexcept
7000 {
7001 return const_iterator{elems_.cbegin()};
7002 }
7003
7005 iterator end() noexcept
7006 {
7007 return iterator{elems_.end()};
7008 }
7009
7011 const_iterator end() const noexcept
7012 {
7013 return const_iterator{elems_.cend()};
7014 }
7015
7017 const_iterator cend() const noexcept
7018 {
7019 return const_iterator{elems_.cend()};
7020 }
7021
7022 private:
7023 template <typename T, typename Array>
7024 using for_each_elem_ref = impl::copy_cvref<
7025 impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>,
7026 Array>;
7027
7028 template <typename Func, typename Array, typename T>
7029 using can_for_each = std::disjunction<
7030 std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
7031 std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
7032 std::is_invocable<Func, for_each_elem_ref<T, Array>>>;
7033
7034 template <typename Func, typename Array, typename T>
7035 using can_for_each_nothrow = std::conditional_t<
7036 // first form
7037 std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
7038 std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
7039 std::conditional_t<
7040 // second form
7041 std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
7042 std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
7043 std::conditional_t<
7044 // third form
7045 std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
7046 std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>,
7047 std::false_type>>>;
7048
7049 template <typename Func, typename Array>
7050 using can_for_each_any = std::disjunction<
7051 can_for_each<Func, Array, table>,
7052 can_for_each<Func, Array, array>,
7053 can_for_each<Func, Array, std::string>,
7054 can_for_each<Func, Array, int64_t>,
7055 can_for_each<Func, Array, double>,
7056 can_for_each<Func, Array, bool>,
7057 can_for_each<Func, Array, date>,
7058 can_for_each<Func, Array, time>,
7059 can_for_each<Func, Array, date_time>>;
7060
7061 template <typename Func, typename Array, typename T>
7062 using for_each_is_nothrow_one = std::disjunction<
7063 std::negation<can_for_each<Func, Array, T>>, //
7064 can_for_each_nothrow<Func, Array, T>>;
7065
7066 template <typename Func, typename Array>
7067 using for_each_is_nothrow = std::conjunction<
7068 for_each_is_nothrow_one<Func, Array, table>,
7069 for_each_is_nothrow_one<Func, Array, array>,
7070 for_each_is_nothrow_one<Func, Array, std::string>,
7071 for_each_is_nothrow_one<Func, Array, int64_t>,
7072 for_each_is_nothrow_one<Func, Array, double>,
7073 for_each_is_nothrow_one<Func, Array, bool>,
7074 for_each_is_nothrow_one<Func, Array, date>,
7075 for_each_is_nothrow_one<Func, Array, time>,
7076 for_each_is_nothrow_one<Func, Array, date_time>>;
7077
7078 template <typename Func, typename Array>
7079 static void do_for_each(Func &&visitor, Array &&arr) //
7080 noexcept(for_each_is_nothrow<Func &&, Array &&>::value)
7081 {
7082 static_assert(
7083 can_for_each_any<Func &&, Array &&>::value,
7084 "TOML array for_each visitors must be invocable for at least one of "
7085 "the toml::node "
7086 "specializations:" TOML_SA_NODE_TYPE_LIST);
7087
7088 for (size_t i = 0; i < arr.size(); i++)
7089 {
7090 using node_ref = impl::copy_cvref<toml::node, Array &&>;
7091 static_assert(std::is_reference_v<node_ref>);
7092
7093#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
7094
7095# ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
7096 static_assert(
7097 impl::always_false<Func, Array, node_ref>, //
7098 TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
7099# endif
7100
7101 static_cast<node_ref>(static_cast<Array &&>(arr)[i])
7102 .visit(
7103 [&]([[maybe_unused]] auto &&elem) //
7104 noexcept(
7105 for_each_is_nothrow_one<Func &&, Array &&, decltype(elem)>::value)
7106 {
7107 using elem_ref = for_each_elem_ref<decltype(elem), Array &&>;
7108 static_assert(std::is_reference_v<elem_ref>);
7109
7110 // func(elem, i)
7111 if constexpr (std::is_invocable_v<Func &&, elem_ref, size_t>)
7112 {
7113 static_cast<Func &&>(visitor)(static_cast<elem_ref>(elem), i);
7114 }
7115
7116 // func(i, elem)
7117 else if constexpr (std::is_invocable_v<Func &&, size_t, elem_ref>)
7118 {
7119 static_cast<Func &&>(visitor)(i, static_cast<elem_ref>(elem));
7120 }
7121
7122 // func(elem)
7123 else if constexpr (std::is_invocable_v<Func &&, elem_ref>)
7124 {
7125 static_cast<Func &&>(visitor)(static_cast<elem_ref>(elem));
7126 }
7127 });
7128
7129#else
7130 const auto keep_going =
7131 static_cast<node_ref>(static_cast<Array &&>(arr)[i])
7132 .visit(
7133 [&]([[maybe_unused]] auto &&elem) //
7134 noexcept(
7135 for_each_is_nothrow_one<Func &&, Array &&, decltype(elem)>::
7136 value)
7137 {
7138 using elem_ref = for_each_elem_ref<decltype(elem), Array &&>;
7139 static_assert(std::is_reference_v<elem_ref>);
7140
7141 // func(elem, i)
7142 if constexpr (std::is_invocable_v<Func &&, elem_ref, size_t>)
7143 {
7144 using return_type = decltype(static_cast<Func &&>(visitor)(
7145 static_cast<elem_ref>(elem), i));
7146
7147 if constexpr (impl::is_constructible_or_convertible<
7148 bool,
7149 return_type>)
7150 {
7151 return static_cast<bool>(static_cast<Func &&>(visitor)(
7152 static_cast<elem_ref>(elem), i));
7153 }
7154 else
7155 {
7156 static_cast<Func &&>(visitor)(
7157 static_cast<elem_ref>(elem), i);
7158 return true;
7159 }
7160 }
7161
7162 // func(i, elem)
7163 else if constexpr (std::
7164 is_invocable_v<Func &&, size_t, elem_ref>)
7165 {
7166 using return_type = decltype(static_cast<Func &&>(visitor)(
7167 i, static_cast<elem_ref>(elem)));
7168
7169 if constexpr (impl::is_constructible_or_convertible<
7170 bool,
7171 return_type>)
7172 {
7173 return static_cast<bool>(static_cast<Func &&>(visitor)(
7174 i, static_cast<elem_ref>(elem)));
7175 }
7176 else
7177 {
7178 static_cast<Func &&>(visitor)(
7179 i, static_cast<elem_ref>(elem));
7180 return true;
7181 }
7182 }
7183
7184 // func(elem)
7185 else if constexpr (std::is_invocable_v<Func &&, elem_ref>)
7186 {
7187 using return_type = decltype(static_cast<Func &&>(visitor)(
7188 static_cast<elem_ref>(elem)));
7189
7190 if constexpr (impl::is_constructible_or_convertible<
7191 bool,
7192 return_type>)
7193 {
7194 return static_cast<bool>(static_cast<Func &&>(visitor)(
7195 static_cast<elem_ref>(elem)));
7196 }
7197 else
7198 {
7199 static_cast<Func &&>(visitor)(static_cast<elem_ref>(elem));
7200 return true;
7201 }
7202 }
7203
7204 // visitor not compatible with this particular type
7205 else
7206 return true;
7207 });
7208
7209 if (!keep_going)
7210 return;
7211#endif
7212 }
7213 }
7214
7215 public:
7216 template <typename Func>
7217 array &for_each(Func &&visitor) & //
7218 noexcept(for_each_is_nothrow<Func &&, array &>::value)
7219 {
7220 do_for_each(static_cast<Func &&>(visitor), *this);
7221 return *this;
7222 }
7223
7224 template <typename Func>
7225 array &&for_each(Func &&visitor) && //
7226 noexcept(for_each_is_nothrow<Func &&, array &&>::value)
7227 {
7228 do_for_each(static_cast<Func &&>(visitor), static_cast<array &&>(*this));
7229 return static_cast<array &&>(*this);
7230 }
7231
7232 template <typename Func>
7233 const array &for_each(Func &&visitor) const & //
7234 noexcept(for_each_is_nothrow<Func &&, const array &>::value)
7235 {
7236 do_for_each(static_cast<Func &&>(visitor), *this);
7237 return *this;
7238 }
7239
7240 template <typename Func>
7241 const array &&for_each(Func &&visitor) const && //
7242 noexcept(for_each_is_nothrow<Func &&, const array &&>::value)
7243 {
7244 do_for_each(
7245 static_cast<Func &&>(visitor), static_cast<const array &&>(*this));
7246 return static_cast<const array &&>(*this);
7247 }
7248
7250 bool empty() const noexcept
7251 {
7252 return elems_.empty();
7253 }
7254
7256 size_t size() const noexcept
7257 {
7258 return elems_.size();
7259 }
7260
7262 size_t max_size() const noexcept
7263 {
7264 return elems_.max_size();
7265 }
7266
7268 size_t capacity() const noexcept
7269 {
7270 return elems_.capacity();
7271 }
7272
7274 void reserve(size_t new_capacity);
7275
7278
7280 void truncate(size_t new_size);
7281
7282 template <typename ElemType>
7284 size_t new_size,
7285 ElemType &&default_init_val,
7286 value_flags default_init_flags = preserve_source_value_flags)
7287 {
7288 static_assert(
7290 "The default element type argument to toml::array::resize may not be "
7291 "toml::node_view.");
7292
7293 if (!new_size)
7294 clear();
7295 else if (new_size > elems_.size())
7296 insert(
7297 cend(),
7298 new_size - elems_.size(),
7299 static_cast<ElemType &&>(default_init_val),
7300 default_init_flags);
7301 else
7302 truncate(new_size);
7303 }
7304
7307
7310
7312 array &flatten() &;
7313
7314 array &&flatten() &&
7315 {
7316 return static_cast<toml::array &&>(this->flatten());
7317 }
7318
7320 array &prune(bool recursive = true) &noexcept;
7321
7322 array &&prune(bool recursive = true) &&noexcept
7323 {
7324 return static_cast<toml::array &&>(this->prune(recursive));
7325 }
7326
7328 void pop_back() noexcept;
7329
7331 void clear() noexcept;
7332
7333 template <typename ElemType>
7336 ElemType &&val,
7338 {
7339 if constexpr (is_node_view<ElemType>)
7340 {
7341 if (!val)
7342 return end();
7343 }
7344 return iterator{insert_at(
7345 const_vector_iterator{pos},
7346 impl::make_node(static_cast<ElemType &&>(val), flags))};
7347 }
7348
7349 template <typename ElemType>
7352 size_t count,
7353 ElemType &&val,
7355 {
7356 if constexpr (is_node_view<ElemType>)
7357 {
7358 if (!val)
7359 return end();
7360 }
7361 switch (count)
7362 {
7363 case 0:
7364 return iterator{
7365 elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
7366 case 1:
7367 return insert(pos, static_cast<ElemType &&>(val), flags);
7368 default:
7369 {
7370 const auto start_idx =
7371 static_cast<size_t>(const_vector_iterator{pos} - elems_.cbegin());
7372 preinsertion_resize(start_idx, count);
7373 size_t i = start_idx;
7374 for (size_t e = start_idx + count - 1u; i < e; i++)
7375 elems_[i] = impl::make_node(val, flags);
7376
7377 elems_[i] = impl::make_node(static_cast<ElemType &&>(val), flags);
7378 return iterator{elems_.begin() + static_cast<ptrdiff_t>(start_idx)};
7379 }
7380 }
7381 }
7382
7383 template <typename Iter>
7386 Iter first,
7387 Iter last,
7389 {
7390 const auto distance = std::distance(first, last);
7391 if (distance <= 0)
7392 return iterator{
7393 elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
7394 else
7395 {
7396 auto count = distance;
7397 using deref_type = decltype(*first);
7398 if constexpr (is_node_view<deref_type>)
7399 {
7400 for (auto it = first; it != last; it++)
7401 if (!(*it))
7402 count--;
7403 if (!count)
7404 return iterator{
7405 elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
7406 }
7407 const auto start_idx =
7408 static_cast<size_t>(const_vector_iterator{pos} - elems_.cbegin());
7409 preinsertion_resize(start_idx, static_cast<size_t>(count));
7410 size_t i = start_idx;
7411 for (auto it = first; it != last; it++)
7412 {
7413 if constexpr (is_node_view<deref_type>)
7414 {
7415 if (!(*it))
7416 continue;
7417 }
7418 if constexpr (std::is_rvalue_reference_v<deref_type>)
7419 elems_[i++] = impl::make_node(std::move(*it), flags);
7420 else
7421 elems_[i++] = impl::make_node(*it, flags);
7422 }
7423 return iterator{elems_.begin() + static_cast<ptrdiff_t>(start_idx)};
7424 }
7425 }
7426
7427 template <typename ElemType>
7430 std::initializer_list<ElemType> ilist,
7432 {
7433 return insert(pos, ilist.begin(), ilist.end(), flags);
7434 }
7435
7436 template <typename ElemType = void, typename... Args>
7438 {
7439 using raw_elem_type = impl::remove_cvref<ElemType>;
7440 using elem_type = std::conditional_t<
7441 std::is_void_v<raw_elem_type>, //
7442 impl::emplaced_type_of<Args &&...>,
7443 raw_elem_type>;
7444
7445 using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
7446 static_assert(
7447 impl::is_native<type> || impl::is_one_of<type, table, array>,
7448 "Emplacement type parameter must be one "
7450
7451 return iterator{insert_at(
7452 const_vector_iterator{pos},
7453 impl::node_ptr{
7454 new impl::wrap_node<type>{static_cast<Args &&>(args)...}})};
7455 }
7456
7457 template <typename ElemType>
7460 ElemType &&val,
7462 {
7463 TOML_ASSERT(pos >= cbegin() && pos < cend());
7464
7465 if constexpr (is_node_view<ElemType>)
7466 {
7467 if (!val)
7468 return end();
7469 }
7470
7471 const auto it =
7472 elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin());
7473 *it = impl::make_node(static_cast<ElemType &&>(val), flags);
7474 return iterator{it};
7475 }
7476
7477 template <typename ElemType>
7478 void
7480 {
7481 emplace_back_if_not_empty_view(static_cast<ElemType &&>(val), flags);
7482 }
7483
7484 template <typename ElemType = void, typename... Args>
7485 decltype(auto) emplace_back(Args &&...args)
7486 {
7487 using raw_elem_type = impl::remove_cvref<ElemType>;
7488 using elem_type = std::conditional_t<
7489 std::is_void_v<raw_elem_type>, //
7490 impl::emplaced_type_of<Args &&...>,
7491 raw_elem_type>;
7492
7493 static constexpr auto moving_node_ptr =
7494 std::is_same_v<elem_type, impl::node_ptr> //
7495 && sizeof...(Args) == 1u //
7496 && impl::first_is_same<impl::node_ptr &&, Args &&...>;
7497
7498 using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
7499
7500 static_assert(
7501 moving_node_ptr //
7502 || impl::is_native<unwrapped_type> //
7503 || impl::is_one_of<unwrapped_type, table, array>, //
7504 "ElemType argument of array::emplace_back() must be one "
7506
7507 if constexpr (moving_node_ptr)
7508 {
7509 insert_at_back(static_cast<Args &&>(args)...);
7510 return *elems_.back();
7511 }
7512 else
7513 {
7514 auto ptr =
7515 new impl::wrap_node<unwrapped_type>{static_cast<Args &&>(args)...};
7516 insert_at_back(impl::node_ptr{ptr});
7517 return *ptr;
7518 }
7519 }
7520
7521 private:
7524 static bool TOML_CALLCONV equal(const array &, const array &) noexcept;
7525
7526 template <typename T>
7527 TOML_NODISCARD static bool
7528 equal_to_container(const array &lhs, const T &rhs) noexcept
7529 {
7530 using element_type = std::remove_const_t<typename T::value_type>;
7531 static_assert(
7532 impl::is_losslessly_convertible_to_native<element_type>,
7533 "Container element type must be losslessly convertible one of the "
7534 "native TOML value types");
7535
7536 if (lhs.size() != rhs.size())
7537 return false;
7538 if (rhs.size() == 0u)
7539 return true;
7540
7541 size_t i{};
7542 for (auto &list_elem : rhs)
7543 {
7544 const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
7545 if (!elem || *elem != list_elem)
7546 return false;
7547 }
7548
7549 return true;
7550 }
7551
7552 public:
7554 friend bool operator==(const array &lhs, const array &rhs) noexcept
7555 {
7556 return equal(lhs, rhs);
7557 }
7558
7560 friend bool operator!=(const array &lhs, const array &rhs) noexcept
7561 {
7562 return !equal(lhs, rhs);
7563 }
7564
7565 template <typename T>
7566 TOML_NODISCARD friend bool
7567 operator==(const array &lhs, const std::initializer_list<T> &rhs) noexcept
7568 {
7569 return equal_to_container(lhs, rhs);
7570 }
7572 const array &,
7573 const std::initializer_list<T> &,
7574 template <typename T>
7575 );
7576
7577 template <typename T>
7578 TOML_NODISCARD friend bool
7579 operator==(const array &lhs, const std::vector<T> &rhs) noexcept
7580 {
7581 return equal_to_container(lhs, rhs);
7582 }
7584 const array &,
7585 const std::vector<T> &,
7586 template <typename T>
7587 );
7588
7589#if TOML_ENABLE_FORMATTERS
7590
7591 friend std::ostream &operator<<(std::ostream &lhs, const array &rhs)
7592 {
7593 impl::print_to_stream(lhs, rhs);
7594 return lhs;
7595 }
7596
7597#endif
7598 };
7599}
7601
7602#ifdef _MSC_VER
7603# pragma pop_macro("min")
7604# pragma pop_macro("max")
7605# ifndef __clang__
7606# pragma inline_recursion(off)
7607# endif
7608#endif
7610
7611//******** impl/key.hpp **********************************************************************************************
7612
7614#ifdef _MSC_VER
7615# ifndef __clang__
7616# pragma inline_recursion(on)
7617# endif
7618# pragma push_macro("min")
7619# pragma push_macro("max")
7620# undef min
7621# undef max
7622#endif
7623
7625{
7626 class key
7627 {
7628 private:
7629 std::string key_;
7630 source_region source_;
7631
7632 public:
7634 key() noexcept = default;
7635
7637 explicit key(std::string_view k, source_region &&src = {}) //
7638 : key_{k}, source_{std::move(src)}
7639 {
7640 }
7641
7643 explicit key(std::string_view k, const source_region &src) //
7644 : key_{k}, source_{src}
7645 {
7646 }
7647
7649 explicit key(std::string &&k, source_region &&src = {}) noexcept //
7650 : key_{std::move(k)}, source_{std::move(src)}
7651 {
7652 }
7653
7655 explicit key(std::string &&k, const source_region &src) noexcept //
7656 : key_{std::move(k)}, source_{src}
7657 {
7658 }
7659
7661 explicit key(const char *k, source_region &&src = {}) //
7662 : key_{k}, source_{std::move(src)}
7663 {
7664 }
7665
7667 explicit key(const char *k, const source_region &src) //
7668 : key_{k}, source_{src}
7669 {
7670 }
7671
7672#if TOML_ENABLE_WINDOWS_COMPAT
7673
7675 explicit key(std::wstring_view k, source_region &&src = {}) //
7676 : key_{impl::narrow(k)}, source_{std::move(src)}
7677 {
7678 }
7679
7681 explicit key(std::wstring_view k, const source_region &src) //
7682 : key_{impl::narrow(k)}, source_{src}
7683 {
7684 }
7685
7686#endif
7687
7689 std::string_view str() const noexcept
7690 {
7691 return std::string_view{key_};
7692 }
7693
7695 /*implicit*/ operator std::string_view() const noexcept
7696 {
7697 return str();
7698 }
7699
7701 bool empty() const noexcept
7702 {
7703 return key_.empty();
7704 }
7705
7707 const char *data() const noexcept
7708 {
7709 return key_.data();
7710 }
7711
7713 size_t length() const noexcept
7714 {
7715 return key_.length();
7716 }
7717
7719 const source_region &source() const noexcept
7720 {
7721 return source_;
7722 }
7723
7725 friend bool operator==(const key &lhs, const key &rhs) noexcept
7726 {
7727 return lhs.key_ == rhs.key_;
7728 }
7729
7731 friend bool operator!=(const key &lhs, const key &rhs) noexcept
7732 {
7733 return lhs.key_ != rhs.key_;
7734 }
7735
7737 friend bool operator<(const key &lhs, const key &rhs) noexcept
7738 {
7739 return lhs.key_ < rhs.key_;
7740 }
7741
7743 friend bool operator<=(const key &lhs, const key &rhs) noexcept
7744 {
7745 return lhs.key_ <= rhs.key_;
7746 }
7747
7749 friend bool operator>(const key &lhs, const key &rhs) noexcept
7750 {
7751 return lhs.key_ > rhs.key_;
7752 }
7753
7755 friend bool operator>=(const key &lhs, const key &rhs) noexcept
7756 {
7757 return lhs.key_ >= rhs.key_;
7758 }
7759
7761 friend bool operator==(const key &lhs, std::string_view rhs) noexcept
7762 {
7763 return lhs.key_ == rhs;
7764 }
7765
7767 friend bool operator!=(const key &lhs, std::string_view rhs) noexcept
7768 {
7769 return lhs.key_ != rhs;
7770 }
7771
7773 friend bool operator<(const key &lhs, std::string_view rhs) noexcept
7774 {
7775 return lhs.key_ < rhs;
7776 }
7777
7779 friend bool operator<=(const key &lhs, std::string_view rhs) noexcept
7780 {
7781 return lhs.key_ <= rhs;
7782 }
7783
7785 friend bool operator>(const key &lhs, std::string_view rhs) noexcept
7786 {
7787 return lhs.key_ > rhs;
7788 }
7789
7791 friend bool operator>=(const key &lhs, std::string_view rhs) noexcept
7792 {
7793 return lhs.key_ >= rhs;
7794 }
7795
7797 friend bool operator==(std::string_view lhs, const key &rhs) noexcept
7798 {
7799 return lhs == rhs.key_;
7800 }
7801
7803 friend bool operator!=(std::string_view lhs, const key &rhs) noexcept
7804 {
7805 return lhs != rhs.key_;
7806 }
7807
7809 friend bool operator<(std::string_view lhs, const key &rhs) noexcept
7810 {
7811 return lhs < rhs.key_;
7812 }
7813
7815 friend bool operator<=(std::string_view lhs, const key &rhs) noexcept
7816 {
7817 return lhs <= rhs.key_;
7818 }
7819
7821 friend bool operator>(std::string_view lhs, const key &rhs) noexcept
7822 {
7823 return lhs > rhs.key_;
7824 }
7825
7827 friend bool operator>=(std::string_view lhs, const key &rhs) noexcept
7828 {
7829 return lhs >= rhs.key_;
7830 }
7831
7832 using const_iterator = const char *;
7833
7834 using iterator = const_iterator;
7835
7837 const_iterator begin() const noexcept
7838 {
7839 return key_.data();
7840 }
7841
7843 const_iterator end() const noexcept
7844 {
7845 return key_.data() + key_.length();
7846 }
7847
7848 friend std::ostream &operator<<(std::ostream &lhs, const key &rhs)
7849 {
7850 impl::print_to_stream(lhs, rhs.key_);
7851 return lhs;
7852 }
7853 };
7854
7855 template <typename T>
7856 inline constexpr bool is_key =
7857 std::is_same_v<impl::remove_cvref<T>, toml::key>;
7858
7859 template <typename T>
7860 inline constexpr bool is_key_or_convertible =
7861 is_key<T> //
7862 || impl::is_constructible_or_convertible<toml::key, T>;
7863}
7865
7866#ifdef _MSC_VER
7867# pragma pop_macro("min")
7868# pragma pop_macro("max")
7869# ifndef __clang__
7870# pragma inline_recursion(off)
7871# endif
7872#endif
7874
7875//******** impl/std_map.hpp ******************************************************************************************
7876
7878#include <map>
7879#include <iterator>
7881
7882//******** impl/table.hpp ********************************************************************************************
7883
7885#ifdef _MSC_VER
7886# ifndef __clang__
7887# pragma inline_recursion(on)
7888# endif
7889# pragma push_macro("min")
7890# pragma push_macro("max")
7891# undef min
7892# undef max
7893#endif
7894
7896{
7897 template <bool IsConst>
7898 struct table_proxy_pair
7899 {
7900 using value_type = std::conditional_t<IsConst, const node, node>;
7901
7902 const toml::key &first;
7903 value_type &second;
7904 };
7905
7906 template <bool IsConst>
7908 {
7909 private:
7910 template <bool>
7911 friend class table_iterator;
7912
7913 using proxy_type = table_proxy_pair<IsConst>;
7914 using mutable_map_iterator =
7915 std::map<toml::key, node_ptr, std::less<>>::iterator;
7916 using const_map_iterator =
7917 std::map<toml::key, node_ptr, std::less<>>::const_iterator;
7918 using map_iterator =
7919 std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>;
7920
7921 mutable map_iterator iter_;
7922 alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)];
7923 mutable bool proxy_instantiated_ = false;
7924
7926 proxy_type *get_proxy() const noexcept
7927 {
7928 if (!proxy_instantiated_)
7929 {
7930 auto p = ::new (static_cast<void *>(proxy_))
7931 proxy_type{iter_->first, *iter_->second.get()};
7932 proxy_instantiated_ = true;
7933 return p;
7934 }
7935 else
7936 return TOML_LAUNDER(reinterpret_cast<proxy_type *>(proxy_));
7937 }
7938
7939 public:
7941 table_iterator() noexcept = default;
7942
7944 explicit table_iterator(mutable_map_iterator iter) noexcept //
7945 : iter_{iter}
7946 {
7947 }
7948
7949 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
7951 explicit table_iterator(const_map_iterator iter) noexcept //
7952 : iter_{iter}
7953 {
7954 }
7955
7956 TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
7959 : iter_{other.iter_}
7960 {
7961 }
7962
7965 : iter_{other.iter_}
7966 {
7967 }
7968
7970 {
7971 iter_ = rhs.iter_;
7972 proxy_instantiated_ = false;
7973 return *this;
7974 }
7975
7976 using value_type = table_proxy_pair<IsConst>;
7980 typename std::iterator_traits<map_iterator>::difference_type;
7982 typename std::iterator_traits<map_iterator>::iterator_category;
7983
7984 table_iterator &operator++() noexcept // ++pre
7985 {
7986 ++iter_;
7987 proxy_instantiated_ = false;
7988 return *this;
7989 }
7990
7991 table_iterator operator++(int) noexcept // post++
7992 {
7993 table_iterator out{iter_};
7994 ++iter_;
7995 proxy_instantiated_ = false;
7996 return out;
7997 }
7998
7999 table_iterator &operator--() noexcept // --pre
8000 {
8001 --iter_;
8002 proxy_instantiated_ = false;
8003 return *this;
8004 }
8005
8006 table_iterator operator--(int) noexcept // post--
8007 {
8008 table_iterator out{iter_};
8009 --iter_;
8010 proxy_instantiated_ = false;
8011 return out;
8012 }
8013
8015 reference operator*() const noexcept
8016 {
8017 return *get_proxy();
8018 }
8019
8021 pointer operator->() const noexcept
8022 {
8023 return get_proxy();
8024 }
8025
8027 explicit operator const map_iterator &() const noexcept
8028 {
8029 return iter_;
8030 }
8031
8032 TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
8034 explicit operator const const_map_iterator() const noexcept
8035 {
8036 return iter_;
8037 }
8038
8040 friend bool
8041 operator==(const table_iterator &lhs, const table_iterator &rhs) noexcept
8042 {
8043 return lhs.iter_ == rhs.iter_;
8044 }
8045
8047 friend bool
8048 operator!=(const table_iterator &lhs, const table_iterator &rhs) noexcept
8049 {
8050 return lhs.iter_ != rhs.iter_;
8051 }
8052 };
8053
8055 {
8056 mutable toml::key key;
8057 mutable node_ptr value;
8058
8059 template <typename K, typename V>
8061 K &&k,
8062 V &&v,
8064 : key{static_cast<K &&>(k)}, value{make_node(static_cast<V &&>(v), flags)}
8065 {
8066 }
8067 };
8068}
8070
8072{
8073 using table_iterator =
8074 POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>);
8075
8077 POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>);
8078
8079 class TOML_EXPORTED_CLASS table : public node
8080 {
8081 private:
8082 using map_type = std::map<toml::key, impl::node_ptr, std::less<>>;
8083 using map_pair = std::pair<const toml::key, impl::node_ptr>;
8084 using map_iterator = typename map_type::iterator;
8085 using const_map_iterator = typename map_type::const_iterator;
8086 map_type map_;
8087
8088 bool inline_ = false;
8089
8092 table(const impl::table_init_pair *, const impl::table_init_pair *);
8093
8094 public:
8097 table() noexcept;
8098
8100 ~table() noexcept;
8101
8104 table(const table &);
8105
8108 table(table &&other) noexcept;
8109
8112 explicit table(std::initializer_list<impl::table_init_pair> kvps) //
8113 : table(kvps.begin(), kvps.end())
8114 {
8115 }
8116
8118 table &operator=(const table &);
8119
8121 table &operator=(table &&rhs) noexcept;
8122
8124 node_type type() const noexcept final
8125 {
8126 return node_type::table;
8127 }
8128
8131 bool is_homogeneous(node_type ntype) const noexcept final;
8132
8135 bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final;
8136
8139 bool is_homogeneous(node_type ntype, const node *&first_nonmatch)
8140 const noexcept final;
8141
8142 template <typename ElemType = void>
8143 TOML_PURE_GETTER bool is_homogeneous() const noexcept
8144 {
8145 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
8146 static_assert(
8147 std::is_void_v<type> || toml::is_value<type> ||
8148 toml::is_container<type>,
8149 "The template type argument of table::is_homogeneous() must be void or "
8150 "one "
8152
8153 return is_homogeneous(impl::node_type_of<type>);
8154 }
8156 bool is_table() const noexcept final
8157 {
8158 return true;
8159 }
8160
8162 bool is_array() const noexcept final
8163 {
8164 return false;
8165 }
8166
8168 bool is_array_of_tables() const noexcept final
8169 {
8170 return false;
8171 }
8172
8174 bool is_value() const noexcept final
8175 {
8176 return false;
8177 }
8178
8180 bool is_string() const noexcept final
8181 {
8182 return false;
8183 }
8184
8186 bool is_integer() const noexcept final
8187 {
8188 return false;
8189 }
8190
8192 bool is_floating_point() const noexcept final
8193 {
8194 return false;
8195 }
8196
8198 bool is_number() const noexcept final
8199 {
8200 return false;
8201 }
8202
8204 bool is_boolean() const noexcept final
8205 {
8206 return false;
8207 }
8208
8210 bool is_date() const noexcept final
8211 {
8212 return false;
8213 }
8214
8216 bool is_time() const noexcept final
8217 {
8218 return false;
8219 }
8220
8222 bool is_date_time() const noexcept final
8223 {
8224 return false;
8225 }
8226
8228 table *as_table() noexcept final
8229 {
8230 return this;
8231 }
8232
8234 array *as_array() noexcept final
8235 {
8236 return nullptr;
8237 }
8238
8240 toml::value<std::string> *as_string() noexcept final
8241 {
8242 return nullptr;
8243 }
8244
8246 toml::value<int64_t> *as_integer() noexcept final
8247 {
8248 return nullptr;
8249 }
8250
8252 toml::value<double> *as_floating_point() noexcept final
8253 {
8254 return nullptr;
8255 }
8256
8258 toml::value<bool> *as_boolean() noexcept final
8259 {
8260 return nullptr;
8261 }
8262
8264 toml::value<date> *as_date() noexcept final
8265 {
8266 return nullptr;
8267 }
8268
8270 toml::value<time> *as_time() noexcept final
8271 {
8272 return nullptr;
8273 }
8274
8276 toml::value<date_time> *as_date_time() noexcept final
8277 {
8278 return nullptr;
8279 }
8280
8282 const table *as_table() const noexcept final
8283 {
8284 return this;
8285 }
8286
8288 const array *as_array() const noexcept final
8289 {
8290 return nullptr;
8291 }
8292
8294 const toml::value<std::string> *as_string() const noexcept final
8295 {
8296 return nullptr;
8297 }
8298
8300 const toml::value<int64_t> *as_integer() const noexcept final
8301 {
8302 return nullptr;
8303 }
8304
8306 const toml::value<double> *as_floating_point() const noexcept final
8307 {
8308 return nullptr;
8309 }
8310
8312 const toml::value<bool> *as_boolean() const noexcept final
8313 {
8314 return nullptr;
8315 }
8316
8318 const toml::value<date> *as_date() const noexcept final
8319 {
8320 return nullptr;
8321 }
8322
8324 const toml::value<time> *as_time() const noexcept final
8325 {
8326 return nullptr;
8327 }
8328
8330 const toml::value<date_time> *as_date_time() const noexcept final
8331 {
8332 return nullptr;
8333 }
8334
8336 bool is_inline() const noexcept
8337 {
8338 return inline_;
8339 }
8340
8341 void is_inline(bool val) noexcept
8342 {
8343 inline_ = val;
8344 }
8345
8348 node *get(std::string_view key) noexcept;
8349
8351 const node *get(std::string_view key) const noexcept
8352 {
8353 return const_cast<table &>(*this).get(key);
8354 }
8355
8356#if TOML_ENABLE_WINDOWS_COMPAT
8357
8359 node *get(std::wstring_view key)
8360 {
8361 if (empty())
8362 return nullptr;
8363
8364 return get(impl::narrow(key));
8365 }
8366
8368 const node *get(std::wstring_view key) const
8369 {
8370 return const_cast<table &>(*this).get(key);
8371 }
8372
8373#endif // TOML_ENABLE_WINDOWS_COMPAT
8374
8375 template <typename T>
8376 TOML_PURE_GETTER impl::wrap_node<T> *get_as(std::string_view key) noexcept
8377 {
8378 const auto n = this->get(key);
8379 return n ? n->template as<T>() : nullptr;
8380 }
8381
8382 template <typename T>
8383 TOML_PURE_GETTER const impl::wrap_node<T> *
8384 get_as(std::string_view key) const noexcept
8385 {
8386 return const_cast<table &>(*this).template get_as<T>(key);
8387 }
8388
8389#if TOML_ENABLE_WINDOWS_COMPAT
8390
8391 template <typename T>
8392 TOML_NODISCARD impl::wrap_node<T> *get_as(std::wstring_view key)
8393 {
8394 if (empty())
8395 return nullptr;
8396
8397 return get_as<T>(impl::narrow(key));
8398 }
8399
8400 template <typename T>
8401 TOML_NODISCARD const impl::wrap_node<T> *get_as(std::wstring_view key) const
8402 {
8403 return const_cast<table &>(*this).template get_as<T>(key);
8404 }
8405
8406#endif // TOML_ENABLE_WINDOWS_COMPAT
8407
8410 node &at(std::string_view key);
8411
8413 const node &at(std::string_view key) const
8414 {
8415 return const_cast<table &>(*this).at(key);
8416 }
8417
8418#if TOML_ENABLE_WINDOWS_COMPAT
8419
8421 node &at(std::wstring_view key)
8422 {
8423 return at(impl::narrow(key));
8424 }
8425
8427 const node &at(std::wstring_view key) const
8428 {
8429 return const_cast<table &>(*this).at(key);
8430 }
8431
8432#endif // TOML_ENABLE_WINDOWS_COMPAT
8433
8434 using iterator = toml::table_iterator;
8435
8436 using const_iterator = toml::const_table_iterator;
8437
8439 iterator begin() noexcept
8440 {
8441 return iterator{map_.begin()};
8442 }
8443
8445 const_iterator begin() const noexcept
8446 {
8447 return const_iterator{map_.cbegin()};
8448 }
8449
8451 const_iterator cbegin() const noexcept
8452 {
8453 return const_iterator{map_.cbegin()};
8454 }
8455
8457 iterator end() noexcept
8458 {
8459 return iterator{map_.end()};
8460 }
8461
8463 const_iterator end() const noexcept
8464 {
8465 return const_iterator{map_.cend()};
8466 }
8467
8469 const_iterator cend() const noexcept
8470 {
8471 return const_iterator{map_.cend()};
8472 }
8473
8474 private:
8475 template <typename T, typename Table>
8476 using for_each_value_ref = impl::copy_cvref<
8477 impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>,
8478 Table>;
8479
8480 template <typename Func, typename Table, typename T>
8481 using can_for_each = std::disjunction<
8482 std::is_invocable<Func, const key &, for_each_value_ref<T, Table>>, //
8483 std::is_invocable<Func, for_each_value_ref<T, Table>>>;
8484
8485 template <typename Func, typename Table, typename T>
8486 using can_for_each_nothrow = std::conditional_t<
8487 // first form
8488 std::is_invocable_v<Func, const key &, for_each_value_ref<T, Table>>,
8489 std::
8490 is_nothrow_invocable<Func, const key &, for_each_value_ref<T, Table>>,
8491 std::conditional_t<
8492 // second form
8493 std::is_invocable_v<Func, for_each_value_ref<T, Table>>,
8494 std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>,
8495 std::false_type>>;
8496
8497 template <typename Func, typename Table>
8498 using can_for_each_any = std::disjunction<
8499 can_for_each<Func, Table, table>,
8500 can_for_each<Func, Table, array>,
8501 can_for_each<Func, Table, std::string>,
8502 can_for_each<Func, Table, int64_t>,
8503 can_for_each<Func, Table, double>,
8504 can_for_each<Func, Table, bool>,
8505 can_for_each<Func, Table, date>,
8506 can_for_each<Func, Table, time>,
8507 can_for_each<Func, Table, date_time>>;
8508
8509 template <typename Func, typename Table, typename T>
8510 using for_each_is_nothrow_one = std::disjunction<
8511 std::negation<can_for_each<Func, Table, T>>, //
8512 can_for_each_nothrow<Func, Table, T>>;
8513
8514 template <typename Func, typename Table>
8515 using for_each_is_nothrow = std::conjunction<
8516 for_each_is_nothrow_one<Func, Table, table>,
8517 for_each_is_nothrow_one<Func, Table, array>,
8518 for_each_is_nothrow_one<Func, Table, std::string>,
8519 for_each_is_nothrow_one<Func, Table, int64_t>,
8520 for_each_is_nothrow_one<Func, Table, double>,
8521 for_each_is_nothrow_one<Func, Table, bool>,
8522 for_each_is_nothrow_one<Func, Table, date>,
8523 for_each_is_nothrow_one<Func, Table, time>,
8524 for_each_is_nothrow_one<Func, Table, date_time>>;
8525
8526 template <typename Func, typename Table>
8527 static void do_for_each(Func &&visitor, Table &&tbl) //
8528 noexcept(for_each_is_nothrow<Func &&, Table &&>::value)
8529 {
8530 static_assert(
8531 can_for_each_any<Func &&, Table &&>::value,
8532 "TOML table for_each visitors must be invocable for at least one of "
8533 "the toml::node "
8534 "specializations:" TOML_SA_NODE_TYPE_LIST);
8535
8536 using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>;
8537
8538 for (kvp_type &kvp : tbl.map_)
8539 {
8540 using node_ref = impl::copy_cvref<toml::node, Table &&>;
8541 static_assert(std::is_reference_v<node_ref>);
8542
8543#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
8544
8545# ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
8546 static_assert(
8547 impl::always_false<Func, Table, kvp_type, node_ref>, //
8548 TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
8549# endif
8550
8551 static_cast<node_ref>(*kvp.second)
8552 .visit(
8553 [&]([[maybe_unused]] auto &&v) //
8554 noexcept(
8555 for_each_is_nothrow_one<Func &&, Table &&, decltype(v)>::value)
8556 {
8557 using value_ref = for_each_value_ref<decltype(v), Table &&>;
8558 static_assert(std::is_reference_v<value_ref>);
8559
8560 // func(key, val)
8561 if constexpr (std::
8562 is_invocable_v<Func &&, const key &, value_ref>)
8563 {
8564 static_cast<Func &&>(visitor)(
8565 static_cast<const key &>(kvp.first),
8566 static_cast<value_ref>(v));
8567 }
8568
8569 // func(val)
8570 else if constexpr (std::is_invocable_v<Func &&, value_ref>)
8571 {
8572 static_cast<Func &&>(visitor)(static_cast<value_ref>(v));
8573 }
8574 });
8575
8576#else
8577 const auto keep_going =
8578 static_cast<node_ref>(*kvp.second)
8579 .visit(
8580 [&]([[maybe_unused]] auto &&v) //
8581 noexcept(
8582 for_each_is_nothrow_one<Func &&, Table &&, decltype(v)>::value)
8583 {
8584 using value_ref = for_each_value_ref<decltype(v), Table &&>;
8585 static_assert(std::is_reference_v<value_ref>);
8586
8587 // func(key, val)
8588 if constexpr (std::
8589 is_invocable_v<Func &&, const key &, value_ref>)
8590 {
8591 using return_type = decltype(static_cast<Func &&>(visitor)(
8592 static_cast<const key &>(kvp.first),
8593 static_cast<value_ref>(v)));
8594
8595 if constexpr (impl::is_constructible_or_convertible<
8596 bool,
8597 return_type>)
8598 {
8599 return static_cast<bool>(static_cast<Func &&>(visitor)(
8600 static_cast<const key &>(kvp.first),
8601 static_cast<value_ref>(v)));
8602 }
8603 else
8604 {
8605 static_cast<Func &&>(visitor)(
8606 static_cast<const key &>(kvp.first),
8607 static_cast<value_ref>(v));
8608 return true;
8609 }
8610 }
8611
8612 // func(val)
8613 else if constexpr (std::is_invocable_v<Func &&, value_ref>)
8614 {
8615 using return_type = decltype(static_cast<Func &&>(visitor)(
8616 static_cast<value_ref>(v)));
8617
8618 if constexpr (impl::is_constructible_or_convertible<
8619 bool,
8620 return_type>)
8621 {
8622 return static_cast<bool>(
8623 static_cast<Func &&>(visitor)(static_cast<value_ref>(v)));
8624 }
8625 else
8626 {
8627 static_cast<Func &&>(visitor)(static_cast<value_ref>(v));
8628 return true;
8629 }
8630 }
8631
8632 // visitor not compatible with this particular type
8633 else
8634 return true;
8635 });
8636
8637 if (!keep_going)
8638 return;
8639#endif
8640 }
8641 }
8642
8643 public:
8644 template <typename Func>
8645 table &for_each(Func &&visitor) & //
8646 noexcept(for_each_is_nothrow<Func &&, table &>::value)
8647 {
8648 do_for_each(static_cast<Func &&>(visitor), *this);
8649 return *this;
8650 }
8651
8652 template <typename Func>
8653 table &&for_each(Func &&visitor) && //
8654 noexcept(for_each_is_nothrow<Func &&, table &&>::value)
8655 {
8656 do_for_each(static_cast<Func &&>(visitor), static_cast<table &&>(*this));
8657 return static_cast<table &&>(*this);
8658 }
8659
8660 template <typename Func>
8661 const table &for_each(Func &&visitor) const & //
8662 noexcept(for_each_is_nothrow<Func &&, const table &>::value)
8663 {
8664 do_for_each(static_cast<Func &&>(visitor), *this);
8665 return *this;
8666 }
8667
8668 template <typename Func>
8669 const table &&for_each(Func &&visitor) const && //
8670 noexcept(for_each_is_nothrow<Func &&, const table &&>::value)
8671 {
8672 do_for_each(
8673 static_cast<Func &&>(visitor), static_cast<const table &&>(*this));
8674 return static_cast<const table &&>(*this);
8675 }
8676
8678 bool empty() const noexcept
8679 {
8680 return map_.empty();
8681 }
8682
8684 size_t size() const noexcept
8685 {
8686 return map_.size();
8687 }
8688
8689 private:
8692 map_iterator get_lower_bound(std::string_view) noexcept;
8693
8694 public:
8696 iterator lower_bound(std::string_view key) noexcept
8697 {
8698 return iterator{get_lower_bound(key)};
8699 }
8700
8702 const_iterator lower_bound(std::string_view key) const noexcept
8703 {
8704 return const_iterator{const_cast<table &>(*this).get_lower_bound(key)};
8705 }
8706
8707#if TOML_ENABLE_WINDOWS_COMPAT
8708
8710 iterator lower_bound(std::wstring_view key)
8711 {
8712 if (empty())
8713 return end();
8714
8715 return lower_bound(impl::narrow(key));
8716 }
8717
8719 const_iterator lower_bound(std::wstring_view key) const
8720 {
8721 if (empty())
8722 return end();
8723
8724 return lower_bound(impl::narrow(key));
8725 }
8726
8727#endif // TOML_ENABLE_WINDOWS_COMPAT
8728
8731 iterator find(std::string_view key) noexcept;
8732
8735 const_iterator find(std::string_view key) const noexcept;
8736
8738 bool contains(std::string_view key) const noexcept
8739 {
8740 return get(key) != nullptr;
8741 }
8742
8743#if TOML_ENABLE_WINDOWS_COMPAT
8744
8746 iterator find(std::wstring_view key)
8747 {
8748 if (empty())
8749 return end();
8750
8751 return find(impl::narrow(key));
8752 }
8753
8755 const_iterator find(std::wstring_view key) const
8756 {
8757 return find(impl::narrow(key));
8758 }
8759
8761 bool contains(std::wstring_view key) const
8762 {
8763 return contains(impl::narrow(key));
8764 }
8765
8766#endif // TOML_ENABLE_WINDOWS_COMPAT
8767
8768 private:
8770 map_iterator erase(const_map_iterator) noexcept;
8771
8773 map_iterator erase(const_map_iterator, const_map_iterator) noexcept;
8774
8775 public:
8777 {
8778 return iterator{erase(const_map_iterator{pos})};
8779 }
8780
8782 {
8783 return iterator{erase(const_map_iterator{pos})};
8784 }
8785
8787 {
8788 return iterator{
8789 erase(const_map_iterator{begin}, const_map_iterator{end})};
8790 }
8791
8793 size_t erase(std::string_view key) noexcept;
8794
8795#if TOML_ENABLE_WINDOWS_COMPAT
8796
8797 size_t erase(std::wstring_view key)
8798 {
8799 if (empty())
8800 return false;
8801
8802 return erase(impl::narrow(key));
8803 }
8804
8805#endif // TOML_ENABLE_WINDOWS_COMPAT
8806
8808 table &prune(bool recursive = true) &noexcept;
8809
8810 table &&prune(bool recursive = true) &&noexcept
8811 {
8812 return static_cast<toml::table &&>(this->prune(recursive));
8813 }
8814
8816 void clear() noexcept;
8817
8818 private:
8820 map_iterator insert_with_hint(const_iterator, key &&, impl::node_ptr &&);
8821
8822 public:
8824 (is_key_or_convertible<KeyType &&> || impl::is_wide_string<KeyType>),
8825 typename ValueType = void,
8826 typename KeyType,
8827 typename... ValueArgs)
8828 iterator
8829 emplace_hint(const_iterator hint, KeyType &&key, ValueArgs &&...args)
8830 {
8831 static_assert(
8832 !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8833 "Emplacement using wide-character keys is only supported on Windows "
8834 "with "
8835 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8836
8837 using raw_value_type = impl::remove_cvref<ValueType>;
8838 using value_type = std::conditional_t<
8839 std::is_void_v<raw_value_type>,
8840 impl::emplaced_type_of<ValueArgs &&...>,
8842
8843 if constexpr (impl::is_wide_string<KeyType>)
8844 {
8845#if TOML_ENABLE_WINDOWS_COMPAT
8846 return emplace_hint<value_type>(
8847 hint,
8848 impl::narrow(static_cast<KeyType &&>(key)),
8849 static_cast<ValueArgs &&>(args)...);
8850#else
8851 static_assert(
8852 impl::always_false<KeyType>, "Evaluated unreachable branch!");
8853#endif
8854 }
8855 else
8856 {
8857 static constexpr auto moving_node_ptr =
8858 std::is_same_v<value_type, impl::node_ptr> //
8859 && sizeof...(ValueArgs) == 1u //
8860 && impl::first_is_same<impl::node_ptr &&, ValueArgs &&...>;
8862 impl::remove_cvref<impl::unwrap_node<value_type>>;
8863
8864 static_assert(
8865 moving_node_ptr //
8866 || impl::is_native<unwrapped_type> //
8867 || impl::is_one_of<unwrapped_type, table, array>, //
8868 "ValueType argument of table::emplace_hint() must be one "
8870
8871 map_iterator ipos = insert_with_hint(
8872 hint, toml::key{static_cast<KeyType &&>(key)}, nullptr);
8873
8874 // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
8875 // so now we have to construct the actual value
8876 if (!ipos->second)
8877 {
8878 if constexpr (moving_node_ptr)
8879 ipos->second = std::move(static_cast<ValueArgs &&>(args)...);
8880 else
8881 {
8882#if TOML_COMPILER_HAS_EXCEPTIONS
8883 try
8884 {
8885#endif
8886 ipos->second.reset(new impl::wrap_node<unwrapped_type>{
8887 static_cast<ValueArgs &&>(args)...});
8888#if TOML_COMPILER_HAS_EXCEPTIONS
8889 }
8890 catch (...)
8891 {
8892 erase(const_map_iterator{ipos}); // strong exception guarantee
8893 throw;
8894 }
8895#endif
8896 }
8897 }
8899 }
8900
8902 }
8903
8905 (is_key_or_convertible<KeyType &&> || impl::is_wide_string<KeyType>),
8906 typename KeyType,
8907 typename ValueType)
8908 std::pair<iterator, bool> insert(
8909 KeyType &&key,
8910 ValueType &&val,
8912 {
8913 static_assert(
8914 !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8915 "Insertion using wide-character keys is only supported on Windows with "
8916 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8917
8918 if constexpr (is_node_view<ValueType>)
8919 {
8920 if (!val)
8921 return {end(), false};
8922 }
8923
8924 if constexpr (impl::is_wide_string<KeyType>)
8925 {
8926#if TOML_ENABLE_WINDOWS_COMPAT
8927 return insert(
8928 impl::narrow(static_cast<KeyType &&>(key)),
8929 static_cast<ValueType &&>(val),
8930 flags);
8931#else
8932 static_assert(
8933 impl::always_false<KeyType>, "Evaluated unreachable branch!");
8934#endif
8935 }
8936 else
8937 {
8938 const auto key_view = std::string_view{key};
8939 map_iterator ipos = get_lower_bound(key_view);
8940 if (ipos == map_.end() || ipos->first != key_view)
8941 {
8942 ipos = insert_with_hint(
8944 toml::key{static_cast<KeyType &&>(key)},
8945 impl::make_node(static_cast<ValueType &&>(val), flags));
8946 return {iterator{ipos}, true};
8947 }
8948 return {iterator{ipos}, false};
8949 }
8950 }
8951
8953 (!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>),
8954 typename Iter)
8955 void insert(
8956 Iter begin,
8957 Iter end,
8959 {
8960 if (begin == end)
8961 return;
8962 for (auto it = begin; it != end; it++)
8963 {
8964 if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
8965 insert(std::move((*it).first), std::move((*it).second), flags);
8966 else
8967 insert((*it).first, (*it).second, flags);
8968 }
8969 }
8970
8972 (is_key_or_convertible<KeyType &&> || impl::is_wide_string<KeyType>),
8973 typename KeyType,
8974 typename ValueType)
8976 KeyType &&key,
8977 ValueType &&val,
8979 {
8980 static_assert(
8981 !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8982 "Insertion using wide-character keys is only supported on Windows with "
8983 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8984
8985 if constexpr (is_node_view<ValueType>)
8986 {
8987 if (!val)
8988 return {end(), false};
8989 }
8990
8991 if constexpr (impl::is_wide_string<KeyType>)
8992 {
8993#if TOML_ENABLE_WINDOWS_COMPAT
8994 return insert_or_assign(
8995 impl::narrow(static_cast<KeyType &&>(key)),
8996 static_cast<ValueType &&>(val),
8997 flags);
8998#else
8999 static_assert(
9000 impl::always_false<KeyType>, "Evaluated unreachable branch!");
9001#endif
9002 }
9003 else
9004 {
9005 const auto key_view = std::string_view{key};
9006 map_iterator ipos = get_lower_bound(key_view);
9007 if (ipos == map_.end() || ipos->first != key_view)
9008 {
9009 ipos = insert_with_hint(
9011 toml::key{static_cast<KeyType &&>(key)},
9012 impl::make_node(static_cast<ValueType &&>(val), flags));
9013 return {iterator{ipos}, true};
9014 }
9015 else
9016 {
9017 (*ipos).second =
9018 impl::make_node(static_cast<ValueType &&>(val), flags);
9019 return {iterator{ipos}, false};
9020 }
9021 }
9022 }
9023
9025 (is_key_or_convertible<KeyType &&> || impl::is_wide_string<KeyType>),
9026 typename ValueType = void,
9027 typename KeyType,
9028 typename... ValueArgs)
9029 std::pair<iterator, bool> emplace(KeyType &&key, ValueArgs &&...args)
9030 {
9031 static_assert(
9032 !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
9033 "Emplacement using wide-character keys is only supported on Windows "
9034 "with "
9035 "TOML_ENABLE_WINDOWS_COMPAT enabled.");
9036
9037 using raw_value_type = impl::remove_cvref<ValueType>;
9038 using value_type = std::conditional_t<
9039 std::is_void_v<raw_value_type>,
9040 impl::emplaced_type_of<ValueArgs &&...>,
9042
9043 if constexpr (impl::is_wide_string<KeyType>)
9044 {
9045#if TOML_ENABLE_WINDOWS_COMPAT
9046 return emplace<value_type>(
9047 impl::narrow(static_cast<KeyType &&>(key)),
9048 static_cast<ValueArgs &&>(args)...);
9049#else
9050 static_assert(
9051 impl::always_false<KeyType>, "Evaluated unreachable branch!");
9052#endif
9053 }
9054 else
9055 {
9056 using unwrapped_type =
9057 impl::remove_cvref<impl::unwrap_node<value_type>>;
9058 static_assert(
9059 (impl::is_native<unwrapped_type> ||
9060 impl::is_one_of<unwrapped_type, table, array>),
9061 "ValueType argument of table::emplace() must be one "
9063
9064 const auto key_view = std::string_view{key};
9065 auto ipos = get_lower_bound(key_view);
9066 if (ipos == map_.end() || ipos->first != key_view)
9067 {
9068 ipos = insert_with_hint(
9070 toml::key{static_cast<KeyType &&>(key)},
9071 impl::node_ptr{new impl::wrap_node<unwrapped_type>{
9072 static_cast<ValueArgs &&>(args)...}});
9073 return {iterator{ipos}, true};
9074 }
9075 return {iterator{ipos}, false};
9076 }
9077 }
9078
9079 using node::operator[]; // inherit operator[toml::path]
9080
9082 node_view<node> operator[](std::string_view key) noexcept
9083 {
9084 return node_view<node>{get(key)};
9085 }
9086
9088 node_view<const node> operator[](std::string_view key) const noexcept
9089 {
9090 return node_view<const node>{get(key)};
9091 }
9092
9093#if TOML_ENABLE_WINDOWS_COMPAT
9094
9096 node_view<node> operator[](std::wstring_view key)
9097 {
9098 return node_view<node>{get(key)};
9099 }
9100
9102 node_view<const node> operator[](std::wstring_view key) const
9103 {
9104 return node_view<const node>{get(key)};
9105 }
9106
9107#endif // TOML_ENABLE_WINDOWS_COMPAT
9108
9109 private:
9112 static bool TOML_CALLCONV equal(const table &, const table &) noexcept;
9113
9114 public:
9116 friend bool operator==(const table &lhs, const table &rhs) noexcept
9117 {
9118 return equal(lhs, rhs);
9119 }
9120
9122 friend bool operator!=(const table &lhs, const table &rhs) noexcept
9123 {
9124 return !equal(lhs, rhs);
9125 }
9126
9127#if TOML_ENABLE_FORMATTERS
9128
9129 friend std::ostream &operator<<(std::ostream &lhs, const table &rhs)
9130 {
9131 impl::print_to_stream(lhs, rhs);
9132 return lhs;
9133 }
9134
9135#endif
9136 };
9137}
9139
9140#ifdef _MSC_VER
9141# pragma pop_macro("min")
9142# pragma pop_macro("max")
9143# ifndef __clang__
9144# pragma inline_recursion(off)
9145# endif
9146#endif
9148
9149//******** impl/unicode_autogenerated.hpp ****************************************************************************
9150
9152#ifdef _MSC_VER
9153# ifndef __clang__
9154# pragma inline_recursion(on)
9155# endif
9156# pragma push_macro("min")
9157# pragma push_macro("max")
9158# undef min
9159# undef max
9160#endif
9161
9162#if TOML_GCC && TOML_GCC < 9
9163# pragma GCC push_options
9164# pragma GCC optimize("O1") // codegen bugs
9165#endif
9166
9167// the functions in this namespace block are automatically generated by a tool - they are not meant to be hand-edited
9168
9170{
9172 constexpr bool is_ascii_horizontal_whitespace(char32_t c) noexcept
9173 {
9174 return c == U'\t' || c == U' ';
9175 }
9176
9178 constexpr bool is_non_ascii_horizontal_whitespace(char32_t c) noexcept
9179 {
9180 // 20 code units from 8 ranges (spanning a search area of 65120)
9181
9182 if (c < U'\xA0' || c > U'\uFEFF')
9183 return false;
9184
9185 const auto child_index_0 =
9186 (static_cast<uint_least64_t>(c) - 0xA0ull) / 0x3FAull;
9187 if ((1ull << child_index_0) & 0x7FFFFFFFFFFFF75Eull)
9188 return false;
9189 if (c == U'\xA0' || c == U'\u3000' || c == U'\uFEFF')
9190 return true;
9191 switch (child_index_0)
9192 {
9193 case 0x05:
9194 return c == U'\u1680' || c == U'\u180E';
9195 case 0x07:
9196 return (U'\u2000' <= c && c <= U'\u200B') ||
9197 (U'\u205F' <= c && c <= U'\u2060') || c == U'\u202F';
9198 default:
9200 }
9201
9203 }
9204
9206 constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept
9207 {
9208 return c >= U'\n' && c <= U'\r';
9209 }
9210
9212 constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept
9213 {
9214 return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
9215 }
9216
9218 constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
9219 {
9220#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
9221 if TOML_UNLIKELY (c == U'+')
9222 return true;
9223#endif
9224 // 64 code units from 5 ranges (spanning a search area of 78)
9225
9226 if (c < U'-' || c > U'z')
9227 return false;
9228
9229 return (((static_cast<uint_least64_t>(c) - 0x2Dull) / 0x40ull) != 0ull) ||
9230 ((1ull << (static_cast<uint_least64_t>(c) - 0x2Dull)) &
9231 0xFFF43FFFFFF01FF9ull);
9232 }
9233
9234#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
9235
9237 constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept
9238 {
9239 // 971732 code units from 16 ranges (spanning a search area of 982862)
9240
9241 if (c < U'\xB2' || c > U'\U000EFFFF')
9242 return false;
9243
9244 const auto child_index_0 =
9245 (static_cast<uint_least64_t>(c) - 0xB2ull) / 0x3BFEull;
9246 if ((1ull << child_index_0) & 0xFFFFFFFFFFFFFFE6ull)
9247 return true;
9248 switch (child_index_0)
9249 {
9250 case 0x00: // [0] 00B2 - 3CAF
9251 {
9252 // 12710 code units from 13 ranges (spanning a search area of 15358)
9253
9254 TOML_ASSUME(c >= U'\xB2' && c <= U'\u3CAF');
9255
9256 constexpr uint_least64_t bitmask_table_1[] = {
9257 0xFFFFFFDFFFFFDC83u, 0xFFFFFFFFFFFFFFDFu, 0xFFFFFFFFFFFFFFFFu,
9258 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9259 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9260 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFEFFFu,
9261 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9262 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9263 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9264 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9265 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9266 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9267 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9268 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9269 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9270 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9271 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9272 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9273 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9274 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9275 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9276 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9277 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9278 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9279 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9280 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9281 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9282 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9283 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9284 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9285 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9286 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9287 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9288 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9289 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9290 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9291 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9292 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9293 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9294 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9295 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9296 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9297 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9298 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000000000C003FFFu,
9299 0xC000000000006000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9300 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000000003FFFFFFFu,
9301 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9302 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9303 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9304 0x0000000000000000u, 0xFFFFC00000000000u, 0xFFFFFFFFFFFFFFFFu,
9305 0xFFFFFFFFFFFFFFFFu, 0x0000000000003FFFu, 0x0000000000000000u,
9306 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9307 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9308 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9309 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9310 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9311 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9312 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9313 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
9314 0x0000000000000000u, 0x0000000000000000u, 0xFFFFFFFFFFFFC000u,
9315 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9316 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9317 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9318 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9319 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu,
9320 0xFFFFFFFFFFFF8000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9321 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9322 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9323 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9324 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9325 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9326 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9327 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9328 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9329 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9330 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9331 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9332 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9333 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9334 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9335 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
9336 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu,
9337 };
9338 return bitmask_table_1
9339 [(static_cast<uint_least64_t>(c) - 0xB2ull) / 0x40ull] &
9340 (0x1ull << ((static_cast<uint_least64_t>(c) - 0xB2ull) % 0x40ull));
9341 }
9342 case 0x03:
9343 return c <= U'\uD7FF';
9344 case 0x04:
9345 return (U'\uF900' <= c && c <= U'\uFDCF') ||
9346 (U'\uFDF0' <= c && c <= U'\uFFFD') || U'\U00010000' <= c;
9347 default:
9349 }
9350
9352 }
9353
9354#endif // TOML_LANG_UNRELEASED
9355}
9357
9358#if TOML_GCC && TOML_GCC < 9
9359# pragma GCC pop_options
9360#endif
9361
9362#ifdef _MSC_VER
9363# pragma pop_macro("min")
9364# pragma pop_macro("max")
9365# ifndef __clang__
9366# pragma inline_recursion(off)
9367# endif
9368#endif
9370
9371//******** impl/unicode.hpp ******************************************************************************************
9372
9374#ifdef _MSC_VER
9375# ifndef __clang__
9376# pragma inline_recursion(on)
9377# endif
9378# pragma push_macro("min")
9379# pragma push_macro("max")
9380# undef min
9381# undef max
9382#endif
9383
9385{
9387 constexpr bool is_string_delimiter(char32_t c) noexcept
9388 {
9389 return c == U'"' || c == U'\'';
9390 }
9391
9393 constexpr bool is_ascii_letter(char32_t c) noexcept
9394 {
9395 return (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z');
9396 }
9397
9399 constexpr bool is_binary_digit(char32_t c) noexcept
9400 {
9401 return c == U'0' || c == U'1';
9402 }
9403
9405 constexpr bool is_octal_digit(char32_t c) noexcept
9406 {
9407 return (c >= U'0' && c <= U'7');
9408 }
9409
9411 constexpr bool is_decimal_digit(char32_t c) noexcept
9412 {
9413 return (c >= U'0' && c <= U'9');
9414 }
9415
9417 constexpr bool is_hexadecimal_digit(char32_t c) noexcept
9418 {
9419 return U'0' <= c && c <= U'f' &&
9420 (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) &
9421 0x7E0000007E03FFull;
9422 }
9423
9424 template <typename T>
9425 TOML_CONST_GETTER constexpr uint_least32_t hex_to_dec(const T c) noexcept
9426 {
9427 if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
9428 return c >= 0x41u // >= 'A'
9429 ? 10u + (c | 0x20u) - 0x61u // - 'a'
9430 : c - 0x30u // - '0'
9431 ;
9432 else
9433 return hex_to_dec(static_cast<uint_least32_t>(c));
9434 }
9435
9437 constexpr bool is_horizontal_whitespace(char32_t c) noexcept
9438 {
9439 return is_ascii_horizontal_whitespace(c) ||
9440 is_non_ascii_horizontal_whitespace(c);
9441 }
9442
9444 constexpr bool is_vertical_whitespace(char32_t c) noexcept
9445 {
9446 return is_ascii_vertical_whitespace(c) ||
9447 is_non_ascii_vertical_whitespace(c);
9448 }
9449
9451 constexpr bool is_whitespace(char32_t c) noexcept
9452 {
9453 return is_horizontal_whitespace(c) || is_vertical_whitespace(c);
9454 }
9455
9457 constexpr bool is_bare_key_character(char32_t c) noexcept
9458 {
9459 return is_ascii_bare_key_character(c)
9460#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
9461 || is_non_ascii_bare_key_character(c)
9462#endif
9463 ;
9464 }
9465
9467 constexpr bool is_value_terminator(char32_t c) noexcept
9468 {
9469 return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
9470 }
9471
9473 constexpr bool is_control_character(char c) noexcept
9474 {
9475 return c <= '\u001F' || c == '\u007F';
9476 }
9477
9479 constexpr bool is_control_character(char32_t c) noexcept
9480 {
9481 return c <= U'\u001F' || c == U'\u007F';
9482 }
9483
9485 constexpr bool is_nontab_control_character(char32_t c) noexcept
9486 {
9487 return c <= U'\u0008' || (c >= U'\u000A' && c <= U'\u001F') ||
9488 c == U'\u007F';
9489 }
9490
9492 constexpr bool is_unicode_surrogate(char32_t c) noexcept
9493 {
9494 return c >= 0xD800u && c <= 0xDFFF;
9495 }
9496
9497 struct utf8_decoder
9498 {
9499 // utf8_decoder based on this: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
9500 // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
9501
9502 uint_least32_t state{};
9503 char32_t codepoint{};
9504
9505 static constexpr uint8_t state_table[]{
9506 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9513 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9514 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7,
9515 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
9516 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 2, 2, 2, 2,
9517 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
9518 2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3,
9519 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8,
9520 8, 8, 8, 8, 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12,
9521 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0,
9522 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12,
9523 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12,
9524 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36,
9525 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12,
9526 12, 12, 12, 12};
9527
9529 constexpr bool error() const noexcept
9530 {
9531 return state == uint_least32_t{12u};
9532 }
9533
9535 constexpr bool has_code_point() const noexcept
9536 {
9537 return state == uint_least32_t{};
9538 }
9539
9541 constexpr bool needs_more_input() const noexcept
9542 {
9543 return !has_code_point() && !error();
9544 }
9545
9546 constexpr void operator()(uint8_t byte) noexcept
9547 {
9549
9550 const auto type = state_table[byte];
9551
9552 codepoint = static_cast<char32_t>(
9553 has_code_point() ? (uint_least32_t{255u} >> type) & byte
9554 : (byte & uint_least32_t{63u}) |
9555 (static_cast<uint_least32_t>(codepoint) << 6));
9556
9557 state = state_table[state + uint_least32_t{256u} + type];
9558 }
9559
9561 constexpr void operator()(char c) noexcept
9562 {
9563 operator()(static_cast<uint8_t>(c));
9564 }
9565
9567 constexpr void reset() noexcept
9568 {
9569 state = {};
9570 }
9571 };
9572
9574 TOML_ATTR(nonnull)
9575 bool is_ascii(const char *str, size_t len) noexcept;
9576}
9578
9579#ifdef _MSC_VER
9580# pragma pop_macro("min")
9581# pragma pop_macro("max")
9582# ifndef __clang__
9583# pragma inline_recursion(off)
9584# endif
9585#endif
9587
9588//******** impl/parse_error.hpp **************************************************************************************
9589
9590#if TOML_ENABLE_PARSER
9591
9592//******** impl/std_except.hpp ***************************************************************************************
9593
9595# if TOML_EXCEPTIONS
9596# include <stdexcept>
9597# endif
9599
9600//******** impl/parse_error.hpp **************************************************************************************
9601
9603# ifdef _MSC_VER
9604# ifndef __clang__
9605# pragma inline_recursion(on)
9606# endif
9607# pragma push_macro("min")
9608# pragma push_macro("max")
9609# undef min
9610# undef max
9611# endif
9612
9613# if TOML_DOXYGEN || !TOML_EXCEPTIONS
9614# define TOML_PARSE_ERROR_BASE
9615# else
9616# define TOML_PARSE_ERROR_BASE : public std::runtime_error
9617# endif
9618
9620{
9622
9624 {
9625 private:
9626# if !TOML_EXCEPTIONS
9627 std::string description_;
9628# endif
9629 source_region source_;
9630
9631 public:
9632# if TOML_EXCEPTIONS
9633
9635 TOML_ATTR(nonnull)
9636 parse_error(const char *desc, source_region &&src) noexcept //
9637 : std::runtime_error{desc}, source_{std::move(src)}
9638 {
9639 }
9640
9642 TOML_ATTR(nonnull)
9643 parse_error(const char *desc, const source_region &src) noexcept //
9644 : parse_error{desc, source_region{src}}
9645 {
9646 }
9647
9649 TOML_ATTR(nonnull)
9651 const char *desc,
9652 const source_position &position,
9653 const source_path_ptr &path = {}) noexcept
9654 : parse_error{desc, source_region{position, position, path}}
9655 {
9656 }
9657
9658# else
9659
9661 parse_error(std::string &&desc, source_region &&src) noexcept //
9662 : description_{std::move(desc)}, source_{std::move(src)}
9663 {
9664 }
9665
9667 parse_error(std::string &&desc, const source_region &src) noexcept //
9668 : parse_error{std::move(desc), source_region{src}}
9669 {
9670 }
9671
9674 std::string &&desc,
9675 const source_position &position,
9676 const source_path_ptr &path = {}) noexcept
9677 : parse_error{std::move(desc), source_region{position, position, path}}
9678 {
9679 }
9680
9681# endif
9682
9684 std::string_view description() const noexcept
9685 {
9686# if TOML_EXCEPTIONS
9687 return std::string_view{what()};
9688# else
9689 return description_;
9690# endif
9691 }
9692
9694 const source_region &source() const noexcept
9695 {
9696 return source_;
9697 }
9698
9699 friend std::ostream &operator<<(std::ostream &lhs, const parse_error &rhs)
9700 {
9701 impl::print_to_stream(lhs, rhs.description());
9702 impl::print_to_stream(lhs, "\n\t(error occurred at "sv);
9703 impl::print_to_stream(lhs, rhs.source());
9704 impl::print_to_stream(lhs, ")"sv);
9705 return lhs;
9706 }
9707 };
9708
9709 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9710}
9712
9713# undef TOML_PARSE_ERROR_BASE
9714
9715# ifdef _MSC_VER
9716# pragma pop_macro("min")
9717# pragma pop_macro("max")
9718# ifndef __clang__
9719# pragma inline_recursion(off)
9720# endif
9721# endif
9723
9724#endif // TOML_ENABLE_PARSER
9725
9726//******** impl/parse_result.hpp *************************************************************************************
9727
9728#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
9729
9731# ifdef _MSC_VER
9732# ifndef __clang__
9733# pragma inline_recursion(on)
9734# endif
9735# pragma push_macro("min")
9736# pragma push_macro("max")
9737# undef min
9738# undef max
9739# endif
9740
9742{
9744
9746 {
9747 private:
9748 struct storage_t
9749 {
9750 static constexpr size_t size =
9751 (sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error)
9752 : sizeof(toml::table));
9753 static constexpr size_t align =
9754 (alignof(toml::table) < alignof(parse_error) ? alignof(parse_error)
9755 : alignof(toml::table));
9756
9757 alignas(align) unsigned char bytes[size];
9758 };
9759
9760 alignas(storage_t::align) mutable storage_t storage_;
9761 bool err_;
9762
9763 template <typename Type>
9764 TOML_NODISCARD TOML_ALWAYS_INLINE static Type *get_as(storage_t &s) noexcept
9765 {
9766 return TOML_LAUNDER(reinterpret_cast<Type *>(s.bytes));
9767 }
9768
9769 void destroy() noexcept
9770 {
9771 if (err_)
9772 get_as<parse_error>(storage_)->~parse_error();
9773 else
9774 get_as<toml::table>(storage_)->~table();
9775 }
9776
9777 public:
9779 parse_result() noexcept //
9780 : err_{true}
9781 {
9782 ::new (static_cast<void *>(storage_.bytes))
9783 parse_error{std::string{}, source_region{}};
9784 }
9785
9787 explicit parse_result(toml::table &&tbl) noexcept //
9788 : err_{false}
9789 {
9790 ::new (static_cast<void *>(storage_.bytes)) toml::table{std::move(tbl)};
9791 }
9792
9794 explicit parse_result(parse_error &&err) noexcept //
9795 : err_{true}
9796 {
9797 ::new (static_cast<void *>(storage_.bytes)) parse_error{std::move(err)};
9798 }
9799
9801 parse_result(parse_result &&res) noexcept //
9802 : err_{res.err_}
9803 {
9804 if (err_)
9805 ::new (static_cast<void *>(storage_.bytes))
9806 parse_error{std::move(res).error()};
9807 else
9808 ::new (static_cast<void *>(storage_.bytes))
9809 toml::table{std::move(res).table()};
9810 }
9811
9813 {
9814 if (err_ != rhs.err_)
9815 {
9816 destroy();
9817 err_ = rhs.err_;
9818 if (err_)
9819 ::new (static_cast<void *>(storage_.bytes))
9820 parse_error{std::move(rhs).error()};
9821 else
9822 ::new (static_cast<void *>(storage_.bytes))
9823 toml::table{std::move(rhs).table()};
9824 }
9825 else
9826 {
9827 if (err_)
9828 error() = std::move(rhs).error();
9829 else
9830 table() = std::move(rhs).table();
9831 }
9832 return *this;
9833 }
9834
9835 ~parse_result() noexcept
9836 {
9837 destroy();
9838 }
9839
9841 bool succeeded() const noexcept
9842 {
9843 return !err_;
9844 }
9845
9847 bool failed() const noexcept
9848 {
9849 return err_;
9850 }
9851
9853 explicit operator bool() const noexcept
9854 {
9855 return !err_;
9856 }
9857
9859 toml::table &table() &noexcept
9860 {
9861 TOML_ASSERT_ASSUME(!err_);
9862 return *get_as<toml::table>(storage_);
9863 }
9864
9866 toml::table &&table() &&noexcept
9867 {
9868 TOML_ASSERT_ASSUME(!err_);
9869 return static_cast<toml::table &&>(*get_as<toml::table>(storage_));
9870 }
9871
9873 const toml::table &table() const &noexcept
9874 {
9875 TOML_ASSERT_ASSUME(!err_);
9876 return *get_as<const toml::table>(storage_);
9877 }
9878
9880 /* implicit */ operator toml::table &() noexcept
9881 {
9882 return table();
9883 }
9884
9886 /* implicit */ operator toml::table &&() noexcept
9887 {
9888 return std::move(table());
9889 }
9890
9892 /* implicit */ operator const toml::table &() const noexcept
9893 {
9894 return table();
9895 }
9896
9898 parse_error &error() &noexcept
9899 {
9900 TOML_ASSERT_ASSUME(err_);
9901 return *get_as<parse_error>(storage_);
9902 }
9903
9905 parse_error &&error() &&noexcept
9906 {
9907 TOML_ASSERT_ASSUME(err_);
9908 return static_cast<parse_error &&>(*get_as<parse_error>(storage_));
9909 }
9910
9912 const parse_error &error() const &noexcept
9913 {
9914 TOML_ASSERT_ASSUME(err_);
9915 return *get_as<const parse_error>(storage_);
9916 }
9917
9919 explicit operator parse_error &() noexcept
9920 {
9921 return error();
9922 }
9923
9925 explicit operator parse_error &&() noexcept
9926 {
9927 return std::move(error());
9928 }
9929
9931 explicit operator const parse_error &() const noexcept
9932 {
9933 return error();
9934 }
9935
9937
9939
9942 {
9943 return err_ ? table_iterator{} : table().begin();
9944 }
9945
9948 {
9949 return err_ ? const_table_iterator{} : table().begin();
9950 }
9951
9954 {
9955 return err_ ? const_table_iterator{} : table().cbegin();
9956 }
9957
9960 {
9961 return err_ ? table_iterator{} : table().end();
9962 }
9963
9965 const_table_iterator end() const noexcept
9966 {
9967 return err_ ? const_table_iterator{} : table().end();
9968 }
9969
9972 {
9973 return err_ ? const_table_iterator{} : table().cend();
9974 }
9975
9977 node_view<node> at_path(std::string_view path) noexcept
9978 {
9979 return err_ ? node_view<node>{} : table().at_path(path);
9980 }
9981
9983 node_view<const node> at_path(std::string_view path) const noexcept
9984 {
9985 return err_ ? node_view<const node>{} : table().at_path(path);
9986 }
9987
9989 node_view<node> at_path(const toml::path &path) noexcept
9990 {
9991 return err_ ? node_view<node>{} : table().at_path(path);
9992 }
9993
9995 node_view<const node> at_path(const toml::path &path) const noexcept
9996 {
9997 return err_ ? node_view<const node>{} : table().at_path(path);
9998 }
9999
10000# if TOML_ENABLE_WINDOWS_COMPAT
10001
10003 node_view<node> at_path(std::wstring_view path)
10004 {
10005 return err_ ? node_view<node>{} : table().at_path(path);
10006 }
10007
10009 node_view<const node> at_path(std::wstring_view path) const
10010 {
10011 return err_ ? node_view<const node>{} : table().at_path(path);
10012 }
10013
10014# endif
10015
10017 node_view<node> operator[](const toml::path &path) noexcept
10018 {
10019 return err_ ? node_view<node>{} : table()[path];
10020 }
10021
10023 node_view<const node> operator[](const toml::path &path) const noexcept
10024 {
10025 return err_ ? node_view<const node>{} : table()[path];
10026 }
10027
10029 node_view<node> operator[](std::string_view key) noexcept
10030 {
10031 return err_ ? node_view<node>{} : table()[key];
10032 }
10033
10035 node_view<const node> operator[](std::string_view key) const noexcept
10036 {
10037 return err_ ? node_view<const node>{} : table()[key];
10038 }
10039
10040# if TOML_ENABLE_WINDOWS_COMPAT
10041
10043 node_view<node> operator[](std::wstring_view key)
10044 {
10045 return err_ ? node_view<node>{} : table()[key];
10046 }
10047
10049 node_view<const node> operator[](std::wstring_view key) const
10050 {
10051 return err_ ? node_view<const node>{} : table()[key];
10052 }
10053
10054# endif // TOML_ENABLE_WINDOWS_COMPAT
10055
10056# if TOML_ENABLE_FORMATTERS
10057
10058 friend std::ostream &
10059 operator<<(std::ostream &os, const parse_result &result)
10060 {
10061 return result.err_ ? (os << result.error()) : (os << result.table());
10062 }
10063
10064# endif
10065 };
10066
10068}
10070
10071# ifdef _MSC_VER
10072# pragma pop_macro("min")
10073# pragma pop_macro("max")
10074# ifndef __clang__
10075# pragma inline_recursion(off)
10076# endif
10077# endif
10079
10080#endif // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
10081
10082//******** impl/parser.hpp *******************************************************************************************
10083
10084#if TOML_ENABLE_PARSER
10085
10087# ifdef _MSC_VER
10088# ifndef __clang__
10089# pragma inline_recursion(on)
10090# endif
10091# pragma push_macro("min")
10092# pragma push_macro("max")
10093# undef min
10094# undef max
10095# endif
10096
10098{
10100
10104 std::string_view doc, std::string_view source_path = {});
10105
10109 std::string_view doc, std::string && source_path);
10110
10113 parse_result TOML_CALLCONV parse_file(std::string_view file_path);
10114
10115# if TOML_HAS_CHAR8
10116
10120 std::u8string_view doc, std::string_view source_path = {});
10121
10125 std::u8string_view doc, std::string && source_path);
10126
10129 parse_result TOML_CALLCONV parse_file(std::u8string_view file_path);
10130
10131# endif // TOML_HAS_CHAR8
10132
10133# if TOML_ENABLE_WINDOWS_COMPAT
10134
10138 std::string_view doc, std::wstring_view source_path);
10139
10143 std::istream & doc, std::wstring_view source_path);
10144
10147 parse_result TOML_CALLCONV parse_file(std::wstring_view file_path);
10148
10149# endif // TOML_ENABLE_WINDOWS_COMPAT
10150
10151# if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
10152
10156 std::u8string_view doc, std::wstring_view source_path);
10157
10158# endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
10159
10163 std::istream & doc, std::string_view source_path = {});
10164
10168 std::istream & doc, std::string && source_path);
10169
10170 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
10171
10172 inline namespace literals
10173 {
10175
10178 parse_result operator"" _toml(const char *str, size_t len)
10179 {
10180 return parse(std::string_view{str, len});
10181 }
10182
10183# if TOML_HAS_CHAR8
10184
10187 parse_result operator"" _toml(const char8_t *str, size_t len)
10188 {
10189 return parse(std::u8string_view{str, len});
10190 }
10191
10192# endif // TOML_HAS_CHAR8
10193
10194 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
10195 } // namespace literals
10196}
10198
10199# ifdef _MSC_VER
10200# pragma pop_macro("min")
10201# pragma pop_macro("max")
10202# ifndef __clang__
10203# pragma inline_recursion(off)
10204# endif
10205# endif
10207
10208#endif // TOML_ENABLE_PARSER
10209
10210//******** impl/formatter.hpp ****************************************************************************************
10211
10212#if TOML_ENABLE_FORMATTERS
10213
10215# ifdef _MSC_VER
10216# ifndef __clang__
10217# pragma inline_recursion(on)
10218# endif
10219# pragma push_macro("min")
10220# pragma push_macro("max")
10221# undef min
10222# undef max
10223# endif
10224
10226{
10227 struct formatter_constants
10228 {
10229 format_flags mandatory_flags;
10230 format_flags ignored_flags;
10231
10232 std::string_view float_pos_inf;
10233 std::string_view float_neg_inf;
10234 std::string_view float_nan;
10235
10236 std::string_view bool_true;
10237 std::string_view bool_false;
10238 };
10239
10241 {
10243 std::string_view indent;
10244 };
10245
10247 {
10248 private:
10249 const node *source_;
10250# if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
10251 const parse_result *result_;
10252# endif
10253 const formatter_constants *constants_;
10254 formatter_config config_;
10255 size_t indent_columns_;
10256 format_flags int_format_mask_;
10257 std::ostream *stream_; //
10258 int indent_; // these are set in attach()
10259 bool naked_newline_; //
10260
10261 protected:
10263 const node &source() const noexcept
10264 {
10265 return *source_;
10266 }
10267
10269 std::ostream &stream() const noexcept
10270 {
10271 return *stream_;
10272 }
10273
10275 int indent() const noexcept
10276 {
10277 return indent_;
10278 }
10279
10280 void indent(int level) noexcept
10281 {
10282 indent_ = level;
10283 }
10284
10285 void increase_indent() noexcept
10286 {
10287 indent_++;
10288 }
10289
10290 void decrease_indent() noexcept
10291 {
10292 indent_--;
10293 }
10294
10296 size_t indent_columns() const noexcept
10297 {
10298 return indent_columns_;
10299 }
10300
10302 bool indent_array_elements() const noexcept
10303 {
10304 return !!(config_.flags & format_flags::indent_array_elements);
10305 }
10306
10308 bool indent_sub_tables() const noexcept
10309 {
10310 return !!(config_.flags & format_flags::indent_sub_tables);
10311 }
10312
10314 bool literal_strings_allowed() const noexcept
10315 {
10316 return !!(config_.flags & format_flags::allow_literal_strings);
10317 }
10318
10320 bool multi_line_strings_allowed() const noexcept
10321 {
10322 return !!(config_.flags & format_flags::allow_multi_line_strings);
10323 }
10324
10326 bool real_tabs_in_strings_allowed() const noexcept
10327 {
10328 return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
10329 }
10330
10332 bool unicode_strings_allowed() const noexcept
10333 {
10334 return !!(config_.flags & format_flags::allow_unicode_strings);
10335 }
10336
10338 bool terse_kvps() const noexcept
10339 {
10340 return !!(config_.flags & format_flags::terse_key_value_pairs);
10341 }
10342
10344 void attach(std::ostream &stream) noexcept;
10345
10347 void detach() noexcept;
10348
10350 void print_newline(bool force = false);
10351
10353 void print_indent();
10354
10356 void print_unformatted(char);
10357
10359 void print_unformatted(std::string_view);
10360
10362 void print_string(
10363 std::string_view str,
10364 bool allow_multi_line = true,
10365 bool allow_bare = false,
10366 bool allow_literal_whitespace = true);
10367
10369 void print(const value<std::string> &);
10370
10372 void print(const value<int64_t> &);
10373
10375 void print(const value<double> &);
10376
10378 void print(const value<bool> &);
10379
10381 void print(const value<date> &);
10382
10384 void print(const value<time> &);
10385
10387 void print(const value<date_time> &);
10388
10390 void print_value(const node &, node_type);
10391
10394 bool dump_failed_parse_result();
10395
10398 formatter(
10399 const node *,
10400 const parse_result *,
10401 const formatter_constants &,
10402 const formatter_config &) noexcept;
10403 };
10404}
10406
10407# ifdef _MSC_VER
10408# pragma pop_macro("min")
10409# pragma pop_macro("max")
10410# ifndef __clang__
10411# pragma inline_recursion(off)
10412# endif
10413# endif
10415
10416#endif // TOML_ENABLE_FORMATTERS
10417
10418//******** impl/toml_formatter.hpp ***********************************************************************************
10419
10420#if TOML_ENABLE_FORMATTERS
10421
10423# ifdef _MSC_VER
10424# ifndef __clang__
10425# pragma inline_recursion(on)
10426# endif
10427# pragma push_macro("min")
10428# pragma push_macro("max")
10429# undef min
10430# undef max
10431# endif
10432
10434{
10435 class TOML_EXPORTED_CLASS toml_formatter : impl::formatter
10436 {
10437 private:
10438 using base = impl::formatter;
10439 std::vector<const key *> key_path_;
10440 bool pending_table_separator_ = false;
10441
10443 void print_pending_table_separator();
10444
10446 void print(const key &);
10447
10449 void print_inline(const toml::table &);
10450
10452 void print(const toml::array &);
10453
10455 void print(const toml::table &);
10456
10458 void print();
10459
10460 static constexpr impl::formatter_constants constants = {
10461 format_flags::none, // mandatory
10462 format_flags::none, // ignored
10463 "inf"sv,
10464 "-inf"sv,
10465 "nan"sv,
10466 "true"sv,
10467 "false"sv};
10468
10469 public:
10470 static constexpr format_flags default_flags =
10471 constants.mandatory_flags //
10472 | format_flags::allow_literal_strings //
10473 | format_flags::allow_multi_line_strings //
10474 | format_flags::allow_unicode_strings //
10475 | format_flags::allow_real_tabs_in_strings //
10476 | format_flags::allow_binary_integers //
10477 | format_flags::allow_octal_integers //
10478 | format_flags::allow_hexadecimal_integers //
10479 | format_flags::indentation;
10480
10482 explicit toml_formatter(
10483 const toml::node &source,
10484 format_flags flags = default_flags) noexcept
10485 : base{&source, nullptr, constants, {flags, " "sv}}
10486 {
10487 }
10488
10489# if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
10490
10492 explicit toml_formatter(
10493 const toml::parse_result &result,
10494 format_flags flags = default_flags) noexcept
10495 : base{nullptr, &result, constants, {
10496 flags,
10497 " "sv
10498 }}
10499 {
10500 }
10501
10502# endif
10503
10504 friend std::ostream &operator<<(std::ostream &lhs, toml_formatter &rhs)
10505 {
10506 rhs.attach(lhs);
10507 rhs.key_path_.clear();
10508 rhs.print();
10509 rhs.detach();
10510 return lhs;
10511 }
10512
10513 friend std::ostream &operator<<(std::ostream &lhs, toml_formatter &&rhs)
10514 {
10515 return lhs << rhs; // as lvalue
10516 }
10517 };
10518}
10520
10521# ifdef _MSC_VER
10522# pragma pop_macro("min")
10523# pragma pop_macro("max")
10524# ifndef __clang__
10525# pragma inline_recursion(off)
10526# endif
10527# endif
10529
10530#endif // TOML_ENABLE_FORMATTERS
10531
10532//******** impl/json_formatter.hpp ***********************************************************************************
10533
10534#if TOML_ENABLE_FORMATTERS
10535
10537# ifdef _MSC_VER
10538# ifndef __clang__
10539# pragma inline_recursion(on)
10540# endif
10541# pragma push_macro("min")
10542# pragma push_macro("max")
10543# undef min
10544# undef max
10545# endif
10546
10548{
10549 class TOML_EXPORTED_CLASS json_formatter : impl::formatter
10550 {
10551 private:
10552 using base = impl::formatter;
10553
10555 void print(const toml::table &);
10556
10558 void print(const toml::array &);
10559
10561 void print();
10562
10563 static constexpr impl::formatter_constants constants = {
10564 format_flags::quote_dates_and_times, // mandatory
10565 format_flags::allow_literal_strings |
10566 format_flags::allow_multi_line_strings, // ignored
10567 "Infinity"sv,
10568 "-Infinity"sv,
10569 "NaN"sv,
10570 "true"sv,
10571 "false"sv};
10572
10573 public:
10574 static constexpr format_flags default_flags =
10575 constants.mandatory_flags //
10576 | format_flags::quote_infinities_and_nans //
10577 | format_flags::allow_unicode_strings //
10578 | format_flags::indentation;
10579
10581 explicit json_formatter(
10582 const toml::node &source,
10583 format_flags flags = default_flags) noexcept
10584 : base{&source, nullptr, constants, {flags, " "sv}}
10585 {
10586 }
10587
10588# if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
10589
10591 explicit json_formatter(
10592 const toml::parse_result &result,
10593 format_flags flags = default_flags) noexcept
10594 : base{nullptr, &result, constants, {
10595 flags,
10596 " "sv
10597 }}
10598 {
10599 }
10600
10601# endif
10602
10603 friend std::ostream &operator<<(std::ostream &lhs, json_formatter &rhs)
10604 {
10605 rhs.attach(lhs);
10606 rhs.print();
10607 rhs.detach();
10608 return lhs;
10609 }
10610
10611 friend std::ostream &operator<<(std::ostream &lhs, json_formatter &&rhs)
10612 {
10613 return lhs << rhs; // as lvalue
10614 }
10615 };
10616}
10618
10619# ifdef _MSC_VER
10620# pragma pop_macro("min")
10621# pragma pop_macro("max")
10622# ifndef __clang__
10623# pragma inline_recursion(off)
10624# endif
10625# endif
10627
10628#endif // TOML_ENABLE_FORMATTERS
10629
10630//******** impl/yaml_formatter.hpp ***********************************************************************************
10631
10632#if TOML_ENABLE_FORMATTERS
10633
10635# ifdef _MSC_VER
10636# ifndef __clang__
10637# pragma inline_recursion(on)
10638# endif
10639# pragma push_macro("min")
10640# pragma push_macro("max")
10641# undef min
10642# undef max
10643# endif
10644
10646{
10647 class TOML_EXPORTED_CLASS yaml_formatter : impl::formatter
10648 {
10649 private:
10650 using base = impl::formatter;
10651
10653 void print_yaml_string(const value<std::string> &);
10654
10656 void print(const toml::table &, bool = false);
10657
10659 void print(const toml::array &, bool = false);
10660
10662 void print();
10663
10664 static constexpr impl::formatter_constants constants = {
10665 //
10666 format_flags::quote_dates_and_times |
10667 format_flags::indentation, // mandatory
10668 format_flags::allow_multi_line_strings, // ignored
10669 ".inf"sv,
10670 "-.inf"sv,
10671 ".NAN"sv,
10672 "true"sv,
10673 "false"sv};
10674
10675 public:
10676 static constexpr format_flags default_flags =
10677 constants.mandatory_flags //
10678 | format_flags::allow_literal_strings //
10679 | format_flags::allow_unicode_strings //
10680 | format_flags::allow_octal_integers //
10681 | format_flags::allow_hexadecimal_integers;
10682
10684 explicit yaml_formatter(
10685 const toml::node &source,
10686 format_flags flags = default_flags) noexcept
10687 : base{&source, nullptr, constants, {flags, " "sv}}
10688 {
10689 }
10690
10691# if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
10692
10694 explicit yaml_formatter(
10695 const toml::parse_result &result,
10696 format_flags flags = default_flags) noexcept
10697 : base{nullptr, &result, constants, {
10698 flags,
10699 " "sv
10700 }}
10701 {
10702 }
10703
10704# endif
10705
10706 friend std::ostream &TOML_CALLCONV
10707 operator<<(std::ostream &lhs, yaml_formatter &rhs)
10708 {
10709 rhs.attach(lhs);
10710 rhs.print();
10711 rhs.detach();
10712 return lhs;
10713 }
10714
10715 friend std::ostream &TOML_CALLCONV
10716 operator<<(std::ostream &lhs, yaml_formatter &&rhs)
10717 {
10718 return lhs << rhs; // as lvalue
10719 }
10720 };
10721}
10723
10724# ifdef _MSC_VER
10725# pragma pop_macro("min")
10726# pragma pop_macro("max")
10727# ifndef __clang__
10728# pragma inline_recursion(off)
10729# endif
10730# endif
10732
10733#endif // TOML_ENABLE_FORMATTERS
10734
10735#if TOML_IMPLEMENTATION
10736
10737//******** impl/std_string.inl ***************************************************************************************
10738
10739# if TOML_WINDOWS
10740
10741# ifndef _WINDOWS_
10742# if TOML_INCLUDE_WINDOWS_H
10743# include <Windows.h>
10744# else
10745
10746extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(
10747 unsigned int CodePage,
10748 unsigned long dwFlags,
10749 const wchar_t *lpWideCharStr,
10750 int cchWideChar,
10751 char *lpMultiByteStr,
10752 int cbMultiByte,
10753 const char *lpDefaultChar,
10754 int *lpUsedDefaultChar);
10755
10756extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(
10757 unsigned int CodePage,
10758 unsigned long dwFlags,
10759 const char *lpMultiByteStr,
10760 int cbMultiByte,
10761 wchar_t *lpWideCharStr,
10762 int cchWideChar);
10763
10764# endif // TOML_INCLUDE_WINDOWS_H
10765# endif // _WINDOWS_
10766
10768# ifdef _MSC_VER
10769# ifndef __clang__
10770# pragma inline_recursion(on)
10771# endif
10772# pragma push_macro("min")
10773# pragma push_macro("max")
10774# undef min
10775# undef max
10776# endif
10777
10779{
10781 std::string narrow(std::wstring_view str)
10782 {
10783 if (str.empty())
10784 return {};
10785
10786 std::string s;
10787 const auto len = ::WideCharToMultiByte(
10788 65001,
10789 0,
10790 str.data(),
10791 static_cast<int>(str.length()),
10792 nullptr,
10793 0,
10794 nullptr,
10795 nullptr);
10796 if (len)
10797 {
10798 s.resize(static_cast<size_t>(len));
10799 ::WideCharToMultiByte(
10800 65001,
10801 0,
10802 str.data(),
10803 static_cast<int>(str.length()),
10804 s.data(),
10805 len,
10806 nullptr,
10807 nullptr);
10808 }
10809 return s;
10810 }
10811
10813 std::wstring widen(std::string_view str)
10814 {
10815 if (str.empty())
10816 return {};
10817
10818 std::wstring s;
10819 const auto len = ::MultiByteToWideChar(
10820 65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
10821 if (len)
10822 {
10823 s.resize(static_cast<size_t>(len));
10824 ::MultiByteToWideChar(
10825 65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
10826 }
10827 return s;
10828 }
10829
10830# if TOML_HAS_CHAR8
10831
10833 std::wstring widen(std::u8string_view str)
10834 {
10835 if (str.empty())
10836 return {};
10837
10838 return widen(std::string_view{
10839 reinterpret_cast<const char *>(str.data()), str.length()});
10840 }
10841
10842# endif // TOML_HAS_CHAR8
10843}
10845
10846# ifdef _MSC_VER
10847# pragma pop_macro("min")
10848# pragma pop_macro("max")
10849# ifndef __clang__
10850# pragma inline_recursion(off)
10851# endif
10852# endif
10854
10855# endif // TOML_WINDOWS
10856
10857//******** impl/print_to_stream.inl **********************************************************************************
10858
10860# include <ostream>
10861# if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
10862# include <charconv>
10863# endif
10864# if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
10865# include <sstream>
10866# endif
10867# if !TOML_INT_CHARCONV
10868# include <iomanip>
10869# endif
10872# ifdef _MSC_VER
10873# ifndef __clang__
10874# pragma inline_recursion(on)
10875# endif
10876# pragma push_macro("min")
10877# pragma push_macro("max")
10878# undef min
10879# undef max
10880# endif
10881
10883{
10884 template <typename T>
10885 inline constexpr size_t charconv_buffer_length = 0;
10886
10887 template <>
10888 inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
10889
10890 template <>
10891 inline constexpr size_t charconv_buffer_length<int16_t> =
10892 6; // strlen("-32768")
10893
10894 template <>
10895 inline constexpr size_t charconv_buffer_length<int32_t> =
10896 11; // strlen("-2147483648")
10897
10898 template <>
10899 inline constexpr size_t charconv_buffer_length<int64_t> =
10900 20; // strlen("-9223372036854775808")
10901
10902 template <>
10903 inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
10904
10905 template <>
10906 inline constexpr size_t charconv_buffer_length<uint16_t> =
10907 5; // strlen("65535")
10908
10909 template <>
10910 inline constexpr size_t charconv_buffer_length<uint32_t> =
10911 10; // strlen("4294967295")
10912
10913 template <>
10914 inline constexpr size_t charconv_buffer_length<uint64_t> =
10915 20; // strlen("18446744073709551615")
10916
10917 template <>
10918 inline constexpr size_t charconv_buffer_length<float> = 64;
10919
10920 template <>
10921 inline constexpr size_t charconv_buffer_length<double> = 64;
10922
10923 template <typename T>
10925 std::ostream & stream,
10926 T val,
10927 value_flags format = {},
10928 size_t min_digits = 0)
10929 {
10930 if (!val)
10931 {
10932 if (!min_digits)
10933 min_digits = 1;
10934
10935 for (size_t i = 0; i < min_digits; i++)
10936 stream.put('0');
10937
10938 return;
10939 }
10940
10941 static constexpr auto value_flags_mask = value_flags::format_as_binary |
10942 value_flags::format_as_octal |
10943 value_flags::format_as_hexadecimal;
10944 format &= value_flags_mask;
10945
10946 int base = 10;
10947 if (format != value_flags::none && val > T{})
10948 {
10949 switch (format)
10950 {
10951 case value_flags::format_as_binary:
10952 base = 2;
10953 break;
10954 case value_flags::format_as_octal:
10955 base = 8;
10956 break;
10957 case value_flags::format_as_hexadecimal:
10958 base = 16;
10959 break;
10960 default:
10961 break;
10962 }
10963 }
10964
10965# if TOML_INT_CHARCONV
10966
10967 char buf[(sizeof(T) * CHAR_BIT)];
10968 const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
10969 const auto len = static_cast<size_t>(res.ptr - buf);
10970 for (size_t i = len; i < min_digits; i++)
10971 stream.put('0');
10972 if (base == 16)
10973 {
10974 for (size_t i = 0; i < len; i++)
10975 if (buf[i] >= 'a')
10976 buf[i] -= 32;
10977 }
10978 impl::print_to_stream(stream, buf, len);
10979
10980# else
10981
10982 using unsigned_type = std::conditional_t<
10983 (sizeof(T) > sizeof(unsigned)),
10984 std::make_unsigned_t<T>,
10985 unsigned>;
10986 using cast_type = std::conditional_t<
10987 std::is_signed_v<T>,
10988 std::make_signed_t<unsigned_type>,
10989 unsigned_type>;
10990
10991 if (base == 2)
10992 {
10993 const auto len = sizeof(T) * CHAR_BIT;
10994 for (size_t i = len; i < min_digits; i++)
10995 stream.put('0');
10996
10997 bool found_one = false;
10998 const auto v = static_cast<unsigned_type>(val);
10999 unsigned_type mask = unsigned_type{1} << (len - 1u);
11000 for (size_t i = 0; i < len; i++)
11001 {
11002 if ((v & mask))
11003 {
11004 stream.put('1');
11005 found_one = true;
11006 }
11007 else if (found_one)
11008 stream.put('0');
11009 mask >>= 1;
11010 }
11011 }
11012 else
11013 {
11014 std::ostringstream ss;
11015 ss.imbue(std::locale::classic());
11016 ss << std::uppercase << std::setbase(base);
11017 if (min_digits)
11018 ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
11019 ss << static_cast<cast_type>(val);
11020 const auto str = std::move(ss).str();
11021 impl::print_to_stream(stream, str);
11022 }
11023
11024# endif
11025 }
11026
11027 template <typename T>
11029 std::ostream & stream,
11030 T val,
11031 value_flags format,
11032 [[maybe_unused]] bool relaxed_precision)
11033 {
11034 switch (impl::fpclassify(val))
11035 {
11036 case impl::fp_class::neg_inf:
11037 impl::print_to_stream(stream, "-inf"sv);
11038 break;
11039
11040 case impl::fp_class::pos_inf:
11041 impl::print_to_stream(stream, "inf"sv);
11042 break;
11043
11044 case impl::fp_class::nan:
11045 impl::print_to_stream(stream, "nan"sv);
11046 break;
11047
11048 case impl::fp_class::ok:
11049 {
11050 static constexpr auto needs_decimal_point = [](auto &&s) noexcept
11051 {
11052 for (auto c : s)
11053 if (c == '.' || c == 'E' || c == 'e')
11054 return false;
11055 return true;
11056 };
11057
11058# if TOML_FLOAT_CHARCONV
11059
11060 const auto hex = !!(format & value_flags::format_as_hexadecimal);
11061 char buf[charconv_buffer_length<T>];
11062 auto res =
11063 hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
11064 : std::to_chars(buf, buf + sizeof(buf), val);
11065 auto str = std::string_view{buf, static_cast<size_t>(res.ptr - buf)};
11066
11067 char buf2[charconv_buffer_length<T>];
11068 if (!hex && relaxed_precision)
11069 {
11070 res = std::to_chars(
11071 buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
11072 const auto str2 =
11073 std::string_view{buf2, static_cast<size_t>(res.ptr - buf2)};
11074 if (str2.length() < str.length())
11075 str = str2;
11076 }
11077
11078 impl::print_to_stream(stream, str);
11079 if (!hex && needs_decimal_point(str))
11080 toml::impl::print_to_stream(stream, ".0"sv);
11081
11082# else
11083
11084 std::ostringstream ss;
11085 ss.imbue(std::locale::classic());
11086 if (!relaxed_precision)
11087 ss.precision(std::numeric_limits<T>::max_digits10);
11088 if (!!(format & value_flags::format_as_hexadecimal))
11089 ss << std::hexfloat;
11090 ss << val;
11091 const auto str = std::move(ss).str();
11092 impl::print_to_stream(stream, str);
11093 if (
11094 !(format & value_flags::format_as_hexadecimal) &&
11095 needs_decimal_point(str))
11096 impl::print_to_stream(stream, ".0"sv);
11097
11098# endif
11099 }
11100 break;
11101
11102 default:
11104 }
11105 }
11106}
11108
11110{
11112 TOML_ATTR(nonnull)
11114 std::ostream & stream, const char *val, size_t len)
11115 {
11116 stream.write(val, static_cast<std::streamsize>(len));
11117 }
11118
11121 std::ostream & stream, std::string_view val)
11122 {
11123 stream.write(val.data(), static_cast<std::streamsize>(val.length()));
11124 }
11125
11128 std::ostream & stream, const std::string &val)
11129 {
11130 stream.write(val.data(), static_cast<std::streamsize>(val.length()));
11131 }
11132
11134 void TOML_CALLCONV print_to_stream(std::ostream & stream, char val)
11135 {
11136 stream.put(val);
11137 }
11138
11141 std::ostream & stream,
11142 signed char val,
11143 value_flags format,
11144 size_t min_digits)
11145 {
11146 TOML_ANON_NAMESPACE::print_integer_to_stream(
11147 stream, val, format, min_digits);
11148 }
11149
11152 std::ostream & stream,
11153 signed short val,
11154 value_flags format,
11155 size_t min_digits)
11156 {
11157 TOML_ANON_NAMESPACE::print_integer_to_stream(
11158 stream, val, format, min_digits);
11159 }
11160
11163 std::ostream & stream,
11164 signed int val,
11165 value_flags format,
11166 size_t min_digits)
11167 {
11168 TOML_ANON_NAMESPACE::print_integer_to_stream(
11169 stream, val, format, min_digits);
11170 }
11171
11174 std::ostream & stream,
11175 signed long val,
11176 value_flags format,
11177 size_t min_digits)
11178 {
11179 TOML_ANON_NAMESPACE::print_integer_to_stream(
11180 stream, val, format, min_digits);
11181 }
11182
11185 std::ostream & stream,
11186 signed long long val,
11187 value_flags format,
11188 size_t min_digits)
11189 {
11190 TOML_ANON_NAMESPACE::print_integer_to_stream(
11191 stream, val, format, min_digits);
11192 }
11193
11196 std::ostream & stream,
11197 unsigned char val,
11198 value_flags format,
11199 size_t min_digits)
11200 {
11201 TOML_ANON_NAMESPACE::print_integer_to_stream(
11202 stream, val, format, min_digits);
11203 }
11204
11207 std::ostream & stream,
11208 unsigned short val,
11209 value_flags format,
11210 size_t min_digits)
11211 {
11212 TOML_ANON_NAMESPACE::print_integer_to_stream(
11213 stream, val, format, min_digits);
11214 }
11215
11218 std::ostream & stream,
11219 unsigned int val,
11220 value_flags format,
11221 size_t min_digits)
11222 {
11223 TOML_ANON_NAMESPACE::print_integer_to_stream(
11224 stream, val, format, min_digits);
11225 }
11226
11229 std::ostream & stream,
11230 unsigned long val,
11231 value_flags format,
11232 size_t min_digits)
11233 {
11234 TOML_ANON_NAMESPACE::print_integer_to_stream(
11235 stream, val, format, min_digits);
11236 }
11237
11240 std::ostream & stream,
11241 unsigned long long val,
11242 value_flags format,
11243 size_t min_digits)
11244 {
11245 TOML_ANON_NAMESPACE::print_integer_to_stream(
11246 stream, val, format, min_digits);
11247 }
11248
11251 std::ostream & stream,
11252 float val,
11253 value_flags format,
11254 bool relaxed_precision)
11255 {
11256 TOML_ANON_NAMESPACE::print_floating_point_to_stream(
11257 stream, val, format, relaxed_precision);
11258 }
11259
11262 std::ostream & stream,
11263 double val,
11264 value_flags format,
11265 bool relaxed_precision)
11266 {
11267 TOML_ANON_NAMESPACE::print_floating_point_to_stream(
11268 stream, val, format, relaxed_precision);
11269 }
11270
11272 void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val)
11273 {
11274 print_to_stream(stream, val ? "true"sv : "false"sv);
11275 }
11276
11279 std::ostream & stream, const toml::date &val)
11280 {
11281 print_to_stream(stream, val.year, {}, 4);
11282 stream.put('-');
11283 print_to_stream(stream, val.month, {}, 2);
11284 stream.put('-');
11285 print_to_stream(stream, val.day, {}, 2);
11286 }
11287
11290 std::ostream & stream, const toml::time &val)
11291 {
11292 print_to_stream(stream, val.hour, {}, 2);
11293 stream.put(':');
11294 print_to_stream(stream, val.minute, {}, 2);
11295 stream.put(':');
11296 print_to_stream(stream, val.second, {}, 2);
11297 if (val.nanosecond && val.nanosecond <= 999999999u)
11298 {
11299 stream.put('.');
11300 auto ns = val.nanosecond;
11301 size_t digits = 9u;
11302 while (ns % 10u == 0u)
11303 {
11304 ns /= 10u;
11305 digits--;
11306 }
11307 print_to_stream(stream, ns, {}, digits);
11308 }
11309 }
11310
11313 std::ostream & stream, const toml::time_offset &val)
11314 {
11315 if (!val.minutes)
11316 {
11317 stream.put('Z');
11318 return;
11319 }
11320
11321 auto mins = static_cast<int>(val.minutes);
11322 if (mins < 0)
11323 {
11324 stream.put('-');
11325 mins = -mins;
11326 }
11327 else
11328 stream.put('+');
11329 const auto hours = mins / 60;
11330 if (hours)
11331 {
11332 print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
11333 mins -= hours * 60;
11334 }
11335 else
11336 print_to_stream(stream, "00"sv);
11337 stream.put(':');
11338 print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
11339 }
11340
11343 std::ostream & stream, const toml::date_time &val)
11344 {
11345 print_to_stream(stream, val.date);
11346 stream.put('T');
11347 print_to_stream(stream, val.time);
11348 if (val.offset)
11349 print_to_stream(stream, *val.offset);
11350 }
11351
11354 std::ostream & stream, const source_position &val)
11355 {
11356 print_to_stream(stream, "line "sv);
11357 print_to_stream(stream, val.line);
11358 print_to_stream(stream, ", column "sv);
11359 print_to_stream(stream, val.column);
11360 }
11361
11364 std::ostream & stream, const source_region &val)
11365 {
11366 print_to_stream(stream, val.begin);
11367 if (val.path)
11368 {
11369 print_to_stream(stream, " of '"sv);
11370 print_to_stream(stream, *val.path);
11371 stream.put('\'');
11372 }
11373 }
11374
11375# if TOML_ENABLE_FORMATTERS
11376
11378 void TOML_CALLCONV print_to_stream(std::ostream & stream, const array &arr)
11379 {
11380 stream << toml_formatter{arr};
11381 }
11382
11384 void TOML_CALLCONV print_to_stream(std::ostream & stream, const table &tbl)
11385 {
11386 stream << toml_formatter{tbl};
11387 }
11388
11391 std::ostream & stream, const value<std::string> &val)
11392 {
11393 stream << toml_formatter{val};
11394 }
11395
11398 std::ostream & stream, const value<int64_t> &val)
11399 {
11400 stream << toml_formatter{val};
11401 }
11402
11405 std::ostream & stream, const value<double> &val)
11406 {
11407 stream << toml_formatter{val};
11408 }
11409
11412 std::ostream & stream, const value<bool> &val)
11413 {
11414 stream << toml_formatter{val};
11415 }
11416
11419 std::ostream & stream, const value<date> &val)
11420 {
11421 stream << toml_formatter{val};
11422 }
11423
11426 std::ostream & stream, const value<time> &val)
11427 {
11428 stream << toml_formatter{val};
11429 }
11430
11433 std::ostream & stream, const value<date_time> &val)
11434 {
11435 stream << toml_formatter{val};
11436 }
11437
11438# endif
11439}
11441
11442# ifdef _MSC_VER
11443# pragma pop_macro("min")
11444# pragma pop_macro("max")
11445# ifndef __clang__
11446# pragma inline_recursion(off)
11447# endif
11448# endif
11450
11451//******** impl/node.inl *********************************************************************************************
11452
11454# ifdef _MSC_VER
11455# ifndef __clang__
11456# pragma inline_recursion(on)
11457# endif
11458# pragma push_macro("min")
11459# pragma push_macro("max")
11460# undef min
11461# undef max
11462# endif
11463
11465{
11467 node::node() noexcept = default;
11468
11470 node::~node() noexcept = default;
11471
11473 node::node(node && other) noexcept //
11474 : source_{std::exchange(other.source_, {})}
11475 {
11476 }
11477
11479 node::node(const node & /*other*/) noexcept
11480 {
11481 // does not copy source information - this is not an error
11482 //
11483 // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
11484 }
11485
11487 node &node::operator=(const node & /*rhs*/) noexcept
11488 {
11489 // does not copy source information - this is not an error
11490 //
11491 // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
11492
11493 source_ = {};
11494 return *this;
11495 }
11496
11498 node &node::operator=(node &&rhs) noexcept
11499 {
11500 if (&rhs != this)
11501 source_ = std::exchange(rhs.source_, {});
11502 return *this;
11503 }
11504
11506 node_view<node> node::at_path(std::string_view path) noexcept
11507 {
11508 return toml::at_path(*this, path);
11509 }
11510
11512 node_view<const node> node::at_path(std::string_view path) const noexcept
11513 {
11514 return toml::at_path(*this, path);
11515 }
11516
11518 node_view<node> node::at_path(const path &p) noexcept
11519 {
11520 return toml::at_path(*this, p);
11521 }
11522
11524 node_view<const node> node::at_path(const path &p) const noexcept
11525 {
11526 return toml::at_path(*this, p);
11527 }
11528
11529# if TOML_ENABLE_WINDOWS_COMPAT
11530
11532 node_view<node> node::at_path(std::wstring_view path)
11533 {
11534 return toml::at_path(*this, path);
11535 }
11536
11538 node_view<const node> node::at_path(std::wstring_view path) const
11539 {
11540 return toml::at_path(*this, path);
11541 }
11542
11543# endif // TOML_ENABLE_WINDOWS_COMPAT
11544
11546 node_view<node> node::operator[](const path &p) noexcept
11547 {
11548 return toml::at_path(*this, p);
11549 }
11550
11552 node_view<const node> node::operator[](const path &p) const noexcept
11553 {
11554 return toml::at_path(*this, p);
11555 }
11556}
11558
11560{
11563 bool TOML_CALLCONV node_deep_equality(
11564 const node *lhs, const node *rhs) noexcept
11565 {
11566 // both same or both null
11567 if (lhs == rhs)
11568 return true;
11569
11570 // lhs null != rhs null or different types
11571 if ((!lhs != !rhs) || lhs->type() != rhs->type())
11572 return false;
11573
11574 return lhs->visit(
11575 [=](auto &l) noexcept
11576 {
11577 using concrete_type = remove_cvref<decltype(l)>;
11578
11579 return l == *(rhs->as<concrete_type>());
11580 });
11581 }
11582}
11584
11585# ifdef _MSC_VER
11586# pragma pop_macro("min")
11587# pragma pop_macro("max")
11588# ifndef __clang__
11589# pragma inline_recursion(off)
11590# endif
11591# endif
11593
11594//******** impl/at_path.inl ******************************************************************************************
11595
11597# if TOML_INT_CHARCONV
11598# include <charconv>
11599# else
11600# include <sstream>
11601# endif
11604# ifdef _MSC_VER
11605# ifndef __clang__
11606# pragma inline_recursion(on)
11607# endif
11608# pragma push_macro("min")
11609# pragma push_macro("max")
11610# undef min
11611# undef max
11612# endif
11613
11615{
11618 const std::string_view path,
11619 void *const data,
11620 const parse_path_callback<std::string_view> on_key,
11621 const parse_path_callback<size_t> on_index)
11622 {
11623 // a blank string is a valid path; it's just one component representing the "" key
11624 if (path.empty())
11625 return on_key(data, ""sv);
11626
11627 size_t pos = 0;
11628 const auto end = path.length();
11629 bool prev_was_array_indexer = false;
11630 bool prev_was_dot = true; // invisible root 'dot'
11631
11632 while (pos < end)
11633 {
11634 // start of an array indexer
11635 if (path[pos] == '[')
11636 {
11637 // find first digit in index
11638 size_t index_start = pos + 1u;
11639 while (true)
11640 {
11641 if TOML_UNLIKELY (index_start >= path.length())
11642 return false;
11643
11644 const auto c = path[index_start];
11645 if TOML_LIKELY (c >= '0' && c <= '9')
11646 break;
11647 else if (c == ' ' || c == '\t')
11648 index_start++;
11649 else
11650 return false;
11651 }
11652 TOML_ASSERT(path[index_start] >= '0');
11653 TOML_ASSERT(path[index_start] <= '9');
11654
11655 // find end of index (first non-digit character)
11656 size_t index_end = index_start + 1u;
11657 while (true)
11658 {
11659 // if an array indexer is missing the trailing ']' at the end of the string, permissively accept it
11660 if TOML_UNLIKELY (index_end >= path.length())
11661 break;
11662
11663 const auto c = path[index_end];
11664 if (c >= '0' && c <= '9')
11665 index_end++;
11666 else if (c == ']' || c == ' ' || c == '\t' || c == '.' || c == '[')
11667 break;
11668 else
11669 return false;
11670 }
11671 TOML_ASSERT(path[index_end - 1u] >= '0');
11672 TOML_ASSERT(path[index_end - 1u] <= '9');
11673
11674 // move pos to after indexer (char after closing ']' or permissively EOL/subkey '.'/next opening '[')
11675 pos = index_end;
11676 while (true)
11677 {
11678 if TOML_UNLIKELY (pos >= path.length())
11679 break;
11680
11681 const auto c = path[pos];
11682 if (c == ']')
11683 {
11684 pos++;
11685 break;
11686 }
11687 else if TOML_UNLIKELY (c == '.' || c == '[')
11688 break;
11689 else if (c == '\t' || c == ' ')
11690 pos++;
11691 else
11692 return false;
11693 }
11694
11695 // get array index substring
11696 auto index_str = path.substr(index_start, index_end - index_start);
11697
11698 // parse the actual array index to an integer type
11699 size_t index;
11700 if (index_str.length() == 1u)
11701 index = static_cast<size_t>(index_str[0] - '0');
11702 else
11703 {
11704# if TOML_INT_CHARCONV
11705
11706 auto fc_result = std::from_chars(
11707 index_str.data(), index_str.data() + index_str.length(), index);
11708 if (fc_result.ec != std::errc{})
11709 return false;
11710
11711# else
11712
11713 std::stringstream ss;
11714 ss.imbue(std::locale::classic());
11715 ss.write(
11716 index_str.data(), static_cast<std::streamsize>(index_str.length()));
11717 if (!(ss >> index))
11718 return false;
11719
11720# endif
11721 }
11722
11723 prev_was_dot = false;
11724 prev_was_array_indexer = true;
11725
11726 if (!on_index(data, index))
11727 return false;
11728 }
11729
11730 // start of a new table child
11731 else if (path[pos] == '.')
11732 {
11733 // a dot immediately following another dot (or at the beginning of the string) is as if we'd asked
11734 // for an empty child in between, e.g.
11735 //
11736 // foo..bar
11737 //
11738 // is equivalent to
11739 //
11740 // "foo".""."bar"
11741 //
11742 if (prev_was_dot && !on_key(data, ""sv))
11743 return false;
11744
11745 pos++;
11746 prev_was_dot = true;
11747 prev_was_array_indexer = false;
11748 }
11749
11750 // an errant closing ']'
11751 else if TOML_UNLIKELY (path[pos] == ']')
11752 return false;
11753
11754 // some regular subkey
11755 else
11756 {
11757 const auto subkey_start = pos;
11758 const auto subkey_len =
11759 impl::min(
11760 path.find_first_of(".[]"sv, subkey_start + 1u), path.length()) -
11761 subkey_start;
11762 const auto subkey = path.substr(subkey_start, subkey_len);
11763
11764 // a regular subkey segment immediately after an array indexer is OK if it was all whitespace, e.g.:
11765 //
11766 // "foo[0] .bar"
11767 // ^^ skip this
11768 //
11769 // otherwise its an error (since it would have to be preceeded by a dot)
11770 if (prev_was_array_indexer)
11771 {
11772 auto non_ws = subkey.find_first_not_of(" \t");
11773 if (non_ws == std::string_view::npos)
11774 {
11775 pos += subkey_len;
11776 prev_was_dot = false;
11777 prev_was_array_indexer = false;
11778 continue;
11779 }
11780 else
11781 return false;
11782 }
11783
11784 pos += subkey_len;
11785 prev_was_dot = false;
11786 prev_was_array_indexer = false;
11787
11788 if (!on_key(data, subkey))
11789 return false;
11790 }
11791 }
11792
11793 // Last character was a '.', which implies an empty string key at the end of the path
11794 if (prev_was_dot && !on_key(data, ""sv))
11795 return false;
11796
11797 return true;
11798 }
11799}
11801
11803{
11806 node & root, std::string_view path) noexcept
11807 {
11808 // early-exit sanity-checks
11809 if (root.is_value())
11810 return {};
11811 if (auto tbl = root.as_table(); tbl && tbl->empty())
11812 return {};
11813 if (auto arr = root.as_array(); arr && arr->empty())
11814 return {};
11815
11816 node *current = &root;
11817
11818 static constexpr auto on_key =
11819 [](void *data, std::string_view key) noexcept -> bool
11820 {
11821 auto &curr = *static_cast<node **>(data);
11822 TOML_ASSERT_ASSUME(curr);
11823
11824 const auto current_table = curr->as<table>();
11825 if (!current_table)
11826 return false;
11827
11828 curr = current_table->get(key);
11829 return curr != nullptr;
11830 };
11831
11832 static constexpr auto on_index =
11833 [](void *data, size_t index) noexcept -> bool
11834 {
11835 auto &curr = *static_cast<node **>(data);
11836 TOML_ASSERT_ASSUME(curr);
11837
11838 const auto current_array = curr->as<array>();
11839 if (!current_array)
11840 return false;
11841
11842 curr = current_array->get(index);
11843 return curr != nullptr;
11844 };
11845
11846 if (!impl::parse_path(path, &current, on_key, on_index))
11847 current = nullptr;
11848
11849 return node_view{current};
11850 }
11851
11854 const node &root, std::string_view path) noexcept
11855 {
11856 return node_view<const node>{
11857 at_path(const_cast<node &>(root), path).node()};
11858 }
11859
11860# if TOML_ENABLE_WINDOWS_COMPAT
11861
11863 node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path)
11864 {
11865 // these are the same top-level checks from the narrow-string version;
11866 // they're hoisted up here to avoid doing the wide -> narrow conversion where it would not be necessary
11867 // (avoids an allocation)
11868 if (root.is_value())
11869 return {};
11870 if (auto tbl = root.as_table(); tbl && tbl->empty())
11871 return {};
11872 if (auto arr = root.as_array(); arr && arr->empty())
11873 return {};
11874
11875 return at_path(root, impl::narrow(path));
11876 }
11877
11880 const node &root, std::wstring_view path)
11881 {
11882 return node_view<const node>{
11883 at_path(const_cast<node &>(root), path).node()};
11884 }
11885
11886# endif // TOML_ENABLE_WINDOWS_COMPAT
11887}
11889
11890# ifdef _MSC_VER
11891# pragma pop_macro("min")
11892# pragma pop_macro("max")
11893# ifndef __clang__
11894# pragma inline_recursion(off)
11895# endif
11896# endif
11898
11899//******** impl/path.inl *********************************************************************************************
11900
11902# if TOML_INT_CHARCONV
11903# include <charconv>
11904# endif
11905# include <sstream>
11908# ifdef _MSC_VER
11909# ifndef __clang__
11910# pragma inline_recursion(on)
11911# endif
11912# pragma push_macro("min")
11913# pragma push_macro("max")
11914# undef min
11915# undef max
11916# endif
11917
11919{
11922 : type_{path_component_type::key}
11923 {
11924 store_key("", value_storage_);
11925 }
11926
11928 path_component::path_component(size_t index) noexcept //
11929 : type_(path_component_type::array_index)
11930 {
11931 store_index(index, value_storage_);
11932 }
11933
11935 path_component::path_component(std::string_view key) //
11936 : type_(path_component_type::key)
11937 {
11938 store_key(key, value_storage_);
11939 }
11940
11941# if TOML_ENABLE_WINDOWS_COMPAT
11942
11944 path_component::path_component(std::wstring_view key) //
11945 : path_component(impl::narrow(key))
11946 {
11947 }
11948
11949# endif
11950
11953 : type_{pc.type_}
11954 {
11955 if (type_ == path_component_type::array_index)
11956 store_index(pc.index(), value_storage_);
11957 else
11958 store_key(pc.key(), value_storage_);
11959 }
11960
11963 : type_{pc.type_}
11964 {
11965 if (type_ == path_component_type::array_index)
11966 store_index(pc.index_ref(), value_storage_);
11967 else
11968 store_key(std::move(pc.key_ref()), value_storage_);
11969 }
11970
11973 {
11974 if (type_ != rhs.type_)
11975 {
11976 destroy();
11977
11978 type_ = rhs.type_;
11979 if (type_ == path_component_type::array_index)
11980 store_index(rhs.index(), value_storage_);
11981 else
11982 store_key(rhs.key(), value_storage_);
11983 }
11984 else
11985 {
11986 if (type_ == path_component_type::array_index)
11987 index_ref() = rhs.index();
11988 else
11989 key_ref() = rhs.key();
11990 }
11991 return *this;
11992 }
11993
11996 {
11997 if (type_ != rhs.type_)
11998 {
11999 destroy();
12000
12001 type_ = rhs.type_;
12002 if (type_ == path_component_type::array_index)
12003 store_index(rhs.index(), value_storage_);
12004 else
12005 store_key(std::move(rhs.key_ref()), value_storage_);
12006 }
12007 else
12008 {
12009 if (type_ == path_component_type::array_index)
12010 index_ref() = rhs.index();
12011 else
12012 key_ref() = std::move(rhs.key_ref());
12013 }
12014 return *this;
12015 }
12016
12019 bool TOML_CALLCONV path_component::equal(
12020 const path_component &lhs, const path_component &rhs) noexcept
12021 {
12022 // Different comparison depending on contents
12023 if (lhs.type_ != rhs.type_)
12024 return false;
12025
12026 if (lhs.type_ == path_component_type::array_index)
12027 return lhs.index() == rhs.index();
12028 else // path_component_type::key
12029 return lhs.key() == rhs.key();
12030 }
12031
12033 path_component &path_component::operator=(size_t new_index) noexcept
12034 {
12035 // If currently a key, string will need to be destroyed regardless
12036 destroy();
12037
12038 type_ = path_component_type::array_index;
12039 store_index(new_index, value_storage_);
12040
12041 return *this;
12042 }
12043
12045 path_component &path_component::operator=(std::string_view new_key)
12046 {
12047 if (type_ == path_component_type::key)
12048 key_ref() = new_key;
12049 else
12050 {
12051 type_ = path_component_type::key;
12052 store_key(new_key, value_storage_);
12053 }
12054
12055 return *this;
12056 }
12057
12058# if TOML_ENABLE_WINDOWS_COMPAT
12059
12061 path_component &path_component::operator=(std::wstring_view new_key)
12062 {
12063 if (type_ == path_component_type::key)
12064 key_ref() = impl::narrow(new_key);
12065 else
12066 {
12067 type_ = path_component_type::key;
12068 store_key(impl::narrow(new_key), value_storage_);
12069 }
12070
12071 return *this;
12072 }
12073
12074# endif
12075}
12077
12079{
12081 bool parse_path_into(
12082 std::string_view path_str, std::vector<path_component> & components)
12083 {
12084 using components_type = std::remove_reference_t<decltype(components)>;
12085
12086 const auto original_size = components.size();
12087
12088 static constexpr auto on_key = [](void *data, std::string_view key) -> bool
12089 {
12090 auto &comps = *static_cast<components_type *>(data);
12091 comps.emplace_back(key);
12092 return true;
12093 };
12094
12095 static constexpr auto on_index = [](void *data, size_t index) -> bool
12096 {
12097 auto &comps = *static_cast<components_type *>(data);
12098 comps.emplace_back(index);
12099 return true;
12100 };
12101
12102 if (!impl::parse_path(path_str, &components, on_key, on_index))
12103 {
12104 components.resize(original_size);
12105 return false;
12106 }
12107
12108 return true;
12109 }
12110}
12112
12114{
12116 void path::print_to(std::ostream & os) const
12117 {
12118 bool root = true;
12119 for (const auto &component : components_)
12120 {
12121 if (component.type() == path_component_type::key) // key
12122 {
12123 if (!root)
12124 impl::print_to_stream(os, '.');
12125 impl::print_to_stream(os, component.key());
12126 }
12127 else if (component.type() == path_component_type::array_index) // array
12128 {
12129 impl::print_to_stream(os, '[');
12130 impl::print_to_stream(os, component.index());
12131 impl::print_to_stream(os, ']');
12132 }
12133 root = false;
12134 }
12135 }
12136
12139 bool TOML_CALLCONV path::equal(const path &lhs, const path &rhs) noexcept
12140 {
12141 return lhs.components_ == rhs.components_;
12142 }
12143
12145 path::path(std::string_view str) //
12146 {
12147 TOML_ANON_NAMESPACE::parse_path_into(str, components_);
12148 }
12149
12150# if TOML_ENABLE_WINDOWS_COMPAT
12151
12153 path::path(std::wstring_view str) //
12154 : path(impl::narrow(str))
12155 {
12156 }
12157
12158# endif
12159
12161 path &path::operator=(std::string_view rhs)
12162 {
12163 components_.clear();
12164 TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
12165 return *this;
12166 }
12167
12168# if TOML_ENABLE_WINDOWS_COMPAT
12169
12171 path &path::operator=(std::wstring_view rhs)
12172 {
12173 return assign(impl::narrow(rhs));
12174 }
12175
12176# endif
12177
12179 path &path::operator+=(const path &rhs)
12180 {
12181 components_.insert(components_.cend(), rhs.begin(), rhs.end());
12182 return *this;
12183 }
12184
12186 path &path::operator+=(path &&rhs)
12187 {
12188 components_.insert(
12189 components_.end(),
12190 std::make_move_iterator(rhs.components_.begin()),
12191 std::make_move_iterator(rhs.components_.end()));
12192 return *this;
12193 }
12194
12196 path &path::operator+=(std::string_view str)
12197 {
12198 TOML_ANON_NAMESPACE::parse_path_into(str, components_);
12199 return *this;
12200 }
12201
12202# if TOML_ENABLE_WINDOWS_COMPAT
12203
12205 path &path::operator+=(std::wstring_view str)
12206 {
12207 return *this += impl::narrow(str);
12208 }
12209
12210# endif
12211
12213 path &path::prepend(const path &source)
12214 {
12215 components_.insert(
12216 components_.begin(),
12217 source.components_.begin(),
12218 source.components_.end());
12219 return *this;
12220 }
12221
12223 path &path::prepend(path && source)
12224 {
12225 components_.insert(
12226 components_.begin(),
12227 std::make_move_iterator(source.components_.begin()),
12228 std::make_move_iterator(source.components_.end()));
12229 return *this;
12230 }
12231
12233 path &path::prepend(std::string_view source)
12234 {
12235 return prepend(path{source});
12236 }
12237
12238# if TOML_ENABLE_WINDOWS_COMPAT
12239
12241 path &path::prepend(std::wstring_view source)
12242 {
12243 return prepend(impl::narrow(source));
12244 }
12245
12246# endif
12247
12249 std::string path::str() const
12250 {
12251 if (empty())
12252 return "";
12253
12254 std::ostringstream ss;
12255 print_to(ss);
12256 return std::move(ss).str();
12257 }
12258
12259# if TOML_ENABLE_WINDOWS_COMPAT
12260
12262 std::wstring path::wide_str() const
12263 {
12264 return impl::widen(str());
12265 }
12266
12267# endif
12268
12270 void path::clear() noexcept
12271 {
12272 components_.clear();
12273 }
12274
12276 path &path::truncate(size_t n)
12277 {
12278 n = n > components_.size() ? components_.size() : n;
12279
12280 auto it_end = components_.end();
12281 components_.erase(it_end - static_cast<int>(n), it_end);
12282
12283 return *this;
12284 }
12285
12287 path path::truncated(size_t n) const
12288 {
12289 path truncated_path{};
12290
12291 n = n > components_.size() ? components_.size() : n;
12292
12293 // Copy all components except one
12294 // Need at least two path components to have a parent, since if there is
12295 // only one path component, the parent is the root/null path ""
12296 truncated_path.components_.insert(
12297 truncated_path.components_.begin(),
12298 components_.begin(),
12299 components_.end() - static_cast<int>(n));
12300
12301 return truncated_path;
12302 }
12303
12305 path path::parent() const
12306 {
12307 return truncated(1);
12308 }
12309
12311 path path::leaf(size_t n) const
12312 {
12313 path leaf_path{};
12314
12315 n = n > components_.size() ? components_.size() : n;
12316
12317 if (n > 0)
12318 {
12319 leaf_path.components_.insert(
12320 leaf_path.components_.begin(),
12321 components_.end() - static_cast<int>(n),
12322 components_.end());
12323 }
12324
12325 return leaf_path;
12326 }
12327
12330 std::vector<path_component>::const_iterator start,
12331 std::vector<path_component>::const_iterator end) const
12332 {
12333 if (start >= end)
12334 return {};
12335
12336 path subpath;
12337 subpath.components_.insert(subpath.components_.begin(), start, end);
12338 return subpath;
12339 }
12340
12342 path path::subpath(size_t start, size_t length) const
12343 {
12344 return subpath(
12345 begin() + static_cast<int>(start),
12346 begin() + static_cast<int>(start + length));
12347 }
12348}
12350
12352{
12355 node & root, const toml::path &path) noexcept
12356 {
12357 // early-exit sanity-checks
12358 if (root.is_value())
12359 return {};
12360 if (auto tbl = root.as_table(); tbl && tbl->empty())
12361 return {};
12362 if (auto arr = root.as_array(); arr && arr->empty())
12363 return {};
12364
12365 node *current = &root;
12366
12367 for (const auto &component : path)
12368 {
12369 auto type = component.type();
12370 if (type == path_component_type::array_index)
12371 {
12372 const auto current_array = current->as<array>();
12373 if (!current_array)
12374 return {}; // not an array, using array index doesn't work
12375
12376 current = current_array->get(component.index());
12377 }
12378 else if (type == path_component_type::key)
12379 {
12380 const auto current_table = current->as<table>();
12381 if (!current_table)
12382 return {};
12383
12384 current = current_table->get(component.key());
12385 }
12386 else
12387 {
12388 // Error: invalid component
12389 return {};
12390 }
12391
12392 if (!current)
12393 return {}; // not found
12394 }
12395
12396 return node_view{current};
12397 }
12398
12401 const node &root, const toml::path &path) noexcept
12402 {
12403 return node_view<const node>{
12404 at_path(const_cast<node &>(root), path).node()};
12405 }
12406}
12408
12409# ifdef _MSC_VER
12410# pragma pop_macro("min")
12411# pragma pop_macro("max")
12412# ifndef __clang__
12413# pragma inline_recursion(off)
12414# endif
12415# endif
12417
12418//******** impl/array.inl ********************************************************************************************
12419
12421# ifdef _MSC_VER
12422# ifndef __clang__
12423# pragma inline_recursion(on)
12424# endif
12425# pragma push_macro("min")
12426# pragma push_macro("max")
12427# undef min
12428# undef max
12429# endif
12430
12432{
12434 array::array() noexcept
12435 {
12436# if TOML_LIFETIME_HOOKS
12437 TOML_ARRAY_CREATED;
12438# endif
12439 }
12440
12442 array::~array() noexcept
12443 {
12444# if TOML_LIFETIME_HOOKS
12445 TOML_ARRAY_DESTROYED;
12446# endif
12447 }
12448
12450 array::array(const impl::array_init_elem *b, const impl::array_init_elem *e)
12451 {
12452# if TOML_LIFETIME_HOOKS
12453 TOML_ARRAY_CREATED;
12454# endif
12455
12458 TOML_ASSERT_ASSUME(b <= e);
12459
12460 if TOML_UNLIKELY (b == e)
12461 return;
12462
12463 size_t cap{};
12464 for (auto it = b; it != e; it++)
12465 {
12466 if (it->value)
12467 cap++;
12468 }
12469 if TOML_UNLIKELY (!cap)
12470 return;
12471
12472 elems_.reserve(cap);
12473 for (; b != e; b++)
12474 {
12475 if (b->value)
12476 elems_.push_back(std::move(b->value));
12477 }
12478 }
12479
12481 array::array(const array &other) //
12482 : node(other)
12483 {
12484 elems_.reserve(other.elems_.size());
12485 for (const auto &elem : other)
12486 elems_.emplace_back(impl::make_node(elem));
12487
12489 TOML_ARRAY_CREATED;
12490# endif
12491 }
12492
12494 array::array(array && other) noexcept //
12495 : node(std::move(other)), elems_(std::move(other.elems_))
12496 {
12497# if TOML_LIFETIME_HOOKS
12498 TOML_ARRAY_CREATED;
12499# endif
12500 }
12501
12503 array &array::operator=(const array &rhs)
12504 {
12505 if (&rhs != this)
12506 {
12507 node::operator=(rhs);
12508 elems_.clear();
12509 elems_.reserve(rhs.elems_.size());
12510 for (const auto &elem : rhs)
12511 elems_.emplace_back(impl::make_node(elem));
12512 }
12513 return *this;
12514 }
12515
12517 array &array::operator=(array &&rhs) noexcept
12518 {
12519 if (&rhs != this)
12520 {
12521 node::operator=(std::move(rhs));
12522 elems_ = std::move(rhs.elems_);
12523 }
12524 return *this;
12525 }
12526
12528 void array::preinsertion_resize(size_t idx, size_t count)
12529 {
12530 TOML_ASSERT(idx <= elems_.size());
12532 const auto old_size = elems_.size();
12533 const auto new_size = old_size + count;
12534 const auto inserting_at_end = idx == old_size;
12535 elems_.resize(new_size);
12536 if (!inserting_at_end)
12537 {
12538 for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
12539 elems_[right] = std::move(elems_[left]);
12540 }
12541 }
12542
12544 void array::insert_at_back(impl::node_ptr && elem)
12545 {
12546 TOML_ASSERT(elem);
12547 elems_.push_back(std::move(elem));
12548 }
12549
12551 array::vector_iterator array::insert_at(
12552 const_vector_iterator pos, impl::node_ptr && elem)
12553 {
12554 return elems_.insert(pos, std::move(elem));
12555 }
12556
12559 bool array::is_homogeneous(node_type ntype) const noexcept
12560 {
12561 if (elems_.empty())
12562 return false;
12563
12564 if (ntype == node_type::none)
12565 ntype = elems_[0]->type();
12566
12567 for (const auto &val : elems_)
12568 if (val->type() != ntype)
12569 return false;
12570
12571 return true;
12572 }
12573
12576 bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
12577 {
12578 if (elems_.empty())
12579 {
12580 first_nonmatch = {};
12581 return false;
12582 }
12583 if (ntype == node_type::none)
12584 ntype = elems_[0]->type();
12585 for (const auto &val : elems_)
12586 {
12587 if (val->type() != ntype)
12588 {
12589 first_nonmatch = val.get();
12590 return false;
12591 }
12592 }
12593 return true;
12594 }
12595
12598 bool array::is_homogeneous(node_type ntype, const node *&first_nonmatch)
12599 const noexcept
12600 {
12601 node *fnm = nullptr;
12602 const auto result = const_cast<array &>(*this).is_homogeneous(ntype, fnm);
12603 first_nonmatch = fnm;
12604 return result;
12605 }
12606
12608 node &array::at(size_t index)
12609 {
12610# if TOML_COMPILER_HAS_EXCEPTIONS
12611
12612 return *elems_.at(index);
12613
12614# else
12615
12616 auto n = get(index);
12617 TOML_ASSERT_ASSUME(n && "element index not found in array!");
12618 return *n;
12619
12620# endif
12621 }
12622
12624 void array::reserve(size_t new_capacity)
12625 {
12626 elems_.reserve(new_capacity);
12627 }
12628
12631 {
12632 elems_.shrink_to_fit();
12633 }
12634
12636 void array::truncate(size_t new_size)
12637 {
12638 if (new_size < elems_.size())
12639 elems_.resize(new_size);
12640 }
12641
12643 array::iterator array::erase(const_iterator pos) noexcept
12644 {
12645 return iterator{elems_.erase(const_vector_iterator{pos})};
12646 }
12647
12650 const_iterator first, const_iterator last) noexcept
12651 {
12652 return iterator{
12653 elems_.erase(const_vector_iterator{first}, const_vector_iterator{last})};
12654 }
12655
12657 size_t array::total_leaf_count() const noexcept
12658 {
12659 size_t leaves{};
12660 for (size_t i = 0, e = elems_.size(); i < e; i++)
12661 {
12662 auto arr = elems_[i]->as_array();
12663 leaves += arr ? arr->total_leaf_count() : size_t{1};
12664 }
12665 return leaves;
12666 }
12667
12669 void array::flatten_child(array && child, size_t & dest_index) noexcept
12670 {
12671 for (size_t i = 0, e = child.size(); i < e; i++)
12672 {
12673 auto type = child.elems_[i]->type();
12674 if (type == node_type::array)
12675 {
12676 array &arr = *reinterpret_cast<array *>(child.elems_[i].get());
12677 if (!arr.empty())
12678 flatten_child(std::move(arr), dest_index);
12679 }
12680 else
12681 elems_[dest_index++] = std::move(child.elems_[i]);
12682 }
12683 }
12684
12687 {
12688 if (elems_.empty())
12689 return *this;
12690
12691 bool requires_flattening = false;
12692 size_t size_after_flattening = elems_.size();
12693 for (size_t i = elems_.size(); i-- > 0u;)
12694 {
12695 auto arr = elems_[i]->as_array();
12696 if (!arr)
12697 continue;
12698 size_after_flattening--; // discount the array itself
12699 const auto leaf_count = arr->total_leaf_count();
12700 if (leaf_count > 0u)
12701 {
12702 requires_flattening = true;
12703 size_after_flattening += leaf_count;
12704 }
12705 else
12706 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
12707 }
12708
12709 if (!requires_flattening)
12710 return *this;
12711
12712 elems_.reserve(size_after_flattening);
12713
12714 size_t i = 0;
12715 while (i < elems_.size())
12716 {
12717 auto arr = elems_[i]->as_array();
12718 if (!arr)
12719 {
12720 i++;
12721 continue;
12722 }
12723
12724 impl::node_ptr arr_storage = std::move(elems_[i]);
12725 const auto leaf_count = arr->total_leaf_count();
12726 if (leaf_count > 1u)
12727 preinsertion_resize(i + 1u, leaf_count - 1u);
12728 flatten_child(std::move(*arr), i); // increments i
12729 }
12730
12731 return *this;
12732 }
12733
12735 array &array::prune(bool recursive) &noexcept
12736 {
12737 if (elems_.empty())
12738 return *this;
12739
12740 for (size_t i = elems_.size(); i-- > 0u;)
12741 {
12742 if (auto arr = elems_[i]->as_array())
12743 {
12744 if (recursive)
12745 arr->prune(true);
12746 if (arr->empty())
12747 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
12748 }
12749 else if (auto tbl = elems_[i]->as_table())
12750 {
12751 if (recursive)
12752 tbl->prune(true);
12753 if (tbl->empty())
12754 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
12755 }
12756 }
12757
12758 return *this;
12759 }
12760
12762 void array::pop_back() noexcept
12763 {
12764 elems_.pop_back();
12765 }
12766
12768 void array::clear() noexcept
12769 {
12770 elems_.clear();
12771 }
12772
12774 bool TOML_CALLCONV array::equal(const array &lhs, const array &rhs) noexcept
12775 {
12776 if (&lhs == &rhs)
12777 return true;
12778 if (lhs.elems_.size() != rhs.elems_.size())
12779 return false;
12780 for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
12781 {
12782 const auto lhs_type = lhs.elems_[i]->type();
12783 const node &rhs_ = *rhs.elems_[i];
12784 const auto rhs_type = rhs_.type();
12785 if (lhs_type != rhs_type)
12786 return false;
12787
12788 const bool equal = lhs.elems_[i]->visit(
12789 [&](const auto &lhs_) noexcept
12790 {
12791 return lhs_ ==
12792 *reinterpret_cast<std::remove_reference_t<decltype(lhs_)> *>(
12793 &rhs_);
12794 });
12795 if (!equal)
12796 return false;
12797 }
12798 return true;
12799 }
12800}
12802
12803# ifdef _MSC_VER
12804# pragma pop_macro("min")
12805# pragma pop_macro("max")
12806# ifndef __clang__
12807# pragma inline_recursion(off)
12808# endif
12809# endif
12811
12812//******** impl/table.inl ********************************************************************************************
12813
12815# ifdef _MSC_VER
12816# ifndef __clang__
12817# pragma inline_recursion(on)
12818# endif
12819# pragma push_macro("min")
12820# pragma push_macro("max")
12821# undef min
12822# undef max
12823# endif
12824
12826{
12828 table::table() noexcept
12829 {
12830# if TOML_LIFETIME_HOOKS
12831 TOML_TABLE_CREATED;
12832# endif
12833 }
12834
12836 table::~table() noexcept
12837 {
12838# if TOML_LIFETIME_HOOKS
12839 TOML_TABLE_DESTROYED;
12840# endif
12841 }
12842
12844 table::table(const impl::table_init_pair *b, const impl::table_init_pair *e)
12845 {
12846# if TOML_LIFETIME_HOOKS
12847 TOML_TABLE_CREATED;
12848# endif
12849
12852 TOML_ASSERT_ASSUME(b <= e);
12853
12854 if TOML_UNLIKELY (b == e)
12855 return;
12856
12857 for (; b != e; b++)
12858 {
12859 if (!b->value) // empty node_views
12860 continue;
12861
12862 map_.insert_or_assign(std::move(b->key), std::move(b->value));
12863 }
12864 }
12865
12867 table::table(const table &other) //
12868 : node(other), inline_{other.inline_}
12869 {
12870 for (auto &&[k, v] : other.map_)
12871 map_.emplace_hint(map_.end(), k, impl::make_node(*v));
12872
12874 TOML_TABLE_CREATED;
12875# endif
12876 }
12877
12879 table::table(table && other) noexcept //
12880 : node(std::move(other)),
12881 map_{std::move(other.map_)},
12882 inline_{other.inline_}
12883 {
12884# if TOML_LIFETIME_HOOKS
12885 TOML_TABLE_CREATED;
12886# endif
12887 }
12888
12890 table &table::operator=(const table &rhs)
12891 {
12892 if (&rhs != this)
12893 {
12894 node::operator=(rhs);
12895 map_.clear();
12896 for (auto &&[k, v] : rhs.map_)
12897 map_.emplace_hint(map_.end(), k, impl::make_node(*v));
12898 inline_ = rhs.inline_;
12899 }
12900 return *this;
12901 }
12902
12904 table &table::operator=(table &&rhs) noexcept
12905 {
12906 if (&rhs != this)
12907 {
12908 node::operator=(std::move(rhs));
12909 map_ = std::move(rhs.map_);
12910 inline_ = rhs.inline_;
12911 }
12912 return *this;
12913 }
12914
12917 bool table::is_homogeneous(node_type ntype) const noexcept
12918 {
12919 if (map_.empty())
12920 return false;
12921
12922 if (ntype == node_type::none)
12923 ntype = map_.cbegin()->second->type();
12924
12925 for (auto &&[k, v] : map_)
12926 {
12927 TOML_UNUSED(k);
12928 if (v->type() != ntype)
12929 return false;
12930 }
12931
12932 return true;
12933 }
12934
12937 bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
12938 {
12939 if (map_.empty())
12940 {
12941 first_nonmatch = {};
12942 return false;
12943 }
12944 if (ntype == node_type::none)
12945 ntype = map_.cbegin()->second->type();
12946 for (const auto &[k, v] : map_)
12947 {
12948 TOML_UNUSED(k);
12949 if (v->type() != ntype)
12950 {
12951 first_nonmatch = v.get();
12952 return false;
12953 }
12954 }
12955 return true;
12956 }
12957
12960 bool table::is_homogeneous(node_type ntype, const node *&first_nonmatch)
12961 const noexcept
12962 {
12963 node *fnm = nullptr;
12964 const auto result = const_cast<table &>(*this).is_homogeneous(ntype, fnm);
12965 first_nonmatch = fnm;
12966 return result;
12967 }
12968
12971 node *table::get(std::string_view key) noexcept
12972 {
12973 if (auto it = map_.find(key); it != map_.end())
12974 return it->second.get();
12975 return nullptr;
12976 }
12977
12979 node &table::at(std::string_view key)
12980 {
12981 auto n = get(key);
12982
12983# if TOML_COMPILER_HAS_EXCEPTIONS
12984
12985 if (!n)
12986 {
12987 auto err = "key '"s;
12988 err.append(key);
12989 err.append("' not found in table"sv);
12990 throw std::out_of_range{err};
12991 }
12992
12993# else
12994
12995 TOML_ASSERT_ASSUME(n && "key not found in table!");
12996
12997# endif
12998
12999 return *n;
13000 }
13001
13004 table::map_iterator table::get_lower_bound(std::string_view key) noexcept
13005 {
13006 return map_.lower_bound(key);
13007 }
13008
13011 table::iterator table::find(std::string_view key) noexcept
13012 {
13013 return iterator{map_.find(key)};
13014 }
13015
13018 table::const_iterator table::find(std::string_view key) const noexcept
13019 {
13020 return const_iterator{map_.find(key)};
13021 }
13022
13024 table::map_iterator table::erase(const_map_iterator pos) noexcept
13025 {
13026 return map_.erase(pos);
13027 }
13028
13030 table::map_iterator table::erase(
13031 const_map_iterator begin, const_map_iterator end) noexcept
13032 {
13033 return map_.erase(begin, end);
13034 }
13035
13037 size_t table::erase(std::string_view key) noexcept
13038 {
13039 if (auto it = map_.find(key); it != map_.end())
13040 {
13041 map_.erase(it);
13042 return size_t{1};
13043 }
13044 return size_t{};
13045 }
13046
13048 table &table::prune(bool recursive) &noexcept
13049 {
13050 if (map_.empty())
13051 return *this;
13052
13053 for (auto it = map_.begin(); it != map_.end();)
13054 {
13055 if (auto arr = it->second->as_array())
13056 {
13057 if (recursive)
13058 arr->prune(true);
13059
13060 if (arr->empty())
13061 {
13062 it = map_.erase(it);
13063 continue;
13064 }
13065 }
13066 else if (auto tbl = it->second->as_table())
13067 {
13068 if (recursive)
13069 tbl->prune(true);
13070
13071 if (tbl->empty())
13072 {
13073 it = map_.erase(it);
13074 continue;
13075 }
13076 }
13077 it++;
13078 }
13079
13080 return *this;
13081 }
13082
13084 void table::clear() noexcept
13085 {
13086 map_.clear();
13087 }
13088
13090 table::map_iterator table::insert_with_hint(
13091 const_iterator hint, key && k, impl::node_ptr && v)
13092 {
13093 return map_.emplace_hint(
13094 const_map_iterator{hint}, std::move(k), std::move(v));
13095 }
13096
13099 bool TOML_CALLCONV table::equal(const table &lhs, const table &rhs) noexcept
13100 {
13101 if (&lhs == &rhs)
13102 return true;
13103 if (lhs.map_.size() != rhs.map_.size())
13104 return false;
13105
13106 for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end();
13107 l != e;
13108 l++, r++)
13109 {
13110 if (l->first != r->first)
13111 return false;
13112
13113 const auto lhs_type = l->second->type();
13114 const node &rhs_ = *r->second;
13115 const auto rhs_type = rhs_.type();
13116 if (lhs_type != rhs_type)
13117 return false;
13118
13119 const bool equal = l->second->visit(
13120 [&](const auto &lhs_) noexcept
13121 {
13122 return lhs_ ==
13123 *reinterpret_cast<std::remove_reference_t<decltype(lhs_)> *>(
13124 &rhs_);
13125 });
13126 if (!equal)
13127 return false;
13128 }
13129 return true;
13130 }
13131}
13133
13134# ifdef _MSC_VER
13135# pragma pop_macro("min")
13136# pragma pop_macro("max")
13137# ifndef __clang__
13138# pragma inline_recursion(off)
13139# endif
13140# endif
13142
13143//******** impl/simd.hpp *********************************************************************************************
13144
13145# if TOML_ENABLE_SIMD
13146
13147# if defined(__SSE2__) || \
13148 (defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || \
13149 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))
13150# define TOML_HAS_SSE2 1
13151# endif
13152
13153# if defined(__SSE4_1__) || \
13154 (defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__)))
13155# define TOML_HAS_SSE4_1 1
13156# endif
13157
13158# endif // TOML_ENABLE_SIMD
13159
13160# ifndef TOML_HAS_SSE2
13161# define TOML_HAS_SSE2 0
13162# endif
13163# ifndef TOML_HAS_SSE4_1
13164# define TOML_HAS_SSE4_1 0
13165# endif
13166
13168# if TOML_HAS_SSE4_1
13169# include <smmintrin.h>
13170# endif
13171# if TOML_HAS_SSE2
13172# include <emmintrin.h>
13173# endif
13175
13176//******** impl/unicode.inl ******************************************************************************************
13177
13179# ifdef _MSC_VER
13180# ifndef __clang__
13181# pragma inline_recursion(on)
13182# endif
13183# pragma push_macro("min")
13184# pragma push_macro("max")
13185# undef min
13186# undef max
13187# endif
13188
13190{
13193 bool is_ascii(const char *str, size_t len) noexcept
13194 {
13195 const char *const end = str + len;
13196
13197# if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
13198 {
13199 constexpr size_t chars_per_vector = 128u / CHAR_BIT;
13200
13201 if (const size_t simdable = len - (len % chars_per_vector))
13202 {
13203 __m128i mask = _mm_setzero_si128();
13204 for (const char *const e = str + simdable; str < e;
13205 str += chars_per_vector)
13206 {
13207 const __m128i current_bytes =
13208 _mm_loadu_si128(reinterpret_cast<const __m128i *>(str));
13209 mask = _mm_or_si128(mask, current_bytes);
13210 }
13211 const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
13212
13213# if TOML_HAS_SSE4_1
13214 if (!_mm_testz_si128(has_error, has_error))
13215 return false;
13216# else
13217 if (
13218 _mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) !=
13219 0xFFFF)
13220 return false;
13221# endif
13222 }
13223 }
13224# endif
13225
13226 for (; str < end; str++)
13227 if (static_cast<unsigned char>(*str) > 127u)
13228 return false;
13229
13230 return true;
13231 }
13232}
13234
13235# ifdef _MSC_VER
13236# pragma pop_macro("min")
13237# pragma pop_macro("max")
13238# ifndef __clang__
13239# pragma inline_recursion(off)
13240# endif
13241# endif
13243
13244//******** impl/parser.inl *******************************************************************************************
13245
13246# if TOML_ENABLE_PARSER
13247
13249# include <istream>
13250# include <fstream>
13251# if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
13252# include <charconv>
13253# endif
13254# if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
13255# include <sstream>
13256# endif
13257# if !TOML_INT_CHARCONV
13258# include <iomanip>
13259# endif
13262# ifdef _MSC_VER
13263# ifndef __clang__
13264# pragma inline_recursion(on)
13265# endif
13266# pragma push_macro("min")
13267# pragma push_macro("max")
13268# undef min
13269# undef max
13270# endif
13271
13273{
13274 template <typename T>
13275 class utf8_byte_stream;
13276
13278 constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
13279
13280 template <typename Char>
13281 class utf8_byte_stream<std::basic_string_view<Char>>
13282 {
13283 static_assert(sizeof(Char) == 1);
13284
13285 private:
13286 std::basic_string_view<Char> source_;
13287 size_t position_ = {};
13288
13289 public:
13291 explicit constexpr utf8_byte_stream(
13292 std::basic_string_view<Char> sv) noexcept //
13293 : source_{sv}
13294 {
13295 // skip bom
13296 if (
13297 source_.length() >= 3u &&
13298 memcmp(utf8_byte_order_mark.data(), source_.data(), 3u) == 0)
13299 position_ += 3u;
13300 }
13301
13303 constexpr bool error() const noexcept
13304 {
13305 return false;
13306 }
13307
13309 constexpr bool eof() const noexcept
13310 {
13311 return position_ >= source_.length();
13312 }
13313
13315 explicit constexpr operator bool() const noexcept
13316 {
13317 return !eof();
13318 }
13319
13321 constexpr bool peek_eof() const noexcept
13322 {
13323 return eof();
13324 }
13325
13327 TOML_ATTR(nonnull)
13328 size_t operator()(void *dest, size_t num) noexcept
13329 {
13331
13332 num = impl::min(position_ + num, source_.length()) - position_;
13333 std::memcpy(dest, source_.data() + position_, num);
13334 position_ += num;
13335 return num;
13336 }
13337 };
13338
13339 template <>
13340 class utf8_byte_stream<std::istream>
13341 {
13342 private:
13343 std::istream *source_;
13344
13345 public:
13347 explicit utf8_byte_stream(std::istream &stream) noexcept(
13349 : source_{&stream}
13350 {
13351 if (!*this) // eof, bad
13352 return;
13353
13354 const auto initial_pos = source_->tellg();
13355 char bom[3];
13356 source_->read(bom, 3);
13357 if (
13358 source_->bad() || (source_->gcount() == 3 &&
13359 memcmp(utf8_byte_order_mark.data(), bom, 3u) == 0))
13360 return;
13361
13362 source_->clear();
13363 source_->seekg(initial_pos, std::istream::beg);
13364 }
13365
13367 bool error() const noexcept
13368 {
13369 return !!(source_->rdstate() & std::istream::badbit);
13370 }
13371
13373 bool eof() const noexcept
13374 {
13375 return !!(source_->rdstate() & std::istream::eofbit);
13376 }
13377
13379 explicit operator bool() const noexcept
13380 {
13381 return !(
13382 source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
13383 }
13384
13387 {
13388 return eof() || source_->peek() == std::istream::traits_type::eof();
13389 }
13390
13392 TOML_ATTR(nonnull)
13393 size_t
13394 operator()(void *dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
13395 {
13396 TOML_ASSERT(*this);
13397
13398 source_->read(
13399 static_cast<char *>(dest), static_cast<std::streamsize>(num));
13400 return static_cast<size_t>(source_->gcount());
13401 }
13402 };
13403
13405 {
13406 char32_t value;
13407 char bytes[4];
13408 size_t count;
13410
13412 constexpr operator const char32_t &() const noexcept
13413 {
13414 return value;
13415 }
13416
13418 constexpr const char32_t &operator*() const noexcept
13419 {
13420 return value;
13421 }
13422 };
13423 static_assert(std::is_trivial_v<utf8_codepoint>);
13424 static_assert(std::is_standard_layout_v<utf8_codepoint>);
13425
13427 {
13429 virtual const source_path_ptr &source_path() const noexcept = 0;
13430
13432 virtual const utf8_codepoint *
13434
13436 virtual bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
13437
13438# if !TOML_EXCEPTIONS
13439
13441 virtual optional<parse_error> &&error() noexcept = 0;
13442
13443# endif
13444
13445 virtual ~utf8_reader_interface() noexcept = default;
13446 };
13447
13448# if TOML_EXCEPTIONS
13449# define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
13450# define utf8_reader_return_after_error(...) static_assert(true)
13451# define utf8_reader_error_check(...) static_assert(true)
13452# else
13453# define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
13454# define utf8_reader_return_after_error(...) return __VA_ARGS__
13455# define utf8_reader_error_check(...) \
13456 do \
13457 { \
13458 if TOML_UNLIKELY (err_) \
13459 return __VA_ARGS__; \
13460 } while (false)
13461
13462# endif
13463
13464# if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
13465# define TOML_OVERALIGNED
13466# else
13467# define TOML_OVERALIGNED alignas(32)
13468# endif
13469
13470 template <typename T>
13472 {
13473 private:
13474 static constexpr size_t block_capacity = 32;
13475 utf8_byte_stream<T> stream_;
13476 source_position next_pos_ = {1, 1};
13477
13478 impl::utf8_decoder decoder_;
13479 struct currently_decoding_t
13480 {
13481 char bytes[4];
13482 size_t count;
13483 } currently_decoding_;
13484
13485 struct codepoints_t
13486 {
13487 TOML_OVERALIGNED utf8_codepoint buffer[block_capacity];
13488 size_t current;
13489 size_t count;
13490 } codepoints_;
13491
13492 source_path_ptr source_path_;
13493
13494# if !TOML_EXCEPTIONS
13495 optional<parse_error> err_;
13496# endif
13497
13498 bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
13499 {
13500 TOML_ASSERT(stream_);
13501
13502 TOML_OVERALIGNED char raw_bytes[block_capacity];
13503 size_t raw_bytes_read;
13504
13505 // read the next raw (encoded) block in from the stream
13506 if constexpr (
13507 noexcept(stream_(raw_bytes, block_capacity)) || !TOML_EXCEPTIONS)
13508 {
13509 raw_bytes_read = stream_(raw_bytes, block_capacity);
13510 }
13511# if TOML_EXCEPTIONS
13512 else
13513 {
13514 try
13515 {
13516 raw_bytes_read = stream_(raw_bytes, block_capacity);
13517 }
13518 catch (const std::exception &exc)
13519 {
13520 throw parse_error{exc.what(), next_pos_, source_path_};
13521 }
13522 catch (...)
13523 {
13524 throw parse_error{
13525 "An unspecified error occurred", next_pos_, source_path_};
13526 }
13527 }
13528# endif // TOML_EXCEPTIONS
13529
13530 // handle a zero-byte read
13531 if TOML_UNLIKELY (!raw_bytes_read)
13532 {
13533 if (stream_.eof())
13534 {
13535 // EOF only sets the error state if the decoder wants more input, otherwise
13536 // a zero-byte read might have just caused the underlying stream to realize it's exhaused and set
13537 // the EOF flag, and that's totally fine
13538 if (decoder_.needs_more_input())
13540 "Encountered EOF during incomplete utf-8 code point sequence",
13541 next_pos_,
13542 source_path_);
13543 }
13544 else
13545 {
13547 "Reading from the underlying stream failed - zero bytes read",
13548 next_pos_,
13549 source_path_);
13550 }
13551 return false;
13552 }
13553
13554 TOML_ASSERT_ASSUME(raw_bytes_read);
13555 std::memset(&codepoints_, 0, sizeof(codepoints_));
13556
13557 // helper for calculating decoded codepoint line+cols
13558 const auto calc_positions = [&]() noexcept
13559 {
13560 for (size_t i = 0; i < codepoints_.count; i++)
13561 {
13562 auto &cp = codepoints_.buffer[i];
13563 cp.position = next_pos_;
13564
13565 if (cp == U'\n')
13566 {
13567 next_pos_.line++;
13568 next_pos_.column = source_index{1};
13569 }
13570 else
13571 next_pos_.column++;
13572 }
13573 };
13574
13575 // decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
13576 const auto ascii_fast_path = !decoder_.needs_more_input() &&
13577 impl::is_ascii(raw_bytes, raw_bytes_read);
13578
13579 // ASCII fast-path
13580 if (ascii_fast_path)
13581 {
13582 decoder_.reset();
13583 currently_decoding_.count = {};
13584
13585 codepoints_.count = raw_bytes_read;
13586 for (size_t i = 0; i < codepoints_.count; i++)
13587 {
13588 auto &cp = codepoints_.buffer[i];
13589 cp.value = static_cast<char32_t>(raw_bytes[i]);
13590 cp.bytes[0] = raw_bytes[i];
13591 cp.count = 1u;
13592 }
13593 }
13594
13595 // UTF-8 slow-path
13596 else
13597 {
13598 // helper for getting precise error location
13599 const auto error_pos = [&]() noexcept -> const source_position &
13600 { //
13601 return codepoints_.count
13602 ? codepoints_.buffer[codepoints_.count - 1u].position
13603 : next_pos_;
13604 };
13605
13606 for (size_t i = 0; i < raw_bytes_read; i++)
13607 {
13608 decoder_(static_cast<uint8_t>(raw_bytes[i]));
13609 if TOML_UNLIKELY (decoder_.error())
13610 {
13611 calc_positions();
13613 "Encountered invalid utf-8 sequence", error_pos(), source_path_);
13615 }
13616
13617 currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];
13618
13619 if (decoder_.has_code_point())
13620 {
13621 auto &cp = codepoints_.buffer[codepoints_.count++];
13622
13623 cp.value = decoder_.codepoint;
13624 cp.count = currently_decoding_.count;
13625 std::memcpy(
13626 cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
13627 currently_decoding_.count = {};
13628 }
13629 else if TOML_UNLIKELY (currently_decoding_.count == 4u)
13630 {
13631 calc_positions();
13633 "Encountered overlong utf-8 sequence", error_pos(), source_path_);
13635 }
13636 }
13637 if TOML_UNLIKELY (decoder_.needs_more_input() && stream_.eof())
13638 {
13639 calc_positions();
13641 "Encountered EOF during incomplete utf-8 code point sequence",
13642 error_pos(),
13643 source_path_);
13645 }
13646 }
13647
13648 TOML_ASSERT_ASSUME(codepoints_.count);
13649 calc_positions();
13650
13651 // handle general I/O errors
13652 // (down here so the next_pos_ benefits from calc_positions())
13653 if TOML_UNLIKELY (stream_.error())
13654 {
13656 "An I/O error occurred while reading from the underlying stream",
13657 next_pos_,
13658 source_path_);
13660 }
13661
13662 return true;
13663 }
13664
13665 public:
13666 template <typename U, typename String = std::string_view>
13668 U &&source,
13669 String &&source_path =
13670 {}) noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U &&>)
13671 : stream_{static_cast<U &&>(source)}
13672 {
13673 currently_decoding_.count = {};
13674
13675 codepoints_.current = {};
13676 codepoints_.count = {};
13677
13678 if (!source_path.empty())
13679 source_path_ = std::make_shared<const std::string>(
13680 static_cast<String &&>(source_path));
13681 }
13682
13684 const source_path_ptr &source_path() const noexcept final
13685 {
13686 return source_path_;
13687 }
13688
13690 const utf8_codepoint *
13692 {
13694
13695 if (codepoints_.current == codepoints_.count)
13696 {
13697 if TOML_UNLIKELY (!stream_ || !read_next_block())
13698 return nullptr;
13699
13700 TOML_ASSERT_ASSUME(!codepoints_.current);
13701 }
13702 TOML_ASSERT_ASSUME(codepoints_.count);
13703 TOML_ASSERT_ASSUME(codepoints_.count <= block_capacity);
13704 TOML_ASSERT_ASSUME(codepoints_.current < codepoints_.count);
13705
13706 return &codepoints_.buffer[codepoints_.current++];
13707 }
13708
13710 bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
13711 {
13712 return stream_.peek_eof();
13713 }
13714
13715# if !TOML_EXCEPTIONS
13716
13718 optional<parse_error> &&error() noexcept final
13719 {
13720 return std::move(err_);
13721 }
13722
13723# endif
13724 };
13725
13726 template <typename Char>
13727 utf8_reader(std::basic_string_view<Char>, std::string_view)
13729 template <typename Char>
13730 utf8_reader(std::basic_string_view<Char>, std::string &&)
13732 template <typename Char>
13733 utf8_reader(std::basic_istream<Char> &, std::string_view)
13735 template <typename Char>
13736 utf8_reader(std::basic_istream<Char> &, std::string &&)
13738
13739# if TOML_EXCEPTIONS
13740# define utf8_buffered_reader_error_check(...) static_assert(true)
13741# else
13742# define utf8_buffered_reader_error_check(...) \
13743 do \
13744 { \
13745 if TOML_UNLIKELY (reader_.error()) \
13746 return __VA_ARGS__; \
13747 } while (false)
13748
13749# endif
13750
13752 {
13753 public:
13754 static constexpr size_t max_history_length = 128;
13755
13756 private:
13757 static constexpr size_t history_buffer_size =
13758 max_history_length - 1; //'head' is stored in the reader
13759 utf8_reader_interface &reader_;
13760 struct
13761 {
13762 utf8_codepoint buffer[history_buffer_size];
13763 size_t count, first;
13764 } history_ = {};
13765 const utf8_codepoint *head_ = {};
13766 size_t negative_offset_ = {};
13767
13768 public:
13770 explicit utf8_buffered_reader(utf8_reader_interface &reader) noexcept //
13771 : reader_{reader}
13772 {
13773 }
13774
13776 const source_path_ptr &source_path() const noexcept
13777 {
13778 return reader_.source_path();
13779 }
13780
13783 {
13785
13786 if (negative_offset_)
13787 {
13788 negative_offset_--;
13789
13790 // an entry negative offset of 1 just means "replay the current head"
13791 if (!negative_offset_)
13792 return head_;
13793
13794 // otherwise step back into the history buffer
13795 else
13796 return history_.buffer +
13797 ((history_.first + history_.count - negative_offset_) %
13798 history_buffer_size);
13799 }
13800 else
13801 {
13802 // first character read from stream
13803 if TOML_UNLIKELY (!history_.count && !head_)
13804 head_ = reader_.read_next();
13805
13806 // subsequent characters and not eof
13807 else if (head_)
13808 {
13809 if TOML_UNLIKELY (history_.count < history_buffer_size)
13810 history_.buffer[history_.count++] = *head_;
13811 else
13812 history_.buffer
13813 [(history_.first++ + history_buffer_size) % history_buffer_size] =
13814 *head_;
13815
13816 head_ = reader_.read_next();
13817 }
13818
13819 return head_;
13820 }
13821 }
13822
13824 const utf8_codepoint *step_back(size_t count) noexcept
13825 {
13827
13828 TOML_ASSERT_ASSUME(history_.count);
13829 TOML_ASSERT_ASSUME(negative_offset_ + count <= history_.count);
13830
13831 negative_offset_ += count;
13832
13833 return negative_offset_
13834 ? history_.buffer +
13835 ((history_.first + history_.count - negative_offset_) %
13836 history_buffer_size)
13837 : head_;
13838 }
13839
13842 {
13843 return reader_.peek_eof();
13844 }
13845
13846# if !TOML_EXCEPTIONS
13847
13849 optional<parse_error> &&error() noexcept
13850 {
13851 return reader_.error();
13852 }
13853
13854# endif
13855 };
13856}
13858
13859# if TOML_EXCEPTIONS
13860# define TOML_RETURNS_BY_THROWING [[noreturn]]
13861# else
13862# define TOML_RETURNS_BY_THROWING
13863# endif
13864
13866{
13867 template <typename... T>
13868 TOML_CONST_GETTER TOML_INTERNAL_LINKAGE constexpr bool is_match(
13869 char32_t codepoint, T... vals) noexcept
13870 {
13871 static_assert((std::is_same_v<char32_t, T> && ...));
13872 return ((codepoint == vals) || ...);
13873 }
13874
13875 template <uint64_t>
13876 struct parse_integer_traits;
13877 template <>
13878 struct parse_integer_traits<2>
13879 {
13880 static constexpr auto scope_qualifier = "binary integer"sv;
13881 static constexpr auto is_digit = impl::is_binary_digit;
13882 static constexpr auto is_signed = false;
13883 static constexpr auto max_digits = 63;
13884 static constexpr auto prefix_codepoint = U'b';
13885 static constexpr auto prefix = "b"sv;
13886 static constexpr auto full_prefix = "0b"sv;
13887 };
13888 template <>
13889 struct parse_integer_traits<8>
13890 {
13891 static constexpr auto scope_qualifier = "octal integer"sv;
13892 static constexpr auto is_digit = impl::is_octal_digit;
13893 static constexpr auto is_signed = false;
13894 static constexpr auto max_digits = 21; // strlen("777777777777777777777")
13895 static constexpr auto prefix_codepoint = U'o';
13896 static constexpr auto prefix = "o"sv;
13897 static constexpr auto full_prefix = "0o"sv;
13898 };
13899 template <>
13900 struct parse_integer_traits<10>
13901 {
13902 static constexpr auto scope_qualifier = "decimal integer"sv;
13903 static constexpr auto is_digit = impl::is_decimal_digit;
13904 static constexpr auto is_signed = true;
13905 static constexpr auto max_digits = 19; // strlen("9223372036854775807")
13906 static constexpr auto full_prefix = ""sv;
13907 };
13908 template <>
13909 struct parse_integer_traits<16>
13910 {
13911 static constexpr auto scope_qualifier = "hexadecimal integer"sv;
13912 static constexpr auto is_digit = impl::is_hexadecimal_digit;
13913 static constexpr auto is_signed = false;
13914 static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
13915 static constexpr auto prefix_codepoint = U'x';
13916 static constexpr auto prefix = "x"sv;
13917 static constexpr auto full_prefix = "0x"sv;
13918 };
13919
13922 std::string_view to_sv(node_type val) noexcept
13923 {
13924 return impl::node_type_friendly_names[impl::unwrap_enum(val)];
13925 }
13926
13929 std::string_view to_sv(const std::string &str) noexcept
13930 {
13931 return std::string_view{str};
13932 }
13933
13936 std::string_view to_sv(bool val) noexcept
13937 {
13938 using namespace std::string_view_literals;
13939
13940 return val ? "true"sv : "false"sv;
13941 }
13942
13945 std::string_view to_sv(const utf8_codepoint &cp) noexcept
13946 {
13947 if (cp.value <= U'\x1F')
13948 return impl::control_char_escapes[cp.value];
13949 else if (cp.value == U'\x7F')
13950 return "\\u007F"sv;
13951 else
13952 return std::string_view{cp.bytes, cp.count};
13953 }
13954
13957 std::string_view to_sv(const utf8_codepoint *cp) noexcept
13958 {
13959 if (cp)
13960 return to_sv(*cp);
13961 return ""sv;
13962 }
13963
13965 {
13967 };
13968
13969 template <typename T>
13970 TOML_ATTR(nonnull)
13972 char *&write_pos, char *const buf_end, const T &arg) noexcept
13973 {
13974 if TOML_UNLIKELY (write_pos >= buf_end)
13975 return;
13976
13977 using arg_type = impl::remove_cvref<T>;
13978
13979 // string views
13980 if constexpr (std::is_same_v<arg_type, std::string_view>)
13981 {
13982 const auto max_chars = static_cast<size_t>(buf_end - write_pos);
13983 const auto len = max_chars < arg.length() ? max_chars : arg.length();
13984 std::memcpy(write_pos, arg.data(), len);
13985 write_pos += len;
13986 }
13987
13988 // doubles
13989 else if constexpr (std::is_same_v<arg_type, double>)
13990 {
13991# if TOML_FLOAT_CHARCONV
13992 const auto result = std::to_chars(write_pos, buf_end, arg);
13993 write_pos = result.ptr;
13994# else
13995 std::ostringstream ss;
13996 ss.imbue(std::locale::classic());
13997 ss.precision(std::numeric_limits<arg_type>::max_digits10);
13998 ss << arg;
13999 concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
14000# endif
14001 }
14002
14003 // 64-bit integers
14004 else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>)
14005 {
14006# if TOML_INT_CHARCONV
14007 const auto result = std::to_chars(write_pos, buf_end, arg);
14008 write_pos = result.ptr;
14009# else
14010 std::ostringstream ss;
14011 ss.imbue(std::locale::classic());
14012 using cast_type =
14013 std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
14014 ss << static_cast<cast_type>(arg);
14015 concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
14016# endif
14017 }
14018
14019 // escaped_codepoint
14020 else if constexpr (std::is_same_v<arg_type, escaped_codepoint>)
14021 {
14022 if (arg.cp.value <= U'\x7F')
14023 concatenate(write_pos, buf_end, to_sv(arg.cp));
14024 else
14025 {
14026 auto val = static_cast<uint_least32_t>(arg.cp.value);
14027 const auto digits = val > 0xFFFFu ? 8u : 4u;
14028 constexpr auto mask = uint_least32_t{0xFu};
14029 char buf[10] = {'\\', digits > 4 ? 'U' : 'u'};
14030 for (auto i = 2u + digits; i-- > 2u;)
14031 {
14032 const auto hexdig = val & mask;
14033 buf[i] = static_cast<char>(
14034 hexdig >= 0xAu ? ('A' + (hexdig - 0xAu)) : ('0' + hexdig));
14035 val >>= 4;
14036 }
14037 concatenate(write_pos, buf_end, std::string_view{buf, digits + 2u});
14038 }
14039 }
14040
14041 // all other floats (fallback - coerce to double)
14042 else if constexpr (std::is_floating_point_v<arg_type>)
14043 concatenate(write_pos, buf_end, static_cast<double>(arg));
14044
14045 // all other integers (fallback - coerce to (u)int64_t)
14046 else if constexpr (
14047 std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>)
14048 {
14049 using cast_type =
14050 std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
14051 concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
14052 }
14053
14054 else
14055 {
14056 static_assert(
14057 impl::always_false<T>,
14058 "concatenate() inputs are limited to std::string_views, integers, "
14059 "floats, and escaped_codepoint");
14060 }
14061 }
14062
14064 {
14065 static constexpr std::size_t buf_size = 512;
14068 char *const max_write_pos =
14069 buf + (buf_size - std::size_t{1}); // allow for null terminator
14070
14072 error_builder(std::string_view scope) noexcept
14073 {
14074 concatenate(write_pos, max_write_pos, "Error while parsing "sv);
14077 }
14078
14079 template <typename T>
14080 void append(const T &arg) noexcept
14081 {
14083 }
14084
14086 auto
14087 finish(const source_position &pos, const source_path_ptr &source_path) const
14088 {
14089 *write_pos = '\0';
14090
14091# if TOML_EXCEPTIONS
14092 throw parse_error{buf, pos, source_path};
14093# else
14094 return parse_error{
14095 std::string(buf, static_cast<size_t>(write_pos - buf)),
14096 pos,
14097 source_path};
14098# endif
14099 }
14100
14102 };
14103
14105 {
14106 std::string_view &storage_;
14107 std::string_view parent_;
14108
14110 explicit parse_scope(
14111 std::string_view &current_scope,
14112 std::string_view new_scope) noexcept
14113 : storage_{current_scope}, parent_{current_scope}
14114 {
14115 storage_ = new_scope;
14116 }
14117
14118 ~parse_scope() noexcept
14119 {
14120 storage_ = parent_;
14121 }
14122
14124 };
14125# define push_parse_scope_2(scope, line) \
14126 parse_scope ps_##line(current_scope, scope)
14127# define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
14128# define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
14129
14131 {
14132 std::string buffer;
14133 std::vector<std::pair<size_t, size_t>> segments;
14134 std::vector<source_position> starts;
14135 std::vector<source_position> ends;
14136
14137 void clear() noexcept
14138 {
14139 buffer.clear();
14140 segments.clear();
14141 starts.clear();
14142 ends.clear();
14143 }
14144
14145 void
14146 push_back(std::string_view segment, source_position b, source_position e)
14147 {
14148 segments.push_back({buffer.length(), segment.length()});
14149 buffer.append(segment);
14150 starts.push_back(b);
14151 ends.push_back(e);
14152 }
14153
14155 std::string_view operator[](size_t i) const noexcept
14156 {
14157 return std::string_view{
14158 buffer.c_str() + segments[i].first, segments[i].second};
14159 }
14160
14162 std::string_view back() const noexcept
14163 {
14164 return (*this)[segments.size() - 1u];
14165 }
14166
14168 bool empty() const noexcept
14169 {
14170 return segments.empty();
14171 }
14172
14174 size_t size() const noexcept
14175 {
14176 return segments.size();
14177 }
14178 };
14179
14181 {
14182 size_t &depth_;
14183
14185 explicit depth_counter_scope(size_t &depth) noexcept //
14186 : depth_{depth}
14187 {
14188 depth_++;
14189 }
14190
14192 {
14193 depth_--;
14194 }
14195
14197 };
14198
14200 {
14201 std::string_view value;
14203 };
14204
14206 {
14207 std::vector<table *> &tables;
14208
14210 explicit table_vector_scope(std::vector<table *> &tables_, table &tbl) //
14211 : tables{tables_}
14212 {
14213 tables.push_back(&tbl);
14214 }
14215
14217 {
14218 tables.pop_back();
14219 }
14220
14222 };
14223}
14225
14226# if 1 // parser helper macros
14227
14228// Q: "what the fuck is this? MACROS????"
14229// A: The parser needs to work in exceptionless mode (returning error objects directly)
14230// and exception mode (reporting parse failures by throwing). Two totally different control flows.
14231// These macros encapsulate the differences between the two modes so I can write code code
14232// as though I was only targeting one mode and not want yeet myself into the sun.
14233// They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
14234// of toml++.
14235
14236# define is_eof() !cp
14237# define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
14238# define return_if_eof(...) \
14239 do \
14240 { \
14241 if TOML_UNLIKELY (is_eof()) \
14242 return __VA_ARGS__; \
14243 } while (false)
14244
14245# if TOML_EXCEPTIONS
14246# define is_error() false
14247# define return_after_error(...) TOML_UNREACHABLE
14248# define assert_not_error() static_assert(true)
14249# define return_if_error(...) static_assert(true)
14250# define return_if_error_or_eof(...) return_if_eof(__VA_ARGS__)
14251# else
14252# define is_error() !!err
14253# define return_after_error(...) return __VA_ARGS__
14254# define assert_not_error() TOML_ASSERT(!is_error())
14255# define return_if_error(...) \
14256 do \
14257 { \
14258 if TOML_UNLIKELY (is_error()) \
14259 return __VA_ARGS__; \
14260 } while (false)
14261# define return_if_error_or_eof(...) \
14262 do \
14263 { \
14264 if TOML_UNLIKELY (is_eof() || is_error()) \
14265 return __VA_ARGS__; \
14266 } while (false)
14267# endif
14268
14269# if defined(TOML_BREAK_AT_PARSE_ERRORS) && TOML_BREAK_AT_PARSE_ERRORS
14270# if defined(__has_builtin)
14271# if __has_builtin(__builtin_debugtrap)
14272# define parse_error_break() __builtin_debugtrap()
14273# elif __has_builtin(__debugbreak)
14274# define parse_error_break() __debugbreak()
14275# endif
14276# endif
14277# ifndef parse_error_break
14278# if TOML_MSVC || TOML_ICC
14279# define parse_error_break() __debugbreak()
14280# else
14281# define parse_error_break() TOML_ASSERT(false)
14282# endif
14283# endif
14284# else
14285# define parse_error_break() static_assert(true)
14286# endif
14287
14288# define set_error_and_return(ret, ...) \
14289 do \
14290 { \
14291 if (!is_error()) \
14292 set_error(__VA_ARGS__); \
14293 return_after_error(ret); \
14294 } while (false)
14295
14296# define set_error_and_return_default(...) \
14297 set_error_and_return({}, __VA_ARGS__)
14298
14299# define set_error_and_return_if_eof(...) \
14300 do \
14301 { \
14302 if TOML_UNLIKELY (is_eof()) \
14303 set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \
14304 } while (false)
14305
14306# define advance_and_return_if_error(...) \
14307 do \
14308 { \
14309 assert_not_eof(); \
14310 advance(); \
14311 return_if_error(__VA_ARGS__); \
14312 } while (false)
14313
14314# define advance_and_return_if_error_or_eof(...) \
14315 do \
14316 { \
14317 assert_not_eof(); \
14318 advance(); \
14319 return_if_error(__VA_ARGS__); \
14320 set_error_and_return_if_eof(__VA_ARGS__); \
14321 } while (false)
14322
14323# endif // parser helper macros
14324
14326{
14327 TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
14328
14330 {
14331 private:
14332 static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES;
14333
14334 utf8_buffered_reader reader;
14335 table root;
14336 source_position prev_pos = {1, 1};
14337 const utf8_codepoint *cp = {};
14338 std::vector<table *> implicit_tables;
14339 std::vector<table *> dotted_key_tables;
14340 std::vector<table *> open_inline_tables;
14341 std::vector<array *> table_arrays;
14342 parse_key_buffer key_buffer;
14343 std::string string_buffer;
14344 std::string recording_buffer; // for diagnostics
14345 bool recording = false, recording_whitespace = true;
14346 std::string_view current_scope;
14347 size_t nested_values = {};
14348# if !TOML_EXCEPTIONS
14349 mutable optional<parse_error> err;
14350# endif
14351
14354 current_position(source_index fallback_offset = 0) const noexcept
14355 {
14356 if (!is_eof())
14357 return cp->position;
14358 return {
14359 prev_pos.line,
14360 static_cast<source_index>(prev_pos.column + fallback_offset)};
14361 }
14362
14363 template <typename... T>
14365 set_error_at(source_position pos, const T &...reason) const
14366 {
14367 static_assert(sizeof...(T) > 0);
14369
14370 error_builder builder{current_scope};
14371 (builder.append(reason), ...);
14372
14374
14375# if TOML_EXCEPTIONS
14376 builder.finish(pos, reader.source_path());
14377# else
14378 err.emplace(builder.finish(pos, reader.source_path()));
14379# endif
14380 }
14381
14382 template <typename... T>
14383 TOML_RETURNS_BY_THROWING void set_error(const T &...reason) const
14384 {
14385 set_error_at(current_position(1), reason...);
14386 }
14387
14388 void go_back(size_t count = 1) noexcept
14389 {
14392
14393 cp = reader.step_back(count);
14394 prev_pos = cp->position;
14395 }
14396
14397 void advance()
14398 {
14401
14402 prev_pos = cp->position;
14403 cp = reader.read_next();
14404
14405# if !TOML_EXCEPTIONS
14406 if (reader.error())
14407 {
14408 err = std::move(reader.error());
14409 return;
14410 }
14411# endif
14412
14413 if (recording && !is_eof())
14414 {
14415 if (recording_whitespace || !is_whitespace(*cp))
14416 recording_buffer.append(cp->bytes, cp->count);
14417 }
14418 }
14419
14420 void start_recording(bool include_current = true) noexcept
14421 {
14423
14424 recording = true;
14425 recording_whitespace = true;
14426 recording_buffer.clear();
14427 if (include_current && !is_eof())
14428 recording_buffer.append(cp->bytes, cp->count);
14429 }
14430
14431 void stop_recording(size_t pop_bytes = 0) noexcept
14432 {
14434
14435 recording = false;
14436 if (pop_bytes)
14437 {
14438 if (pop_bytes >= recording_buffer.length())
14439 recording_buffer.clear();
14440 else if (pop_bytes == 1u)
14441 recording_buffer.pop_back();
14442 else
14443 recording_buffer.erase(
14444 recording_buffer.begin() +
14445 static_cast<ptrdiff_t>(recording_buffer.length() - pop_bytes),
14446 recording_buffer.end());
14447 }
14448 }
14449
14450 bool consume_leading_whitespace()
14451 {
14453
14454 bool consumed = false;
14455 while (!is_eof() && is_horizontal_whitespace(*cp))
14456 {
14457 if TOML_UNLIKELY (!is_ascii_horizontal_whitespace(*cp))
14459 "expected space or tab, saw '"sv, escaped_codepoint{*cp}, "'"sv);
14460
14461 consumed = true;
14463 }
14464 return consumed;
14465 }
14466
14467 bool consume_line_break()
14468 {
14470
14471 if TOML_UNLIKELY (is_match(*cp, U'\v', U'\f'))
14473 R"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);
14474
14475 if (*cp == U'\r')
14476 {
14477 advance_and_return_if_error({}); // skip \r
14478
14479 if TOML_UNLIKELY (is_eof())
14480 set_error_and_return_default("expected '\\n' after '\\r', saw EOF"sv);
14481
14482 if TOML_UNLIKELY (*cp != U'\n')
14484 "expected '\\n' after '\\r', saw '"sv,
14485 escaped_codepoint{*cp},
14486 "'"sv);
14487 }
14488 else if (*cp != U'\n')
14489 return false;
14490
14491 advance_and_return_if_error({}); // skip \n
14492 return true;
14493 }
14494
14495 bool consume_rest_of_line()
14496 {
14498
14499 do
14500 {
14501 if (is_ascii_vertical_whitespace(*cp))
14502 return consume_line_break();
14503 else
14504 advance();
14505 return_if_error({});
14506 } while (!is_eof());
14507
14508 return true;
14509 }
14510
14511 bool consume_comment()
14512 {
14514
14515 if (*cp != U'#')
14516 return false;
14517
14518 push_parse_scope("comment"sv);
14519
14520 advance_and_return_if_error({}); // skip the '#'
14521
14522 while (!is_eof())
14523 {
14524 if (consume_line_break())
14525 return true;
14526 return_if_error({});
14527
14528# if TOML_LANG_AT_LEAST(1, 0, 0)
14529
14530 // toml/issues/567 (disallow non-TAB control characters in comments)
14531 if TOML_UNLIKELY (is_nontab_control_character(*cp))
14533 "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv);
14534
14535 // toml/pull/720 (disallow surrogates in comments)
14536 else if TOML_UNLIKELY (is_unicode_surrogate(*cp))
14538 "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
14539# endif
14540
14542 }
14543
14544 return true;
14545 }
14546
14548 bool consume_expected_sequence(std::u32string_view seq)
14549 {
14550 return_if_error({});
14551 TOML_ASSERT(!seq.empty());
14552
14553 for (auto c : seq)
14554 {
14556 if (*cp != c)
14557 return false;
14559 }
14560 return true;
14561 }
14562
14563 template <typename T>
14564 TOML_NODISCARD bool consume_digit_sequence(T *digits, size_t len)
14565 {
14566 return_if_error({});
14567 TOML_ASSERT_ASSUME(digits);
14568 TOML_ASSERT_ASSUME(len);
14569
14570 for (size_t i = 0; i < len; i++)
14571 {
14573 if (!is_decimal_digit(*cp))
14574 return false;
14575
14576 digits[i] = static_cast<T>(*cp - U'0');
14578 }
14579 return true;
14580 }
14581
14582 template <typename T>
14583 TOML_NODISCARD size_t
14584 consume_variable_length_digit_sequence(T *buffer, size_t max_len)
14585 {
14586 return_if_error({});
14587 TOML_ASSERT_ASSUME(buffer);
14588 TOML_ASSERT_ASSUME(max_len);
14589
14590 size_t i = {};
14591 for (; i < max_len; i++)
14592 {
14593 if (is_eof() || !is_decimal_digit(*cp))
14594 break;
14595
14596 buffer[i] = static_cast<T>(*cp - U'0');
14598 }
14599 return i;
14600 }
14601
14604 std::string_view parse_basic_string(bool multi_line)
14605 {
14606 return_if_error({});
14608 TOML_ASSERT_ASSUME(*cp == U'"');
14609 push_parse_scope("string"sv);
14610
14611 // skip the '"'
14613
14614 // multi-line strings ignore a single line ending right at the beginning
14615 if (multi_line)
14616 {
14617 consume_line_break();
14618 return_if_error({});
14620 }
14621
14622 auto &str = string_buffer;
14623 str.clear();
14624 bool escaped = false;
14625 bool skipping_whitespace = false;
14626 do
14627 {
14628 if (escaped)
14629 {
14630 escaped = false;
14631
14632 // handle 'line ending slashes' in multi-line mode
14633 if (multi_line && is_whitespace(*cp))
14634 {
14635 consume_leading_whitespace();
14636
14637 if TOML_UNLIKELY (!consume_line_break())
14639 "line-ending backslashes must be the last non-whitespace character on the line"sv);
14640
14641 skipping_whitespace = true;
14642 return_if_error({});
14643 continue;
14644 }
14645
14646 bool skip_escaped_codepoint = true;
14648 switch (const auto escaped_codepoint = *cp)
14649 {
14650 // 'regular' escape codes
14651 case U'b':
14652 str += '\b';
14653 break;
14654 case U'f':
14655 str += '\f';
14656 break;
14657 case U'n':
14658 str += '\n';
14659 break;
14660 case U'r':
14661 str += '\r';
14662 break;
14663 case U't':
14664 str += '\t';
14665 break;
14666 case U'"':
14667 str += '"';
14668 break;
14669 case U'\\':
14670 str += '\\';
14671 break;
14672
14673# if TOML_LANG_UNRELEASED // toml/pull/790 (\e shorthand for \x1B)
14674 case U'e':
14675 str += '\x1B';
14676 break;
14677# else
14678 case U'e':
14680 "escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
14681# endif
14682
14683# if TOML_LANG_UNRELEASED // toml/pull/796 (\xHH unicode scalar sequences)
14684 case U'x':
14685 [[fallthrough]];
14686# else
14687 case U'x':
14689 "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
14690# endif
14691
14692 // unicode scalar sequences
14693 case U'u':
14694 [[fallthrough]];
14695 case U'U':
14696 {
14697 push_parse_scope("unicode scalar sequence"sv);
14699 skip_escaped_codepoint = false;
14700
14701 uint32_t place_value =
14702 escaped_codepoint == U'U'
14703 ? 0x10000000u
14704 : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
14705 uint32_t sequence_value{};
14706 while (place_value)
14707 {
14709
14710 if TOML_UNLIKELY (!is_hexadecimal_digit(*cp))
14712 "expected hex digit, saw '"sv, to_sv(*cp), "'"sv);
14713
14714 sequence_value += place_value * hex_to_dec(*cp);
14715 place_value /= 16u;
14717 }
14718
14719 if TOML_UNLIKELY (is_unicode_surrogate(sequence_value))
14721 "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
14722 else if TOML_UNLIKELY (sequence_value > 0x10FFFFu)
14724 "values greater than U+10FFFF are invalid"sv);
14725
14726 if (sequence_value < 0x80)
14727 {
14728 str += static_cast<char>(sequence_value);
14729 }
14730 else if (sequence_value < 0x800u)
14731 {
14732 str += static_cast<char>((sequence_value >> 6) | 0xC0u);
14733 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
14734 }
14735 else if (sequence_value < 0x10000u)
14736 {
14737 str += static_cast<char>((sequence_value >> 12) | 0xE0u);
14738 str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
14739 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
14740 }
14741 else if (sequence_value < 0x110000u)
14742 {
14743 str += static_cast<char>((sequence_value >> 18) | 0xF0u);
14744 str +=
14745 static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
14746 str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
14747 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
14748 }
14749 break;
14750 }
14751
14752 // ???
14754 default:
14756 "unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
14757 }
14758
14759 if (skip_escaped_codepoint)
14761 }
14762 else
14763 {
14764 // handle closing delimiters
14765 if (*cp == U'"')
14766 {
14767 if (multi_line)
14768 {
14769 size_t lookaheads = {};
14770 size_t consecutive_delimiters = 1;
14771 do
14772 {
14774 lookaheads++;
14775 if (!is_eof() && *cp == U'"')
14776 consecutive_delimiters++;
14777 else
14778 break;
14779 } while (lookaheads < 4u);
14780
14781 switch (consecutive_delimiters)
14782 {
14783 // """ " (one quote somewhere in a ML string)
14784 case 1:
14785 str += '"';
14786 skipping_whitespace = false;
14787 continue;
14788
14789 // """ "" (two quotes somewhere in a ML string)
14790 case 2:
14791 str.append("\"\""sv);
14792 skipping_whitespace = false;
14793 continue;
14794
14795 // """ """ (the end of the string)
14796 case 3:
14797 return str;
14798
14799 // """ """" (one at the end of the string)
14800 case 4:
14801 str += '"';
14802 return str;
14803
14804 // """ """"" (two quotes at the end of the string)
14805 case 5:
14806 str.append("\"\""sv);
14807 advance_and_return_if_error({}); // skip the last '"'
14808 return str;
14809
14810 default:
14812 }
14813 }
14814 else
14815 {
14816 advance_and_return_if_error({}); // skip the closing delimiter
14817 return str;
14818 }
14819 }
14820
14821 // handle escapes
14822 else if (*cp == U'\\')
14823 {
14824 advance_and_return_if_error_or_eof({}); // skip the '\'
14825 skipping_whitespace = false;
14826 escaped = true;
14827 continue;
14828 }
14829
14830 // handle line endings in multi-line mode
14831 if (multi_line && is_ascii_vertical_whitespace(*cp))
14832 {
14833 consume_line_break();
14834 return_if_error({});
14835 if (!skipping_whitespace)
14836 str += '\n';
14837 continue;
14838 }
14839
14840 // handle control characters
14841 if TOML_UNLIKELY (is_nontab_control_character(*cp))
14843 "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv);
14844
14845# if TOML_LANG_AT_LEAST(1, 0, 0)
14846
14847 // handle surrogates in strings
14848 if TOML_UNLIKELY (is_unicode_surrogate(*cp))
14850 "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
14851# endif
14852
14853 if (multi_line)
14854 {
14855 if (!skipping_whitespace || !is_horizontal_whitespace(*cp))
14856 {
14857 skipping_whitespace = false;
14858 str.append(cp->bytes, cp->count);
14859 }
14860 }
14861 else
14862 str.append(cp->bytes, cp->count);
14863
14865 }
14866 } while (!is_eof());
14867
14868 set_error_and_return_default("encountered end-of-file"sv);
14869 }
14870
14873 std::string_view parse_literal_string(bool multi_line)
14874 {
14875 return_if_error({});
14877 TOML_ASSERT_ASSUME(*cp == U'\'');
14878 push_parse_scope("literal string"sv);
14879
14880 // skip the delimiter
14882
14883 // multi-line strings ignore a single line ending right at the beginning
14884 if (multi_line)
14885 {
14886 consume_line_break();
14887 return_if_error({});
14889 }
14890
14891 auto &str = string_buffer;
14892 str.clear();
14893 do
14894 {
14895 return_if_error({});
14896
14897 // handle closing delimiters
14898 if (*cp == U'\'')
14899 {
14900 if (multi_line)
14901 {
14902 size_t lookaheads = {};
14903 size_t consecutive_delimiters = 1;
14904 do
14905 {
14907 lookaheads++;
14908 if (!is_eof() && *cp == U'\'')
14909 consecutive_delimiters++;
14910 else
14911 break;
14912 } while (lookaheads < 4u);
14913
14914 switch (consecutive_delimiters)
14915 {
14916 // ''' ' (one quote somewhere in a ML string)
14917 case 1:
14918 str += '\'';
14919 continue;
14920
14921 // ''' '' (two quotes somewhere in a ML string)
14922 case 2:
14923 str.append("''"sv);
14924 continue;
14925
14926 // ''' ''' (the end of the string)
14927 case 3:
14928 return str;
14929
14930 // ''' '''' (one at the end of the string)
14931 case 4:
14932 str += '\'';
14933 return str;
14934
14935 // ''' ''''' (two quotes at the end of the string)
14936 case 5:
14937 str.append("''"sv);
14938 advance_and_return_if_error({}); // skip the last '
14939 return str;
14940
14941 default:
14943 }
14944 }
14945 else
14946 {
14947 advance_and_return_if_error({}); // skip the closing delimiter
14948 return str;
14949 }
14950 }
14951
14952 // handle line endings in multi-line mode
14953 if (multi_line && is_ascii_vertical_whitespace(*cp))
14954 {
14955 consume_line_break();
14956 return_if_error({});
14957 str += '\n';
14958 continue;
14959 }
14960
14961 // handle control characters
14962 if TOML_UNLIKELY (is_nontab_control_character(*cp))
14964 "control characters other than TAB (U+0009) are explicitly prohibited"sv);
14965
14966# if TOML_LANG_AT_LEAST(1, 0, 0)
14967
14968 // handle surrogates in strings
14969 if TOML_UNLIKELY (is_unicode_surrogate(*cp))
14971 "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
14972# endif
14973
14974 str.append(cp->bytes, cp->count);
14976 } while (!is_eof());
14977
14978 set_error_and_return_default("encountered end-of-file"sv);
14979 }
14980
14983 parsed_string parse_string()
14984 {
14985 return_if_error({});
14987 TOML_ASSERT_ASSUME(is_string_delimiter(*cp));
14988 push_parse_scope("string"sv);
14989
14990 // get the first three characters to determine the string type
14991 const auto first = cp->value;
14993 const auto second = cp->value;
14995 const auto third = cp ? cp->value : U'\0';
14996
14997 // if we were eof at the third character then first and second need to be
14998 // the same string character (otherwise it's an unterminated string)
14999 if (is_eof())
15000 {
15001 if (second == first)
15002 return {};
15003
15004 set_error_and_return_default("encountered end-of-file"sv);
15005 }
15006
15007 // if the first three characters are all the same string delimiter then
15008 // it's a multi-line string.
15009 else if (first == second && first == third)
15010 {
15011 return {
15012 first == U'\'' ? parse_literal_string(true)
15013 : parse_basic_string(true),
15014 true};
15015 }
15016
15017 // otherwise it's just a regular string.
15018 else
15019 {
15020 // step back two characters so that the current
15021 // character is the string delimiter
15022 go_back(2u);
15023
15024 return {
15025 first == U'\'' ? parse_literal_string(false)
15026 : parse_basic_string(false),
15027 false};
15028 }
15029 }
15030
15033 std::string_view parse_bare_key_segment()
15034 {
15035 return_if_error({});
15037 TOML_ASSERT_ASSUME(is_bare_key_character(*cp));
15038
15039 string_buffer.clear();
15040
15041 while (!is_eof())
15042 {
15043 if (!is_bare_key_character(*cp))
15044 break;
15045
15046 string_buffer.append(cp->bytes, cp->count);
15048 }
15049
15050 return string_buffer;
15051 }
15052
15055 bool parse_boolean()
15056 {
15057 return_if_error({});
15059 TOML_ASSERT_ASSUME(is_match(*cp, U't', U'f', U'T', U'F'));
15060 push_parse_scope("boolean"sv);
15061
15062 start_recording(true);
15063 auto result = is_match(*cp, U't', U'T');
15064 if (!consume_expected_sequence(result ? U"true"sv : U"false"sv))
15066 "expected '"sv,
15067 to_sv(result),
15068 "', saw '"sv,
15069 to_sv(recording_buffer),
15070 "'"sv);
15071 stop_recording();
15072
15073 if (cp && !is_value_terminator(*cp))
15075 "expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
15076
15077 return result;
15078 }
15079
15082 double parse_inf_or_nan()
15083 {
15084 return_if_error({});
15086 TOML_ASSERT_ASSUME(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
15087 push_parse_scope("floating-point"sv);
15088
15089 start_recording(true);
15090 const bool negative = *cp == U'-';
15091 if (negative || *cp == U'+')
15093
15094 const bool inf = is_match(*cp, U'i', U'I');
15095 if (!consume_expected_sequence(inf ? U"inf"sv : U"nan"sv))
15097 "expected '"sv,
15098 inf ? "inf"sv : "nan"sv,
15099 "', saw '"sv,
15100 to_sv(recording_buffer),
15101 "'"sv);
15102 stop_recording();
15103
15104 if (cp && !is_value_terminator(*cp))
15106 "expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
15107
15108 return inf ? (negative ? -std::numeric_limits<double>::infinity()
15109 : std::numeric_limits<double>::infinity())
15110 : std::numeric_limits<double>::quiet_NaN();
15111 }
15112
15115 double parse_float()
15116 {
15117 return_if_error({});
15120 is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
15121 push_parse_scope("floating-point"sv);
15122
15123 // sign
15124 const int sign = *cp == U'-' ? -1 : 1;
15125 if (is_match(*cp, U'+', U'-'))
15127
15128 // consume value chars
15130 size_t length = {};
15131 const utf8_codepoint *prev = {};
15132 bool seen_decimal = false, seen_exponent = false;
15133 char first_integer_part = '\0';
15134 while (!is_eof() && !is_value_terminator(*cp))
15135 {
15136 if (*cp == U'_')
15137 {
15138 if (!prev || !is_decimal_digit(*prev))
15140 "underscores may only follow digits"sv);
15141
15142 prev = cp;
15144 continue;
15145 }
15146 else if TOML_UNLIKELY (prev && *prev == U'_' && !is_decimal_digit(*cp))
15148 "underscores must be followed by digits"sv);
15149 else if TOML_UNLIKELY (length == sizeof(chars))
15151 "exceeds length limit of "sv,
15152 sizeof(chars),
15153 " digits"sv,
15154 (seen_exponent ? ""sv : " (consider using exponent notation)"sv));
15155 else if (*cp == U'.')
15156 {
15157 // .1
15158 // -.1
15159 // +.1 (no integer part)
15160 if (!first_integer_part)
15161 set_error_and_return_default("expected decimal digit, saw '.'"sv);
15162
15163 // 1.0e+.10 (exponent cannot have '.')
15164 else if (seen_exponent)
15166 "expected exponent decimal digit or sign, saw '.'"sv);
15167
15168 // 1.0.e+.10
15169 // 1..0
15170 // (multiple '.')
15171 else if (seen_decimal)
15173 "expected decimal digit or exponent, saw '.'"sv);
15174
15175 seen_decimal = true;
15176 }
15177 else if (is_match(*cp, U'e', U'E'))
15178 {
15179 if (prev && !is_decimal_digit(*prev))
15181 "expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
15182
15183 // 1.0ee+10 (multiple 'e')
15184 else if (seen_exponent)
15186 "expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
15187
15188 seen_decimal = true; // implied
15189 seen_exponent = true;
15190 }
15191 else if (is_match(*cp, U'+', U'-'))
15192 {
15193 // 1.-0 (sign in mantissa)
15194 if (!seen_exponent)
15196 "expected decimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
15197
15198 // 1.0e1-0 (misplaced exponent sign)
15199 else if (!is_match(*prev, U'e', U'E'))
15201 "expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
15202 }
15203 else if (is_decimal_digit(*cp))
15204 {
15205 if (!seen_decimal)
15206 {
15207 if (!first_integer_part)
15208 first_integer_part = static_cast<char>(cp->bytes[0]);
15209 else if (first_integer_part == '0')
15210 set_error_and_return_default("leading zeroes are prohibited"sv);
15211 }
15212 }
15213 else
15215 "expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
15216
15217 chars[length++] = static_cast<char>(cp->bytes[0]);
15218 prev = cp;
15220 }
15221
15222 // sanity-check ending state
15223 if (prev)
15224 {
15225 if (*prev == U'_')
15226 {
15229 "underscores must be followed by digits"sv);
15230 }
15231 else if (is_match(*prev, U'e', U'E', U'+', U'-', U'.'))
15232 {
15235 "expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
15236 }
15237 }
15238
15239 // convert to double
15240 double result;
15241# if TOML_FLOAT_CHARCONV
15242 {
15243 auto fc_result = std::from_chars(chars, chars + length, result);
15244 switch (fc_result.ec)
15245 {
15247 case std::errc{}: // ok
15248 return result * sign;
15249
15250 case std::errc::invalid_argument:
15252 "'"sv,
15253 std::string_view{chars, length},
15254 "' could not be interpreted as a value"sv);
15255 break;
15256
15257 case std::errc::result_out_of_range:
15259 "'"sv,
15260 std::string_view{chars, length},
15261 "' is not representable in 64 bits"sv);
15262 break;
15263
15264 default: //??
15266 "an unspecified error occurred while trying to interpret '"sv,
15267 std::string_view{chars, length},
15268 "' as a value"sv);
15269 }
15270 }
15271# else
15272 {
15273 std::stringstream ss;
15274 ss.imbue(std::locale::classic());
15275 ss.write(chars, static_cast<std::streamsize>(length));
15276 if ((ss >> result))
15277 return result * sign;
15278 else
15280 "'"sv,
15281 std::string_view{chars, length},
15282 "' could not be interpreted as a value"sv);
15283 }
15284# endif
15285 }
15286
15289 double parse_hex_float()
15290 {
15291 return_if_error({});
15293 TOML_ASSERT_ASSUME(is_match(*cp, U'0', U'+', U'-'));
15294 push_parse_scope("hexadecimal floating-point"sv);
15295
15296# if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
15297
15298 // sign
15299 const int sign = *cp == U'-' ? -1 : 1;
15300 if (is_match(*cp, U'+', U'-'))
15302
15303 // '0'
15304 if (*cp != U'0')
15306 " expected '0', saw '"sv, to_sv(*cp), "'"sv);
15308
15309 // 'x' or 'X'
15310 if (!is_match(*cp, U'x', U'X'))
15312 "expected 'x' or 'X', saw '"sv, to_sv(*cp), "'"sv);
15314
15315 // <HEX DIGITS> ([.]<HEX DIGITS>)? [pP] [+-]? <DEC DIGITS>
15316
15317 // consume value fragments
15318 struct fragment
15319 {
15320 char chars[24];
15321 size_t length;
15322 double value;
15323 };
15324 fragment fragments[] = {
15325 {}, // mantissa, whole part
15326 {}, // mantissa, fractional part
15327 {} // exponent
15328 };
15329 fragment *current_fragment = fragments;
15330 const utf8_codepoint *prev = {};
15331 int exponent_sign = 1;
15332 while (!is_eof() && !is_value_terminator(*cp))
15333 {
15334 if (*cp == U'_')
15335 {
15336 if (!prev || !is_hexadecimal_digit(*prev))
15338 "underscores may only follow digits"sv);
15339
15340 prev = cp;
15342 continue;
15343 }
15344 else if (prev && *prev == U'_' && !is_hexadecimal_digit(*cp))
15346 "underscores must be followed by digits"sv);
15347 else if (*cp == U'.')
15348 {
15349 // 0x10.0p-.0 (exponent cannot have '.')
15350 if (current_fragment == fragments + 2)
15352 "expected exponent digit or sign, saw '.'"sv);
15353
15354 // 0x10.0.p-0 (multiple '.')
15355 else if (current_fragment == fragments + 1)
15357 "expected hexadecimal digit or exponent, saw '.'"sv);
15358
15359 else
15360 current_fragment++;
15361 }
15362 else if (is_match(*cp, U'p', U'P'))
15363 {
15364 // 0x10.0pp-0 (multiple 'p')
15365 if (current_fragment == fragments + 2)
15367 "expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
15368
15369 // 0x.p-0 (mantissa is just '.')
15370 else if (fragments[0].length == 0u && fragments[1].length == 0u)
15372 "expected hexadecimal digit, saw '"sv, to_sv(*cp), "'"sv);
15373
15374 else
15375 current_fragment = fragments + 2;
15376 }
15377 else if (is_match(*cp, U'+', U'-'))
15378 {
15379 // 0x-10.0p-0 (sign in mantissa)
15380 if (current_fragment != fragments + 2)
15382 "expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
15383
15384 // 0x10.0p0- (misplaced exponent sign)
15385 else if (!is_match(*prev, U'p', U'P'))
15387 "expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
15388
15389 else
15390 exponent_sign = *cp == U'-' ? -1 : 1;
15391 }
15392 else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*cp))
15394 "expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
15395 else if (current_fragment == fragments + 2 && !is_decimal_digit(*cp))
15397 "expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
15398 else if (current_fragment->length == sizeof(fragment::chars))
15400 "fragment exceeeds maximum length of "sv,
15401 sizeof(fragment::chars),
15402 " characters"sv);
15403 else
15404 current_fragment->chars[current_fragment->length++] =
15405 static_cast<char>(cp->bytes[0]);
15406
15407 prev = cp;
15409 }
15410
15411 // sanity-check ending state
15412 if (current_fragment != fragments + 2 || current_fragment->length == 0u)
15413 {
15415 set_error_and_return_default("missing exponent"sv);
15416 }
15417 else if (prev && *prev == U'_')
15418 {
15421 "underscores must be followed by digits"sv);
15422 }
15423
15424 // calculate values for the three fragments
15425 for (int fragment_idx = 0; fragment_idx < 3; fragment_idx++)
15426 {
15427 auto &f = fragments[fragment_idx];
15428 const uint32_t base = fragment_idx == 2 ? 10u : 16u;
15429
15430 // left-trim zeroes
15431 const char *c = f.chars;
15432 size_t sig = {};
15433 while (f.length && *c == '0')
15434 {
15435 f.length--;
15436 c++;
15437 sig++;
15438 }
15439 if (!f.length)
15440 continue;
15441
15442 // calculate value
15443 auto place = 1u;
15444 for (size_t i = 0; i < f.length - 1u; i++)
15445 place *= base;
15446 uint32_t val{};
15447 while (place)
15448 {
15449 if (base == 16)
15450 val += place * hex_to_dec(*c);
15451 else
15452 val += place * static_cast<uint32_t>(*c - '0');
15453 if (fragment_idx == 1)
15454 sig++;
15455 c++;
15456 place /= base;
15457 }
15458 f.value = static_cast<double>(val);
15459
15460 // shift the fractional part
15461 if (fragment_idx == 1)
15462 {
15463 while (sig--)
15464 f.value /= base;
15465 }
15466 }
15467
15468 return (fragments[0].value + fragments[1].value) *
15469 pow(2.0, fragments[2].value * exponent_sign) * sign;
15470
15471# else // !TOML_LANG_UNRELEASED
15472
15474 "hexadecimal floating-point values are not supported "
15475 "in TOML 1.0.0 and earlier"sv);
15476
15477# endif // !TOML_LANG_UNRELEASED
15478 }
15479
15480 template <uint64_t base>
15481 TOML_NODISCARD TOML_NEVER_INLINE int64_t parse_integer()
15482 {
15483 return_if_error({});
15485 using traits = parse_integer_traits<base>;
15486 push_parse_scope(traits::scope_qualifier);
15487
15488 [[maybe_unused]] int64_t sign = 1;
15489 if constexpr (traits::is_signed)
15490 {
15491 sign = *cp == U'-' ? -1 : 1;
15492 if (is_match(*cp, U'+', U'-'))
15494 }
15495
15496 if constexpr (base == 10)
15497 {
15498 if (!traits::is_digit(*cp))
15500 "expected expected digit or sign, saw '"sv, to_sv(*cp), "'"sv);
15501 }
15502 else
15503 {
15504 // '0'
15505 if (*cp != U'0')
15507 "expected '0', saw '"sv, to_sv(*cp), "'"sv);
15509
15510 // 'b', 'o', 'x'
15511 if (*cp != traits::prefix_codepoint)
15513 "expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
15515
15516 if (!traits::is_digit(*cp))
15518 "expected digit, saw '"sv, to_sv(*cp), "'"sv);
15519 }
15520
15521 // consume digits
15523 size_t length = {};
15524 const utf8_codepoint *prev = {};
15525 while (!is_eof() && !is_value_terminator(*cp))
15526 {
15527 if (*cp == U'_')
15528 {
15529 if (!prev || !traits::is_digit(*prev))
15531 "underscores may only follow digits"sv);
15532
15533 prev = cp;
15535 continue;
15536 }
15537 else if TOML_UNLIKELY (prev && *prev == U'_' && !traits::is_digit(*cp))
15539 "underscores must be followed by digits"sv);
15540 else if TOML_UNLIKELY (!traits::is_digit(*cp))
15542 "expected digit, saw '"sv, to_sv(*cp), "'"sv);
15543 else if TOML_UNLIKELY (length == sizeof(digits))
15545 "exceeds length limit of "sv, sizeof(digits), " digits"sv);
15546 else
15547 digits[length++] = static_cast<char>(cp->bytes[0]);
15548
15549 prev = cp;
15551 }
15552
15553 // sanity check ending state
15554 if (prev && *prev == U'_')
15555 {
15558 "underscores must be followed by digits"sv);
15559 }
15560
15561 // single digits can be converted trivially
15562 if (length == 1u)
15563 {
15564 int64_t result;
15565
15566 if constexpr (base == 16)
15567 result = static_cast<int64_t>(hex_to_dec(digits[0]));
15568 else
15569 result = static_cast<int64_t>(digits[0] - '0');
15570
15571 if constexpr (traits::is_signed)
15572 result *= sign;
15573
15574 return result;
15575 }
15576
15577 // bin, oct and hex allow leading zeroes so trim them first
15578 const char *end = digits + length;
15579 const char *msd = digits;
15580 if constexpr (base != 10)
15581 {
15582 while (msd < end && *msd == '0')
15583 msd++;
15584 if (msd == end)
15585 return 0ll;
15586 }
15587
15588 // decimal integers do not allow leading zeroes
15589 else
15590 {
15591 if TOML_UNLIKELY (digits[0] == '0')
15592 set_error_and_return_default("leading zeroes are prohibited"sv);
15593 }
15594
15595 // range check
15596 if TOML_UNLIKELY (static_cast<size_t>(end - msd) > traits::max_digits)
15598 "'"sv,
15599 traits::full_prefix,
15600 std::string_view{digits, length},
15601 "' is not representable as a signed 64-bit integer"sv);
15602
15603 // do the thing
15604 {
15605 uint64_t result = {};
15606 {
15607 uint64_t power = 1;
15608 while (--end >= msd)
15609 {
15610 if constexpr (base == 16)
15611 result += power * hex_to_dec(*end);
15612 else
15613 result += power * static_cast<uint64_t>(*end - '0');
15614
15615 power *= base;
15616 }
15617 }
15618
15619 // range check
15620 static constexpr auto i64_max =
15621 static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
15622 if TOML_UNLIKELY (result > i64_max + (sign < 0 ? 1u : 0u))
15624 "'"sv,
15625 traits::full_prefix,
15626 std::string_view{digits, length},
15627 "' is not representable as a signed 64-bit integer"sv);
15628
15629 if constexpr (traits::is_signed)
15630 {
15631 // avoid signed multiply UB when parsing INT64_MIN
15632 if TOML_UNLIKELY (sign < 0 && result == i64_max + 1u)
15633 return (std::numeric_limits<int64_t>::min)();
15634
15635 return static_cast<int64_t>(result) * sign;
15636 }
15637 else
15638 return static_cast<int64_t>(result);
15639 }
15640 }
15641
15644 date parse_date(bool part_of_datetime = false)
15645 {
15646 return_if_error({});
15648 TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
15649 push_parse_scope("date"sv);
15650
15651 // "YYYY"
15652 uint32_t digits[4];
15653 if (!consume_digit_sequence(digits, 4u))
15655 "expected 4-digit year, saw '"sv, to_sv(cp), "'"sv);
15656 const auto year =
15657 digits[3] + digits[2] * 10u + digits[1] * 100u + digits[0] * 1000u;
15658 const auto is_leap_year =
15659 (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
15661
15662 // '-'
15663 if (*cp != U'-')
15665 "expected '-', saw '"sv, to_sv(*cp), "'"sv);
15667
15668 // "MM"
15669 if (!consume_digit_sequence(digits, 2u))
15671 "expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
15672 const auto month = digits[1] + digits[0] * 10u;
15673 if (month == 0u || month > 12u)
15675 "expected month between 1 and 12 (inclusive), saw "sv, month);
15676 const auto max_days_in_month =
15677 month == 2u
15678 ? (is_leap_year ? 29u : 28u)
15679 : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u
15680 : 31u);
15682
15683 // '-'
15684 if (*cp != U'-')
15686 "expected '-', saw '"sv, to_sv(*cp), "'"sv);
15688
15689 // "DD"
15690 if (!consume_digit_sequence(digits, 2u))
15692 "expected 2-digit day, saw '"sv, to_sv(cp), "'"sv);
15693 const auto day = digits[1] + digits[0] * 10u;
15694 if (day == 0u || day > max_days_in_month)
15696 "expected day between 1 and "sv,
15697 max_days_in_month,
15698 " (inclusive), saw "sv,
15699 day);
15700
15701 if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
15703 "expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
15704
15705 return {year, month, day};
15706 }
15707
15710 time parse_time(bool part_of_datetime = false)
15711 {
15712 return_if_error({});
15714 TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
15715 push_parse_scope("time"sv);
15716
15717 static constexpr size_t max_digits =
15718 64; // far more than necessary but needed to allow fractional
15719 // millisecond truncation per the spec
15720 uint32_t digits[max_digits];
15721
15722 // "HH"
15723 if (!consume_digit_sequence(digits, 2u))
15725 "expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
15726 const auto hour = digits[1] + digits[0] * 10u;
15727 if (hour > 23u)
15729 "expected hour between 0 to 59 (inclusive), saw "sv, hour);
15731
15732 // ':'
15733 if (*cp != U':')
15735 "expected ':', saw '"sv, to_sv(*cp), "'"sv);
15737
15738 // "MM"
15739 if (!consume_digit_sequence(digits, 2u))
15741 "expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
15742 const auto minute = digits[1] + digits[0] * 10u;
15743 if (minute > 59u)
15745 "expected minute between 0 and 59 (inclusive), saw "sv, minute);
15746 auto time = toml::time{hour, minute};
15747
15748 // ':'
15749 if constexpr (
15750 TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
15751 {
15752 if (
15753 is_eof() || is_value_terminator(*cp) ||
15754 (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
15755 return time;
15756 }
15757 else
15759 if (*cp != U':')
15761 "expected ':', saw '"sv, to_sv(*cp), "'"sv);
15763
15764 // "SS"
15765 if (!consume_digit_sequence(digits, 2u))
15767 "expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
15768 const auto second = digits[1] + digits[0] * 10u;
15769 if (second > 59u)
15771 "expected second between 0 and 59 (inclusive), saw "sv, second);
15772 time.second = static_cast<decltype(time.second)>(second);
15773
15774 // '.' (early-exiting is allowed; fractional is optional)
15775 if (
15776 is_eof() || is_value_terminator(*cp) ||
15777 (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
15778 return time;
15779 if (*cp != U'.')
15781 "expected '.', saw '"sv, to_sv(*cp), "'"sv);
15783
15784 // "FFFFFFFFF"
15785 size_t digit_count =
15786 consume_variable_length_digit_sequence(digits, max_digits);
15787 if (!digit_count)
15788 {
15791 "expected fractional digits, saw '"sv, to_sv(*cp), "'"sv);
15792 }
15793 else if (!is_eof())
15794 {
15795 if (digit_count == max_digits && is_decimal_digit(*cp))
15797 "fractional component exceeds maximum precision of "sv, max_digits);
15798 else if (!part_of_datetime && !is_value_terminator(*cp))
15800 "expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
15801 }
15802 uint32_t value = 0u;
15803 uint32_t place = 1u;
15804 for (auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;)
15805 {
15806 value += digits[i] * place;
15807 place *= 10u;
15808 }
15809 for (auto i = digit_count; i < 9u; i++) // implicit zeros
15810 value *= 10u;
15811 time.nanosecond = value;
15812 return time;
15813 }
15814
15817 date_time parse_date_time()
15818 {
15819 return_if_error({});
15821 TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
15822 push_parse_scope("date-time"sv);
15823
15824 // "YYYY-MM-DD"
15825 auto date = parse_date(true);
15827
15828 // ' ', 'T' or 't'
15829 if (!is_match(*cp, U' ', U'T', U't'))
15831 "expected space, 'T' or 't', saw '"sv, to_sv(*cp), "'"sv);
15833
15834 // "HH:MM:SS.FFFFFFFFF"
15835 auto time = parse_time(true);
15836 return_if_error({});
15837
15838 // no offset
15839 if (is_eof() || is_value_terminator(*cp))
15840 return {date, time};
15841
15842 // zero offset ('Z' or 'z')
15843 time_offset offset{};
15844 if (is_match(*cp, U'Z', U'z'))
15846
15847 // explicit offset ("+/-HH:MM")
15848 else if (is_match(*cp, U'+', U'-'))
15849 {
15850 push_parse_scope("date-time offset"sv);
15851
15852 // sign
15853 int sign = *cp == U'-' ? -1 : 1;
15855
15856 // "HH"
15857 int digits[2];
15858 if (!consume_digit_sequence(digits, 2u))
15860 "expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
15861 const auto hour = digits[1] + digits[0] * 10;
15862 if (hour > 23)
15864 "expected hour between 0 and 23 (inclusive), saw "sv, hour);
15866
15867 // ':'
15868 if (*cp != U':')
15870 "expected ':', saw '"sv, to_sv(*cp), "'"sv);
15872
15873 // "MM"
15874 if (!consume_digit_sequence(digits, 2u))
15876 "expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
15877 const auto minute = digits[1] + digits[0] * 10;
15878 if (minute > 59)
15880 "expected minute between 0 and 59 (inclusive), saw "sv, minute);
15881 offset.minutes =
15882 static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
15883 }
15884
15885 if (!is_eof() && !is_value_terminator(*cp))
15887 "expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
15888
15889 return {date, time, offset};
15890 }
15891
15893 node_ptr parse_array();
15894
15896 node_ptr parse_inline_table();
15897
15899 node_ptr parse_value_known_prefixes()
15900 {
15901 return_if_error({});
15903 TOML_ASSERT_ASSUME(!is_control_character(*cp));
15904 TOML_ASSERT_ASSUME(*cp != U'_');
15905
15906 switch (cp->value)
15907 {
15908 // arrays
15909 case U'[':
15910 return parse_array();
15911
15912 // inline tables
15913 case U'{':
15914 return parse_inline_table();
15915
15916 // floats beginning with '.'
15917 case U'.':
15918 return node_ptr{new value{parse_float()}};
15919
15920 // strings
15921 case U'"':
15922 [[fallthrough]];
15923 case U'\'':
15924 return node_ptr{new value{parse_string().value}};
15925
15926 default:
15927 {
15928 const auto cp_upper = static_cast<uint_least32_t>(cp->value) & ~0x20u;
15929
15930 // bools
15931 if (cp_upper == 70u || cp_upper == 84u) // F or T
15932 return node_ptr{new value{parse_boolean()}};
15933
15934 // inf/nan
15935 else if (cp_upper == 73u || cp_upper == 78u) // I or N
15936 return node_ptr{new value{parse_inf_or_nan()}};
15937
15938 else
15939 return nullptr;
15940 }
15941 }
15943 }
15944
15946 node_ptr parse_value()
15947 {
15948 return_if_error({});
15950 TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
15951 push_parse_scope("value"sv);
15952
15953 const depth_counter_scope depth_counter{nested_values};
15954 if TOML_UNLIKELY (nested_values > max_nested_values)
15956 "exceeded maximum nested value depth of "sv,
15957 max_nested_values,
15958 " (TOML_MAX_NESTED_VALUES)"sv);
15959
15960 // check if it begins with some control character
15961 // (note that this will also fail for whitespace but we're assuming we've
15962 // called consume_leading_whitespace() before calling parse_value())
15963 if TOML_UNLIKELY (is_control_character(*cp))
15964 set_error_and_return_default("unexpected control character"sv);
15965
15966 // underscores at the beginning
15967 else if (*cp == U'_')
15968 set_error_and_return_default("values may not begin with underscores"sv);
15969
15970 const auto begin_pos = cp->position;
15971 node_ptr val;
15972
15973 do
15974 {
15975 TOML_ASSERT_ASSUME(!is_control_character(*cp));
15976 TOML_ASSERT_ASSUME(*cp != U'_');
15977
15978 // detect the value type and parse accordingly,
15979 // starting with value types that can be detected
15980 // unambiguously from just one character.
15981
15982 val = parse_value_known_prefixes();
15983 return_if_error({});
15984 if (val)
15985 break;
15986
15987 // value types from here down require more than one character to unambiguously identify
15988 // so scan ahead and collect a set of value 'traits'.
15990 {
15991 has_nothing = 0,
15992 has_digits = 1,
15993 has_b = 1 << 1, // as second char only (0b)
15994 has_e = 1 << 2, // only float exponents
15995 has_o = 1 << 3, // as second char only (0o)
15996 has_p = 1 << 4, // only hexfloat exponents
15997 has_t = 1 << 5,
15998 has_x = 1 << 6, // as second or third char only (0x, -0x, +0x)
15999 has_z = 1 << 7,
16000 has_colon = 1 << 8,
16001 has_plus = 1 << 9,
16002 has_minus = 1 << 10,
16003 has_dot = 1 << 11,
16004 begins_sign = 1 << 12,
16005 begins_digit = 1 << 13,
16006 begins_zero = 1 << 14,
16007 signs_msk = has_plus | has_minus,
16008 bdigit_msk = has_digits | begins_digit,
16009 bzero_msk = bdigit_msk | begins_zero,
16010 };
16011 value_traits traits = has_nothing;
16012 const auto has_any = [&](auto t) noexcept
16013 { return (traits & t) != has_nothing; };
16014 const auto has_none = [&](auto t) noexcept
16015 { return (traits & t) == has_nothing; };
16016 const auto add_trait = [&](auto t) noexcept
16017 { traits = static_cast<value_traits>(traits | t); };
16018
16019 // examine the first character to get the 'begins with' traits
16020 // (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
16021 if (is_decimal_digit(*cp))
16022 {
16023 add_trait(begins_digit);
16024 if (*cp == U'0')
16025 add_trait(begins_zero);
16026 }
16027 else if (is_match(*cp, U'+', U'-'))
16028 add_trait(begins_sign);
16029 else
16030 break;
16031
16032 // scan the rest of the value to determine the remaining traits
16034 size_t char_count = {}, advance_count = {};
16035 bool eof_while_scanning = false;
16036 const auto scan = [&]() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
16037 {
16038 if (is_eof())
16039 return;
16040 TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
16041
16042 do
16043 {
16044 if (const auto c = **cp; c != U'_')
16045 {
16046 chars[char_count++] = c;
16047
16048 if (is_decimal_digit(c))
16049 add_trait(has_digits);
16050 else if (is_ascii_letter(c))
16051 {
16053 (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
16054 switch (static_cast<char32_t>(c | 32u))
16055 {
16056 case U'b':
16057 if (char_count == 2u && has_any(begins_zero))
16058 add_trait(has_b);
16059 break;
16060
16061 case U'e':
16062 if (
16063 char_count > 1u &&
16064 has_none(
16065 has_b | has_o | has_p | has_t | has_x | has_z |
16066 has_colon) &&
16067 (has_none(has_plus | has_minus) || has_any(begins_sign)))
16068 add_trait(has_e);
16069 break;
16070
16071 case U'o':
16072 if (char_count == 2u && has_any(begins_zero))
16073 add_trait(has_o);
16074 break;
16075
16076 case U'p':
16077 if (has_any(has_x))
16078 add_trait(has_p);
16079 break;
16080
16081 case U'x':
16082 if (
16083 (char_count == 2u && has_any(begins_zero)) ||
16084 (char_count == 3u && has_any(begins_sign) &&
16085 chars[1] == U'0'))
16086 add_trait(has_x);
16087 break;
16088
16089 case U't':
16090 add_trait(has_t);
16091 break;
16092 case U'z':
16093 add_trait(has_z);
16094 break;
16095 }
16096 }
16097 else if (c <= U':')
16098 {
16099 TOML_ASSERT_ASSUME(c < U'0' || c > U'9');
16100 switch (c)
16101 {
16102 case U'+':
16103 add_trait(has_plus);
16104 break;
16105 case U'-':
16106 add_trait(has_minus);
16107 break;
16108 case U'.':
16109 add_trait(has_dot);
16110 break;
16111 case U':':
16112 add_trait(has_colon);
16113 break;
16114 }
16115 }
16116 }
16117
16119 advance_count++;
16120 eof_while_scanning = is_eof();
16121 } while (advance_count <
16123 !is_eof() && !is_value_terminator(*cp));
16124 };
16125 scan();
16126 return_if_error({});
16127
16128 // force further scanning if this could have been a date-time with a space instead of a T
16129 if (
16130 char_count == 10u //
16131 && (traits | begins_zero) == (bzero_msk | has_minus) //
16132 && chars[4] == U'-' //
16133 && chars[7] == U'-' //
16134 && !is_eof() //
16135 && *cp == U' ')
16136 {
16137 const auto pre_advance_count = advance_count;
16138 const auto pre_scan_traits = traits;
16139 chars[char_count++] = *cp;
16140 add_trait(has_t);
16141
16142 const auto backpedal = [&]() noexcept
16143 {
16144 go_back(advance_count - pre_advance_count);
16145 advance_count = pre_advance_count;
16146 traits = pre_scan_traits;
16147 char_count = 10u;
16148 };
16149
16151 advance_count++;
16152
16153 if (is_eof() || !is_decimal_digit(*cp))
16154 backpedal();
16155 else
16156 {
16157 chars[char_count++] = *cp;
16158
16160 advance_count++;
16161
16162 scan();
16163 return_if_error({});
16164
16165 if (char_count == 12u)
16166 backpedal();
16167 }
16168 }
16169
16170 // set the reader back to where we started
16171 go_back(advance_count);
16172
16173 // if after scanning ahead we still only have one value character,
16174 // the only valid value type is an integer.
16175 if (char_count == 1u)
16176 {
16177 if (has_any(begins_digit))
16178 {
16179 val.reset(new value{static_cast<int64_t>(chars[0] - U'0')});
16180 advance(); // skip the digit
16181 break;
16182 }
16183
16184 // anything else would be ambiguous.
16185 else
16187 eof_while_scanning ? "encountered end-of-file"sv
16188 : "could not determine value type"sv);
16189 }
16190
16191 // now things that can be identified from two or more characters
16192 return_if_error({});
16193 TOML_ASSERT_ASSUME(char_count >= 2u);
16194
16195 // do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
16196 // typed parse functions to take over and show better diagnostics if there's an issue
16197 // (as opposed to the fallback "could not determine type" message)
16198 if (has_any(has_p))
16199 val.reset(new value{parse_hex_float()});
16200 else if (has_any(has_x | has_o | has_b))
16201 {
16202 int64_t i;
16203 value_flags flags;
16204 if (has_any(has_x))
16205 {
16206 i = parse_integer<16>();
16207 flags = value_flags::format_as_hexadecimal;
16208 }
16209 else if (has_any(has_o))
16210 {
16211 i = parse_integer<8>();
16212 flags = value_flags::format_as_octal;
16213 }
16214 else // has_b
16215 {
16216 i = parse_integer<2>();
16217 flags = value_flags::format_as_binary;
16218 }
16219 return_if_error({});
16220
16221 val.reset(new value{i});
16222 val->ref_cast<int64_t>().flags(flags);
16223 }
16224 else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
16225 val.reset(new value{parse_float()});
16226 else if (has_any(begins_sign))
16227 {
16228 // single-digit signed integers
16229 if (char_count == 2u && has_any(has_digits))
16230 {
16231 val.reset(new value{
16232 static_cast<int64_t>(chars[1] - U'0') *
16233 (chars[0] == U'-' ? -1LL : 1LL)});
16234 advance(); // skip the sign
16235 advance(); // skip the digit
16236 break;
16237 }
16238
16239 // simple signed floats (e.g. +1.0)
16240 if (is_decimal_digit(chars[1]) && chars[2] == U'.')
16241 val.reset(new value{parse_float()});
16242
16243 // signed infinity or nan
16244 else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
16245 val.reset(new value{parse_inf_or_nan()});
16246 }
16247
16248 return_if_error({});
16249 if (val)
16250 break;
16251
16252 // match trait masks against what they can match exclusively.
16253 // all correct value parses will come out of this list, so doing this as a switch is likely to
16254 // be a better friend to the optimizer on the success path (failure path can be slow but that
16255 // doesn't matter much).
16256 switch (unwrap_enum(traits))
16257 {
16258 // binary integers
16259 // 0b10
16260 case bzero_msk | has_b:
16261 val.reset(new value{parse_integer<2>()});
16262 val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
16263 break;
16264
16265 // octal integers
16266 // 0o10
16267 case bzero_msk | has_o:
16268 val.reset(new value{parse_integer<8>()});
16269 val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
16270 break;
16271
16272 // decimal integers
16273 // 00
16274 // 10
16275 // +10
16276 // -10
16277 case bzero_msk:
16278 [[fallthrough]];
16279 case bdigit_msk:
16280 [[fallthrough]];
16281 case begins_sign | has_digits | has_minus:
16282 [[fallthrough]];
16283 case begins_sign | has_digits | has_plus:
16284 {
16285 // if the value was so long we exhausted the history buffer it's reasonable to assume
16286 // there was more and the value's actual type is impossible to identify without making the
16287 // buffer bigger (since it could have actually been a float), so emit an error.
16288 //
16289 // (this will likely only come up during fuzzing and similar scenarios)
16290 static constexpr size_t max_numeric_value_length =
16292 if TOML_UNLIKELY (
16293 !eof_while_scanning && advance_count > max_numeric_value_length)
16295 "numeric value too long to identify type - cannot exceed "sv,
16296 max_numeric_value_length,
16297 " characters"sv);
16298
16299 val.reset(new value{parse_integer<10>()});
16300 break;
16301 }
16302
16303 // hexadecimal integers
16304 // 0x10
16305 case bzero_msk | has_x:
16306 val.reset(new value{parse_integer<16>()});
16307 val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
16308 break;
16309
16310 // decimal floats
16311 // 0e1
16312 // 0e-1
16313 // 0e+1
16314 // 0.0
16315 // 0.0e1
16316 // 0.0e-1
16317 // 0.0e+1
16318 case bzero_msk | has_e:
16319 [[fallthrough]];
16320 case bzero_msk | has_e | has_minus:
16321 [[fallthrough]];
16322 case bzero_msk | has_e | has_plus:
16323 [[fallthrough]];
16324 case bzero_msk | has_dot:
16325 [[fallthrough]];
16326 case bzero_msk | has_dot | has_e:
16327 [[fallthrough]];
16328 case bzero_msk | has_dot | has_e | has_minus:
16329 [[fallthrough]];
16330 case bzero_msk | has_dot | has_e | has_plus:
16331 [[fallthrough]];
16332 // 1e1
16333 // 1e-1
16334 // 1e+1
16335 // 1.0
16336 // 1.0e1
16337 // 1.0e-1
16338 // 1.0e+1
16339 case bdigit_msk | has_e:
16340 [[fallthrough]];
16341 case bdigit_msk | has_e | has_minus:
16342 [[fallthrough]];
16343 case bdigit_msk | has_e | has_plus:
16344 [[fallthrough]];
16345 case bdigit_msk | has_dot:
16346 [[fallthrough]];
16347 case bdigit_msk | has_dot | has_e:
16348 [[fallthrough]];
16349 case bdigit_msk | has_dot | has_e | has_minus:
16350 [[fallthrough]];
16351 case bdigit_msk | has_dot | has_e | has_plus:
16352 [[fallthrough]];
16353 // +1e1
16354 // +1.0
16355 // +1.0e1
16356 // +1.0e+1
16357 // +1.0e-1
16358 // -1.0e+1
16359 case begins_sign | has_digits | has_e | has_plus:
16360 [[fallthrough]];
16361 case begins_sign | has_digits | has_dot | has_plus:
16362 [[fallthrough]];
16363 case begins_sign | has_digits | has_dot | has_e | has_plus:
16364 [[fallthrough]];
16365 case begins_sign | has_digits | has_dot | has_e | signs_msk:
16366 [[fallthrough]];
16367 // -1e1
16368 // -1e+1
16369 // +1e-1
16370 // -1.0
16371 // -1.0e1
16372 // -1.0e-1
16373 case begins_sign | has_digits | has_e | has_minus:
16374 [[fallthrough]];
16375 case begins_sign | has_digits | has_e | signs_msk:
16376 [[fallthrough]];
16377 case begins_sign | has_digits | has_dot | has_minus:
16378 [[fallthrough]];
16379 case begins_sign | has_digits | has_dot | has_e | has_minus:
16380 val.reset(new value{parse_float()});
16381 break;
16382
16383 // hexadecimal floats
16384 // 0x10p0
16385 // 0x10p-0
16386 // 0x10p+0
16387 case bzero_msk | has_x | has_p:
16388 [[fallthrough]];
16389 case bzero_msk | has_x | has_p | has_minus:
16390 [[fallthrough]];
16391 case bzero_msk | has_x | has_p | has_plus:
16392 [[fallthrough]];
16393 // -0x10p0
16394 // -0x10p-0
16395 // +0x10p0
16396 // +0x10p+0
16397 // -0x10p+0
16398 // +0x10p-0
16399 case begins_sign | has_digits | has_x | has_p | has_minus:
16400 [[fallthrough]];
16401 case begins_sign | has_digits | has_x | has_p | has_plus:
16402 [[fallthrough]];
16403 case begins_sign | has_digits | has_x | has_p | signs_msk:
16404 [[fallthrough]];
16405 // 0x10.1p0
16406 // 0x10.1p-0
16407 // 0x10.1p+0
16408 case bzero_msk | has_x | has_dot | has_p:
16409 [[fallthrough]];
16410 case bzero_msk | has_x | has_dot | has_p | has_minus:
16411 [[fallthrough]];
16412 case bzero_msk | has_x | has_dot | has_p | has_plus:
16413 [[fallthrough]];
16414 // -0x10.1p0
16415 // -0x10.1p-0
16416 // +0x10.1p0
16417 // +0x10.1p+0
16418 // -0x10.1p+0
16419 // +0x10.1p-0
16420 case begins_sign | has_digits | has_x | has_dot | has_p | has_minus:
16421 [[fallthrough]];
16422 case begins_sign | has_digits | has_x | has_dot | has_p | has_plus:
16423 [[fallthrough]];
16424 case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
16425 val.reset(new value{parse_hex_float()});
16426 break;
16427
16428 // times
16429 // HH:MM
16430 // HH:MM:SS
16431 // HH:MM:SS.FFFFFF
16432 case bzero_msk | has_colon:
16433 [[fallthrough]];
16434 case bzero_msk | has_colon | has_dot:
16435 [[fallthrough]];
16436 case bdigit_msk | has_colon:
16437 [[fallthrough]];
16438 case bdigit_msk | has_colon | has_dot:
16439 val.reset(new value{parse_time()});
16440 break;
16441
16442 // local dates
16443 // YYYY-MM-DD
16444 case bzero_msk | has_minus:
16445 [[fallthrough]];
16446 case bdigit_msk | has_minus:
16447 val.reset(new value{parse_date()});
16448 break;
16449
16450 // date-times
16451 // YYYY-MM-DDTHH:MM
16452 // YYYY-MM-DDTHH:MM-HH:MM
16453 // YYYY-MM-DDTHH:MM+HH:MM
16454 // YYYY-MM-DD HH:MM
16455 // YYYY-MM-DD HH:MM-HH:MM
16456 // YYYY-MM-DD HH:MM+HH:MM
16457 // YYYY-MM-DDTHH:MM:SS
16458 // YYYY-MM-DDTHH:MM:SS-HH:MM
16459 // YYYY-MM-DDTHH:MM:SS+HH:MM
16460 // YYYY-MM-DD HH:MM:SS
16461 // YYYY-MM-DD HH:MM:SS-HH:MM
16462 // YYYY-MM-DD HH:MM:SS+HH:MM
16463 case bzero_msk | has_minus | has_colon | has_t:
16464 [[fallthrough]];
16465 case bzero_msk | signs_msk | has_colon | has_t:
16466 [[fallthrough]];
16467 case bdigit_msk | has_minus | has_colon | has_t:
16468 [[fallthrough]];
16469 case bdigit_msk | signs_msk | has_colon | has_t:
16470 [[fallthrough]];
16471 // YYYY-MM-DDTHH:MM:SS.FFFFFF
16472 // YYYY-MM-DDTHH:MM:SS.FFFFFF-HH:MM
16473 // YYYY-MM-DDTHH:MM:SS.FFFFFF+HH:MM
16474 // YYYY-MM-DD HH:MM:SS.FFFFFF
16475 // YYYY-MM-DD HH:MM:SS.FFFFFF-HH:MM
16476 // YYYY-MM-DD HH:MM:SS.FFFFFF+HH:MM
16477 case bzero_msk | has_minus | has_colon | has_dot | has_t:
16478 [[fallthrough]];
16479 case bzero_msk | signs_msk | has_colon | has_dot | has_t:
16480 [[fallthrough]];
16481 case bdigit_msk | has_minus | has_colon | has_dot | has_t:
16482 [[fallthrough]];
16483 case bdigit_msk | signs_msk | has_colon | has_dot | has_t:
16484 [[fallthrough]];
16485 // YYYY-MM-DDTHH:MMZ
16486 // YYYY-MM-DD HH:MMZ
16487 // YYYY-MM-DDTHH:MM:SSZ
16488 // YYYY-MM-DD HH:MM:SSZ
16489 // YYYY-MM-DDTHH:MM:SS.FFFFFFZ
16490 // YYYY-MM-DD HH:MM:SS.FFFFFFZ
16491 case bzero_msk | has_minus | has_colon | has_z | has_t:
16492 [[fallthrough]];
16493 case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t:
16494 [[fallthrough]];
16495 case bdigit_msk | has_minus | has_colon | has_z | has_t:
16496 [[fallthrough]];
16497 case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
16498 val.reset(new value{parse_date_time()});
16499 break;
16500 }
16501 } while (false);
16502
16503 if (!val)
16504 {
16505 set_error_at(begin_pos, "could not determine value type"sv);
16507 }
16508
16509 val->source_ = {begin_pos, current_position(1), reader.source_path()};
16510 return val;
16511 }
16512
16514 bool parse_key()
16515 {
16516 return_if_error({});
16519 is_bare_key_character(*cp) || is_string_delimiter(*cp));
16520 push_parse_scope("key"sv);
16521
16522 key_buffer.clear();
16523 recording_whitespace = false;
16524
16525 while (!is_error())
16526 {
16527 std::string_view key_segment;
16528 const auto key_begin = current_position();
16529
16530 // bare_key_segment
16531 if (is_bare_key_character(*cp))
16532 key_segment = parse_bare_key_segment();
16533
16534 // "quoted key segment"
16535 else if (is_string_delimiter(*cp))
16536 {
16537 const auto begin_pos = cp->position;
16538
16539 recording_whitespace = true;
16540 parsed_string str = parse_string();
16541 recording_whitespace = false;
16542 return_if_error({});
16543
16544 if (str.was_multi_line)
16545 {
16546 set_error_at(
16547 begin_pos,
16548 "multi-line strings are prohibited in "sv,
16549 key_buffer.empty() ? ""sv : "dotted "sv,
16550 "keys"sv);
16552 }
16553 else
16554 key_segment = str.value;
16555 }
16556
16557 // ???
16558 else
16560 "expected bare key starting character or string delimiter, saw '"sv,
16561 to_sv(*cp),
16562 "'"sv);
16563
16564 const auto key_end = current_position();
16565
16566 // whitespace following the key segment
16567 consume_leading_whitespace();
16568
16569 // store segment
16570 key_buffer.push_back(key_segment, key_begin, key_end);
16571
16572 // eof or no more key to come
16573 if (is_eof() || *cp != U'.')
16574 break;
16575
16576 // was a dotted key - go around again
16578 consume_leading_whitespace();
16580 }
16581 return_if_error({});
16582
16583 return true;
16584 }
16585
16587 key make_key(size_t segment_index) const
16588 {
16589 TOML_ASSERT(key_buffer.size() > segment_index);
16590
16591 return key{
16592 key_buffer[segment_index],
16594 key_buffer.starts[segment_index],
16595 key_buffer.ends[segment_index],
16596 root.source().path}};
16597 }
16598
16601 table *parse_table_header()
16602 {
16603 return_if_error({});
16605 TOML_ASSERT_ASSUME(*cp == U'[');
16606 push_parse_scope("table header"sv);
16607
16608 const source_position header_begin_pos = cp->position;
16609 source_position header_end_pos;
16610 bool is_arr = false;
16611
16612 // parse header
16613 {
16614 // skip first '['
16616
16617 // skip past any whitespace that followed the '['
16618 const bool had_leading_whitespace = consume_leading_whitespace();
16620
16621 // skip second '[' (if present)
16622 if (*cp == U'[')
16623 {
16624 if (had_leading_whitespace)
16626 "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv);
16627
16628 is_arr = true;
16630
16631 // skip past any whitespace that followed the '['
16632 consume_leading_whitespace();
16634 }
16635
16636 // check for a premature closing ']'
16637 if (*cp == U']')
16639 "tables with blank bare keys are explicitly prohibited"sv);
16640
16641 // get the actual key
16642 start_recording();
16643 parse_key();
16644 stop_recording(1u);
16645 return_if_error({});
16646
16647 // skip past any whitespace that followed the key
16648 consume_leading_whitespace();
16649 return_if_error({});
16651
16652 // consume the closing ']'
16653 if (*cp != U']')
16655 "expected ']', saw '"sv, to_sv(*cp), "'"sv);
16656 if (is_arr)
16657 {
16659 if (*cp != U']')
16661 "expected ']', saw '"sv, to_sv(*cp), "'"sv);
16662 }
16664 header_end_pos = current_position(1);
16665
16666 // handle the rest of the line after the header
16667 consume_leading_whitespace();
16668 if (!is_eof() && !consume_comment() && !consume_line_break())
16670 "expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
16671 }
16672 TOML_ASSERT(!key_buffer.empty());
16673
16674 // check if each parent is a table/table array, or can be created implicitly as a table.
16675 table *parent = &root;
16676 for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++)
16677 {
16678 const std::string_view segment = key_buffer[i];
16679 auto pit = parent->lower_bound(segment);
16680
16681 // parent already existed
16682 if (pit != parent->end() && pit->first == segment)
16683 {
16684 node &p = pit->second;
16685
16686 if (auto tbl = p.as_table())
16687 {
16688 // adding to closed inline tables is illegal
16689 if (
16690 tbl->is_inline() &&
16691 !impl::find(
16692 open_inline_tables.begin(), open_inline_tables.end(), tbl))
16694 "cannot insert '"sv,
16695 to_sv(recording_buffer),
16696 "' into existing inline table"sv);
16697
16698 parent = tbl;
16699 }
16700 else if (auto arr = p.as_array();
16701 arr &&
16702 impl::find(table_arrays.begin(), table_arrays.end(), arr))
16703 {
16704 // table arrays are a special case;
16705 // the spec dictates we select the most recently declared element in the array.
16706 TOML_ASSERT(!arr->empty());
16707 TOML_ASSERT(arr->back().is_table());
16708 parent = &arr->back().ref_cast<table>();
16709 }
16710 else
16711 {
16712 if (!is_arr && p.type() == node_type::table)
16714 "cannot redefine existing table '"sv,
16715 to_sv(recording_buffer),
16716 "'"sv);
16717 else
16719 "cannot redefine existing "sv,
16720 to_sv(p.type()),
16721 " '"sv,
16722 to_sv(recording_buffer),
16723 "' as "sv,
16724 is_arr ? "array-of-tables"sv : "table"sv);
16725 }
16726 }
16727
16728 // need to create a new implicit table
16729 else
16730 {
16731 pit = parent->emplace_hint<table>(pit, make_key(i));
16732 table &p = pit->second.ref_cast<table>();
16733 p.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
16734
16735 implicit_tables.push_back(&p);
16736 parent = &p;
16737 }
16738 }
16739
16740 const auto last_segment = key_buffer.back();
16741 auto it = parent->lower_bound(last_segment);
16742
16743 // if there was already a matching node some sanity checking is necessary;
16744 // this is ok if we're making an array and the existing element is already an array (new element)
16745 // or if we're making a table and the existing element is an implicitly-created table (promote it),
16746 // otherwise this is a redefinition error.
16747 if (it != parent->end() && it->first == last_segment)
16748 {
16749 node &matching_node = it->second;
16750 if (auto arr = matching_node.as_array();
16751 is_arr && arr &&
16752 impl::find(table_arrays.begin(), table_arrays.end(), arr))
16753 {
16754 table &tbl = arr->emplace_back<table>();
16755 tbl.source_ = {
16756 header_begin_pos, header_end_pos, reader.source_path()};
16757 return &tbl;
16758 }
16759
16760 else if (auto tbl = matching_node.as_table();
16761 !is_arr && tbl && !implicit_tables.empty())
16762 {
16763 if (auto found =
16764 impl::find(implicit_tables.begin(), implicit_tables.end(), tbl);
16765 found)
16766 {
16767 bool ok = true;
16768 if (!tbl->empty())
16769 {
16770 for (auto &[_, child] : *tbl)
16771 {
16772 if (!child.is_table() && !child.is_array_of_tables())
16773 {
16774 ok = false;
16775 break;
16776 }
16777 }
16778 }
16779
16780 if (ok)
16781 {
16782 implicit_tables.erase(
16783 implicit_tables.cbegin() + (found - implicit_tables.data()));
16784 tbl->source_.begin = header_begin_pos;
16785 tbl->source_.end = header_end_pos;
16786 return tbl;
16787 }
16788 }
16789 }
16790
16791 // if we get here it's a redefinition error.
16792 if (!is_arr && matching_node.type() == node_type::table)
16793 {
16794 set_error_at(
16795 header_begin_pos,
16796 "cannot redefine existing table '"sv,
16797 to_sv(recording_buffer),
16798 "'"sv);
16800 }
16801 else
16802 {
16803 set_error_at(
16804 header_begin_pos,
16805 "cannot redefine existing "sv,
16806 to_sv(matching_node.type()),
16807 " '"sv,
16808 to_sv(recording_buffer),
16809 "' as "sv,
16810 is_arr ? "array-of-tables"sv : "table"sv);
16812 }
16813 }
16814
16815 // there was no matching node, sweet - we can freely instantiate a new table/table array.
16816 else
16817 {
16818 auto last_key = make_key(key_buffer.size() - 1u);
16819
16820 // if it's an array we need to make the array and it's first table element,
16821 // set the starting regions, and return the table element
16822 if (is_arr)
16823 {
16824 it = parent->emplace_hint<array>(it, std::move(last_key));
16825 array &tbl_arr = it->second.ref_cast<array>();
16826 table_arrays.push_back(&tbl_arr);
16827 tbl_arr.source_ = {
16828 header_begin_pos, header_end_pos, reader.source_path()};
16829
16830 table &tbl = tbl_arr.emplace_back<table>();
16831 tbl.source_ = {
16832 header_begin_pos, header_end_pos, reader.source_path()};
16833 return &tbl;
16834 }
16835
16836 // otherwise we're just making a table
16837 else
16838 {
16839 it = parent->emplace_hint<table>(it, std::move(last_key));
16840 table &tbl = it->second.ref_cast<table>();
16841 tbl.source_ = {
16842 header_begin_pos, header_end_pos, reader.source_path()};
16843 return &tbl;
16844 }
16845 }
16846 }
16847
16849 bool parse_key_value_pair_and_insert(table *tbl)
16850 {
16851 return_if_error({});
16854 is_string_delimiter(*cp) || is_bare_key_character(*cp));
16855 push_parse_scope("key-value pair"sv);
16856
16857 // read the key into the key buffer
16858 start_recording();
16859 parse_key();
16860 stop_recording(1u);
16861 return_if_error({});
16862 TOML_ASSERT(key_buffer.size() >= 1u);
16863
16864 // skip past any whitespace that followed the key
16865 consume_leading_whitespace();
16867
16868 // '='
16869 if (*cp != U'=')
16871 "expected '=', saw '"sv, to_sv(*cp), "'"sv);
16873
16874 // skip past any whitespace that followed the '='
16875 consume_leading_whitespace();
16876 return_if_error({});
16878
16879 // check that the next character could actually be a value
16880 if (is_value_terminator(*cp))
16882 "expected value, saw '"sv, to_sv(*cp), "'"sv);
16883
16884 // if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
16885 // and set the target table to the second-to-last one in the chain
16886 if (key_buffer.size() > 1u)
16887 {
16888 for (size_t i = 0; i < key_buffer.size() - 1u; i++)
16889 {
16890 const std::string_view segment = key_buffer[i];
16891 auto pit = tbl->lower_bound(segment);
16892
16893 // parent already existed
16894 if (pit != tbl->end() && pit->first == segment)
16895 {
16896 table *p = pit->second.as_table();
16897
16898 // redefinition
16899 if TOML_UNLIKELY (
16900 !p ||
16901 !(impl::find(
16902 dotted_key_tables.begin(), dotted_key_tables.end(), p) ||
16903 impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
16904 {
16905 set_error_at(
16906 key_buffer.starts[i],
16907 "cannot redefine existing "sv,
16908 to_sv(pit->second.type()),
16909 " as dotted key-value pair"sv);
16911 }
16912
16913 tbl = p;
16914 }
16915
16916 // need to create a new implicit table
16917 else
16918 {
16919 pit = tbl->emplace_hint<table>(pit, make_key(i));
16920 table &p = pit->second.ref_cast<table>();
16921 p.source_ = pit->first.source();
16922
16923 dotted_key_tables.push_back(&p);
16924 tbl = &p;
16925 }
16926 }
16927 }
16928
16929 // ensure this isn't a redefinition
16930 const std::string_view last_segment = key_buffer.back();
16931 auto it = tbl->lower_bound(last_segment);
16932 if (it != tbl->end() && it->first == last_segment)
16933 {
16934 set_error(
16935 "cannot redefine existing "sv,
16936 to_sv(it->second.type()),
16937 " '"sv,
16938 to_sv(recording_buffer),
16939 "'"sv);
16941 }
16942
16943 // create the key first since the key buffer will likely get overwritten during value parsing (inline
16944 // tables)
16945 auto last_key = make_key(key_buffer.size() - 1u);
16946
16947 // now we can actually parse the value
16948 node_ptr val = parse_value();
16949 return_if_error({});
16950
16951 tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
16952 return true;
16953 }
16954
16955 void parse_document()
16956 {
16959 push_parse_scope("root table"sv);
16960
16961 table *current_table = &root;
16962
16963 do
16964 {
16966
16967 // leading whitespace, line endings, comments
16968 if (
16969 consume_leading_whitespace() || consume_line_break() ||
16970 consume_comment())
16971 continue;
16973
16974 // [tables]
16975 // [[table array]]
16976 if (*cp == U'[')
16977 current_table = parse_table_header();
16978
16979 // bare_keys
16980 // dotted.keys
16981 // "quoted keys"
16982 else if (is_bare_key_character(*cp) || is_string_delimiter(*cp))
16983 {
16984 push_parse_scope("key-value pair"sv);
16985
16986 parse_key_value_pair_and_insert(current_table);
16987
16988 // handle the rest of the line after the kvp
16989 // (this is not done in parse_key_value_pair() because that is also used for inline tables)
16990 consume_leading_whitespace();
16992 if (!is_eof() && !consume_comment() && !consume_line_break())
16993 set_error(
16994 "expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
16995 }
16996
16997 else // ??
16998 set_error(
16999 "expected keys, tables, whitespace or comments, saw '"sv,
17000 to_sv(cp),
17001 "'"sv);
17002 } while (!is_eof());
17003
17004 auto eof_pos = current_position(1);
17005 root.source_.end = eof_pos;
17006 if (
17007 current_table && current_table != &root &&
17008 current_table->source_.end <= current_table->source_.begin)
17009 current_table->source_.end = eof_pos;
17010 }
17011
17012 static void update_region_ends(node &nde) noexcept
17013 {
17014 const auto type = nde.type();
17015 if (type > node_type::array)
17016 return;
17017
17018 if (type == node_type::table)
17019 {
17020 auto &tbl = nde.ref_cast<table>();
17021 if (
17022 tbl
17023 .is_inline()) // inline tables (and all their inline descendants) are already correctly
17024 // terminated
17025 return;
17026
17027 auto end = nde.source_.end;
17028 for (auto &&[k, v] : tbl)
17029 {
17030 TOML_UNUSED(k);
17031 update_region_ends(v);
17032 if (end < v.source_.end)
17033 end = v.source_.end;
17034 }
17035 }
17036 else // arrays
17037 {
17038 auto &arr = nde.ref_cast<array>();
17039 auto end = nde.source_.end;
17040 for (auto &&v : arr)
17041 {
17042 update_region_ends(v);
17043 if (end < v.source_.end)
17044 end = v.source_.end;
17045 }
17046 nde.source_.end = end;
17047 }
17048 }
17049
17050 public:
17052 : reader{reader_}
17053 {
17054 root.source_ = {prev_pos, prev_pos, reader.source_path()};
17055
17056 if (!reader.peek_eof())
17057 {
17058 cp = reader.read_next();
17059
17060# if !TOML_EXCEPTIONS
17061 if (reader.error())
17062 {
17063 err = std::move(reader.error());
17064 return;
17065 }
17066# endif
17067
17068 if (cp)
17069 parse_document();
17070 }
17071
17072 update_region_ends(root);
17073 }
17074
17076 operator parse_result() &&noexcept
17077 {
17078# if TOML_EXCEPTIONS
17079
17080 return {std::move(root)};
17081
17082# else
17083
17084 if (err)
17085 return parse_result{*std::move(err)};
17086 else
17087 return parse_result{std::move(root)};
17088
17089# endif
17090 }
17091 };
17092
17094 node_ptr parser::parse_array()
17095 {
17096 return_if_error({});
17098 TOML_ASSERT_ASSUME(*cp == U'[');
17099 push_parse_scope("array"sv);
17100
17101 // skip opening '['
17103
17104 node_ptr arr_ptr{new array{}};
17105 array &arr = arr_ptr->ref_cast<array>();
17106 enum class TOML_CLOSED_ENUM parse_type : int
17107 {
17108 none,
17109 comma,
17110 val
17111 };
17112 parse_type prev = parse_type::none;
17113
17114 while (!is_error())
17115 {
17116 while (consume_leading_whitespace() || consume_line_break() ||
17117 consume_comment())
17118 continue;
17120
17121 // commas - only legal after a value
17122 if (*cp == U',')
17123 {
17124 if (prev == parse_type::val)
17125 {
17126 prev = parse_type::comma;
17128 continue;
17129 }
17131 "expected value or closing ']', saw comma"sv);
17132 }
17133
17134 // closing ']'
17135 else if (*cp == U']')
17136 {
17138 break;
17139 }
17140
17141 // must be a value
17142 else
17143 {
17144 if (prev == parse_type::val)
17145 {
17147 "expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
17148 continue;
17149 }
17150 prev = parse_type::val;
17151
17152 auto val = parse_value();
17153 return_if_error({});
17154
17155 if (!arr.capacity())
17156 arr.reserve(4u);
17157 arr.emplace_back<node_ptr>(std::move(val));
17158 }
17159 }
17160
17161 return_if_error({});
17162 return arr_ptr;
17163 }
17164
17166 node_ptr parser::parse_inline_table()
17167 {
17168 return_if_error({});
17170 TOML_ASSERT_ASSUME(*cp == U'{');
17171 push_parse_scope("inline table"sv);
17172
17173 // skip opening '{'
17175
17176 node_ptr tbl_ptr{new table{}};
17177 table &tbl = tbl_ptr->ref_cast<table>();
17178 tbl.is_inline(true);
17179 table_vector_scope table_scope{open_inline_tables, tbl};
17180
17181 enum class TOML_CLOSED_ENUM parse_type : int
17182 {
17183 none,
17184 comma,
17185 kvp
17186 };
17187 parse_type prev = parse_type::none;
17188 while (!is_error())
17189 {
17190 if constexpr (
17191 TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
17192 {
17193 while (consume_leading_whitespace() || consume_line_break() ||
17194 consume_comment())
17195 continue;
17196 }
17197 else
17198 {
17199 while (consume_leading_whitespace())
17200 continue;
17201 }
17202 return_if_error({});
17204
17205 // commas - only legal after a key-value pair
17206 if (*cp == U',')
17207 {
17208 if (prev == parse_type::kvp)
17209 {
17210 prev = parse_type::comma;
17212 }
17213 else
17215 "expected key-value pair or closing '}', saw comma"sv);
17216 }
17217
17218 // closing '}'
17219 else if (*cp == U'}')
17220 {
17221 if constexpr (
17222 !TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
17223 {
17224 if (prev == parse_type::comma)
17225 {
17227 "expected key-value pair, saw closing '}' (dangling comma)"sv);
17228 continue;
17229 }
17230 }
17232 break;
17233 }
17234
17235 // key-value pair
17236 else if (is_string_delimiter(*cp) || is_bare_key_character(*cp))
17237 {
17238 if (prev == parse_type::kvp)
17240 "expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
17241 else
17242 {
17243 prev = parse_type::kvp;
17244 parse_key_value_pair_and_insert(&tbl);
17245 }
17246 }
17247
17248 else
17250 "expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
17251 }
17252
17253 return_if_error({});
17254 return tbl_ptr;
17255 }
17256
17257 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
17258}
17260
17261# undef TOML_RETURNS_BY_THROWING
17262# undef advance_and_return_if_error
17263# undef advance_and_return_if_error_or_eof
17264# undef assert_not_eof
17265# undef assert_not_error
17266# undef is_eof
17267# undef is_error
17268# undef parse_error_break
17269# undef push_parse_scope
17270# undef push_parse_scope_1
17271# undef push_parse_scope_2
17272# undef return_after_error
17273# undef return_if_eof
17274# undef return_if_error
17275# undef return_if_error_or_eof
17276# undef set_error_and_return
17277# undef set_error_and_return_default
17278# undef set_error_and_return_if_eof
17279# undef utf8_buffered_reader_error_check
17280# undef utf8_reader_error
17281# undef utf8_reader_error_check
17282# undef utf8_reader_return_after_error
17283
17285{
17288 parse_result do_parse(utf8_reader_interface && reader)
17289 {
17290 return impl::parser{std::move(reader)};
17291 }
17292
17295 parse_result do_parse_file(std::string_view file_path)
17296 {
17297# if TOML_EXCEPTIONS
17298# define TOML_PARSE_FILE_ERROR(msg, path) \
17299 throw parse_error( \
17300 msg, \
17301 source_position{}, \
17302 std::make_shared<const std::string>(std::move(path)))
17303# else
17304# define TOML_PARSE_FILE_ERROR(msg, path) \
17305 return parse_result(parse_error( \
17306 msg, \
17307 source_position{}, \
17308 std::make_shared<const std::string>(std::move(path))))
17309# endif
17310
17311 std::string file_path_str(file_path);
17312
17313 // open file with a custom-sized stack buffer
17314 std::ifstream file;
17315 TOML_OVERALIGNED char file_buffer[sizeof(void *) * 1024u];
17316 file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
17317# if TOML_WINDOWS
17318 file.open(
17319 impl::widen(file_path_str).c_str(),
17320 std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
17321# else
17322 file.open(
17323 file_path_str,
17324 std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
17325# endif
17326 if (!file.is_open())
17328 "File could not be opened for reading", file_path_str);
17329
17330 // get size
17331 const auto file_size = file.tellg();
17332 if (file_size == -1)
17333 TOML_PARSE_FILE_ERROR("Could not determine file size", file_path_str);
17334 file.seekg(0, std::ifstream::beg);
17335
17336 // read the whole file into memory first if the file isn't too large
17337 constexpr auto large_file_threshold = 1024 * 1024 * 2; // 2 MB
17338 if (file_size <= large_file_threshold)
17339 {
17340 std::vector<char> file_data;
17341 file_data.resize(static_cast<size_t>(file_size));
17342 file.read(file_data.data(), static_cast<std::streamsize>(file_size));
17343 return parse(
17344 std::string_view{file_data.data(), file_data.size()},
17345 std::move(file_path_str));
17346 }
17347
17348 // otherwise parse it using the streams
17349 else
17350 return parse(file, std::move(file_path_str));
17351
17352# undef TOML_PARSE_FILE_ERROR
17353 }
17354}
17356
17358{
17360
17363 std::string_view doc, std::string_view source_path)
17364 {
17365 return TOML_ANON_NAMESPACE::do_parse(
17366 TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
17367 }
17368
17371 std::string_view doc, std::string && source_path)
17372 {
17373 return TOML_ANON_NAMESPACE::do_parse(
17374 TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
17375 }
17376
17379 std::istream & doc, std::string_view source_path)
17380 {
17381 return TOML_ANON_NAMESPACE::do_parse(
17382 TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
17383 }
17384
17387 std::istream & doc, std::string && source_path)
17388 {
17389 return TOML_ANON_NAMESPACE::do_parse(
17390 TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
17391 }
17392
17394 parse_result TOML_CALLCONV parse_file(std::string_view file_path)
17395 {
17396 return TOML_ANON_NAMESPACE::do_parse_file(file_path);
17397 }
17398
17399# if TOML_HAS_CHAR8
17400
17403 std::u8string_view doc, std::string_view source_path)
17404 {
17405 return TOML_ANON_NAMESPACE::do_parse(
17406 TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
17407 }
17408
17411 std::u8string_view doc, std::string && source_path)
17412 {
17413 return TOML_ANON_NAMESPACE::do_parse(
17414 TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
17415 }
17416
17418 parse_result TOML_CALLCONV parse_file(std::u8string_view file_path)
17419 {
17420 std::string file_path_str;
17421 file_path_str.resize(file_path.length());
17422 memcpy(file_path_str.data(), file_path.data(), file_path.length());
17423 return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
17424 }
17425
17426# endif // TOML_HAS_CHAR8
17427
17428# if TOML_ENABLE_WINDOWS_COMPAT
17429
17432 std::string_view doc, std::wstring_view source_path)
17433 {
17434 return TOML_ANON_NAMESPACE::do_parse(
17435 TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
17436 }
17437
17440 std::istream & doc, std::wstring_view source_path)
17441 {
17442 return TOML_ANON_NAMESPACE::do_parse(
17443 TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
17444 }
17445
17447 parse_result TOML_CALLCONV parse_file(std::wstring_view file_path)
17448 {
17449 return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
17450 }
17451
17452# endif // TOML_ENABLE_WINDOWS_COMPAT
17453
17454# if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
17455
17458 std::u8string_view doc, std::wstring_view source_path)
17459 {
17460 return TOML_ANON_NAMESPACE::do_parse(
17461 TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
17462 }
17463
17464# endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
17465
17466 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
17467}
17469
17470# undef TOML_OVERALIGNED
17471
17472# ifdef _MSC_VER
17473# pragma pop_macro("min")
17474# pragma pop_macro("max")
17475# ifndef __clang__
17476# pragma inline_recursion(off)
17477# endif
17478# endif
17480
17481# endif // TOML_ENABLE_PARSER
17482
17483//******** impl/formatter.inl ****************************************************************************************
17484
17485# if TOML_ENABLE_FORMATTERS
17486
17488# ifdef _MSC_VER
17489# ifndef __clang__
17490# pragma inline_recursion(on)
17491# endif
17492# pragma push_macro("min")
17493# pragma push_macro("max")
17494# undef min
17495# undef max
17496# endif
17497
17499{
17500 enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
17501 {
17502 none,
17503 line_breaks = 1u << 0, // \n
17504 tabs = 1u << 1, // \t
17505 control_chars = 1u << 2, // also includes non-ascii vertical whitespace
17506 single_quotes = 1u << 3,
17507 non_bare = 1u << 4, // anything not satisfying "is bare key character"
17508 non_ascii = 1u << 5, // any codepoint >= 128
17509
17510 all = (non_ascii << 1u) - 1u
17511 };
17512 TOML_MAKE_FLAGS(formatted_string_traits);
17513
17516 const node *source_node,
17517 const parse_result *source_pr,
17518 const formatter_constants &constants,
17519 const formatter_config &config) noexcept //
17520# if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
17521 : source_{source_pr && *source_pr ? &source_pr->table() : source_node},
17522 result_{source_pr},
17523# else
17524 : source_{source_pr ? source_pr : source_node},
17525# endif
17526 constants_{&constants},
17527 config_{config}
17528 {
17529 TOML_ASSERT_ASSUME(source_);
17530
17531 config_.flags = (config_.flags | constants_->mandatory_flags) &
17532 ~constants_->ignored_flags;
17533
17534 indent_columns_ = {};
17535 for (auto c : config_.indent)
17536 indent_columns_ += c == '\t' ? 4u : 1u;
17537
17538 int_format_mask_ =
17539 config_.flags & (format_flags::allow_binary_integers |
17540 format_flags::allow_octal_integers |
17541 format_flags::allow_hexadecimal_integers);
17542 }
17543
17545 void formatter::attach(std::ostream & stream) noexcept
17546 {
17547 indent_ = {};
17548 naked_newline_ = true;
17549 stream_ = &stream;
17550 }
17551
17553 void formatter::detach() noexcept
17554 {
17555 stream_ = nullptr;
17556 }
17557
17560 {
17561 if (!naked_newline_ || force)
17562 {
17563 print_to_stream(*stream_, '\n');
17564 naked_newline_ = true;
17565 }
17566 }
17567
17570 {
17571 for (int i = 0; i < indent_; i++)
17572 {
17573 print_to_stream(*stream_, config_.indent);
17574 naked_newline_ = false;
17575 }
17576 }
17577
17580 {
17581 print_to_stream(*stream_, c);
17582 naked_newline_ = false;
17583 }
17584
17586 void formatter::print_unformatted(std::string_view str)
17587 {
17588 print_to_stream(*stream_, str);
17589 naked_newline_ = false;
17590 }
17591
17594 std::string_view str,
17595 bool allow_multi_line,
17596 bool allow_bare,
17597 bool allow_literal_whitespace)
17598 {
17599 if (str.empty())
17600 {
17601 print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
17602 return;
17603 }
17604
17605 // pre-scan the string to determine how we should output it
17606 formatted_string_traits traits = {};
17607
17608 if (!allow_bare)
17609 traits |= formatted_string_traits::non_bare;
17610 bool unicode_allowed = unicode_strings_allowed();
17611
17612 // ascii fast path
17613 if (is_ascii(str.data(), str.length()))
17614 {
17615 for (auto c : str)
17616 {
17617 switch (c)
17618 {
17619 case '\n':
17620 traits |= formatted_string_traits::line_breaks;
17621 break;
17622 case '\t':
17623 traits |= formatted_string_traits::tabs;
17624 break;
17625 case '\'':
17626 traits |= formatted_string_traits::single_quotes;
17627 break;
17628 default:
17629 {
17630 if TOML_UNLIKELY (is_control_character(c))
17631 traits |= formatted_string_traits::control_chars;
17632
17633 if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
17634 traits |= formatted_string_traits::non_bare;
17635 break;
17636 }
17637 }
17638
17639 static constexpr auto all_ascii_traits =
17640 formatted_string_traits::all & ~formatted_string_traits::non_ascii;
17641 if (traits == all_ascii_traits)
17642 break;
17643 }
17644 }
17645
17646 // unicode slow path
17647 else
17648 {
17649 traits |= formatted_string_traits::non_ascii;
17650 utf8_decoder decoder;
17651
17652 // if the unicode is malformed just treat the string as a single-line non-literal and
17653 // escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
17654 const auto bad_unicode = [&]() noexcept
17655 {
17656 traits &= ~formatted_string_traits::line_breaks;
17657 traits |= formatted_string_traits::control_chars |
17658 formatted_string_traits::non_bare;
17659 unicode_allowed = false;
17660 };
17661
17662 for (auto c : str)
17663 {
17664 decoder(c);
17665
17666 if TOML_UNLIKELY (decoder.error())
17667 {
17668 bad_unicode();
17669 break;
17670 }
17671
17672 if (!decoder.has_code_point())
17673 continue;
17674
17675 switch (decoder.codepoint)
17676 {
17677 case U'\n':
17678 traits |= formatted_string_traits::line_breaks;
17679 break;
17680 case U'\t':
17681 traits |= formatted_string_traits::tabs;
17682 break;
17683 case U'\'':
17684 traits |= formatted_string_traits::single_quotes;
17685 break;
17686 default:
17687 {
17688 if TOML_UNLIKELY (
17689 is_control_character(decoder.codepoint) ||
17690 is_non_ascii_vertical_whitespace(decoder.codepoint))
17691 traits |= formatted_string_traits::control_chars;
17692
17693 if (!is_bare_key_character(decoder.codepoint))
17694 traits |= formatted_string_traits::non_bare;
17695 break;
17696 }
17697 }
17698 }
17699
17700 if (decoder.needs_more_input())
17701 bad_unicode();
17702 }
17703
17704 // strings with line breaks, tabs, and single-quotes can't be bare
17705 if (!!(
17706 traits & (formatted_string_traits::line_breaks |
17707 formatted_string_traits::tabs |
17708 formatted_string_traits::single_quotes)))
17709 traits |= formatted_string_traits::non_bare;
17710
17711 // if the string meets the requirements of being 'bare' we can emit a bare string
17712 // (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
17713 if (
17714 !(traits & formatted_string_traits::non_bare) &&
17715 (!(traits & formatted_string_traits::non_ascii) || unicode_allowed))
17716 {
17717 print_unformatted(str);
17718 return;
17719 }
17720 const auto real_tabs_allowed =
17721 allow_literal_whitespace && real_tabs_in_strings_allowed();
17722
17723 // determine if this should be a multi-line string (triple-quotes)
17724 const auto multi_line = allow_literal_whitespace //
17725 && allow_multi_line //
17727 &&
17728 !!(traits & formatted_string_traits::line_breaks);
17729
17730 // determine if this should be a literal string (single-quotes with no escaping)
17731 const auto literal =
17733 && !(traits & formatted_string_traits::control_chars) //
17734 && (!(traits & formatted_string_traits::single_quotes) || multi_line) //
17735 && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed) //
17736 && (!(traits & formatted_string_traits::line_breaks) || multi_line) //
17737 && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
17738
17739 // literal strings (single quotes, no escape codes)
17740 if (literal)
17741 {
17742 const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
17743 print_unformatted(quot);
17744 print_unformatted(str);
17745 print_unformatted(quot);
17746 return;
17747 }
17748
17749 // anything from here down is a non-literal string, so requires iteration and escaping.
17750 print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
17751
17752 // ascii fast path
17753 if (!(traits & formatted_string_traits::non_ascii))
17754 {
17755 for (auto c : str)
17756 {
17757 switch (c)
17758 {
17759 case '"':
17760 print_to_stream(*stream_, R"(\")"sv);
17761 break;
17762 case '\\':
17763 print_to_stream(*stream_, R"(\\)"sv);
17764 break;
17765 case '\x7F':
17766 print_to_stream(*stream_, R"(\u007F)"sv);
17767 break;
17768 case '\t':
17769 print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv);
17770 break;
17771 case '\n':
17772 print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv);
17773 break;
17774 default:
17775 {
17776 // control characters from lookup table
17777 if TOML_UNLIKELY (c >= '\x00' && c <= '\x1F')
17779
17780 // regular characters
17781 else
17782 print_to_stream(*stream_, c);
17783 }
17784 }
17785 }
17786 }
17787
17788 // unicode slow path
17789 else
17790 {
17791 utf8_decoder decoder;
17792 const char *cp_start = str.data();
17793 const char *cp_end = cp_start;
17794 for (auto c : str)
17795 {
17796 decoder(c);
17797 cp_end++;
17798
17799 // if the decoder encounters malformed unicode just emit raw bytes and
17800 if (decoder.error())
17801 {
17802 while (cp_start != cp_end)
17803 {
17804 print_to_stream(*stream_, R"(\u00)"sv);
17806 *stream_,
17807 static_cast<uint8_t>(*cp_start),
17808 value_flags::format_as_hexadecimal,
17809 2);
17810 cp_start++;
17811 }
17812 decoder.reset();
17813 continue;
17814 }
17815
17816 if (!decoder.has_code_point())
17817 continue;
17818
17819 switch (decoder.codepoint)
17820 {
17821 case U'"':
17822 print_to_stream(*stream_, R"(\")"sv);
17823 break;
17824 case U'\\':
17825 print_to_stream(*stream_, R"(\\)"sv);
17826 break;
17827 case U'\x7F':
17828 print_to_stream(*stream_, R"(\u007F)"sv);
17829 break;
17830 case U'\t':
17831 print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv);
17832 break;
17833 case U'\n':
17834 print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv);
17835 break;
17836 default:
17837 {
17838 // control characters from lookup table
17839 if TOML_UNLIKELY (decoder.codepoint <= U'\x1F')
17841 *stream_,
17842 control_char_escapes[static_cast<uint_least32_t>(
17843 decoder.codepoint)]);
17844
17845 // escaped unicode characters
17846 else if (
17847 decoder.codepoint > U'\x7F' &&
17848 (!unicode_allowed ||
17849 is_non_ascii_vertical_whitespace(decoder.codepoint)))
17850 {
17851 if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu)
17852 {
17853 print_to_stream(*stream_, R"(\U)"sv);
17855 *stream_,
17856 static_cast<uint_least32_t>(decoder.codepoint),
17857 value_flags::format_as_hexadecimal,
17858 8);
17859 }
17860 else
17861 {
17862 print_to_stream(*stream_, R"(\u)"sv);
17864 *stream_,
17865 static_cast<uint_least32_t>(decoder.codepoint),
17866 value_flags::format_as_hexadecimal,
17867 4);
17868 }
17869 }
17870
17871 // regular characters
17872 else
17874 *stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
17875 }
17876 }
17877
17878 cp_start = cp_end;
17879 }
17880 }
17881
17882 print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
17883 }
17884
17887 {
17888 print_string(val.get());
17889 }
17890
17893 {
17894 naked_newline_ = false;
17895
17896 if (*val >= 0 && !!int_format_mask_)
17897 {
17898 static constexpr auto value_flags_mask =
17899 value_flags::format_as_binary | value_flags::format_as_octal |
17900 value_flags::format_as_hexadecimal;
17901
17902 const auto fmt = val.flags() & value_flags_mask;
17903 switch (fmt)
17904 {
17905 case value_flags::format_as_binary:
17906 if (!!(int_format_mask_ & format_flags::allow_binary_integers))
17907 {
17908 print_to_stream(*stream_, "0b"sv);
17909 print_to_stream(*stream_, *val, fmt);
17910 return;
17911 }
17912 break;
17913
17914 case value_flags::format_as_octal:
17915 if (!!(int_format_mask_ & format_flags::allow_octal_integers))
17916 {
17917 print_to_stream(*stream_, "0o"sv);
17918 print_to_stream(*stream_, *val, fmt);
17919 return;
17920 }
17921 break;
17922
17923 case value_flags::format_as_hexadecimal:
17924 if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers))
17925 {
17926 print_to_stream(*stream_, "0x"sv);
17927 print_to_stream(*stream_, *val, fmt);
17928 return;
17929 }
17930 break;
17931
17932 default:
17933 break;
17934 }
17935 }
17936
17937 // fallback to decimal
17938 print_to_stream(*stream_, *val);
17939 }
17940
17943 {
17944 const std::string_view *inf_nan = nullptr;
17945 switch (fpclassify(*val))
17946 {
17947 case fp_class::neg_inf:
17948 inf_nan = &constants_->float_neg_inf;
17949 break;
17950 case fp_class::pos_inf:
17951 inf_nan = &constants_->float_pos_inf;
17952 break;
17953 case fp_class::nan:
17954 inf_nan = &constants_->float_nan;
17955 break;
17956 case fp_class::ok:
17958 *stream_,
17959 *val,
17960 value_flags::none,
17961 !!(config_.flags & format_flags::relaxed_float_precision));
17962 break;
17963 default:
17965 }
17966
17967 if (inf_nan)
17968 {
17969 if (!!(config_.flags & format_flags::quote_infinities_and_nans))
17970 print_to_stream_bookended(*stream_, *inf_nan, '"');
17971 else
17972 print_to_stream(*stream_, *inf_nan);
17973 }
17974
17975 naked_newline_ = false;
17976 }
17977
17980 {
17981 print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
17982 }
17983
17986 {
17987 if (!!(config_.flags & format_flags::quote_dates_and_times))
17989 *stream_, *val, literal_strings_allowed() ? '\'' : '"');
17990 else
17991 print_to_stream(*stream_, *val);
17992 naked_newline_ = false;
17993 }
17994
17997 {
17998 if (!!(config_.flags & format_flags::quote_dates_and_times))
18000 *stream_, *val, literal_strings_allowed() ? '\'' : '"');
18001 else
18002 print_to_stream(*stream_, *val);
18003 naked_newline_ = false;
18004 }
18005
18008 {
18009 if (!!(config_.flags & format_flags::quote_dates_and_times))
18011 *stream_, *val, literal_strings_allowed() ? '\'' : '"');
18012 else
18013 print_to_stream(*stream_, *val);
18014 naked_newline_ = false;
18015 }
18016
18018 void formatter::print_value(const node &val_node, node_type type)
18019 {
18020 TOML_ASSUME(type > node_type::array);
18021 switch (type)
18022 {
18023 case node_type::string:
18024 print(*reinterpret_cast<const value<std::string> *>(&val_node));
18025 break;
18026 case node_type::integer:
18027 print(*reinterpret_cast<const value<int64_t> *>(&val_node));
18028 break;
18029 case node_type::floating_point:
18030 print(*reinterpret_cast<const value<double> *>(&val_node));
18031 break;
18032 case node_type::boolean:
18033 print(*reinterpret_cast<const value<bool> *>(&val_node));
18034 break;
18035 case node_type::date:
18036 print(*reinterpret_cast<const value<date> *>(&val_node));
18037 break;
18038 case node_type::time:
18039 print(*reinterpret_cast<const value<time> *>(&val_node));
18040 break;
18041 case node_type::date_time:
18042 print(*reinterpret_cast<const value<date_time> *>(&val_node));
18043 break;
18044 default:
18046 }
18047 }
18048
18049# if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
18050
18053 {
18054 if (result_ && !(*result_))
18055 {
18056 stream() << result_->error();
18057 return true;
18058 }
18059 return false;
18060 }
18061
18062# else
18063
18065 TOML_ATTR(const)
18066 bool formatter::dump_failed_parse_result()
18067 {
18068 return false;
18069 }
18070
18071# endif
18072}
18074
18075# ifdef _MSC_VER
18076# pragma pop_macro("min")
18077# pragma pop_macro("max")
18078# ifndef __clang__
18079# pragma inline_recursion(off)
18080# endif
18081# endif
18083
18084# endif // TOML_ENABLE_FORMATTERS
18085
18086//******** impl/toml_formatter.inl ***********************************************************************************
18087
18088# if TOML_ENABLE_FORMATTERS
18089
18091# ifdef _MSC_VER
18092# ifndef __clang__
18093# pragma inline_recursion(on)
18094# endif
18095# pragma push_macro("min")
18096# pragma push_macro("max")
18097# undef min
18098# undef max
18099# endif
18100
18102
18104{
18106 size_t toml_formatter_count_inline_columns(
18107 const node &node, size_t line_wrap_cols) noexcept
18108 {
18109 switch (node.type())
18110 {
18111 case node_type::table:
18112 {
18113 auto &tbl = *reinterpret_cast<const table *>(&node);
18114 if (tbl.empty())
18115 return 2u; // "{}"
18116 size_t weight = 3u; // "{ }"
18117 for (auto &&[k, v] : tbl)
18118 {
18119 weight += k.length() +
18120 toml_formatter_count_inline_columns(v, line_wrap_cols) +
18121 2u; // + ", "
18122 if (weight >= line_wrap_cols)
18123 break;
18124 }
18125 return weight;
18126 }
18127
18128 case node_type::array:
18129 {
18130 auto &arr = *reinterpret_cast<const array *>(&node);
18131 if (arr.empty())
18132 return 2u; // "[]"
18133 size_t weight = 3u; // "[ ]"
18134 for (auto &elem : arr)
18135 {
18136 weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) +
18137 2u; // + ", "
18138 if (weight >= line_wrap_cols)
18139 break;
18140 }
18141 return weight;
18142 }
18143
18144 case node_type::string:
18145 {
18146 // todo: proper utf8 decoding?
18147 // todo: tab awareness?
18148 auto &str = (*reinterpret_cast<const value<std::string> *>(&node)).get();
18149 return str.length() + 2u; // + ""
18150 }
18151
18152 case node_type::integer:
18153 {
18154 auto val = (*reinterpret_cast<const value<int64_t> *>(&node)).get();
18155 if (!val)
18156 return 1u;
18157 size_t weight = {};
18158 if (val < 0)
18159 {
18160 weight += 1u;
18161 val *= -1;
18162 }
18163 return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
18164 }
18165
18166 case node_type::floating_point:
18167 {
18168 auto val = (*reinterpret_cast<const value<double> *>(&node)).get();
18169 if (val == 0.0)
18170 return 3u; // "0.0"
18171 size_t weight = 2u; // ".0"
18172 if (val < 0.0)
18173 {
18174 weight += 1u;
18175 val *= -1.0;
18176 }
18177 return weight + static_cast<size_t>(log10(val)) + 1u;
18178 }
18179
18180 case node_type::boolean:
18181 return 5u;
18182 case node_type::date:
18183 [[fallthrough]];
18184 case node_type::time:
18185 return 10u;
18186 case node_type::date_time:
18187 return 30u;
18188 case node_type::none:
18190 default:
18192 }
18193
18195 }
18196
18198 bool toml_formatter_forces_multiline(
18199 const node &node,
18200 size_t line_wrap_cols,
18201 size_t starting_column_bias) noexcept
18202 {
18203 return (toml_formatter_count_inline_columns(node, line_wrap_cols) +
18204 starting_column_bias) >= line_wrap_cols;
18205 }
18206}
18208
18210{
18212 void toml_formatter::print_pending_table_separator()
18213 {
18214 if (pending_table_separator_)
18215 {
18216 print_newline(true);
18217 print_newline(true);
18218 pending_table_separator_ = false;
18219 }
18220 }
18221
18223 void toml_formatter::print(const key &k)
18224 {
18225 print_string(k.str(), false, true, false);
18226 }
18227
18229 void toml_formatter::print_inline(const table &tbl)
18230 {
18231 if (tbl.empty())
18232 {
18233 print_unformatted("{}"sv);
18234 return;
18235 }
18236
18237 print_unformatted("{ "sv);
18238
18239 bool first = false;
18240 for (auto &&[k, v] : tbl)
18241 {
18242 if (first)
18243 print_unformatted(", "sv);
18244 first = true;
18245
18246 print(k);
18247 if (terse_kvps())
18248 print_unformatted("="sv);
18249 else
18250 print_unformatted(" = "sv);
18251
18252 const auto type = v.type();
18253 TOML_ASSUME(type != node_type::none);
18254 switch (type)
18255 {
18256 case node_type::table:
18257 print_inline(*reinterpret_cast<const table *>(&v));
18258 break;
18259 case node_type::array:
18260 print(*reinterpret_cast<const array *>(&v));
18261 break;
18262 default:
18263 print_value(v, type);
18264 }
18265 }
18266
18267 print_unformatted(" }"sv);
18268 }
18269
18271 void toml_formatter::print(const array &arr)
18272 {
18273 if (arr.empty())
18274 {
18275 print_unformatted("[]"sv);
18276 return;
18277 }
18278
18279 const auto original_indent = indent();
18280 const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
18281 arr,
18282 120u,
18283 indent_columns() *
18284 static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
18285
18286 print_unformatted("["sv);
18287
18288 if (multiline)
18289 {
18290 if (original_indent < 0)
18291 indent(0);
18293 increase_indent();
18294 }
18295 else
18296 print_unformatted(' ');
18297
18298 for (size_t i = 0; i < arr.size(); i++)
18299 {
18300 if (i > 0u)
18301 {
18302 print_unformatted(',');
18303 if (!multiline)
18304 print_unformatted(' ');
18305 }
18306
18307 if (multiline)
18308 {
18309 print_newline(true);
18310 print_indent();
18311 }
18312
18313 auto &v = arr[i];
18314 const auto type = v.type();
18315 TOML_ASSUME(type != node_type::none);
18316 switch (type)
18317 {
18318 case node_type::table:
18319 print_inline(*reinterpret_cast<const table *>(&v));
18320 break;
18321 case node_type::array:
18322 print(*reinterpret_cast<const array *>(&v));
18323 break;
18324 default:
18325 print_value(v, type);
18326 }
18327 }
18328 if (multiline)
18329 {
18330 indent(original_indent);
18331 print_newline(true);
18332 print_indent();
18333 }
18334 else
18335 print_unformatted(' ');
18336
18337 print_unformatted("]"sv);
18338 }
18339
18341 void toml_formatter::print(const table &tbl)
18342 {
18343 static constexpr auto is_non_inline_array_of_tables =
18344 [](const node &n) noexcept
18345 {
18346 const auto arr = n.as_array();
18347 if (!arr || !arr->is_array_of_tables())
18348 return false;
18349
18350 return !reinterpret_cast<const table *>(&(*arr)[0])->is_inline();
18351 };
18352
18353 // values, arrays, and inline tables/table arrays
18354 for (auto &&[k, v] : tbl)
18355 {
18356 const auto type = v.type();
18357 if (
18358 (type == node_type::table &&
18359 !reinterpret_cast<const table *>(&v)->is_inline()) ||
18360 (type == node_type::array && is_non_inline_array_of_tables(v)))
18361 continue;
18362
18363 pending_table_separator_ = true;
18364 print_newline();
18365 print_indent();
18366 print(k);
18367 if (terse_kvps())
18368 print_unformatted("="sv);
18369 else
18370 print_unformatted(" = "sv);
18371 TOML_ASSUME(type != node_type::none);
18372 switch (type)
18373 {
18374 case node_type::table:
18375 print_inline(*reinterpret_cast<const table *>(&v));
18376 break;
18377 case node_type::array:
18378 print(*reinterpret_cast<const array *>(&v));
18379 break;
18380 default:
18381 print_value(v, type);
18382 }
18383 }
18384
18385 const auto print_key_path = [&]()
18386 {
18387 size_t i{};
18388 for (const auto k : key_path_)
18389 {
18390 if (i++)
18391 print_unformatted('.');
18392 print(*k);
18393 }
18394 };
18395
18396 // non-inline tables
18397 for (auto &&[k, v] : tbl)
18398 {
18399 const auto type = v.type();
18400 if (
18401 type != node_type::table ||
18402 reinterpret_cast<const table *>(&v)->is_inline())
18403 continue;
18404 auto &child_tbl = *reinterpret_cast<const table *>(&v);
18405
18406 // we can skip indenting and emitting the headers for tables that only contain other tables
18407 // (so we don't over-nest)
18408 size_t child_value_count{}; // includes inline tables and non-table arrays
18409 size_t child_table_count{};
18410 size_t child_table_array_count{};
18411 for (auto &&[child_k, child_v] : child_tbl)
18412 {
18413 TOML_UNUSED(child_k);
18414 const auto child_type = child_v.type();
18415 TOML_ASSUME(child_type != node_type::none);
18416 switch (child_type)
18417 {
18418 case node_type::table:
18419 if (reinterpret_cast<const table *>(&child_v)->is_inline())
18420 child_value_count++;
18421 else
18422 child_table_count++;
18423 break;
18424
18425 case node_type::array:
18426 if (is_non_inline_array_of_tables(child_v))
18427 child_table_array_count++;
18428 else
18429 child_value_count++;
18430 break;
18431
18432 default:
18433 child_value_count++;
18434 }
18435 }
18436 bool skip_self = false;
18437 if (
18438 child_value_count == 0u &&
18439 (child_table_count > 0u || child_table_array_count > 0u))
18440 skip_self = true;
18441
18442 key_path_.push_back(&k);
18443
18444 if (!skip_self)
18445 {
18446 print_pending_table_separator();
18447 if (indent_sub_tables())
18448 increase_indent();
18449 print_indent();
18450 print_unformatted("["sv);
18451 print_key_path();
18452 print_unformatted("]"sv);
18453 pending_table_separator_ = true;
18454 }
18455
18456 print(child_tbl);
18457
18458 key_path_.pop_back();
18459 if (!skip_self && indent_sub_tables())
18460 decrease_indent();
18461 }
18462
18463 // table arrays
18464 for (auto &&[k, v] : tbl)
18465 {
18466 if (!is_non_inline_array_of_tables(v))
18467 continue;
18468 auto &arr = *reinterpret_cast<const array *>(&v);
18469
18470 if (indent_sub_tables())
18471 increase_indent();
18472 key_path_.push_back(&k);
18473
18474 for (size_t i = 0; i < arr.size(); i++)
18475 {
18476 print_pending_table_separator();
18477 print_indent();
18478 print_unformatted("[["sv);
18479 print_key_path();
18480 print_unformatted("]]"sv);
18481 pending_table_separator_ = true;
18482 print(*reinterpret_cast<const table *>(&arr[i]));
18483 }
18484
18485 key_path_.pop_back();
18486 if (indent_sub_tables())
18487 decrease_indent();
18488 }
18489 }
18490
18492 void toml_formatter::print()
18493 {
18494 if (dump_failed_parse_result())
18495 return;
18496
18497 switch (auto source_type = source().type())
18498 {
18499 case node_type::table:
18500 {
18501 auto &tbl = *reinterpret_cast<const table *>(&source());
18502 if (tbl.is_inline())
18503 print_inline(tbl);
18504 else
18505 {
18506 decrease_indent(); // so root kvps and tables have the same indent
18507 print(tbl);
18508 }
18509 break;
18510 }
18511
18512 case node_type::array:
18513 print(*reinterpret_cast<const array *>(&source()));
18514 break;
18515
18516 default:
18517 print_value(source(), source_type);
18518 }
18519 }
18520}
18522
18523# ifdef _MSC_VER
18524# pragma pop_macro("min")
18525# pragma pop_macro("max")
18526# ifndef __clang__
18527# pragma inline_recursion(off)
18528# endif
18529# endif
18531
18532# endif // TOML_ENABLE_FORMATTERS
18533
18534//******** impl/json_formatter.inl ***********************************************************************************
18535
18536# if TOML_ENABLE_FORMATTERS
18537
18539# ifdef _MSC_VER
18540# ifndef __clang__
18541# pragma inline_recursion(on)
18542# endif
18543# pragma push_macro("min")
18544# pragma push_macro("max")
18545# undef min
18546# undef max
18547# endif
18548
18550{
18552 void json_formatter::print(const toml::table &tbl)
18553 {
18554 if (tbl.empty())
18555 {
18556 print_unformatted("{}"sv);
18557 return;
18558 }
18559
18560 print_unformatted('{');
18561
18562 if (indent_sub_tables())
18563 increase_indent();
18564 bool first = false;
18565 for (auto &&[k, v] : tbl)
18566 {
18567 if (first)
18568 print_unformatted(',');
18569 first = true;
18570 print_newline(true);
18571 print_indent();
18572
18573 print_string(k.str(), false);
18574 if (terse_kvps())
18575 print_unformatted(":"sv);
18576 else
18577 print_unformatted(" : "sv);
18578
18579 const auto type = v.type();
18580 TOML_ASSUME(type != node_type::none);
18581 switch (type)
18582 {
18583 case node_type::table:
18584 print(*reinterpret_cast<const table *>(&v));
18585 break;
18586 case node_type::array:
18587 print(*reinterpret_cast<const array *>(&v));
18588 break;
18589 default:
18590 print_value(v, type);
18591 }
18592 }
18593 if (indent_sub_tables())
18594 decrease_indent();
18595 print_newline(true);
18596 print_indent();
18597
18598 print_unformatted('}');
18599 }
18600
18602 void json_formatter::print(const toml::array &arr)
18603 {
18604 if (arr.empty())
18605 {
18606 print_unformatted("[]"sv);
18607 return;
18608 }
18609
18610 print_unformatted('[');
18612 increase_indent();
18613 for (size_t i = 0; i < arr.size(); i++)
18614 {
18615 if (i > 0u)
18616 print_unformatted(',');
18617 print_newline(true);
18618 print_indent();
18619
18620 auto &v = arr[i];
18621 const auto type = v.type();
18622 TOML_ASSUME(type != node_type::none);
18623 switch (type)
18624 {
18625 case node_type::table:
18626 print(*reinterpret_cast<const table *>(&v));
18627 break;
18628 case node_type::array:
18629 print(*reinterpret_cast<const array *>(&v));
18630 break;
18631 default:
18632 print_value(v, type);
18633 }
18634 }
18636 decrease_indent();
18637 print_newline(true);
18638 print_indent();
18639 print_unformatted(']');
18640 }
18641
18643 void json_formatter::print()
18644 {
18645 if (dump_failed_parse_result())
18646 return;
18647
18648 switch (auto source_type = source().type())
18649 {
18650 case node_type::table:
18651 print(*reinterpret_cast<const table *>(&source()));
18652 break;
18653 case node_type::array:
18654 print(*reinterpret_cast<const array *>(&source()));
18655 break;
18656 default:
18657 print_value(source(), source_type);
18658 }
18659 }
18660}
18662
18663# ifdef _MSC_VER
18664# pragma pop_macro("min")
18665# pragma pop_macro("max")
18666# ifndef __clang__
18667# pragma inline_recursion(off)
18668# endif
18669# endif
18671
18672# endif // TOML_ENABLE_FORMATTERS
18673
18674//******** impl/yaml_formatter.inl ***********************************************************************************
18675
18676# if TOML_ENABLE_FORMATTERS
18677
18679# ifdef _MSC_VER
18680# ifndef __clang__
18681# pragma inline_recursion(on)
18682# endif
18683# pragma push_macro("min")
18684# pragma push_macro("max")
18685# undef min
18686# undef max
18687# endif
18688
18690{
18692 void yaml_formatter::print_yaml_string(const value<std::string> &str)
18693 {
18694 if (str->empty())
18695 {
18696 base::print(str);
18697 return;
18698 }
18699
18700 bool contains_newline = false;
18701 for (auto c = str->c_str(), e = str->c_str() + str->length();
18702 c < e && !contains_newline;
18703 c++)
18704 contains_newline = *c == '\n';
18705
18706 if (contains_newline)
18707 {
18708 print_unformatted("|-"sv);
18709
18710 increase_indent();
18711
18712 auto line_end = str->c_str() - 1u;
18713 const auto end = str->c_str() + str->length();
18714 while (line_end != end)
18715 {
18716 auto line_start = line_end + 1u;
18717 line_end = line_start;
18718 for (; line_end != end && *line_end != '\n'; line_end++)
18719 ;
18720
18721 if TOML_LIKELY (line_start != line_end || line_end != end)
18722 {
18723 print_newline();
18724 print_indent();
18725 print_unformatted(std::string_view{
18726 line_start, static_cast<size_t>(line_end - line_start)});
18727 }
18728 }
18729
18730 decrease_indent();
18731 }
18732 else
18733 print_string(*str, false, true);
18734 }
18735
18737 void yaml_formatter::print(const toml::table &tbl, bool parent_is_array)
18738 {
18739 if (tbl.empty())
18740 {
18741 print_unformatted("{}"sv);
18742 return;
18743 }
18744
18745 increase_indent();
18746
18747 for (auto &&[k, v] : tbl)
18748 {
18749 if (!parent_is_array)
18750 {
18751 print_newline();
18752 print_indent();
18753 }
18754 parent_is_array = false;
18755
18756 print_string(k.str(), false, true);
18757 if (terse_kvps())
18758 print_unformatted(":"sv);
18759 else
18760 print_unformatted(": "sv);
18761
18762 const auto type = v.type();
18763 TOML_ASSUME(type != node_type::none);
18764 switch (type)
18765 {
18766 case node_type::table:
18767 print(*reinterpret_cast<const table *>(&v));
18768 break;
18769 case node_type::array:
18770 print(*reinterpret_cast<const array *>(&v));
18771 break;
18772 case node_type::string:
18773 print_yaml_string(*reinterpret_cast<const value<std::string> *>(&v));
18774 break;
18775 default:
18776 print_value(v, type);
18777 }
18778 }
18779
18780 decrease_indent();
18781 }
18782
18784 void yaml_formatter::print(const toml::array &arr, bool parent_is_array)
18785 {
18786 if (arr.empty())
18787 {
18788 print_unformatted("[]"sv);
18789 return;
18790 }
18791
18792 increase_indent();
18793
18794 for (auto &&v : arr)
18795 {
18796 if (!parent_is_array)
18797 {
18798 print_newline();
18799 print_indent();
18800 }
18801 parent_is_array = false;
18802
18803 print_unformatted("- "sv);
18804
18805 const auto type = v.type();
18806 TOML_ASSUME(type != node_type::none);
18807 switch (type)
18808 {
18809 case node_type::table:
18810 print(*reinterpret_cast<const table *>(&v), true);
18811 break;
18812 case node_type::array:
18813 print(*reinterpret_cast<const array *>(&v), true);
18814 break;
18815 case node_type::string:
18816 print_yaml_string(*reinterpret_cast<const value<std::string> *>(&v));
18817 break;
18818 default:
18819 print_value(v, type);
18820 }
18821 }
18822
18823 decrease_indent();
18824 }
18825
18827 void yaml_formatter::print()
18828 {
18829 if (dump_failed_parse_result())
18830 return;
18831
18832 switch (auto source_type = source().type())
18833 {
18834 case node_type::table:
18835 decrease_indent(); // so root kvps and tables have the same indent
18836 print(*reinterpret_cast<const table *>(&source()));
18837 break;
18838
18839 case node_type::array:
18840 print(*reinterpret_cast<const array *>(&source()));
18841 break;
18842
18843 case node_type::string:
18844 print_yaml_string(
18845 *reinterpret_cast<const value<std::string> *>(&source()));
18846 break;
18847
18848 default:
18849 print_value(source(), source_type);
18850 }
18851 }
18852}
18854
18855# ifdef _MSC_VER
18856# pragma pop_macro("min")
18857# pragma pop_macro("max")
18858# ifndef __clang__
18859# pragma inline_recursion(off)
18860# endif
18861# endif
18863
18864# endif // TOML_ENABLE_FORMATTERS
18865
18866#endif // TOML_IMPLEMENTATION
18867
18869
18870// macro hygiene
18871#if TOML_UNDEF_MACROS
18872# undef TOML_ABI_NAMESPACE_BOOL
18873# undef TOML_ABI_NAMESPACE_END
18874# undef TOML_ABI_NAMESPACE_START
18875# undef TOML_ABI_NAMESPACES
18876# undef TOML_ABSTRACT_INTERFACE
18877# undef TOML_ALWAYS_INLINE
18878# undef TOML_ANON_NAMESPACE
18879# undef TOML_ANON_NAMESPACE_END
18880# undef TOML_ANON_NAMESPACE_START
18881# undef TOML_ARCH_AMD64
18882# undef TOML_ARCH_ARM
18883# undef TOML_ARCH_ARM32
18884# undef TOML_ARCH_ARM64
18885# undef TOML_ARCH_BITNESS
18886# undef TOML_ARCH_ITANIUM
18887# undef TOML_ARCH_X64
18888# undef TOML_ARCH_X86
18889# undef TOML_ASSERT
18890# undef TOML_ASSERT_ASSUME
18891# undef TOML_ASSUME
18892# undef TOML_ASYMMETRICAL_EQUALITY_OPS
18893# undef TOML_ATTR
18894# undef TOML_CLANG
18895# undef TOML_CLANG_VERSION
18896# undef TOML_CLOSED_ENUM
18897# undef TOML_CLOSED_FLAGS_ENUM
18898# undef TOML_COMPILER_HAS_EXCEPTIONS
18899# undef TOML_COMPILER_HAS_RTTI
18900# undef TOML_CONST
18901# undef TOML_CONST_GETTER
18902# undef TOML_CONST_INLINE_GETTER
18903# undef TOML_CONSTRAINED_TEMPLATE
18904# undef TOML_CPP
18905# undef TOML_DECLSPEC
18906# undef TOML_DELETE_DEFAULTS
18907# undef TOML_DISABLE_ARITHMETIC_WARNINGS
18908# undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
18909# undef TOML_DISABLE_SPAM_WARNINGS
18910# undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
18911# undef TOML_DISABLE_SPAM_WARNINGS_CLANG_11
18912# undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
18913# undef TOML_DISABLE_SWITCH_WARNINGS
18914# undef TOML_DISABLE_WARNINGS
18915# undef TOML_DOXYGEN
18916# undef TOML_EMPTY_BASES
18917# undef TOML_ENABLE_IF
18918# undef TOML_ENABLE_WARNINGS
18919# undef TOML_EVAL_BOOL_0
18920# undef TOML_EVAL_BOOL_1
18921# undef TOML_EXTERNAL_LINKAGE
18922# undef TOML_FLAGS_ENUM
18923# undef TOML_FLOAT_CHARCONV
18924# undef TOML_FLOAT128
18925# undef TOML_FLOAT16_DIG
18926# undef TOML_FLOAT16_LIMITS_SET
18927# undef TOML_FLOAT16_MANT_DIG
18928# undef TOML_FLOAT16_MAX_10_EXP
18929# undef TOML_FLOAT16_MAX_EXP
18930# undef TOML_FLOAT16_MIN_10_EXP
18931# undef TOML_FLOAT16_MIN_EXP
18932# undef TOML_GCC
18933# undef TOML_GCC_LIKE
18934# undef TOML_HAS_ATTR
18935# undef TOML_HAS_BUILTIN
18936# undef TOML_HAS_CHAR8
18937# undef TOML_HAS_CPP_ATTR
18938# undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
18939# undef TOML_HAS_FEATURE
18940# undef TOML_HAS_INCLUDE
18941# undef TOML_HAS_SSE2
18942# undef TOML_HAS_SSE4_1
18943# undef TOML_HIDDEN_CONSTRAINT
18944# undef TOML_ICC
18945# undef TOML_ICC_CL
18946# undef TOML_IMPL_NAMESPACE_END
18947# undef TOML_IMPL_NAMESPACE_START
18948# undef TOML_IMPLEMENTATION
18949# undef TOML_INCLUDE_WINDOWS_H
18950# undef TOML_INLINE_GETTER
18951# undef TOML_INT_CHARCONV
18952# undef TOML_INT128
18953# undef TOML_INTELLISENSE
18954# undef TOML_INTERNAL_LINKAGE
18955# undef TOML_LANG_AT_LEAST
18956# undef TOML_LANG_EFFECTIVE_VERSION
18957# undef TOML_LANG_HIGHER_THAN
18958# undef TOML_LANG_UNRELEASED
18959# undef TOML_LAUNDER
18960# undef TOML_LIFETIME_HOOKS
18961# undef TOML_LIKELY
18962# undef TOML_LIKELY_CASE
18963# undef TOML_LINUX
18964# undef TOML_MAKE_FLAGS
18965# undef TOML_MAKE_FLAGS_
18966# undef TOML_MAKE_FLAGS_1
18967# undef TOML_MAKE_FLAGS_2
18968# undef TOML_MAKE_STRING
18969# undef TOML_MAKE_STRING_1
18970# undef TOML_MAKE_VERSION
18971# undef TOML_MSVC
18972# undef TOML_MSVC_LIKE
18973# undef TOML_NAMESPACE
18974# undef TOML_NEVER_INLINE
18975# undef TOML_NODISCARD
18976# undef TOML_NODISCARD_CTOR
18977# undef TOML_NVCC
18978# undef TOML_OPEN_ENUM
18979# undef TOML_OPEN_FLAGS_ENUM
18980# undef TOML_PARSER_TYPENAME
18981# undef TOML_POP_WARNINGS
18982# undef TOML_PRAGMA_CLANG
18983# undef TOML_PRAGMA_CLANG_GE_10
18984# undef TOML_PRAGMA_CLANG_GE_11
18985# undef TOML_PRAGMA_CLANG_GE_8
18986# undef TOML_PRAGMA_CLANG_GE_9
18987# undef TOML_PRAGMA_GCC
18988# undef TOML_PRAGMA_ICC
18989# undef TOML_PRAGMA_MSVC
18990# undef TOML_PURE
18991# undef TOML_PURE_GETTER
18992# undef TOML_PURE_INLINE_GETTER
18993# undef TOML_PUSH_WARNINGS
18994# undef TOML_REQUIRES
18995# undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
18996# undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
18997# undef TOML_SA_LIST_BEG
18998# undef TOML_SA_LIST_END
18999# undef TOML_SA_LIST_NEW
19000# undef TOML_SA_LIST_NXT
19001# undef TOML_SA_LIST_SEP
19002# undef TOML_SA_NATIVE_VALUE_TYPE_LIST
19003# undef TOML_SA_NEWLINE
19004# undef TOML_SA_NODE_TYPE_LIST
19005# undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
19006# undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
19007# undef TOML_SA_VALUE_FUNC_MESSAGE
19008# undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
19009# undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
19010# undef TOML_SA_VALUE_MESSAGE_WSTRING
19011# undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
19012# undef TOML_TRIVIAL_ABI
19013# undef TOML_UINT128
19014# undef TOML_UNIX
19015# undef TOML_UNLIKELY
19016# undef TOML_UNLIKELY_CASE
19017# undef TOML_UNREACHABLE
19018# undef TOML_UNUSED
19019# undef TOML_WINDOWS
19020#endif
19021
19022#endif // TOMLPLUSPLUS_HPP
BigInt power(const BigInt &base, const BigInt &exponent)
Definition arith_tools.cpp:161
static const twodig_t base
Definition bigint.cpp:28
#define error(x)
Definition bigint.cpp:16
BigInt operator+(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:341
BigInt operator*(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:349
bool operator<(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:406
bool operator>(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:410
BigInt operator-(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:345
bool operator!=(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:426
bool operator<=(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:414
bool operator==(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:422
bool operator>=(const BigInt &lhs, const BigInt &rhs)
Definition bigint.hh:418
@ none
Definition builtin_names.h:35
static void parse_float(llvm::SmallVectorImpl< char > &src, BigInt &significand, BigInt &exponent)
Definition clang_c_convert_literals.cpp:96
Definition toml.hpp:9624
TOML_NODISCARD_CTOR parse_error(std::string &&desc, source_region &&src) noexcept
Definition toml.hpp:9661
TOML_NODISCARD_CTOR parse_error(std::string &&desc, const source_region &src) noexcept
Definition toml.hpp:9667
friend std::ostream & operator<<(std::ostream &lhs, const parse_error &rhs)
Definition toml.hpp:9699
TOML_NODISCARD const source_region & source() const noexcept
Definition toml.hpp:9694
TOML_NODISCARD_CTOR parse_error(std::string &&desc, const source_position &position, const source_path_ptr &path={}) noexcept
Definition toml.hpp:9673
TOML_NODISCARD std::string_view description() const noexcept
Definition toml.hpp:9684
Definition toml.hpp:6607
iterator emplace(const_iterator pos, Args &&...args)
Definition toml.hpp:7437
TOML_NODISCARD iterator begin() noexcept
Definition toml.hpp:6987
TOML_CONST_INLINE_GETTER table * as_table() noexcept final
Definition toml.hpp:6801
TOML_PURE_INLINE_GETTER node * get(size_t index) noexcept
Definition toml.hpp:6909
TOML_PURE_GETTER bool is_homogeneous() const noexcept
Definition toml.hpp:6716
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:7567
TOML_CONST_INLINE_GETTER bool is_boolean() const noexcept final
Definition toml.hpp:6777
TOML_CONST_INLINE_GETTER bool is_array() const noexcept final
Definition toml.hpp:6735
TOML_CONST_INLINE_GETTER bool is_date_time() const noexcept final
Definition toml.hpp:6795
TOML_NODISCARD friend bool operator==(const array &lhs, const std::vector< T > &rhs) noexcept
Definition toml.hpp:7579
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:6825
TOML_CONST_INLINE_GETTER const toml::value< bool > * as_boolean() const noexcept final
Definition toml.hpp:6885
TOML_NODISCARD iterator end() noexcept
Definition toml.hpp:7005
const array & for_each(Func &&visitor) const &noexcept(for_each_is_nothrow< Func &&, const array & >::value)
Definition toml.hpp:7233
TOML_CONST_INLINE_GETTER bool is_string() const noexcept final
Definition toml.hpp:6753
TOML_NODISCARD const_iterator cbegin() const noexcept
Definition toml.hpp:6999
TOML_CONST_INLINE_GETTER toml::value< std::string > * as_string() noexcept final
Definition toml.hpp:6813
TOML_NODISCARD node & back() noexcept
Definition toml.hpp:6971
array && prune(bool recursive=true) &&noexcept
Definition toml.hpp:7322
TOML_NODISCARD size_t capacity() const noexcept
Definition toml.hpp:7268
iterator insert(const_iterator pos, size_t count, ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7350
TOML_NODISCARD friend bool operator!=(const array &lhs, const array &rhs) noexcept
Definition toml.hpp:7560
TOML_CONST_INLINE_GETTER bool is_floating_point() const noexcept final
Definition toml.hpp:6765
TOML_CONST_INLINE_GETTER toml::value< bool > * as_boolean() noexcept final
Definition toml.hpp:6831
TOML_PURE_INLINE_GETTER const node * get(size_t index) const noexcept
Definition toml.hpp:6915
TOML_EXPORTED_MEMBER_FUNCTION iterator erase(const_iterator pos) noexcept
TOML_ASYMMETRICAL_EQUALITY_OPS(const array &, const std::vector< T > &, template< typename T >)
array && for_each(Func &&visitor) &&noexcept(for_each_is_nothrow< Func &&, array && >::value)
Definition toml.hpp:7225
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:6943
TOML_NODISCARD const_iterator cend() const noexcept
Definition toml.hpp:7017
TOML_EXPORTED_MEMBER_FUNCTION void pop_back() noexcept
TOML_CONST_INLINE_GETTER const toml::value< time > * as_time() const noexcept final
Definition toml.hpp:6897
TOML_CONST_INLINE_GETTER bool is_time() const noexcept final
Definition toml.hpp:6789
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:6903
TOML_CONST_INLINE_GETTER bool is_integer() const noexcept final
Definition toml.hpp:6759
TOML_EXPORTED_MEMBER_FUNCTION array & prune(bool recursive=true) &noexcept
array && flatten() &&
Definition toml.hpp:7314
TOML_EXPORTED_MEMBER_FUNCTION void clear() noexcept
TOML_CONST_INLINE_GETTER toml::value< int64_t > * as_integer() noexcept final
Definition toml.hpp:6819
TOML_PURE_GETTER bool is_array_of_tables() const noexcept final
Definition toml.hpp:6741
TOML_NODISCARD const_iterator begin() const noexcept
Definition toml.hpp:6993
TOML_NODISCARD const_iterator end() const noexcept
Definition toml.hpp:7011
TOML_CONST_INLINE_GETTER const array * as_array() const noexcept final
Definition toml.hpp:6861
iterator insert(const_iterator pos, std::initializer_list< ElemType > ilist, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7428
const array && for_each(Func &&visitor) const &&noexcept(for_each_is_nothrow< Func &&, const array && >::value)
Definition toml.hpp:7241
TOML_EXPORTED_MEMBER_FUNCTION iterator erase(const_iterator first, const_iterator last) noexcept
TOML_EXPORTED_MEMBER_FUNCTION void truncate(size_t new_size)
node & reference
Definition toml.hpp:6657
TOML_NODISCARD friend bool operator==(const array &lhs, const array &rhs) noexcept
Definition toml.hpp:7554
TOML_CONST_INLINE_GETTER toml::value< date_time > * as_date_time() noexcept final
Definition toml.hpp:6849
TOML_CONST_INLINE_GETTER node_type type() const noexcept final
Definition toml.hpp:6697
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, const node *&first_nonmatch) const noexcept final
TOML_CONST_INLINE_GETTER const table * as_table() const noexcept final
Definition toml.hpp:6855
array & for_each(Func &&visitor) &noexcept(for_each_is_nothrow< Func &&, array & >::value)
Definition toml.hpp:7217
TOML_CONST_INLINE_GETTER bool is_value() const noexcept final
Definition toml.hpp:6747
TOML_NODISCARD node & operator[](size_t index) noexcept
Definition toml.hpp:6937
TOML_NODISCARD bool empty() const noexcept
Definition toml.hpp:7250
decltype(auto) emplace_back(Args &&...args)
Definition toml.hpp:7485
TOML_NODISCARD size_t max_size() const noexcept
Definition toml.hpp:7262
size_t size_type
Definition toml.hpp:6655
TOML_CONST_INLINE_GETTER const toml::value< double > * as_floating_point() const noexcept final
Definition toml.hpp:6879
TOML_CONST_INLINE_GETTER const toml::value< int64_t > * as_integer() const noexcept final
Definition toml.hpp:6873
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final
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:6867
TOML_CONST_INLINE_GETTER toml::value< time > * as_time() noexcept final
Definition toml.hpp:6843
ptrdiff_t difference_type
Definition toml.hpp:6656
TOML_NODISCARD const node & at(size_t index) const
Definition toml.hpp:6953
void resize(size_t new_size, ElemType &&default_init_val, value_flags default_init_flags=preserve_source_value_flags)
Definition toml.hpp:7283
TOML_NODISCARD node & front() noexcept
Definition toml.hpp:6959
TOML_EXPORTED_MEMBER_FUNCTION array & flatten() &
ElemTypes && vals
Definition toml.hpp:6683
iterator replace(const_iterator pos, ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7458
TOML_CONST_INLINE_GETTER const toml::value< date > * as_date() const noexcept final
Definition toml.hpp:6891
TOML_CONST_INLINE_GETTER toml::value< date > * as_date() noexcept final
Definition toml.hpp:6837
friend std::ostream & operator<<(std::ostream &lhs, const array &rhs)
Definition toml.hpp:7591
array_iterator iterator
Definition toml.hpp:6982
TOML_CONST_INLINE_GETTER bool is_number() const noexcept final
Definition toml.hpp:6771
const_array_iterator const_iterator
Definition toml.hpp:6984
iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7384
TOML_CONST_INLINE_GETTER array * as_array() noexcept final
Definition toml.hpp:6807
TOML_NODISCARD impl::wrap_node< ElemType > * get_as(size_t index) noexcept
Definition toml.hpp:6921
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:6965
TOML_NODISCARD const node & back() const noexcept
Definition toml.hpp:6977
TOML_NODISCARD size_t size() const noexcept
Definition toml.hpp:7256
iterator insert(const_iterator pos, ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7334
node value_type
Definition toml.hpp:6654
TOML_CONST_INLINE_GETTER bool is_table() const noexcept final
Definition toml.hpp:6729
TOML_NODISCARD const impl::wrap_node< ElemType > * get_as(size_t index) const noexcept
Definition toml.hpp:6930
const node & const_reference
Definition toml.hpp:6658
TOML_CONST_INLINE_GETTER bool is_date() const noexcept final
Definition toml.hpp:6783
void push_back(ElemType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:7479
Definition toml.hpp:10247
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:17593
TOML_EXPORTED_MEMBER_FUNCTION void print_indent()
Definition toml.hpp:17569
TOML_PURE_INLINE_GETTER bool multi_line_strings_allowed() const noexcept
Definition toml.hpp:10320
TOML_PURE_INLINE_GETTER size_t indent_columns() const noexcept
Definition toml.hpp:10296
void indent(int level) noexcept
Definition toml.hpp:10280
void decrease_indent() noexcept
Definition toml.hpp:10290
TOML_PURE_INLINE_GETTER std::ostream & stream() const noexcept
Definition toml.hpp:10269
TOML_PURE_INLINE_GETTER const node & source() const noexcept
Definition toml.hpp:10263
TOML_EXPORTED_MEMBER_FUNCTION void print_unformatted(char)
Definition toml.hpp:17579
TOML_PURE_INLINE_GETTER bool real_tabs_in_strings_allowed() const noexcept
Definition toml.hpp:10326
TOML_PURE_INLINE_GETTER bool indent_sub_tables() const noexcept
Definition toml.hpp:10308
TOML_EXPORTED_MEMBER_FUNCTION void detach() noexcept
Definition toml.hpp:17553
TOML_EXPORTED_MEMBER_FUNCTION void print_value(const node &, node_type)
Definition toml.hpp:18018
TOML_PURE_INLINE_GETTER bool terse_kvps() const noexcept
Definition toml.hpp:10338
TOML_PURE_INLINE_GETTER bool indent_array_elements() const noexcept
Definition toml.hpp:10302
TOML_PURE_INLINE_GETTER bool unicode_strings_allowed() const noexcept
Definition toml.hpp:10332
TOML_EXPORTED_MEMBER_FUNCTION void attach(std::ostream &stream) noexcept
Definition toml.hpp:17545
TOML_PURE_INLINE_GETTER int indent() const noexcept
Definition toml.hpp:10275
TOML_EXPORTED_MEMBER_FUNCTION void print(const value< std::string > &)
Definition toml.hpp:17886
TOML_PURE_INLINE_GETTER bool literal_strings_allowed() const noexcept
Definition toml.hpp:10314
TOML_EXPORTED_MEMBER_FUNCTION void print_newline(bool force=false)
Definition toml.hpp:17559
void increase_indent() noexcept
Definition toml.hpp:10285
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool dump_failed_parse_result()
Definition toml.hpp:18052
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION formatter(const node *, const parse_result *, const formatter_constants &, const formatter_config &) noexcept
Definition toml.hpp:17515
Definition toml.hpp:1525
Definition toml.hpp:9746
TOML_NODISCARD toml::table && table() &&noexcept
Definition toml.hpp:9866
TOML_NODISCARD toml::table & table() &noexcept
Definition toml.hpp:9859
TOML_NODISCARD node_view< const node > operator[](const toml::path &path) const noexcept
Definition toml.hpp:10023
TOML_NODISCARD node_view< node > at_path(std::string_view path) noexcept
Definition toml.hpp:9977
TOML_NODISCARD node_view< node > at_path(const toml::path &path) noexcept
Definition toml.hpp:9989
TOML_NODISCARD const toml::table & table() const &noexcept
Definition toml.hpp:9873
TOML_NODISCARD const_table_iterator begin() const noexcept
Definition toml.hpp:9947
TOML_NODISCARD bool failed() const noexcept
Definition toml.hpp:9847
friend std::ostream & operator<<(std::ostream &os, const parse_result &result)
Definition toml.hpp:10059
TOML_NODISCARD_CTOR parse_result(parse_result &&res) noexcept
Definition toml.hpp:9801
TOML_NODISCARD node_view< const node > at_path(const toml::path &path) const noexcept
Definition toml.hpp:9995
TOML_NODISCARD table_iterator end() noexcept
Definition toml.hpp:9959
~parse_result() noexcept
Definition toml.hpp:9835
TOML_NODISCARD_CTOR parse_result(toml::table &&tbl) noexcept
Definition toml.hpp:9787
table_iterator iterator
Definition toml.hpp:9936
TOML_NODISCARD table_iterator begin() noexcept
Definition toml.hpp:9941
const_table_iterator const_iterator
Definition toml.hpp:9938
parse_result & operator=(parse_result &&rhs) noexcept
Definition toml.hpp:9812
TOML_NODISCARD_CTOR parse_result() noexcept
Definition toml.hpp:9779
TOML_NODISCARD node_view< node > operator[](std::string_view key) noexcept
Definition toml.hpp:10029
TOML_NODISCARD const_table_iterator end() const noexcept
Definition toml.hpp:9965
TOML_NODISCARD node_view< const node > operator[](std::string_view key) const noexcept
Definition toml.hpp:10035
TOML_NODISCARD_CTOR parse_result(parse_error &&err) noexcept
Definition toml.hpp:9794
TOML_NODISCARD const_table_iterator cend() const noexcept
Definition toml.hpp:9971
TOML_NODISCARD node_view< node > operator[](const toml::path &path) noexcept
Definition toml.hpp:10017
TOML_NODISCARD parse_error && error() &&noexcept
Definition toml.hpp:9905
TOML_NODISCARD const parse_error & error() const &noexcept
Definition toml.hpp:9912
TOML_NODISCARD node_view< const node > at_path(std::string_view path) const noexcept
Definition toml.hpp:9983
TOML_NODISCARD bool succeeded() const noexcept
Definition toml.hpp:9841
TOML_NODISCARD parse_error & error() &noexcept
Definition toml.hpp:9898
TOML_NODISCARD const_table_iterator cbegin() const noexcept
Definition toml.hpp:9953
parser(utf8_reader_interface &&reader_)
Definition toml.hpp:17051
Definition toml.hpp:3227
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component()
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(const path_component &rhs)
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:3351
TOML_PURE_INLINE_GETTER friend bool operator==(const path_component &lhs, const path_component &rhs) noexcept
Definition toml.hpp:3371
~path_component() noexcept
Definition toml.hpp:3332
TOML_PURE_INLINE_GETTER friend bool operator!=(const path_component &lhs, const path_component &rhs) noexcept
Definition toml.hpp:3378
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(std::string_view new_key)
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(size_t new_index) noexcept
TOML_PURE_GETTER size_t index() const noexcept
Definition toml.hpp:3338
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component(size_t index) 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:3364
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component(path_component &&pc) noexcept
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(path_component &&rhs) noexcept
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator!=(std::string_view lhs, const path &rhs)
Definition toml.hpp:3666
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:3638
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator!=(const path &lhs, std::string_view rhs)
Definition toml.hpp:3659
std::vector< path_component >::const_iterator const_iterator
Definition toml.hpp:3705
TOML_PURE_INLINE_GETTER friend bool operator==(const path &lhs, const path &rhs) noexcept
Definition toml.hpp:3632
TOML_PURE_INLINE_GETTER const path_component & operator[](size_t index) const noexcept
Definition toml.hpp:3446
TOML_ALWAYS_INLINE friend std::ostream & operator<<(std::ostream &os, const path &rhs)
Definition toml.hpp:3599
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path truncated(size_t n) const
TOML_PURE_INLINE_GETTER iterator end() noexcept
Definition toml.hpp:3714
TOML_ALWAYS_INLINE path & append(std::string_view str)
Definition toml.hpp:3523
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(path &&)
std::vector< path_component >::iterator iterator
Definition toml.hpp:3703
TOML_NODISCARD friend path operator+(const path &lhs, std::string_view rhs)
Definition toml.hpp:3563
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition toml.hpp:3421
TOML_NODISCARD friend path operator+(std::string_view lhs, const path &rhs)
Definition toml.hpp:3571
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:3708
TOML_PURE_INLINE_GETTER const_iterator begin() const noexcept
Definition toml.hpp:3720
path & operator=(path &&) noexcept=default
TOML_PURE_INLINE_GETTER path_component & operator[](size_t index) noexcept
Definition toml.hpp:3439
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(std::string_view)
TOML_ALWAYS_INLINE path & append(const path &p)
Definition toml.hpp:3511
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(const path &)
TOML_PURE_INLINE_GETTER const_iterator end() const noexcept
Definition toml.hpp:3726
TOML_NODISCARD TOML_ALWAYS_INLINE friend bool operator==(std::string_view lhs, const path &rhs)
Definition toml.hpp:3652
TOML_PURE_INLINE_GETTER const_iterator cbegin() const noexcept
Definition toml.hpp:3732
TOML_EXPORTED_MEMBER_FUNCTION path & operator+=(const path &)
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition toml.hpp:3433
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path leaf(size_t n=1) const
TOML_ALWAYS_INLINE path & assign(const path &p)
Definition toml.hpp:3467
TOML_PURE_INLINE_GETTER const_iterator cend() const noexcept
Definition toml.hpp:3738
TOML_NODISCARD friend path operator+(const path &lhs, const path &rhs)
Definition toml.hpp:3555
TOML_EXPORTED_MEMBER_FUNCTION path & operator+=(std::string_view)
TOML_ALWAYS_INLINE path & assign(path &&p) noexcept
Definition toml.hpp:3473
TOML_ALWAYS_INLINE path & append(path &&p)
Definition toml.hpp:3517
path & operator=(const path &)=default
TOML_ALWAYS_INLINE path & assign(std::string_view str)
Definition toml.hpp:3479
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:3645
~path() noexcept=default
Definition toml.hpp:7908
table_iterator & operator=(const table_iterator &rhs) noexcept
Definition toml.hpp:7969
table_iterator & operator--() noexcept
Definition toml.hpp:7999
table_proxy_pair< IsConst > value_type
Definition toml.hpp:7976
TOML_NODISCARD_CTOR table_iterator(const table_iterator &other) noexcept
Definition toml.hpp:7964
table_iterator & operator++() noexcept
Definition toml.hpp:7984
TOML_NODISCARD_CTOR table_iterator(const table_iterator< false > &other) noexcept
Definition toml.hpp:7958
TOML_PURE_INLINE_GETTER friend bool operator==(const table_iterator &lhs, const table_iterator &rhs) noexcept
Definition toml.hpp:8041
TOML_NODISCARD_CTOR table_iterator() noexcept=default
table_iterator operator++(int) noexcept
Definition toml.hpp:7991
typename std::iterator_traits< map_iterator >::iterator_category iterator_category
Definition toml.hpp:7981
value_type * pointer
Definition toml.hpp:7978
table_iterator operator--(int) noexcept
Definition toml.hpp:8006
TOML_PURE_INLINE_GETTER pointer operator->() const noexcept
Definition toml.hpp:8021
typename std::iterator_traits< map_iterator >::difference_type difference_type
Definition toml.hpp:7979
TOML_NODISCARD_CTOR table_iterator(const_map_iterator iter) noexcept
Definition toml.hpp:7951
TOML_PURE_INLINE_GETTER friend bool operator!=(const table_iterator &lhs, const table_iterator &rhs) noexcept
Definition toml.hpp:8048
value_type & reference
Definition toml.hpp:7977
TOML_PURE_INLINE_GETTER reference operator*() const noexcept
Definition toml.hpp:8015
friend class table_iterator
Definition toml.hpp:7911
Definition toml.hpp:8080
TOML_PURE_INLINE_GETTER const_iterator begin() const noexcept
Definition toml.hpp:8445
TOML_EXPORTED_MEMBER_FUNCTION table & prune(bool recursive=true) &noexcept
TOML_UNREACHABLE
Definition toml.hpp:8901
KeyType && key
Definition toml.hpp:8829
TOML_CONST_INLINE_GETTER bool is_date_time() const noexcept final
Definition toml.hpp:8222
TOML_NODISCARD const node & at(std::string_view key) const
Definition toml.hpp:8413
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION node & at(std::string_view key)
TOML_CONST_INLINE_GETTER bool is_string() const noexcept final
Definition toml.hpp:8180
TOML_PURE_INLINE_GETTER const node * get(std::string_view key) const noexcept
Definition toml.hpp:8351
TOML_CONST_INLINE_GETTER const toml::value< std::string > * as_string() const noexcept final
Definition toml.hpp:8294
TOML_CONST_INLINE_GETTER bool is_number() const noexcept final
Definition toml.hpp:8198
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION table() noexcept
iterator erase(const_iterator pos) noexcept
Definition toml.hpp:8781
table && for_each(Func &&visitor) &&noexcept(for_each_is_nothrow< Func &&, table && >::value)
Definition toml.hpp:8653
TOML_CONST_INLINE_GETTER const toml::value< double > * as_floating_point() const noexcept final
Definition toml.hpp:8306
TOML_CONST_INLINE_GETTER toml::value< bool > * as_boolean() noexcept final
Definition toml.hpp:8258
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, const node *&first_nonmatch) const noexcept final
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:8300
table & for_each(Func &&visitor) &noexcept(for_each_is_nothrow< Func &&, table & >::value)
Definition toml.hpp:8645
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition toml.hpp:8678
TOML_CONST_INLINE_GETTER const toml::value< time > * as_time() const noexcept final
Definition toml.hpp:8324
TOML_PURE_GETTER bool contains(std::string_view key) const noexcept
Definition toml.hpp:8738
Iter value_flags flags
Definition toml.hpp:8958
const table && for_each(Func &&visitor) const &&noexcept(for_each_is_nothrow< Func &&, const table && >::value)
Definition toml.hpp:8669
TOML_CONST_INLINE_GETTER bool is_array() const noexcept final
Definition toml.hpp:8162
TOML_CONST_INLINE_GETTER node_type type() const noexcept final
Definition toml.hpp:8124
TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible< Iter > &&!impl::is_wide_string< Iter >), typename Iter) void insert(Iter begin
TOML_CONST_INLINE_GETTER array * as_array() noexcept final
Definition toml.hpp:8234
iterator erase(const_iterator begin, const_iterator end) noexcept
Definition toml.hpp:8786
TOML_PURE_GETTER bool is_homogeneous() const noexcept
Definition toml.hpp:8143
toml::const_table_iterator const_iterator
Definition toml.hpp:8436
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION bool is_homogeneous(node_type ntype, node *&first_nonmatch) noexcept final
TOML_EXPORTED_MEMBER_FUNCTION table & operator=(table &&rhs) noexcept
map_iterator ipos
Definition toml.hpp:8871
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:8376
TOML_EXPORTED_MEMBER_FUNCTION void clear() noexcept
toml::table_iterator iterator
Definition toml.hpp:8434
TOML_NODISCARD node_view< node > operator[](std::string_view key) noexcept
Definition toml.hpp:9082
impl::remove_cvref< ValueType > raw_value_type
Definition toml.hpp:8837
TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible< KeyType && >||impl::is_wide_string< KeyType >), typename ValueType=void, typename KeyType, typename... ValueArgs) std
Definition toml.hpp:9024
TOML_PURE_GETTER const_iterator lower_bound(std::string_view key) const noexcept
Definition toml.hpp:8702
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:8228
TOML_EXPORTED_MEMBER_FUNCTION table & operator=(const table &)
TOML_CONST_INLINE_GETTER toml::value< time > * as_time() noexcept final
Definition toml.hpp:8270
TOML_PURE_INLINE_GETTER const_iterator end() const noexcept
Definition toml.hpp:8463
TOML_CONST_INLINE_GETTER const toml::value< date_time > * as_date_time() const noexcept final
Definition toml.hpp:8330
TOML_PURE_INLINE_GETTER iterator begin() noexcept
Definition toml.hpp:8439
TOML_NODISCARD node_view< const node > operator[](std::string_view key) const noexcept
Definition toml.hpp:9088
TOML_CONST_INLINE_GETTER bool is_table() const noexcept final
Definition toml.hpp:8156
TOML_EXPORTED_MEMBER_FUNCTION ~table() noexcept
TOML_CONST_INLINE_GETTER bool is_value() const noexcept final
Definition toml.hpp:8174
TOML_NODISCARD friend bool operator==(const table &lhs, const table &rhs) noexcept
Definition toml.hpp:9116
TOML_CONST_INLINE_GETTER const table * as_table() const noexcept final
Definition toml.hpp:8282
friend std::ostream & operator<<(std::ostream &lhs, const table &rhs)
Definition toml.hpp:9129
TOML_CONST_INLINE_GETTER bool is_boolean() const noexcept final
Definition toml.hpp:8204
TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible< KeyType && >||impl::is_wide_string< KeyType >), typename KeyType, typename ValueType) std
Definition toml.hpp:8904
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:8246
Iter end
Definition toml.hpp:8957
const table & for_each(Func &&visitor) const &noexcept(for_each_is_nothrow< Func &&, const table & >::value)
Definition toml.hpp:8661
table && prune(bool recursive=true) &&noexcept
Definition toml.hpp:8810
TOML_CONST_INLINE_GETTER bool is_floating_point() const noexcept final
Definition toml.hpp:8192
TOML_PURE_INLINE_GETTER const_iterator cbegin() const noexcept
Definition toml.hpp:8451
TOML_CONST_INLINE_GETTER bool is_date() const noexcept final
Definition toml.hpp:8210
TOML_PURE_INLINE_GETTER iterator end() noexcept
Definition toml.hpp:8457
TOML_CONST_INLINE_GETTER toml::value< date > * as_date() noexcept final
Definition toml.hpp:8264
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:8336
TOML_CONST_INLINE_GETTER const array * as_array() const noexcept final
Definition toml.hpp:8288
TOML_PURE_GETTER const impl::wrap_node< T > * get_as(std::string_view key) const noexcept
Definition toml.hpp:8384
std::conditional_t< std::is_void_v< raw_value_type >, impl::emplaced_type_of< ValueArgs &&... >, raw_value_type > value_type
Definition toml.hpp:8838
KeyType ValueArgs && args
Definition toml.hpp:8830
TOML_NODISCARD friend bool operator!=(const table &lhs, const table &rhs) noexcept
Definition toml.hpp:9122
TOML_CONST_INLINE_GETTER const toml::value< date > * as_date() const noexcept final
Definition toml.hpp:8318
impl::remove_cvref< impl::unwrap_node< value_type > > unwrapped_type
Definition toml.hpp:8861
TOML_CONST_INLINE_GETTER toml::value< double > * as_floating_point() noexcept final
Definition toml.hpp:8252
TOML_PURE_GETTER iterator lower_bound(std::string_view key) noexcept
Definition toml.hpp:8696
TOML_CONST_INLINE_GETTER toml::value< date_time > * as_date_time() noexcept final
Definition toml.hpp:8276
TOML_PURE_GETTER bool is_array_of_tables() const noexcept final
Definition toml.hpp:8168
TOML_CONST_INLINE_GETTER bool is_integer() const noexcept final
Definition toml.hpp:8186
TOML_CONST_INLINE_GETTER const toml::value< bool > * as_boolean() const noexcept final
Definition toml.hpp:8312
void is_inline(bool val) noexcept
Definition toml.hpp:8341
TOML_PURE_INLINE_GETTER const_iterator cend() const noexcept
Definition toml.hpp:8469
TOML_CONST_INLINE_GETTER bool is_time() const noexcept final
Definition toml.hpp:8216
TOML_CONST_INLINE_GETTER toml::value< std::string > * as_string() noexcept final
Definition toml.hpp:8240
Iter value_flags bool insert_or_assign(KeyType &&key, ValueType &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:8975
iterator erase(iterator pos) noexcept
Definition toml.hpp:8776
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition toml.hpp:8684
Definition toml.hpp:13752
utf8_codepoint buffer[history_buffer_size]
Definition toml.hpp:13762
TOML_PURE_INLINE_GETTER const source_path_ptr & source_path() const noexcept
Definition toml.hpp:13776
TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:13782
size_t count
Definition toml.hpp:13763
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:13841
TOML_NODISCARD const utf8_codepoint * step_back(size_t count) noexcept
Definition toml.hpp:13824
size_t first
Definition toml.hpp:13763
TOML_NODISCARD optional< parse_error > && error() noexcept
Definition toml.hpp:13849
static constexpr size_t max_history_length
Definition toml.hpp:13754
TOML_NODISCARD_CTOR utf8_buffered_reader(utf8_reader_interface &reader) noexcept
Definition toml.hpp:13770
TOML_PURE_INLINE_GETTER constexpr bool peek_eof() const noexcept
Definition toml.hpp:13321
TOML_NODISCARD_CTOR constexpr utf8_byte_stream(std::basic_string_view< Char > sv) noexcept
Definition toml.hpp:13291
TOML_CONST_INLINE_GETTER constexpr bool error() const noexcept
Definition toml.hpp:13303
TOML_PURE_INLINE_GETTER constexpr bool eof() const noexcept
Definition toml.hpp:13309
TOML_PURE_INLINE_GETTER bool eof() const noexcept
Definition toml.hpp:13373
TOML_NODISCARD_CTOR utf8_byte_stream(std::istream &stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:13347
TOML_NODISCARD size_t operator()(void *dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:13394
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition toml.hpp:13386
TOML_PURE_INLINE_GETTER bool error() const noexcept
Definition toml.hpp:13367
Definition toml.hpp:13472
TOML_NODISCARD_CTOR utf8_reader(U &&source, String &&source_path={}) noexcept(std::is_nothrow_constructible_v< utf8_byte_stream< T >, U && >)
Definition toml.hpp:13667
TOML_NODISCARD optional< parse_error > && error() noexcept final
Definition toml.hpp:13718
TOML_PURE_INLINE_GETTER const source_path_ptr & source_path() const noexcept final
Definition toml.hpp:13684
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
Definition toml.hpp:13710
TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
Definition toml.hpp:13691
Definition toml.hpp:1531
configt config
Definition config.cpp:8
@ other
Definition converter_compare.cpp:887
int count
Definition cuda.h:51
#define N
Definition exp2f.c:23
#define T
Definition exp2f.c:24
#define C
Definition exp2f.c:25
std::ostream & operator<<(std::ostream &out, const interval_templatet< T > &i)
Definition interval_template.h:800
guard2tc & operator-=(guard2tc &g1, const guard2tc &g2)
Definition irep2_guard.cpp:334
#define CHAR_BIT
Definition limits.h:11
literalt pos(literalt a)
Definition literal.h:130
double log10(double x)
Definition log10.c:35
#define A
Definition logf.c:22
float e
Definition cmath.py:18
Definition float.py:1
Definition format.h:30
Definition int.py:1
Definition toml.hpp:3771
Any equal(Any a, Any b)
Definition numpy.py:362
list[Any] array(list[Any] data)
Definition numpy.py:15
list[float] empty(int shape)
Definition numpy.py:29
Definition os.py:1
Definition __init__.py:1
Definition path.py:1
int U
Definition re.py:251
Definition exception.cpp:51
Definition string.py:1
Definition time.py:1
Definition toml.hpp:1383
interval at(const std::string &function, double x)
The results at x, a single value where every implementation is exact.
Definition transcendental.cpp:239
type
Definition transform.py:9
end
Definition transform.py:37
args
Definition transform.py:10
double nan(const char *x)
Definition nan.c:3
@ eof
Definition nested_func_transform.cpp:69
double pow(double x, double y)
Definition pow.c:52
static __inline__ __device__ bool all(bool cond)
Definition sm_atomic_functions.h:548
void * value
Definition solidity_mapping.c:2
uint256_t key
Definition solidity_mapping.c:1
unsigned stack_budget_guardt< Tag >::depth
Definition stack_budget.h:72
#define true
Definition stdbool.h:11
#define false
Definition stdbool.h:10
#define bool
Definition stdbool.h:9
long int ptrdiff_t
Definition stddef.h:30
unsigned int size_t
Definition stddef.h:47
short wchar_t
Definition stddef.h:36
int memcmp(const void *s1, const void *s2, size_t n)
Definition string.c:412
void * memcpy(void *__ESBMC_restrict dst, const void *__ESBMC_restrict src, size_t n)
node_ptr value
Definition toml.hpp:6586
TOML_NODISCARD_CTOR array_init_elem(T &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:6590
std::add_const_t< Dest > type
Definition toml.hpp:1788
std::add_cv_t< Dest > type
Definition toml.hpp:1800
std::add_volatile_t< Dest > type
Definition toml.hpp:1794
Definition toml.hpp:1781
Dest type
Definition toml.hpp:1782
std::add_lvalue_reference_t< Dest > type
Definition toml.hpp:1765
std::add_rvalue_reference_t< Dest > type
Definition toml.hpp:1771
Definition toml.hpp:1758
Dest type
Definition toml.hpp:1759
Definition toml.hpp:3040
TOML_NODISCARD_CTOR constexpr date_time(const toml::date &d) noexcept
Definition toml.hpp:3057
toml::date date
Definition toml.hpp:3041
TOML_PURE_INLINE_GETTER friend constexpr bool operator>(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:3123
TOML_PURE_INLINE_GETTER friend constexpr bool operator!=(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:3094
TOML_PURE_GETTER friend constexpr bool operator==(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:3085
TOML_PURE_GETTER friend constexpr bool operator<(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:3101
TOML_PURE_GETTER friend constexpr bool operator<=(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:3112
TOML_NODISCARD_CTOR date_time() noexcept=default
TOML_PURE_INLINE_GETTER constexpr bool is_local() const noexcept
Definition toml.hpp:3078
TOML_PURE_INLINE_GETTER friend constexpr bool operator>=(const date_time &lhs, const date_time &rhs) noexcept
Definition toml.hpp:3130
friend std::ostream & operator<<(std::ostream &lhs, const date_time &rhs)
Definition toml.hpp:3135
TOML_NODISCARD_CTOR constexpr date_time(const toml::date &d, const toml::time &t, const toml::time_offset &off) noexcept
Definition toml.hpp:3069
optional< toml::time_offset > offset
Definition toml.hpp:3045
TOML_NODISCARD_CTOR constexpr date_time(const toml::time &t) noexcept
Definition toml.hpp:3063
Definition toml.hpp:1834
static constexpr auto type
Definition toml.hpp:1840
static constexpr bool can_represent_native
Definition toml.hpp:1838
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1837
void native_type
Definition toml.hpp:1835
static constexpr bool can_partially_represent_native
Definition toml.hpp:1839
static constexpr bool is_native
Definition toml.hpp:1836
Definition toml.hpp:14181
~depth_counter_scope() noexcept
Definition toml.hpp:14191
size_t & depth_
Definition toml.hpp:14182
TOML_DELETE_DEFAULTS(depth_counter_scope)
TOML_NODISCARD_CTOR depth_counter_scope(size_t &depth) noexcept
Definition toml.hpp:14185
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:6317
typename emplaced_type_of_< remove_cvref< T > >::type type
Definition toml.hpp:6326
Definition toml.hpp:6310
void type
Definition toml.hpp:6311
Definition toml.hpp:14064
void append(const T &arg) noexcept
Definition toml.hpp:14080
char buf[buf_size]
Definition toml.hpp:14066
static constexpr std::size_t buf_size
Definition toml.hpp:14065
TOML_NODISCARD_CTOR error_builder(std::string_view scope) noexcept
Definition toml.hpp:14072
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:14087
char *const max_write_pos
Definition toml.hpp:14068
char * write_pos
Definition toml.hpp:14067
Definition toml.hpp:13965
const utf8_codepoint & cp
Definition toml.hpp:13966
Definition toml.hpp:2016
static constexpr int bits
Definition toml.hpp:2022
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:2026
double native_type
Definition toml.hpp:2018
static constexpr bool can_represent_native
Definition toml.hpp:2031
static constexpr bool is_signed
Definition toml.hpp:2020
static constexpr int digits10
Definition toml.hpp:2024
static constexpr auto type
Definition toml.hpp:2017
static constexpr bool is_native
Definition toml.hpp:2019
static constexpr int digits
Definition toml.hpp:2023
static constexpr bool can_partially_represent_native
Definition toml.hpp:2034
Definition toml.hpp:2042
Definition toml.hpp:10241
std::string_view indent
Definition toml.hpp:10243
format_flags flags
Definition toml.hpp:10242
void type
Definition toml.hpp:6298
typename inserted_type_of_< remove_cvref< T > >::type type
Definition toml.hpp:6292
Definition toml.hpp:1702
T value
Definition toml.hpp:1705
Definition toml.hpp:1889
static constexpr T max
Definition toml.hpp:1892
static constexpr T min
Definition toml.hpp:1890
Definition toml.hpp:1897
static constexpr auto type
Definition toml.hpp:1903
static constexpr bool is_signed
Definition toml.hpp:1901
static constexpr bool is_native
Definition toml.hpp:1899
int64_t native_type
Definition toml.hpp:1898
static constexpr bool can_partially_represent_native
Definition toml.hpp:1904
Definition toml.hpp:1928
TOML_NODISCARD static TOML_ALWAYS_INLINE U && make(U &&val) noexcept
Definition toml.hpp:5118
Definition toml.hpp:2204
static constexpr bool is_native
Definition toml.hpp:2206
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:2207
static constexpr bool can_partially_represent_native
Definition toml.hpp:2209
static constexpr auto type
Definition toml.hpp:2210
T native_type
Definition toml.hpp:2205
static constexpr bool can_represent_native
Definition toml.hpp:2208
static constexpr auto value
Definition toml.hpp:2349
static constexpr auto value
Definition toml.hpp:2344
static constexpr auto value
Definition toml.hpp:2354
Definition toml.hpp:2338
static constexpr auto value
Definition toml.hpp:2339
std::add_const_t< T > type
Definition toml.hpp:2321
std::add_volatile_t< std::add_const_t< T > > type
Definition toml.hpp:2331
T type
Definition toml.hpp:2316
std::add_volatile_t< T > type
Definition toml.hpp:2326
Definition toml.hpp:2310
T type
Definition toml.hpp:2311
value< bool > type
Definition toml.hpp:2287
std::add_const_t< typename node_wrapper< T >::type > type
Definition toml.hpp:2256
std::add_const_t< std::add_volatile_t< typename node_wrapper< T >::type > > type
Definition toml.hpp:2266
value< date > type
Definition toml.hpp:2292
value< date_time > type
Definition toml.hpp:2302
value< double > type
Definition toml.hpp:2282
value< int64_t > type
Definition toml.hpp:2277
value< std::string > type
Definition toml.hpp:2272
value< time > type
Definition toml.hpp:2297
std::add_volatile_t< typename node_wrapper< T >::type > type
Definition toml.hpp:2261
Definition toml.hpp:2250
T type
Definition toml.hpp:2251
static constexpr auto full_prefix
Definition toml.hpp:13906
static constexpr auto scope_qualifier
Definition toml.hpp:13902
static constexpr auto is_signed
Definition toml.hpp:13904
static constexpr auto is_digit
Definition toml.hpp:13903
static constexpr auto max_digits
Definition toml.hpp:13905
static constexpr auto max_digits
Definition toml.hpp:13914
static constexpr auto is_signed
Definition toml.hpp:13913
static constexpr auto full_prefix
Definition toml.hpp:13917
static constexpr auto scope_qualifier
Definition toml.hpp:13911
static constexpr auto prefix
Definition toml.hpp:13916
static constexpr auto is_digit
Definition toml.hpp:13912
static constexpr auto prefix_codepoint
Definition toml.hpp:13915
static constexpr auto prefix
Definition toml.hpp:13885
static constexpr auto full_prefix
Definition toml.hpp:13886
static constexpr auto is_digit
Definition toml.hpp:13881
static constexpr auto prefix_codepoint
Definition toml.hpp:13884
static constexpr auto is_signed
Definition toml.hpp:13882
static constexpr auto scope_qualifier
Definition toml.hpp:13880
static constexpr auto max_digits
Definition toml.hpp:13883
static constexpr auto max_digits
Definition toml.hpp:13894
static constexpr auto prefix_codepoint
Definition toml.hpp:13895
static constexpr auto is_signed
Definition toml.hpp:13893
static constexpr auto prefix
Definition toml.hpp:13896
static constexpr auto is_digit
Definition toml.hpp:13892
static constexpr auto scope_qualifier
Definition toml.hpp:13891
static constexpr auto full_prefix
Definition toml.hpp:13897
Definition toml.hpp:14131
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition toml.hpp:14174
std::vector< std::pair< size_t, size_t > > segments
Definition toml.hpp:14133
std::vector< source_position > starts
Definition toml.hpp:14134
std::vector< source_position > ends
Definition toml.hpp:14135
TOML_PURE_INLINE_GETTER std::string_view back() const noexcept
Definition toml.hpp:14162
void clear() noexcept
Definition toml.hpp:14137
void push_back(std::string_view segment, source_position b, source_position e)
Definition toml.hpp:14146
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition toml.hpp:14168
std::string buffer
Definition toml.hpp:14132
TOML_PURE_INLINE_GETTER std::string_view operator[](size_t i) const noexcept
Definition toml.hpp:14155
TOML_DELETE_DEFAULTS(parse_scope)
std::string_view parent_
Definition toml.hpp:14107
~parse_scope() noexcept
Definition toml.hpp:14118
TOML_NODISCARD_CTOR parse_scope(std::string_view &current_scope, std::string_view new_scope) noexcept
Definition toml.hpp:14110
std::string_view & storage_
Definition toml.hpp:14106
Definition toml.hpp:14200
std::string_view value
Definition toml.hpp:14201
bool was_multi_line
Definition toml.hpp:14202
Definition toml.hpp:1915
static constexpr bool can_represent_native
Definition toml.hpp:1921
int64_t native_type
Definition toml.hpp:1916
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1917
Definition toml.hpp:2685
TOML_PURE_GETTER friend constexpr bool operator>=(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2744
TOML_PURE_INLINE_GETTER friend constexpr bool operator!=(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2707
source_index line
Definition toml.hpp:2686
source_index column
Definition toml.hpp:2688
TOML_PURE_GETTER friend constexpr bool operator==(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2699
TOML_PURE_GETTER friend constexpr bool operator>(const source_position &lhs, const source_position &rhs) noexcept
Definition toml.hpp:2737
Definition toml.hpp:2758
source_path_ptr path
Definition toml.hpp:2763
friend std::ostream & operator<<(std::ostream &lhs, const source_region &rhs)
Definition toml.hpp:2777
source_position end
Definition toml.hpp:2761
source_position begin
Definition toml.hpp:2759
Definition toml.hpp:2099
static constexpr auto type
Definition toml.hpp:2107
static constexpr bool is_native
Definition toml.hpp:2101
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:2102
static constexpr bool can_partially_represent_native
Definition toml.hpp:2106
std::string native_type
Definition toml.hpp:2100
static constexpr bool can_represent_native
Definition toml.hpp:2103
Definition toml.hpp:8055
node_ptr value
Definition toml.hpp:8057
TOML_NODISCARD_CTOR table_init_pair(K &&k, V &&v, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:8060
toml::key key
Definition toml.hpp:8056
std::vector< table * > & tables
Definition toml.hpp:14207
~table_vector_scope() noexcept
Definition toml.hpp:14216
TOML_DELETE_DEFAULTS(table_vector_scope)
TOML_NODISCARD_CTOR table_vector_scope(std::vector< table * > &tables_, table &tbl)
Definition toml.hpp:14210
Definition toml.hpp:2975
TOML_PURE_INLINE_GETTER friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:3013
friend std::ostream & operator<<(std::ostream &lhs, const time_offset &rhs)
Definition toml.hpp:3030
TOML_PURE_INLINE_GETTER friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:3019
TOML_PURE_INLINE_GETTER friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:3007
TOML_PURE_INLINE_GETTER friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:3025
int16_t minutes
Definition toml.hpp:2976
TOML_PURE_INLINE_GETTER friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:2995
M m noexcept
Definition toml.hpp:2988
TOML_PURE_INLINE_GETTER friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
Definition toml.hpp:3001
M m M(h) *impl
Definition toml.hpp:2988
TOML_NODISCARD_CTOR time_offset() noexcept=default
TOML_CONSTRAINED_TEMPLATE((impl::all_integral< H, M >), typename H, typename M) TOML_NODISCARD_CTOR const expr time_offset(H h
uint8_t minute
Definition toml.hpp:2893
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:2909
M m
Definition toml.hpp:2909
uint32_t nanosecond
Definition toml.hpp:2897
uint8_t hour
Definition toml.hpp:2891
uint8_t second
Definition toml.hpp:2895
TOML_NODISCARD_CTOR time() noexcept=default
T type
Definition toml.hpp:1826
Definition toml.hpp:1820
std::underlying_type_t< T > type
Definition toml.hpp:1821
Definition toml.hpp:1908
static constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:1909
static constexpr bool can_represent_native
Definition toml.hpp:1911
Definition toml.hpp:13405
TOML_PURE_INLINE_GETTER constexpr const char32_t & operator*() const noexcept
Definition toml.hpp:13418
source_position position
Definition toml.hpp:13409
char32_t value
Definition toml.hpp:13406
size_t count
Definition toml.hpp:13408
char bytes[4]
Definition toml.hpp:13407
Definition toml.hpp:13427
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:1858
Definition toml.hpp:1848
default_value_traits type
Definition toml.hpp:1851
Definition toml.hpp:1863
Definition toml.hpp:5229
enum TOML_OPEN_FLAGS_ENUM format_as_hexadecimal
Definition toml.hpp:1672
typename underlying_type_< T >::type underlying_type
Definition toml.hpp:1829
#define TOML_ANON_NAMESPACE_END
Definition toml.hpp:1262
#define TOML_PARSER_TYPENAME
Definition toml.hpp:1617
#define TOML_UNUSED(...)
Definition toml.hpp:661
#define TOML_NODISCARD_CTOR
Definition toml.hpp:498
toml_formatter default_formatter
Definition toml.hpp:1712
constexpr bool is_constructible_or_convertible
Definition toml.hpp:2361
constexpr bool is_native
Definition toml.hpp:2234
enum TOML_OPEN_FLAGS_ENUM value_flags
Definition toml.hpp:1666
constexpr size_t charconv_buffer_length< int16_t >
Definition toml.hpp:10891
#define TOML_TRIVIAL_ABI
Definition toml.hpp:478
#define TOML_DISABLE_ARITHMETIC_WARNINGS
Definition toml.hpp:922
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE
Definition toml.hpp:1085
constexpr size_t charconv_buffer_length< uint8_t >
Definition toml.hpp:10903
#define TOML_LIFETIME_HOOKS
Definition toml.hpp:1130
#define POXY_IMPLEMENTATION_DETAIL(...)
Definition toml.hpp:688
constexpr bool value_retrieval_is_nothrow
Definition toml.hpp:1743
#define TOML_UNLIKELY(...)
Definition toml.hpp:596
#define TOML_ABI_NAMESPACE_BOOL(cond, T, F)
Definition toml.hpp:1248
#define TOML_SA_LIST_BEG
Definition toml.hpp:1293
#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST
Definition toml.hpp:1322
constexpr bool is_number
Definition toml.hpp:2394
#define TOML_EMPTY_BASES
Definition toml.hpp:470
#define TOML_RETURNS_BY_THROWING
Definition toml.hpp:13862
#define TOML_LIKELY(...)
Definition toml.hpp:583
enum TOML_OPEN_FLAGS_ENUM format_as_octal
Definition toml.hpp:1671
enum TOML_CLOSED_FLAGS_ENUM allow_multi_line_strings
Definition toml.hpp:1686
enum TOML_CLOSED_FLAGS_ENUM quote_dates_and_times
Definition toml.hpp:1683
#define TOML_PUSH_WARNINGS
Definition toml.hpp:907
#define TOML_CONSTRAINED_TEMPLATE(condition,...)
Definition toml.hpp:1187
#define TOML_SA_NODE_TYPE_LIST
Definition toml.hpp:1310
#define TOML_CALLCONV
Definition toml.hpp:1104
TOML_PURE_GETTER fp_class fpclassify(const double &val) noexcept
Definition toml.hpp:2455
constexpr node_type node_type_of
Definition toml.hpp:2357
#define TOML_ABI_NAMESPACE_END
Definition toml.hpp:1249
enum TOML_CLOSED_FLAGS_ENUM allow_unicode_strings
Definition toml.hpp:1688
#define TOML_NEVER_INLINE
Definition toml.hpp:461
#define TOML_INTERNAL_LINKAGE
Definition toml.hpp:1265
TOML_PURE_GETTER auto find(Iterator start, Iterator end, const T &needle) noexcept -> decltype(&(*start))
Definition toml.hpp:2480
typename value_traits< T >::native_type native_type_of
Definition toml.hpp:2232
#define set_error_and_return_if_eof(...)
Definition toml.hpp:14299
constexpr size_t charconv_buffer_length< int64_t >
Definition toml.hpp:10899
std::common_type_t< std::make_signed_t< T >... > common_signed_type
Definition toml.hpp:1722
#define TOML_CLOSED_ENUM
Definition toml.hpp:615
#define TOML_EXPORTED_CLASS
Definition toml.hpp:1005
constexpr bool is_boolean
Definition toml.hpp:2397
enum TOML_CLOSED_FLAGS_ENUM allow_real_tabs_in_strings
Definition toml.hpp:1687
TOML_EXPORTED_FREE_FUNCTION void TOML_CALLCONV print_to_stream(std::ostream &, std::string_view)
#define TOML_UNLIKELY_CASE
Definition toml.hpp:599
constexpr bool is_floating_point
Definition toml.hpp:2389
constexpr bool is_date
Definition toml.hpp:2402
constexpr bool can_partially_represent_native
Definition toml.hpp:2239
constexpr bool is_key
Definition toml.hpp:7856
#define TOML_EXTERNAL_LINKAGE
Definition toml.hpp:1264
TOML_NODISCARD node_ptr make_node(T &&val, value_flags flags=preserve_source_value_flags)
Definition toml.hpp:6302
#define TOML_UNREACHABLE
Definition toml.hpp:572
typename node_wrapper< std::remove_reference_t< T > >::type wrap_node
Definition toml.hpp:2305
#define set_error_and_return_default(...)
Definition toml.hpp:14296
#define TOML_DISABLE_WARNINGS
Definition toml.hpp:928
TOML_NODISCARD TOML_EXPORTED_FREE_FUNCTION parse_result TOML_CALLCONV parse_file(std::string_view file_path)
Definition toml.hpp:17394
#define TOML_NODISCARD
Definition toml.hpp:489
enum TOML_CLOSED_FLAGS_ENUM allow_octal_integers
Definition toml.hpp:1690
#define TOML_ANON_NAMESPACE_START
Definition toml.hpp:1261
#define TOML_LAUNDER(x)
Definition toml.hpp:1364
#define TOML_DISABLE_SWITCH_WARNINGS
Definition toml.hpp:913
TOML_PURE_GETTER bool is_ascii(const char *str, size_t len) noexcept
typename copy_cv_< Dest, Src >::type copy_cv
Definition toml.hpp:1777
enum TOML_CLOSED_FLAGS_ENUM allow_binary_integers
Definition toml.hpp:1689
constexpr bool is_string
Definition toml.hpp:2379
POXY_IMPLEMENTATION_DETAIL(impl::array_iterator< true >) const_array_iterator
Definition toml.hpp:6603
#define return_if_error_or_eof(...)
Definition toml.hpp:14261
#define is_error()
Definition toml.hpp:14252
#define TOML_CONST_GETTER
Definition toml.hpp:538
#define TOML_LANG_UNRELEASED
Definition toml.hpp:1233
#define TOML_SA_LIST_END
Definition toml.hpp:1294
#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS
Definition toml.hpp:916
constexpr std::string_view control_char_escapes[]
Definition toml.hpp:1559
TOML_NODISCARD TOML_EXPORTED_FREE_FUNCTION parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path={})
Definition toml.hpp:17362
TOML_INTERNAL_LINKAGE void print_floating_point_to_stream(std::ostream &stream, T val, value_flags format, bool relaxed_precision)
Definition toml.hpp:11028
#define TOML_COMPILER_HAS_EXCEPTIONS
Definition toml.hpp:373
constexpr bool is_array
Definition toml.hpp:2373
constexpr bool first_is_same
Definition toml.hpp:1814
#define TOML_ENV_MESSAGE
Definition toml.hpp:1462
constexpr size_t charconv_buffer_length< uint16_t >
Definition toml.hpp:10906
#define TOML_OVERALIGNED
Definition toml.hpp:13467
constexpr bool all_integral
Definition toml.hpp:1728
#define utf8_reader_error(...)
Definition toml.hpp:13453
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:13922
enum TOML_CLOSED_FLAGS_ENUM quote_infinities_and_nans
Definition toml.hpp:1684
constexpr bool is_chronological
Definition toml.hpp:2417
constexpr bool is_date_time
Definition toml.hpp:2412
enum TOML_CLOSED_FLAGS_ENUM allow_hexadecimal_integers
Definition toml.hpp:1691
#define TOML_PARSE_FILE_ERROR(msg, path)
constexpr bool is_one_of
Definition toml.hpp:1725
constexpr size_t charconv_buffer_length< int8_t >
Definition toml.hpp:10888
typename emplaced_type_of_< remove_cvref< T >... >::type emplaced_type_of
Definition toml.hpp:6330
#define TOML_EXPORTED_STATIC_FUNCTION
Definition toml.hpp:1011
#define TOML_POP_WARNINGS
Definition toml.hpp:925
#define return_if_error(...)
Definition toml.hpp:14255
enum TOML_CLOSED_FLAGS_ENUM allow_literal_strings
Definition toml.hpp:1685
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:2384
#define TOML_ASSERT(expr)
Definition toml.hpp:1143
TOML_CONST_GETTER optional< T > node_integer_cast(int64_t val) noexcept
Definition toml.hpp:5197
constexpr bool is_losslessly_convertible_to_native
Definition toml.hpp:2242
#define return_after_error(...)
Definition toml.hpp:14253
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:2682
constexpr bool always_false
Definition toml.hpp:1811
#define TOML_EXCEPTIONS
Definition toml.hpp:1099
#define TOML_PURE_GETTER
Definition toml.hpp:527
enum TOML_CLOSED_FLAGS_ENUM terse_key_value_pairs
Definition toml.hpp:1696
#define TOML_ENABLE_WINDOWS_COMPAT
Definition toml.hpp:1069
constexpr bool is_natively_one_of
Definition toml.hpp:2245
#define TOML_ABI_NAMESPACE_START(name)
Definition toml.hpp:1247
#define TOML_LIKELY_CASE
Definition toml.hpp:586
#define push_parse_scope(scope)
Definition toml.hpp:14128
constexpr bool is_cvref
Definition toml.hpp:1731
#define utf8_reader_error_check(...)
Definition toml.hpp:13455
constexpr size_t charconv_buffer_length< uint32_t >
Definition toml.hpp:10910
#define TOML_ASSERT_ASSUME(expr)
Definition toml.hpp:1148
#define TOML_NAMESPACE_START
Definition toml.hpp:1244
#define TOML_MAX_NESTED_VALUES
Definition toml.hpp:1112
#define assert_not_error()
Definition toml.hpp:14254
constexpr size_t charconv_buffer_length< int32_t >
Definition toml.hpp:10895
#define TOML_OPEN_FLAGS_ENUM
Definition toml.hpp:619
#define advance_and_return_if_error_or_eof(...)
Definition toml.hpp:14314
constexpr bool is_container
Definition toml.hpp:2376
constexpr size_t charconv_buffer_length< uint64_t >
Definition toml.hpp:10914
#define TOML_PRAGMA_CLANG(decl)
Definition toml.hpp:398
#define TOML_NAMESPACE_END
Definition toml.hpp:1245
#define TOML_SA_LIST_NEW
Definition toml.hpp:1295
#define TOML_SA_LIST_NXT
Definition toml.hpp:1296
#define TOML_CLOSED_FLAGS_ENUM
Definition toml.hpp:620
constexpr value_flags preserve_source_value_flags
Definition toml.hpp:1676
#define TOML_HIDDEN_CONSTRAINT(condition,...)
Definition toml.hpp:1190
#define TOML_ATTR(...)
Definition toml.hpp:355
enum TOML_CLOSED_FLAGS_ENUM relaxed_float_precision
Definition toml.hpp:1695
#define TOML_PURE_INLINE_GETTER
Definition toml.hpp:532
enum TOML_OPEN_FLAGS_ENUM format_as_binary
Definition toml.hpp:1670
#define TOML_ALWAYS_INLINE
Definition toml.hpp:445
#define TOML_IMPL_NAMESPACE_END
Definition toml.hpp:1259
constexpr bool is_node_view
Definition toml.hpp:2430
#define TOML_DISABLE_SPAM_WARNINGS
Definition toml.hpp:919
enum TOML_CLOSED_FLAGS_ENUM format_flags
Definition toml.hpp:1680
#define TOML_EXPORTED_FREE_FUNCTION
Definition toml.hpp:1014
#define parse_error_break()
Definition toml.hpp:14285
#define utf8_buffered_reader_error_check(...)
Definition toml.hpp:13742
node_view(const T &) -> node_view< const node >
#define TOML_IMPL_NAMESPACE_START
Definition toml.hpp:1258
#define is_eof()
Definition toml.hpp:14236
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS,...)
Definition toml.hpp:669
#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg)
Definition toml.hpp:5073
#define advance_and_return_if_error(...)
Definition toml.hpp:14306
POXY_IMPLEMENTATION_DETAIL(impl::table_iterator< true >) const_table_iterator
Definition toml.hpp:8076
constexpr size_t charconv_buffer_length< double >
Definition toml.hpp:10921
#define assert_not_eof()
Definition toml.hpp:14237
#define TOML_CONST_INLINE_GETTER
Definition toml.hpp:543
#define TOML_ENABLE_WARNINGS
Definition toml.hpp:931
constexpr bool can_represent_native
Definition toml.hpp:2236
constexpr bool is_node
Definition toml.hpp:2425
TOML_INTERNAL_LINKAGE constexpr auto utf8_byte_order_mark
Definition toml.hpp:13278
value(T) -> value< impl::native_type_of< impl::remove_cvref< T > > >
constexpr size_t charconv_buffer_length< float >
Definition toml.hpp:10918
std::basic_ostream< Char > & operator<<(std::basic_ostream< Char > &lhs, node_type rhs)
Definition toml.hpp:1648
copy_ref< copy_ref< copy_cv< std::remove_reference_t< Dest >, std::remove_reference_t< Src > >, Dest >, Src > copy_cvref
Definition toml.hpp:1804
#define TOML_EXPORTED_MEMBER_FUNCTION
Definition toml.hpp:1008
TOML_INTERNAL_LINKAGE void print_integer_to_stream(std::ostream &stream, T val, value_flags format={}, size_t min_digits=0)
Definition toml.hpp:10924
enum TOML_CLOSED_FLAGS_ENUM indent_sub_tables
Definition toml.hpp:1692
#define TOML_SA_NATIVE_VALUE_TYPE_LIST
Definition toml.hpp:1300
constexpr bool is_time
Definition toml.hpp:2407
#define TOML_NVCC_WORKAROUND
Definition toml.hpp:3827
typename node_unwrapper< std::remove_reference_t< T > >::type unwrap_node
Definition toml.hpp:2334
TOML_PURE_INLINE_GETTER constexpr const T & min(const T &a, const T &b) noexcept
Definition toml.hpp:2491
enum TOML_CLOSED_FLAGS_ENUM indentation
Definition toml.hpp:1694
inserter(T &&) -> inserter< T && >
constexpr bool is_key_or_convertible
Definition toml.hpp:7860
#define TOML_MAKE_FLAGS(T)
Definition toml.hpp:659
#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg)
Definition toml.hpp:5054
enum TOML_CLOSED_FLAGS_ENUM indent_array_elements
Definition toml.hpp:1693
#define TOML_SA_LIST_SEP
Definition toml.hpp:1292
TOML_INTERNAL_LINKAGE void concatenate(char *&write_pos, char *const buf_end, const T &arg) noexcept
Definition toml.hpp:13971
constexpr std::string_view node_type_friendly_names[]
Definition toml.hpp:1595
constexpr bool is_wide_string
Definition toml.hpp:1735
#define utf8_reader_return_after_error(...)
Definition toml.hpp:13454
#define TOML_ASSUME(expr)
Definition toml.hpp:560
constexpr bool is_value
Definition toml.hpp:2421
typename copy_ref_< Dest, Src >::type copy_ref
Definition toml.hpp:1754
void print_to_stream_bookended(std::ostream &stream, const T &val, const U &bookend)
Definition toml.hpp:2646
#define TOML_ABSTRACT_INTERFACE
Definition toml.hpp:467