Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:31

0001 //----------------------------------------------------------------------------------------------------------------------
0002 //
0003 // toml++ v3.4.0
0004 // https://github.com/marzer/tomlplusplus
0005 // SPDX-License-Identifier: MIT
0006 //
0007 //----------------------------------------------------------------------------------------------------------------------
0008 //
0009 // -         THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY            -
0010 //
0011 // If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this
0012 // file was assembled from a number of smaller files by a python script, and code contributions should not be made
0013 // against it directly. You should instead make your changes in the relevant source file(s). The file names of the files
0014 // that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file.
0015 //
0016 //----------------------------------------------------------------------------------------------------------------------
0017 //
0018 // TOML Language Specifications:
0019 // latest:      https://github.com/toml-lang/toml/blob/master/README.md
0020 // v1.0.0:      https://toml.io/en/v1.0.0
0021 // v0.5.0:      https://toml.io/en/v0.5.0
0022 // changelog:   https://github.com/toml-lang/toml/blob/master/CHANGELOG.md
0023 //
0024 //----------------------------------------------------------------------------------------------------------------------
0025 //
0026 // MIT License
0027 //
0028 // Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
0029 //
0030 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
0031 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
0032 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
0033 // permit persons to whom the Software is furnished to do so, subject to the following conditions:
0034 //
0035 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
0036 // Software.
0037 //
0038 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
0039 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
0040 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
0041 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0042 //
0043 //----------------------------------------------------------------------------------------------------------------------
0044 #ifndef TOMLPLUSPLUS_HPP
0045 #define TOMLPLUSPLUS_HPP
0046 
0047 #define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3
0048 #define TOMLPLUSPLUS_H         // guard name used in the legacy toml.h
0049 
0050 //********  impl/preprocessor.hpp  *************************************************************************************
0051 
0052 #ifndef __cplusplus
0053 #error toml++ is a C++ library.
0054 #endif
0055 
0056 #ifndef TOML_CPP
0057 #ifdef _MSVC_LANG
0058 #if _MSVC_LANG > __cplusplus
0059 #define TOML_CPP _MSVC_LANG
0060 #endif
0061 #endif
0062 #ifndef TOML_CPP
0063 #define TOML_CPP __cplusplus
0064 #endif
0065 #if TOML_CPP >= 202900L
0066 #undef TOML_CPP
0067 #define TOML_CPP 29
0068 #elif TOML_CPP >= 202600L
0069 #undef TOML_CPP
0070 #define TOML_CPP 26
0071 #elif TOML_CPP >= 202302L
0072 #undef TOML_CPP
0073 #define TOML_CPP 23
0074 #elif TOML_CPP >= 202002L
0075 #undef TOML_CPP
0076 #define TOML_CPP 20
0077 #elif TOML_CPP >= 201703L
0078 #undef TOML_CPP
0079 #define TOML_CPP 17
0080 #elif TOML_CPP >= 201402L
0081 #undef TOML_CPP
0082 #define TOML_CPP 14
0083 #elif TOML_CPP >= 201103L
0084 #undef TOML_CPP
0085 #define TOML_CPP 11
0086 #else
0087 #undef TOML_CPP
0088 #define TOML_CPP 0
0089 #endif
0090 #endif
0091 
0092 #if !TOML_CPP
0093 #error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml
0094 #elif TOML_CPP < 17
0095 #error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11
0096 #endif
0097 
0098 #ifndef TOML_MAKE_VERSION
0099 #define TOML_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + ((patch)))
0100 #endif
0101 
0102 #ifndef TOML_INTELLISENSE
0103 #ifdef __INTELLISENSE__
0104 #define TOML_INTELLISENSE 1
0105 #else
0106 #define TOML_INTELLISENSE 0
0107 #endif
0108 #endif
0109 
0110 #ifndef TOML_DOXYGEN
0111 #if defined(DOXYGEN) || defined(__DOXYGEN) || defined(__DOXYGEN__) || defined(__doxygen__) || defined(__POXY__)        \
0112     || defined(__poxy__)
0113 #define TOML_DOXYGEN 1
0114 #else
0115 #define TOML_DOXYGEN 0
0116 #endif
0117 #endif
0118 
0119 #ifndef TOML_CLANG
0120 #ifdef __clang__
0121 #define TOML_CLANG __clang_major__
0122 #else
0123 #define TOML_CLANG 0
0124 #endif
0125 
0126 // special handling for apple clang; see:
0127 // - https://github.com/marzer/tomlplusplus/issues/189
0128 // - https://en.wikipedia.org/wiki/Xcode
0129 // -
0130 // https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time
0131 #if TOML_CLANG && defined(__apple_build_version__)
0132 #undef TOML_CLANG
0133 #define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
0134 #if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0)
0135 #define TOML_CLANG 16
0136 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0)
0137 #define TOML_CLANG 15
0138 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0)
0139 #define TOML_CLANG 14
0140 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6)
0141 #define TOML_CLANG 13
0142 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0)
0143 #define TOML_CLANG 12
0144 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5)
0145 #define TOML_CLANG 11
0146 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0)
0147 #define TOML_CLANG 10
0148 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3)
0149 #define TOML_CLANG 9
0150 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0)
0151 #define TOML_CLANG 8
0152 #elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1)
0153 #define TOML_CLANG 7
0154 #else
0155 #define TOML_CLANG 6 // not strictly correct but doesn't matter below this
0156 #endif
0157 #undef TOML_CLANG_VERSION
0158 #endif
0159 #endif
0160 
0161 #ifndef TOML_ICC
0162 #ifdef __INTEL_COMPILER
0163 #define TOML_ICC __INTEL_COMPILER
0164 #ifdef __ICL
0165 #define TOML_ICC_CL TOML_ICC
0166 #else
0167 #define TOML_ICC_CL 0
0168 #endif
0169 #else
0170 #define TOML_ICC    0
0171 #define TOML_ICC_CL 0
0172 #endif
0173 #endif
0174 
0175 #ifndef TOML_MSVC_LIKE
0176 #ifdef _MSC_VER
0177 #define TOML_MSVC_LIKE _MSC_VER
0178 #else
0179 #define TOML_MSVC_LIKE 0
0180 #endif
0181 #endif
0182 
0183 #ifndef TOML_MSVC
0184 #if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC
0185 #define TOML_MSVC TOML_MSVC_LIKE
0186 #else
0187 #define TOML_MSVC 0
0188 #endif
0189 #endif
0190 
0191 #ifndef TOML_GCC_LIKE
0192 #ifdef __GNUC__
0193 #define TOML_GCC_LIKE __GNUC__
0194 #else
0195 #define TOML_GCC_LIKE 0
0196 #endif
0197 #endif
0198 
0199 #ifndef TOML_GCC
0200 #if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC
0201 #define TOML_GCC TOML_GCC_LIKE
0202 #else
0203 #define TOML_GCC 0
0204 #endif
0205 #endif
0206 
0207 #ifndef TOML_CUDA
0208 #if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__)
0209 #define TOML_CUDA 1
0210 #else
0211 #define TOML_CUDA 0
0212 #endif
0213 #endif
0214 
0215 #ifndef TOML_NVCC
0216 #ifdef __NVCOMPILER_MAJOR__
0217 #define TOML_NVCC __NVCOMPILER_MAJOR__
0218 #else
0219 #define TOML_NVCC 0
0220 #endif
0221 #endif
0222 
0223 #ifndef TOML_ARCH_ITANIUM
0224 #if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64)
0225 #define TOML_ARCH_ITANIUM 1
0226 #define TOML_ARCH_BITNESS 64
0227 #else
0228 #define TOML_ARCH_ITANIUM 0
0229 #endif
0230 #endif
0231 
0232 #ifndef TOML_ARCH_AMD64
0233 #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
0234 #define TOML_ARCH_AMD64   1
0235 #define TOML_ARCH_BITNESS 64
0236 #else
0237 #define TOML_ARCH_AMD64 0
0238 #endif
0239 #endif
0240 
0241 #ifndef TOML_ARCH_X86
0242 #if defined(__i386__) || defined(_M_IX86)
0243 #define TOML_ARCH_X86     1
0244 #define TOML_ARCH_BITNESS 32
0245 #else
0246 #define TOML_ARCH_X86 0
0247 #endif
0248 #endif
0249 
0250 #ifndef TOML_ARCH_ARM
0251 #if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE)             \
0252     || defined(_M_ARM64EC)
0253 #define TOML_ARCH_ARM32   0
0254 #define TOML_ARCH_ARM64   1
0255 #define TOML_ARCH_ARM     1
0256 #define TOML_ARCH_BITNESS 64
0257 #elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE)
0258 #define TOML_ARCH_ARM32   1
0259 #define TOML_ARCH_ARM64   0
0260 #define TOML_ARCH_ARM     1
0261 #define TOML_ARCH_BITNESS 32
0262 #else
0263 #define TOML_ARCH_ARM32 0
0264 #define TOML_ARCH_ARM64 0
0265 #define TOML_ARCH_ARM   0
0266 #endif
0267 #endif
0268 
0269 #ifndef TOML_ARCH_BITNESS
0270 #define TOML_ARCH_BITNESS 0
0271 #endif
0272 
0273 #ifndef TOML_ARCH_X64
0274 #if TOML_ARCH_BITNESS == 64
0275 #define TOML_ARCH_X64 1
0276 #else
0277 #define TOML_ARCH_X64 0
0278 #endif
0279 #endif
0280 
0281 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__)
0282 #define TOML_WINDOWS 1
0283 #else
0284 #define TOML_WINDOWS 0
0285 #endif
0286 
0287 #ifdef __unix__
0288 #define TOML_UNIX 1
0289 #else
0290 #define TOML_UNIX 0
0291 #endif
0292 
0293 #ifdef __linux__
0294 #define TOML_LINUX 1
0295 #else
0296 #define TOML_LINUX 0
0297 #endif
0298 
0299 // TOML_HAS_INCLUDE
0300 #ifndef TOML_HAS_INCLUDE
0301 #ifdef __has_include
0302 #define TOML_HAS_INCLUDE(header)        __has_include(header)
0303 #else
0304 #define TOML_HAS_INCLUDE(header) 0
0305 #endif
0306 #endif
0307 
0308 // TOML_HAS_BUILTIN
0309 #ifndef TOML_HAS_BUILTIN
0310 #ifdef __has_builtin
0311 #define TOML_HAS_BUILTIN(name) __has_builtin(name)
0312 #else
0313 #define TOML_HAS_BUILTIN(name) 0
0314 #endif
0315 #endif
0316 
0317 // TOML_HAS_FEATURE
0318 #ifndef TOML_HAS_FEATURE
0319 #ifdef __has_feature
0320 #define TOML_HAS_FEATURE(name) __has_feature(name)
0321 #else
0322 #define TOML_HAS_FEATURE(name) 0
0323 #endif
0324 #endif
0325 
0326 // TOML_HAS_ATTR
0327 #ifndef TOML_HAS_ATTR
0328 #ifdef __has_attribute
0329 #define TOML_HAS_ATTR(attr) __has_attribute(attr)
0330 #else
0331 #define TOML_HAS_ATTR(attr) 0
0332 #endif
0333 #endif
0334 
0335 // TOML_HAS_CPP_ATTR
0336 #ifndef TOML_HAS_CPP_ATTR
0337 #ifdef __has_cpp_attribute
0338 #define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr)
0339 #else
0340 #define TOML_HAS_CPP_ATTR(attr) 0
0341 #endif
0342 #endif
0343 
0344 // TOML_ATTR (gnu attributes)
0345 #ifndef TOML_ATTR
0346 #if TOML_CLANG || TOML_GCC_LIKE
0347 #define TOML_ATTR(...) __attribute__((__VA_ARGS__))
0348 #else
0349 #define TOML_ATTR(...)
0350 #endif
0351 #endif
0352 
0353 // TOML_DECLSPEC (msvc attributes)
0354 #ifndef TOML_DECLSPEC
0355 #if TOML_MSVC_LIKE
0356 #define TOML_DECLSPEC(...) __declspec(__VA_ARGS__)
0357 #else
0358 #define TOML_DECLSPEC(...)
0359 #endif
0360 #endif
0361 
0362 // TOML_COMPILER_HAS_EXCEPTIONS
0363 #ifndef TOML_COMPILER_HAS_EXCEPTIONS
0364 #if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions)
0365 #define TOML_COMPILER_HAS_EXCEPTIONS 1
0366 #else
0367 #define TOML_COMPILER_HAS_EXCEPTIONS 0
0368 #endif
0369 #endif
0370 
0371 // TOML_COMPILER_HAS_RTTI
0372 #ifndef TOML_COMPILER_HAS_RTTI
0373 #if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti)
0374 #define TOML_COMPILER_HAS_RTTI 1
0375 #else
0376 #define TOML_COMPILER_HAS_RTTI 0
0377 #endif
0378 #endif
0379 
0380 // TOML_CONCAT
0381 #define TOML_CONCAT_1(x, y) x##y
0382 #define TOML_CONCAT(x, y)   TOML_CONCAT_1(x, y)
0383 
0384 // TOML_MAKE_STRING
0385 #define TOML_MAKE_STRING_1(s) #s
0386 #define TOML_MAKE_STRING(s)   TOML_MAKE_STRING_1(s)
0387 
0388 // TOML_PRAGMA_XXXX (compiler-specific pragmas)
0389 #if TOML_CLANG
0390 #define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl))
0391 #else
0392 #define TOML_PRAGMA_CLANG(decl)
0393 #endif
0394 #if TOML_CLANG >= 8
0395 #define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl)
0396 #else
0397 #define TOML_PRAGMA_CLANG_GE_8(decl)
0398 #endif
0399 #if TOML_CLANG >= 9
0400 #define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl)
0401 #else
0402 #define TOML_PRAGMA_CLANG_GE_9(decl)
0403 #endif
0404 #if TOML_CLANG >= 10
0405 #define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl)
0406 #else
0407 #define TOML_PRAGMA_CLANG_GE_10(decl)
0408 #endif
0409 #if TOML_CLANG >= 11
0410 #define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl)
0411 #else
0412 #define TOML_PRAGMA_CLANG_GE_11(decl)
0413 #endif
0414 #if TOML_GCC
0415 #define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl))
0416 #else
0417 #define TOML_PRAGMA_GCC(decl)
0418 #endif
0419 #if TOML_MSVC
0420 #define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__)
0421 #else
0422 #define TOML_PRAGMA_MSVC(...)
0423 #endif
0424 #if TOML_ICC
0425 #define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__)
0426 #else
0427 #define TOML_PRAGMA_ICC(...)
0428 #endif
0429 
0430 // TOML_ALWAYS_INLINE
0431 #ifndef TOML_ALWAYS_INLINE
0432 #ifdef _MSC_VER
0433 #define TOML_ALWAYS_INLINE __forceinline
0434 #elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__)
0435 #define TOML_ALWAYS_INLINE                                                                                             \
0436     TOML_ATTR(__always_inline__)                                                                                       \
0437     inline
0438 #else
0439 #define TOML_ALWAYS_INLINE inline
0440 #endif
0441 #endif
0442 
0443 // TOML_NEVER_INLINE
0444 #ifndef TOML_NEVER_INLINE
0445 #ifdef _MSC_VER
0446 #define TOML_NEVER_INLINE TOML_DECLSPEC(noinline)
0447 #elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555
0448 #define TOML_NEVER_INLINE TOML_ATTR(noinline)
0449 #else
0450 #if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__)
0451 #define TOML_NEVER_INLINE TOML_ATTR(__noinline__)
0452 #endif
0453 #endif
0454 #ifndef TOML_NEVER_INLINE
0455 #define TOML_NEVER_INLINE
0456 #endif
0457 #endif
0458 
0459 // MSVC attributes
0460 #ifndef TOML_ABSTRACT_INTERFACE
0461 #define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable)
0462 #endif
0463 #ifndef TOML_EMPTY_BASES
0464 #define TOML_EMPTY_BASES        TOML_DECLSPEC(empty_bases)
0465 #endif
0466 
0467 // TOML_TRIVIAL_ABI
0468 #ifndef TOML_TRIVIAL_ABI
0469 #if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__)
0470 #define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__)
0471 #else
0472 #define TOML_TRIVIAL_ABI
0473 #endif
0474 #endif
0475 
0476 // TOML_NODISCARD
0477 #ifndef TOML_NODISCARD
0478 #if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603
0479 #define TOML_NODISCARD [[nodiscard]]
0480 #elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__)
0481 #define TOML_NODISCARD TOML_ATTR(__warn_unused_result__)
0482 #else
0483 #define TOML_NODISCARD
0484 #endif
0485 #endif
0486 
0487 // TOML_NODISCARD_CTOR
0488 #ifndef TOML_NODISCARD_CTOR
0489 #if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907
0490 #define TOML_NODISCARD_CTOR [[nodiscard]]
0491 #else
0492 #define TOML_NODISCARD_CTOR
0493 #endif
0494 #endif
0495 
0496 // pure + const
0497 #ifndef TOML_PURE
0498 #ifdef NDEBUG
0499 #define TOML_PURE                                                                                                      \
0500     TOML_DECLSPEC(noalias)                                                                                             \
0501     TOML_ATTR(pure)
0502 #else
0503 #define TOML_PURE
0504 #endif
0505 #endif
0506 #ifndef TOML_CONST
0507 #ifdef NDEBUG
0508 #define TOML_CONST                                                                                                     \
0509     TOML_DECLSPEC(noalias)                                                                                             \
0510     TOML_ATTR(const)
0511 #else
0512 #define TOML_CONST
0513 #endif
0514 #endif
0515 #ifndef TOML_INLINE_GETTER
0516 #define TOML_INLINE_GETTER                                                                                             \
0517     TOML_NODISCARD                                                                                                     \
0518     TOML_ALWAYS_INLINE
0519 #endif
0520 #ifndef TOML_PURE_GETTER
0521 #define TOML_PURE_GETTER                                                                                               \
0522     TOML_NODISCARD                                                                                                     \
0523     TOML_PURE
0524 #endif
0525 #ifndef TOML_PURE_INLINE_GETTER
0526 #define TOML_PURE_INLINE_GETTER                                                                                        \
0527     TOML_NODISCARD                                                                                                     \
0528     TOML_ALWAYS_INLINE                                                                                                 \
0529     TOML_PURE
0530 #endif
0531 #ifndef TOML_CONST_GETTER
0532 #define TOML_CONST_GETTER                                                                                              \
0533     TOML_NODISCARD                                                                                                     \
0534     TOML_CONST
0535 #endif
0536 #ifndef TOML_CONST_INLINE_GETTER
0537 #define TOML_CONST_INLINE_GETTER                                                                                       \
0538     TOML_NODISCARD                                                                                                     \
0539     TOML_ALWAYS_INLINE                                                                                                 \
0540     TOML_CONST
0541 #endif
0542 
0543 // TOML_ASSUME
0544 #ifndef TOML_ASSUME
0545 #ifdef _MSC_VER
0546 #define TOML_ASSUME(expr) __assume(expr)
0547 #elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume)
0548 #define TOML_ASSUME(expr) __builtin_assume(expr)
0549 #elif TOML_HAS_CPP_ATTR(assume) >= 202207
0550 #define TOML_ASSUME(expr) [[assume(expr)]]
0551 #elif TOML_HAS_ATTR(__assume__)
0552 #define TOML_ASSUME(expr) __attribute__((__assume__(expr)))
0553 #else
0554 #define TOML_ASSUME(expr) static_cast<void>(0)
0555 #endif
0556 #endif
0557 
0558 // TOML_UNREACHABLE
0559 #ifndef TOML_UNREACHABLE
0560 #ifdef _MSC_VER
0561 #define TOML_UNREACHABLE __assume(0)
0562 #elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable)
0563 #define TOML_UNREACHABLE __builtin_unreachable()
0564 #else
0565 #define TOML_UNREACHABLE static_cast<void>(0)
0566 #endif
0567 #endif
0568 
0569 // TOML_LIKELY
0570 #if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803
0571 #define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
0572 #define TOML_LIKELY_CASE [[likely]]
0573 #elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
0574 #define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1))
0575 #else
0576 #define TOML_LIKELY(...) (__VA_ARGS__)
0577 #endif
0578 #ifndef TOML_LIKELY_CASE
0579 #define TOML_LIKELY_CASE
0580 #endif
0581 
0582 // TOML_UNLIKELY
0583 #if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803
0584 #define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
0585 #define TOML_UNLIKELY_CASE [[unlikely]]
0586 #elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
0587 #define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0))
0588 #else
0589 #define TOML_UNLIKELY(...) (__VA_ARGS__)
0590 #endif
0591 #ifndef TOML_UNLIKELY_CASE
0592 #define TOML_UNLIKELY_CASE
0593 #endif
0594 
0595 // TOML_FLAGS_ENUM
0596 #if TOML_CLANG || TOML_HAS_ATTR(flag_enum)
0597 #define TOML_FLAGS_ENUM __attribute__((flag_enum))
0598 #else
0599 #define TOML_FLAGS_ENUM
0600 #endif
0601 
0602 // TOML_OPEN_ENUM + TOML_CLOSED_ENUM
0603 #if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility)
0604 #define TOML_OPEN_ENUM   __attribute__((enum_extensibility(open)))
0605 #define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed)))
0606 #else
0607 #define TOML_OPEN_ENUM
0608 #define TOML_CLOSED_ENUM
0609 #endif
0610 
0611 // TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM
0612 #define TOML_OPEN_FLAGS_ENUM   TOML_OPEN_ENUM TOML_FLAGS_ENUM
0613 #define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM
0614 
0615 // TOML_MAKE_FLAGS
0616 #define TOML_MAKE_FLAGS_2(T, op, linkage)                                                                              \
0617     TOML_CONST_INLINE_GETTER                                                                                           \
0618     linkage constexpr T operator op(T lhs, T rhs) noexcept                                                             \
0619     {                                                                                                                  \
0620         using under = std::underlying_type_t<T>;                                                                       \
0621         return static_cast<T>(static_cast<under>(lhs) op static_cast<under>(rhs));                                     \
0622     }                                                                                                                  \
0623                                                                                                                        \
0624     linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept                                          \
0625     {                                                                                                                  \
0626         return lhs = (lhs op rhs);                                                                                     \
0627     }                                                                                                                  \
0628                                                                                                                        \
0629     static_assert(true)
0630 #define TOML_MAKE_FLAGS_1(T, linkage)                                                                                  \
0631     static_assert(std::is_enum_v<T>);                                                                                  \
0632                                                                                                                        \
0633     TOML_MAKE_FLAGS_2(T, &, linkage);                                                                                  \
0634     TOML_MAKE_FLAGS_2(T, |, linkage);                                                                                  \
0635     TOML_MAKE_FLAGS_2(T, ^, linkage);                                                                                  \
0636                                                                                                                        \
0637     TOML_CONST_INLINE_GETTER                                                                                           \
0638     linkage constexpr T operator~(T val) noexcept                                                                      \
0639     {                                                                                                                  \
0640         using under = std::underlying_type_t<T>;                                                                       \
0641         return static_cast<T>(~static_cast<under>(val));                                                               \
0642     }                                                                                                                  \
0643                                                                                                                        \
0644     TOML_CONST_INLINE_GETTER                                                                                           \
0645     linkage constexpr bool operator!(T val) noexcept                                                                   \
0646     {                                                                                                                  \
0647         using under = std::underlying_type_t<T>;                                                                       \
0648         return !static_cast<under>(val);                                                                               \
0649     }                                                                                                                  \
0650                                                                                                                        \
0651     static_assert(true)
0652 #define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, )
0653 
0654 #define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
0655 
0656 #define TOML_DELETE_DEFAULTS(T)                                                                                        \
0657     T(const T&)            = delete;                                                                                   \
0658     T(T&&)                 = delete;                                                                                   \
0659     T& operator=(const T&) = delete;                                                                                   \
0660     T& operator=(T&&)      = delete
0661 
0662 #define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...)                                                                  \
0663     __VA_ARGS__ TOML_NODISCARD                                                                                         \
0664     friend bool operator==(RHS rhs, LHS lhs) noexcept                                                                  \
0665     {                                                                                                                  \
0666         return lhs == rhs;                                                                                             \
0667     }                                                                                                                  \
0668     __VA_ARGS__ TOML_NODISCARD                                                                                         \
0669     friend bool operator!=(LHS lhs, RHS rhs) noexcept                                                                  \
0670     {                                                                                                                  \
0671         return !(lhs == rhs);                                                                                          \
0672     }                                                                                                                  \
0673     __VA_ARGS__ TOML_NODISCARD                                                                                         \
0674     friend bool operator!=(RHS rhs, LHS lhs) noexcept                                                                  \
0675     {                                                                                                                  \
0676         return !(lhs == rhs);                                                                                          \
0677     }                                                                                                                  \
0678     static_assert(true)
0679 
0680 #define TOML_EVAL_BOOL_1(T, F) T
0681 #define TOML_EVAL_BOOL_0(T, F) F
0682 
0683 #if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL)
0684 #define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__
0685 #endif
0686 
0687 // COMPILER-SPECIFIC WARNING MANAGEMENT
0688 
0689 #if TOML_CLANG
0690 
0691 #define TOML_PUSH_WARNINGS                                                                                             \
0692     TOML_PRAGMA_CLANG(diagnostic push)                                                                                 \
0693     TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option")                                                   \
0694     static_assert(true)
0695 
0696 #define TOML_DISABLE_SWITCH_WARNINGS                                                                                   \
0697     TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch")                                                                   \
0698     static_assert(true)
0699 
0700 #define TOML_DISABLE_ARITHMETIC_WARNINGS                                                                               \
0701     TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wimplicit-int-float-conversion")                                      \
0702     TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal")                                                              \
0703     TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion")                                                         \
0704     TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts")                                                          \
0705     TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow")                                                      \
0706     static_assert(true)
0707 
0708 #define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
0709     TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted")                                          \
0710     TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported")                                              \
0711     TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant")                                      \
0712     TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override")                                        \
0713     TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables")                                                             \
0714     TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables")                                                    \
0715     TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion")                                                         \
0716     TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts")                                                          \
0717     TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers")                                               \
0718     TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded")                                                                   \
0719     static_assert(true)
0720 
0721 #define TOML_POP_WARNINGS                                                                                              \
0722     TOML_PRAGMA_CLANG(diagnostic pop)                                                                                  \
0723     static_assert(true)
0724 
0725 #define TOML_DISABLE_WARNINGS                                                                                          \
0726     TOML_PRAGMA_CLANG(diagnostic push)                                                                                 \
0727     TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything")                                                               \
0728     static_assert(true, "")
0729 
0730 #define TOML_ENABLE_WARNINGS                                                                                           \
0731     TOML_PRAGMA_CLANG(diagnostic pop)                                                                                  \
0732     static_assert(true)
0733 
0734 #define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1
0735 
0736 #elif TOML_MSVC
0737 
0738 #define TOML_PUSH_WARNINGS                                                                                             \
0739     __pragma(warning(push))                                                                                            \
0740     static_assert(true)
0741 
0742 #if TOML_HAS_INCLUDE(<CodeAnalysis/Warnings.h>)
0743 #pragma warning(push, 0)
0744 #include <CodeAnalysis/Warnings.h>
0745 #pragma warning(pop)
0746 #define TOML_DISABLE_CODE_ANALYSIS_WARNINGS                                                                            \
0747     __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS))                                                            \
0748     static_assert(true)
0749 #else
0750 #define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
0751 #endif
0752 
0753 #define TOML_DISABLE_SWITCH_WARNINGS                                                                                   \
0754     __pragma(warning(disable : 4061))                                                                                  \
0755     __pragma(warning(disable : 4062))                                                                                  \
0756     __pragma(warning(disable : 4063))                                                                                  \
0757     __pragma(warning(disable : 5262))  /* switch-case implicit fallthrough (false-positive) */                         \
0758     __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */                                               \
0759     static_assert(true)
0760 
0761 #define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
0762     __pragma(warning(disable : 4127)) /* conditional expr is constant */                                               \
0763     __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */                            \
0764     __pragma(warning(disable : 4348))                                                                                  \
0765     __pragma(warning(disable : 4464)) /* relative include path contains '..' */                                        \
0766     __pragma(warning(disable : 4505)) /* unreferenced local function removed */                                        \
0767     __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */                              \
0768     __pragma(warning(disable : 4582)) /* constructor is not implicitly called */                                       \
0769     __pragma(warning(disable : 4619)) /*  there is no warning number 'XXXX' */                                         \
0770     __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */                      \
0771     __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */                         \
0772     __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */                      \
0773     __pragma(warning(disable : 4710)) /* function not inlined */                                                       \
0774     __pragma(warning(disable : 4711)) /* function selected for automatic expansion */                                  \
0775     __pragma(warning(disable : 4820)) /* N bytes padding added */                                                      \
0776     __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */                              \
0777     __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted */                         \
0778     __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted */                 \
0779     __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */              \
0780     __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */                                    \
0781     __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */                                \
0782     __pragma(warning(disable : 26451))                                                                                 \
0783     __pragma(warning(disable : 26490))                                                                                 \
0784     __pragma(warning(disable : 26495))                                                                                 \
0785     __pragma(warning(disable : 26812))                                                                                 \
0786     __pragma(warning(disable : 26819))                                                                                 \
0787     static_assert(true)
0788 
0789 #define TOML_DISABLE_ARITHMETIC_WARNINGS                                                                               \
0790     __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */                                          \
0791     __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */                                      \
0792     __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */                                 \
0793     static_assert(true)
0794 
0795 #define TOML_POP_WARNINGS                                                                                              \
0796     __pragma(warning(pop))                                                                                             \
0797     static_assert(true)
0798 
0799 #define TOML_DISABLE_WARNINGS                                                                                          \
0800     __pragma(warning(push, 0))                                                                                         \
0801     __pragma(warning(disable : 4348))                                                                                  \
0802     __pragma(warning(disable : 4668))                                                                                  \
0803     __pragma(warning(disable : 5105))                                                                                  \
0804     __pragma(warning(disable : 5264))                                                                                  \
0805     TOML_DISABLE_CODE_ANALYSIS_WARNINGS;                                                                               \
0806     TOML_DISABLE_SWITCH_WARNINGS;                                                                                      \
0807     TOML_DISABLE_SPAM_WARNINGS;                                                                                        \
0808     TOML_DISABLE_ARITHMETIC_WARNINGS;                                                                                  \
0809     static_assert(true)
0810 
0811 #define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
0812 
0813 #elif TOML_ICC
0814 
0815 #define TOML_PUSH_WARNINGS                                                                                             \
0816     __pragma(warning(push))                                                                                            \
0817     static_assert(true)
0818 
0819 #define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
0820     __pragma(warning(disable : 82))   /* storage class is not first */                                                 \
0821     __pragma(warning(disable : 111))  /* statement unreachable (false-positive) */                                     \
0822     __pragma(warning(disable : 869))  /* unreferenced parameter */                                                     \
0823     __pragma(warning(disable : 1011)) /* missing return (false-positive) */                                            \
0824     __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */                                         \
0825     static_assert(true)
0826 
0827 #define TOML_POP_WARNINGS                                                                                              \
0828     __pragma(warning(pop))                                                                                             \
0829     static_assert(true)
0830 
0831 #define TOML_DISABLE_WARNINGS                                                                                          \
0832     __pragma(warning(push, 0))                                                                                         \
0833     TOML_DISABLE_SPAM_WARNINGS
0834 
0835 #define TOML_ENABLE_WARNINGS                                                                                           \
0836     __pragma(warning(pop))                                                                                             \
0837     static_assert(true)
0838 
0839 #elif TOML_GCC
0840 
0841 #define TOML_PUSH_WARNINGS                                                                                             \
0842     TOML_PRAGMA_GCC(diagnostic push)                                                                                   \
0843     static_assert(true)
0844 
0845 #define TOML_DISABLE_SWITCH_WARNINGS                                                                                   \
0846     TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch")                                                                     \
0847     TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum")                                                                \
0848     TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default")                                                             \
0849     static_assert(true)
0850 
0851 #define TOML_DISABLE_ARITHMETIC_WARNINGS                                                                               \
0852     TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal")                                                                \
0853     TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion")                                                            \
0854     TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts")                                                            \
0855     static_assert(true)
0856 
0857 #define TOML_DISABLE_SUGGEST_ATTR_WARNINGS                                                                             \
0858     TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const")                                                    \
0859     TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure")                                                     \
0860     static_assert(true)
0861 
0862 #define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
0863     TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded")                                                                     \
0864     TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align")                                                                 \
0865     TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment")                                                                    \
0866     TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits")                                                                \
0867     TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast")                                                               \
0868     TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts")                                                            \
0869     TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage")                                                          \
0870     TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers")                                                 \
0871     TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized")                                                        \
0872     TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept")                                                                   \
0873     TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference")                                                           \
0874     TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches")                                                        \
0875     static_assert(true)
0876 
0877 #define TOML_POP_WARNINGS                                                                                              \
0878     TOML_PRAGMA_GCC(diagnostic pop)                                                                                    \
0879     static_assert(true)
0880 
0881 #define TOML_DISABLE_WARNINGS                                                                                          \
0882     TOML_PRAGMA_GCC(diagnostic push)                                                                                   \
0883     TOML_PRAGMA_GCC(diagnostic ignored "-Wall")                                                                        \
0884     TOML_PRAGMA_GCC(diagnostic ignored "-Wextra")                                                                      \
0885     TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic")                                                                   \
0886     TOML_DISABLE_SWITCH_WARNINGS;                                                                                      \
0887     TOML_DISABLE_ARITHMETIC_WARNINGS;                                                                                  \
0888     TOML_DISABLE_SUGGEST_ATTR_WARNINGS;                                                                                \
0889     TOML_DISABLE_SPAM_WARNINGS;                                                                                        \
0890     static_assert(true)
0891 
0892 #define TOML_ENABLE_WARNINGS                                                                                           \
0893     TOML_PRAGMA_GCC(diagnostic pop)                                                                                    \
0894     static_assert(true)
0895 
0896 #endif
0897 
0898 #ifndef TOML_PUSH_WARNINGS
0899 #define TOML_PUSH_WARNINGS static_assert(true)
0900 #endif
0901 #ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
0902 #define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
0903 #endif
0904 #ifndef TOML_DISABLE_SWITCH_WARNINGS
0905 #define TOML_DISABLE_SWITCH_WARNINGS static_assert(true)
0906 #endif
0907 #ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
0908 #define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true)
0909 #endif
0910 #ifndef TOML_DISABLE_SPAM_WARNINGS
0911 #define TOML_DISABLE_SPAM_WARNINGS static_assert(true)
0912 #endif
0913 #ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
0914 #define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true)
0915 #endif
0916 #ifndef TOML_POP_WARNINGS
0917 #define TOML_POP_WARNINGS static_assert(true)
0918 #endif
0919 #ifndef TOML_DISABLE_WARNINGS
0920 #define TOML_DISABLE_WARNINGS static_assert(true)
0921 #endif
0922 #ifndef TOML_ENABLE_WARNINGS
0923 #define TOML_ENABLE_WARNINGS static_assert(true)
0924 #endif
0925 #ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
0926 #define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0
0927 #endif
0928 
0929 #ifdef TOML_CONFIG_HEADER
0930 #include TOML_CONFIG_HEADER
0931 #endif
0932 
0933 // is the library being built as a shared lib/dll using meson and friends?
0934 #ifndef TOML_SHARED_LIB
0935 #define TOML_SHARED_LIB 0
0936 #endif
0937 
0938 // header-only mode
0939 #if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0
0940 #define TOML_HEADER_ONLY TOML_ALL_INLINE
0941 #endif
0942 #if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
0943 #undef TOML_HEADER_ONLY
0944 #define TOML_HEADER_ONLY 1
0945 #endif
0946 #if TOML_DOXYGEN || TOML_SHARED_LIB
0947 #undef TOML_HEADER_ONLY
0948 #define TOML_HEADER_ONLY 0
0949 #endif
0950 
0951 // internal implementation switch
0952 #if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
0953 #undef TOML_IMPLEMENTATION
0954 #define TOML_IMPLEMENTATION 1
0955 #else
0956 #define TOML_IMPLEMENTATION 0
0957 #endif
0958 
0959 // dll/shared lib function exports (legacy - TOML_API was the old name for this setting)
0960 #if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && !defined(TOML_EXPORTED_STATIC_FUNCTION)                                 \
0961     && !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && defined(TOML_API)
0962 #define TOML_EXPORTED_MEMBER_FUNCTION TOML_API
0963 #define TOML_EXPORTED_STATIC_FUNCTION TOML_API
0964 #define TOML_EXPORTED_FREE_FUNCTION   TOML_API
0965 #endif
0966 
0967 // dll/shared lib exports
0968 #if TOML_SHARED_LIB
0969 #undef TOML_API
0970 #undef TOML_EXPORTED_CLASS
0971 #undef TOML_EXPORTED_MEMBER_FUNCTION
0972 #undef TOML_EXPORTED_STATIC_FUNCTION
0973 #undef TOML_EXPORTED_FREE_FUNCTION
0974 #if TOML_WINDOWS
0975 #if TOML_IMPLEMENTATION
0976 #define TOML_EXPORTED_CLASS         __declspec(dllexport)
0977 #define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport)
0978 #else
0979 #define TOML_EXPORTED_CLASS         __declspec(dllimport)
0980 #define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport)
0981 #endif
0982 #ifndef TOML_CALLCONV
0983 #define TOML_CALLCONV __cdecl
0984 #endif
0985 #elif defined(__GNUC__) && __GNUC__ >= 4
0986 #define TOML_EXPORTED_CLASS           __attribute__((visibility("default")))
0987 #define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default")))
0988 #define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default")))
0989 #define TOML_EXPORTED_FREE_FUNCTION   __attribute__((visibility("default")))
0990 #endif
0991 #endif
0992 #ifndef TOML_EXPORTED_CLASS
0993 #define TOML_EXPORTED_CLASS
0994 #endif
0995 #ifndef TOML_EXPORTED_MEMBER_FUNCTION
0996 #define TOML_EXPORTED_MEMBER_FUNCTION
0997 #endif
0998 #ifndef TOML_EXPORTED_STATIC_FUNCTION
0999 #define TOML_EXPORTED_STATIC_FUNCTION
1000 #endif
1001 #ifndef TOML_EXPORTED_FREE_FUNCTION
1002 #define TOML_EXPORTED_FREE_FUNCTION
1003 #endif
1004 
1005 // experimental language features
1006 #if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES
1007                                                                                    // pre-3.0
1008 #define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES
1009 #endif
1010 #if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE
1011 #undef TOML_ENABLE_UNRELEASED_FEATURES
1012 #define TOML_ENABLE_UNRELEASED_FEATURES 1
1013 #endif
1014 #ifndef TOML_ENABLE_UNRELEASED_FEATURES
1015 #define TOML_ENABLE_UNRELEASED_FEATURES 0
1016 #endif
1017 
1018 // parser
1019 #if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0
1020 #define TOML_ENABLE_PARSER TOML_PARSER
1021 #endif
1022 #if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE
1023 #undef TOML_ENABLE_PARSER
1024 #define TOML_ENABLE_PARSER 1
1025 #endif
1026 
1027 // formatters
1028 #if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE
1029 #undef TOML_ENABLE_FORMATTERS
1030 #define TOML_ENABLE_FORMATTERS 1
1031 #endif
1032 
1033 // SIMD
1034 #if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE
1035 #undef TOML_ENABLE_SIMD
1036 #define TOML_ENABLE_SIMD 1
1037 #endif
1038 
1039 // windows compat
1040 #if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0
1041 #define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT
1042 #endif
1043 #if !defined(TOML_ENABLE_WINDOWS_COMPAT) || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT)        \
1044     || TOML_INTELLISENSE
1045 #undef TOML_ENABLE_WINDOWS_COMPAT
1046 #define TOML_ENABLE_WINDOWS_COMPAT 1
1047 #endif
1048 
1049 #if !TOML_WINDOWS
1050 #undef TOML_ENABLE_WINDOWS_COMPAT
1051 #define TOML_ENABLE_WINDOWS_COMPAT 0
1052 #endif
1053 
1054 #ifndef TOML_INCLUDE_WINDOWS_H
1055 #define TOML_INCLUDE_WINDOWS_H 0
1056 #endif
1057 
1058 // custom optional
1059 #ifdef TOML_OPTIONAL_TYPE
1060 #define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
1061 #else
1062 #define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
1063 #endif
1064 
1065 // exceptions (library use)
1066 #if TOML_COMPILER_HAS_EXCEPTIONS
1067 #if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
1068 #undef TOML_EXCEPTIONS
1069 #define TOML_EXCEPTIONS 1
1070 #endif
1071 #else
1072 #if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS
1073 #error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler.
1074 #endif
1075 #undef TOML_EXCEPTIONS
1076 #define TOML_EXCEPTIONS 0
1077 #endif
1078 
1079 // calling convention for static/free/friend functions
1080 #ifndef TOML_CALLCONV
1081 #define TOML_CALLCONV
1082 #endif
1083 
1084 #ifndef TOML_UNDEF_MACROS
1085 #define TOML_UNDEF_MACROS 1
1086 #endif
1087 
1088 #ifndef TOML_MAX_NESTED_VALUES
1089 #define TOML_MAX_NESTED_VALUES 256
1090 // this refers to the depth of nested values, e.g. inline tables and arrays.
1091 // 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
1092 #endif
1093 
1094 #ifdef TOML_CHAR_8_STRINGS
1095 #if TOML_CHAR_8_STRINGS
1096 #error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly.
1097 #endif
1098 #endif
1099 
1100 #ifdef TOML_LARGE_FILES
1101 #if !TOML_LARGE_FILES
1102 #error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0.
1103 #endif
1104 #endif
1105 
1106 #ifndef TOML_LIFETIME_HOOKS
1107 #define TOML_LIFETIME_HOOKS 0
1108 #endif
1109 
1110 #ifdef NDEBUG
1111 #undef TOML_ASSERT
1112 #define TOML_ASSERT(expr) static_assert(true)
1113 #endif
1114 #ifndef TOML_ASSERT
1115 #ifndef assert
1116 TOML_DISABLE_WARNINGS;
1117 #include <cassert>
1118 TOML_ENABLE_WARNINGS;
1119 #endif
1120 #define TOML_ASSERT(expr) assert(expr)
1121 #endif
1122 #ifdef NDEBUG
1123 #define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr)
1124 #else
1125 #define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr)
1126 #endif
1127 
1128 #ifndef TOML_ENABLE_FLOAT16
1129 #define TOML_ENABLE_FLOAT16 0
1130 #endif
1131 
1132 #if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL))
1133 // not supported by any version of GCC or Clang as of 26/11/2020
1134 // not supported by any version of ICC on Linux as of 11/01/2021
1135 #define TOML_FLOAT_CHARCONV 0
1136 #endif
1137 #if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__))
1138 // causes link errors on emscripten
1139 // causes Mac OS SDK version errors on some versions of Apple Clang
1140 #define TOML_INT_CHARCONV 0
1141 #endif
1142 #ifndef TOML_INT_CHARCONV
1143 #define TOML_INT_CHARCONV 1
1144 #endif
1145 #ifndef TOML_FLOAT_CHARCONV
1146 #define TOML_FLOAT_CHARCONV 1
1147 #endif
1148 #if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE(<charconv>)
1149 #undef TOML_INT_CHARCONV
1150 #undef TOML_FLOAT_CHARCONV
1151 #define TOML_INT_CHARCONV   0
1152 #define TOML_FLOAT_CHARCONV 0
1153 #endif
1154 
1155 #if defined(__cpp_concepts) && __cpp_concepts >= 201907
1156 #define TOML_REQUIRES(...) requires(__VA_ARGS__)
1157 #else
1158 #define TOML_REQUIRES(...)
1159 #endif
1160 #define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0
1161 #define TOML_CONSTRAINED_TEMPLATE(condition, ...)                                                                      \
1162     template <__VA_ARGS__ TOML_ENABLE_IF(condition)>                                                                   \
1163     TOML_REQUIRES(condition)
1164 #define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__)
1165 
1166 #if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && defined(__LDBL_MANT_DIG__)                         \
1167     && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__
1168 #define TOML_FLOAT128 __float128
1169 #endif
1170 
1171 #ifdef __SIZEOF_INT128__
1172 #define TOML_INT128  __int128_t
1173 #define TOML_UINT128 __uint128_t
1174 #endif
1175 
1176 // clang-format off
1177 
1178 //********  impl/version.hpp  ******************************************************************************************
1179 
1180 #define TOML_LIB_MAJOR 3
1181 #define TOML_LIB_MINOR 4
1182 #define TOML_LIB_PATCH 0
1183 
1184 #define TOML_LANG_MAJOR 1
1185 #define TOML_LANG_MINOR 0
1186 #define TOML_LANG_PATCH 0
1187 
1188 //********  impl/preprocessor.hpp  *************************************************************************************
1189 
1190 #define TOML_LIB_SINGLE_HEADER 1
1191 
1192 #if TOML_ENABLE_UNRELEASED_FEATURES
1193     #define TOML_LANG_EFFECTIVE_VERSION                                                 \
1194         TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
1195 #else
1196     #define TOML_LANG_EFFECTIVE_VERSION                                                 \
1197         TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
1198 #endif
1199 
1200 #define TOML_LANG_HIGHER_THAN(major, minor, patch)                                      \
1201         (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch))
1202 
1203 #define TOML_LANG_AT_LEAST(major, minor, patch)                                         \
1204         (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch))
1205 
1206 #define TOML_LANG_UNRELEASED                                                            \
1207         TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
1208 
1209 #ifndef TOML_ABI_NAMESPACES
1210     #if TOML_DOXYGEN
1211         #define TOML_ABI_NAMESPACES 0
1212     #else
1213         #define TOML_ABI_NAMESPACES 1
1214     #endif
1215 #endif
1216 #if TOML_ABI_NAMESPACES
1217     #define TOML_NAMESPACE_START                namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR)
1218     #define TOML_NAMESPACE_END                  } static_assert(true)
1219     #define TOML_NAMESPACE                      ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR)
1220     #define TOML_ABI_NAMESPACE_START(name)      inline namespace name { static_assert(true)
1221     #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F))
1222     #define TOML_ABI_NAMESPACE_END              } static_assert(true)
1223 #else
1224     #define TOML_NAMESPACE_START                namespace toml
1225     #define TOML_NAMESPACE_END                  static_assert(true)
1226     #define TOML_NAMESPACE                      toml
1227     #define TOML_ABI_NAMESPACE_START(...)       static_assert(true)
1228     #define TOML_ABI_NAMESPACE_BOOL(...)        static_assert(true)
1229     #define TOML_ABI_NAMESPACE_END              static_assert(true)
1230 #endif
1231 #define TOML_IMPL_NAMESPACE_START               TOML_NAMESPACE_START { namespace impl
1232 #define TOML_IMPL_NAMESPACE_END                 } TOML_NAMESPACE_END
1233 #if TOML_HEADER_ONLY
1234     #define TOML_ANON_NAMESPACE_START           static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START
1235     #define TOML_ANON_NAMESPACE_END             TOML_IMPL_NAMESPACE_END
1236     #define TOML_ANON_NAMESPACE                 TOML_NAMESPACE::impl
1237     #define TOML_EXTERNAL_LINKAGE               inline
1238     #define TOML_INTERNAL_LINKAGE               inline
1239 #else
1240     #define TOML_ANON_NAMESPACE_START           static_assert(TOML_IMPLEMENTATION); \
1241                                                 using namespace toml;               \
1242                                                 namespace
1243     #define TOML_ANON_NAMESPACE_END             static_assert(true)
1244     #define TOML_ANON_NAMESPACE
1245     #define TOML_EXTERNAL_LINKAGE
1246     #define TOML_INTERNAL_LINKAGE               static
1247 #endif
1248 
1249 // clang-format on
1250 
1251 // clang-format off
1252 
1253 #if TOML_SIMPLE_STATIC_ASSERT_MESSAGES
1254 
1255     #define TOML_SA_NEWLINE     " "
1256     #define TOML_SA_LIST_SEP    ", "
1257     #define TOML_SA_LIST_BEG    " ("
1258     #define TOML_SA_LIST_END    ")"
1259     #define TOML_SA_LIST_NEW    " "
1260     #define TOML_SA_LIST_NXT    ", "
1261 
1262 #else
1263 
1264     #define TOML_SA_NEWLINE         "\n| "
1265     #define TOML_SA_LIST_SEP        TOML_SA_NEWLINE "  - "
1266     #define TOML_SA_LIST_BEG        TOML_SA_LIST_SEP
1267     #define TOML_SA_LIST_END
1268     #define TOML_SA_LIST_NEW        TOML_SA_NEWLINE TOML_SA_NEWLINE
1269     #define TOML_SA_LIST_NXT        TOML_SA_LIST_NEW
1270 
1271 #endif
1272 
1273 #define TOML_SA_NATIVE_VALUE_TYPE_LIST                          \
1274     TOML_SA_LIST_BEG    "std::string"                           \
1275     TOML_SA_LIST_SEP    "int64_t"                               \
1276     TOML_SA_LIST_SEP    "double"                                \
1277     TOML_SA_LIST_SEP    "bool"                                  \
1278     TOML_SA_LIST_SEP    "toml::date"                            \
1279     TOML_SA_LIST_SEP    "toml::time"                            \
1280     TOML_SA_LIST_SEP    "toml::date_time"                       \
1281     TOML_SA_LIST_END
1282 
1283 #define TOML_SA_NODE_TYPE_LIST                                  \
1284     TOML_SA_LIST_BEG    "toml::table"                           \
1285     TOML_SA_LIST_SEP    "toml::array"                           \
1286     TOML_SA_LIST_SEP    "toml::value<std::string>"              \
1287     TOML_SA_LIST_SEP    "toml::value<int64_t>"                  \
1288     TOML_SA_LIST_SEP    "toml::value<double>"                   \
1289     TOML_SA_LIST_SEP    "toml::value<bool>"                     \
1290     TOML_SA_LIST_SEP    "toml::value<toml::date>"               \
1291     TOML_SA_LIST_SEP    "toml::value<toml::time>"               \
1292     TOML_SA_LIST_SEP    "toml::value<toml::date_time>"          \
1293     TOML_SA_LIST_END
1294 
1295 #define TOML_SA_UNWRAPPED_NODE_TYPE_LIST                        \
1296     TOML_SA_LIST_NEW    "A native TOML value type"              \
1297     TOML_SA_NATIVE_VALUE_TYPE_LIST                              \
1298                                                                 \
1299     TOML_SA_LIST_NXT    "A TOML node type"                      \
1300     TOML_SA_NODE_TYPE_LIST
1301 
1302 // clang-format on
1303 
1304 TOML_PUSH_WARNINGS;
1305 TOML_DISABLE_SPAM_WARNINGS;
1306 TOML_DISABLE_SWITCH_WARNINGS;
1307 TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
1308 
1309 // misc warning false-positives
1310 #if TOML_MSVC
1311 #pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
1312 #if TOML_SHARED_LIB
1313 #pragma warning(disable : 4251) // dll exports for std lib types
1314 #endif
1315 #elif TOML_CLANG
1316 TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene")
1317 #if TOML_CLANG >= 12
1318 TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions")
1319 #endif
1320 #if TOML_CLANG == 13
1321 TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier")
1322 #endif
1323 #endif
1324 
1325 //********  impl/std_new.hpp  ******************************************************************************************
1326 
1327 TOML_DISABLE_WARNINGS;
1328 #include <new>
1329 TOML_ENABLE_WARNINGS;
1330 
1331 #if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914
1332 #define TOML_LAUNDER(x) __builtin_launder(x)
1333 #elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
1334 #define TOML_LAUNDER(x) std::launder(x)
1335 #else
1336 #define TOML_LAUNDER(x) x
1337 #endif
1338 
1339 //********  impl/std_string.hpp  ***************************************************************************************
1340 
1341 TOML_DISABLE_WARNINGS;
1342 #include <string_view>
1343 #include <string>
1344 TOML_ENABLE_WARNINGS;
1345 
1346 #if TOML_DOXYGEN                                                                                                       \
1347     || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t)                                \
1348         && __cpp_lib_char8_t >= 201907)
1349 #define TOML_HAS_CHAR8 1
1350 #else
1351 #define TOML_HAS_CHAR8 0
1352 #endif
1353 
1354 namespace toml // non-abi namespace; this is not an error
1355 {
1356     using namespace std::string_literals;
1357     using namespace std::string_view_literals;
1358 }
1359 
1360 #if TOML_ENABLE_WINDOWS_COMPAT
1361 
1362 TOML_IMPL_NAMESPACE_START
1363 {
1364     TOML_NODISCARD
1365     TOML_EXPORTED_FREE_FUNCTION
1366     std::string narrow(std::wstring_view);
1367 
1368     TOML_NODISCARD
1369     TOML_EXPORTED_FREE_FUNCTION
1370     std::wstring widen(std::string_view);
1371 
1372 #if TOML_HAS_CHAR8
1373 
1374     TOML_NODISCARD
1375     TOML_EXPORTED_FREE_FUNCTION
1376     std::wstring widen(std::u8string_view);
1377 
1378 #endif
1379 }
1380 TOML_IMPL_NAMESPACE_END;
1381 
1382 #endif // TOML_ENABLE_WINDOWS_COMPAT
1383 
1384 //********  impl/std_optional.hpp  *************************************************************************************
1385 
1386 TOML_DISABLE_WARNINGS;
1387 #if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
1388 #include <optional>
1389 #endif
1390 TOML_ENABLE_WARNINGS;
1391 
1392 TOML_NAMESPACE_START
1393 {
1394 #if TOML_HAS_CUSTOM_OPTIONAL_TYPE
1395 
1396     template <typename T>
1397     using optional = TOML_OPTIONAL_TYPE<T>;
1398 
1399 #else
1400 
1401     template <typename T>
1402     using optional = std::optional<T>;
1403 
1404 #endif
1405 }
1406 TOML_NAMESPACE_END;
1407 
1408 //********  impl/forward_declarations.hpp  *****************************************************************************
1409 
1410 TOML_DISABLE_WARNINGS;
1411 #include <cstdint>
1412 #include <cstddef>
1413 #include <cstring>
1414 #include <cfloat>
1415 #include <climits>
1416 #include <cmath>
1417 #include <limits>
1418 #include <memory>
1419 #include <iosfwd>
1420 #include <type_traits>
1421 TOML_ENABLE_WARNINGS;
1422 TOML_PUSH_WARNINGS;
1423 #ifdef _MSC_VER
1424 #ifndef __clang__
1425 #pragma inline_recursion(on)
1426 #endif
1427 #pragma push_macro("min")
1428 #pragma push_macro("max")
1429 #undef min
1430 #undef max
1431 #endif
1432 
1433 #ifndef TOML_DISABLE_ENVIRONMENT_CHECKS
1434 #define TOML_ENV_MESSAGE                                                                                               \
1435     "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to "      \
1436     "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the "            \
1437     "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining "             \
1438     "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at "                  \
1439     "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. "           \
1440     "Thanks!"
1441 
1442 static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE);
1443 #ifdef FLT_RADIX
1444 static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE);
1445 #endif
1446 static_assert('A' == 65, TOML_ENV_MESSAGE);
1447 static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE);
1448 static_assert(std::numeric_limits<double>::is_iec559, TOML_ENV_MESSAGE);
1449 static_assert(std::numeric_limits<double>::digits == 53, TOML_ENV_MESSAGE);
1450 static_assert(std::numeric_limits<double>::digits10 == 15, TOML_ENV_MESSAGE);
1451 static_assert(std::numeric_limits<double>::radix == 2, TOML_ENV_MESSAGE);
1452 
1453 #undef TOML_ENV_MESSAGE
1454 #endif // !TOML_DISABLE_ENVIRONMENT_CHECKS
1455 
1456 // undocumented forward declarations are hidden from doxygen because they fuck it up =/
1457 
1458 namespace toml // non-abi namespace; this is not an error
1459 {
1460     using ::std::size_t;
1461     using ::std::intptr_t;
1462     using ::std::uintptr_t;
1463     using ::std::ptrdiff_t;
1464     using ::std::nullptr_t;
1465     using ::std::int8_t;
1466     using ::std::int16_t;
1467     using ::std::int32_t;
1468     using ::std::int64_t;
1469     using ::std::uint8_t;
1470     using ::std::uint16_t;
1471     using ::std::uint32_t;
1472     using ::std::uint64_t;
1473     using ::std::uint_least32_t;
1474     using ::std::uint_least64_t;
1475 }
1476 
1477 TOML_NAMESPACE_START
1478 {
1479     struct date;
1480     struct time;
1481     struct time_offset;
1482 
1483     TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt);
1484     struct date_time;
1485     TOML_ABI_NAMESPACE_END;
1486 
1487     struct source_position;
1488     struct source_region;
1489 
1490     class node;
1491     template <typename>
1492     class node_view;
1493 
1494     class key;
1495     class array;
1496     class table;
1497     template <typename>
1498     class value;
1499 
1500     class path;
1501 
1502     class toml_formatter;
1503     class json_formatter;
1504     class yaml_formatter;
1505 
1506     TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
1507 #if TOML_EXCEPTIONS
1508     using parse_result = table;
1509 #else
1510     class parse_result;
1511 #endif
1512     TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
1513 }
1514 TOML_NAMESPACE_END;
1515 
1516 TOML_IMPL_NAMESPACE_START
1517 {
1518     using node_ptr = std::unique_ptr<node>;
1519 
1520     TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
1521     class parser;
1522     TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
1523 
1524     // clang-format off
1525 
1526     inline constexpr std::string_view control_char_escapes[] =
1527     {
1528         "\\u0000"sv,
1529         "\\u0001"sv,
1530         "\\u0002"sv,
1531         "\\u0003"sv,
1532         "\\u0004"sv,
1533         "\\u0005"sv,
1534         "\\u0006"sv,
1535         "\\u0007"sv,
1536         "\\b"sv,
1537         "\\t"sv,
1538         "\\n"sv,
1539         "\\u000B"sv,
1540         "\\f"sv,
1541         "\\r"sv,
1542         "\\u000E"sv,
1543         "\\u000F"sv,
1544         "\\u0010"sv,
1545         "\\u0011"sv,
1546         "\\u0012"sv,
1547         "\\u0013"sv,
1548         "\\u0014"sv,
1549         "\\u0015"sv,
1550         "\\u0016"sv,
1551         "\\u0017"sv,
1552         "\\u0018"sv,
1553         "\\u0019"sv,
1554         "\\u001A"sv,
1555         "\\u001B"sv,
1556         "\\u001C"sv,
1557         "\\u001D"sv,
1558         "\\u001E"sv,
1559         "\\u001F"sv,
1560     };
1561 
1562     inline constexpr std::string_view node_type_friendly_names[] =
1563     {
1564         "none"sv,
1565         "table"sv,
1566         "array"sv,
1567         "string"sv,
1568         "integer"sv,
1569         "floating-point"sv,
1570         "boolean"sv,
1571         "date"sv,
1572         "time"sv,
1573         "date-time"sv
1574     };
1575 
1576     // clang-format on
1577 }
1578 TOML_IMPL_NAMESPACE_END;
1579 
1580 #if TOML_ABI_NAMESPACES
1581 #if TOML_EXCEPTIONS
1582 #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser
1583 #else
1584 #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser
1585 #endif
1586 #else
1587 #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser
1588 #endif
1589 
1590 namespace toml
1591 {
1592 }
1593 
1594 TOML_NAMESPACE_START // abi namespace
1595 {
1596     inline namespace literals
1597     {
1598     }
1599 
1600     enum class TOML_CLOSED_ENUM node_type : uint8_t
1601     {
1602         none,
1603         table,
1604         array,
1605         string,
1606         integer,
1607         floating_point,
1608         boolean,
1609         date,
1610         time,
1611         date_time
1612     };
1613 
1614     template <typename Char>
1615     inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, node_type rhs)
1616     {
1617         const auto str   = impl::node_type_friendly_names[static_cast<std::underlying_type_t<node_type>>(rhs)];
1618         using str_char_t = decltype(str)::value_type;
1619         if constexpr (std::is_same_v<Char, str_char_t>)
1620             return lhs << str;
1621         else
1622         {
1623             if constexpr (sizeof(Char) == sizeof(str_char_t))
1624                 return lhs << std::basic_string_view<Char>{ reinterpret_cast<const Char*>(str.data()), str.length() };
1625             else
1626                 return lhs << str.data();
1627         }
1628     }
1629 
1630     enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error
1631     {
1632         none,
1633         format_as_binary = 1,
1634         format_as_octal = 2,
1635         format_as_hexadecimal = 3,
1636     };
1637     TOML_MAKE_FLAGS(value_flags);
1638 
1639     inline constexpr value_flags preserve_source_value_flags =
1640         POXY_IMPLEMENTATION_DETAIL(value_flags{ static_cast<std::underlying_type_t<value_flags>>(-1) });
1641 
1642     enum class TOML_CLOSED_FLAGS_ENUM format_flags : uint64_t
1643     {
1644         none,
1645         quote_dates_and_times = (1ull << 0),
1646         quote_infinities_and_nans = (1ull << 1),
1647         allow_literal_strings = (1ull << 2),
1648         allow_multi_line_strings = (1ull << 3),
1649         allow_real_tabs_in_strings = (1ull << 4),
1650         allow_unicode_strings = (1ull << 5),
1651         allow_binary_integers = (1ull << 6),
1652         allow_octal_integers = (1ull << 7),
1653         allow_hexadecimal_integers = (1ull << 8),
1654         indent_sub_tables = (1ull << 9),
1655         indent_array_elements = (1ull << 10),
1656         indentation = indent_sub_tables | indent_array_elements,
1657         relaxed_float_precision = (1ull << 11),
1658         terse_key_value_pairs = (1ull << 12),
1659     };
1660     TOML_MAKE_FLAGS(format_flags);
1661 
1662     template <typename T>
1663     struct TOML_TRIVIAL_ABI inserter
1664     {
1665         static_assert(std::is_reference_v<T>);
1666 
1667         T value;
1668     };
1669     template <typename T>
1670     inserter(T&&) -> inserter<T&&>;
1671     template <typename T>
1672     inserter(T&) -> inserter<T&>;
1673 
1674     using default_formatter = toml_formatter;
1675 }
1676 TOML_NAMESPACE_END;
1677 
1678 TOML_IMPL_NAMESPACE_START
1679 {
1680     template <typename T>
1681     using remove_cvref = std::remove_cv_t<std::remove_reference_t<T>>;
1682 
1683     template <typename... T>
1684     using common_signed_type = std::common_type_t<std::make_signed_t<T>...>;
1685 
1686     template <typename T, typename... U>
1687     inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, U>);
1688 
1689     template <typename... T>
1690     inline constexpr bool all_integral = (std::is_integral_v<T> && ...);
1691 
1692     template <typename T>
1693     inline constexpr bool is_cvref = std::is_reference_v<T> || std::is_const_v<T> || std::is_volatile_v<T>;
1694 
1695     template <typename T>
1696     inline constexpr bool is_wide_string =
1697         is_one_of<std::decay_t<T>, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>;
1698 
1699     template <typename T>
1700     inline constexpr bool value_retrieval_is_nothrow = !std::is_same_v<remove_cvref<T>, std::string>
1701 #if TOML_HAS_CHAR8
1702                                                     && !std::is_same_v<remove_cvref<T>, std::u8string>
1703 #endif
1704 
1705                                                     && !is_wide_string<T>;
1706 
1707     template <typename, typename>
1708     struct copy_ref_;
1709     template <typename Dest, typename Src>
1710     using copy_ref = typename copy_ref_<Dest, Src>::type;
1711 
1712     template <typename Dest, typename Src>
1713     struct copy_ref_
1714     {
1715         using type = Dest;
1716     };
1717 
1718     template <typename Dest, typename Src>
1719     struct copy_ref_<Dest, Src&>
1720     {
1721         using type = std::add_lvalue_reference_t<Dest>;
1722     };
1723 
1724     template <typename Dest, typename Src>
1725     struct copy_ref_<Dest, Src&&>
1726     {
1727         using type = std::add_rvalue_reference_t<Dest>;
1728     };
1729 
1730     template <typename, typename>
1731     struct copy_cv_;
1732     template <typename Dest, typename Src>
1733     using copy_cv = typename copy_cv_<Dest, Src>::type;
1734 
1735     template <typename Dest, typename Src>
1736     struct copy_cv_
1737     {
1738         using type = Dest;
1739     };
1740 
1741     template <typename Dest, typename Src>
1742     struct copy_cv_<Dest, const Src>
1743     {
1744         using type = std::add_const_t<Dest>;
1745     };
1746 
1747     template <typename Dest, typename Src>
1748     struct copy_cv_<Dest, volatile Src>
1749     {
1750         using type = std::add_volatile_t<Dest>;
1751     };
1752 
1753     template <typename Dest, typename Src>
1754     struct copy_cv_<Dest, const volatile Src>
1755     {
1756         using type = std::add_cv_t<Dest>;
1757     };
1758 
1759     template <typename Dest, typename Src>
1760     using copy_cvref =
1761         copy_ref<copy_ref<copy_cv<std::remove_reference_t<Dest>, std::remove_reference_t<Src>>, Dest>, Src>;
1762 
1763     template <typename...>
1764     inline constexpr bool always_false = false;
1765 
1766     template <typename T, typename... U>
1767     inline constexpr bool first_is_same = false;
1768     template <typename T, typename... U>
1769     inline constexpr bool first_is_same<T, T, U...> = true;
1770 
1771     template <typename T, bool = std::is_enum_v<T>>
1772     struct underlying_type_
1773     {
1774         using type = std::underlying_type_t<T>;
1775     };
1776     template <typename T>
1777     struct underlying_type_<T, false>
1778     {
1779         using type = T;
1780     };
1781     template <typename T>
1782     using underlying_type = typename underlying_type_<T>::type;
1783 
1784     // general value traits
1785     // (as they relate to their equivalent native TOML type)
1786     struct default_value_traits
1787     {
1788         using native_type                                         = void;
1789         static constexpr bool is_native                           = false;
1790         static constexpr bool is_losslessly_convertible_to_native = false;
1791         static constexpr bool can_represent_native                = false;
1792         static constexpr bool can_partially_represent_native      = false;
1793         static constexpr auto type                                = node_type::none;
1794     };
1795 
1796     template <typename T>
1797     struct value_traits;
1798 
1799     template <typename T, bool = std::is_enum_v<T>>
1800     struct value_traits_base_selector
1801     {
1802         static_assert(!is_cvref<T>);
1803 
1804         using type = default_value_traits;
1805     };
1806     template <typename T>
1807     struct value_traits_base_selector<T, true>
1808     {
1809         static_assert(!is_cvref<T>);
1810 
1811         using type = value_traits<underlying_type<T>>;
1812     };
1813 
1814     template <typename T>
1815     struct value_traits : value_traits_base_selector<T>::type
1816     {};
1817     template <typename T>
1818     struct value_traits<const T> : value_traits<T>
1819     {};
1820     template <typename T>
1821     struct value_traits<volatile T> : value_traits<T>
1822     {};
1823     template <typename T>
1824     struct value_traits<const volatile T> : value_traits<T>
1825     {};
1826     template <typename T>
1827     struct value_traits<T&> : value_traits<T>
1828     {};
1829     template <typename T>
1830     struct value_traits<T&&> : value_traits<T>
1831     {};
1832 
1833     // integer value_traits specializations - standard types
1834     template <typename T>
1835     struct integer_limits
1836     {
1837         static constexpr T min = T{ (std::numeric_limits<underlying_type<T>>::min)() };
1838         static constexpr T max = T{ (std::numeric_limits<underlying_type<T>>::max)() };
1839     };
1840     template <typename T>
1841     struct integer_traits_base : integer_limits<T>
1842     {
1843         using native_type               = int64_t;
1844         static constexpr bool is_native = std::is_same_v<underlying_type<T>, native_type>;
1845         static constexpr bool is_signed = static_cast<underlying_type<T>>(-1) < underlying_type<T>{};
1846         static constexpr auto type      = node_type::integer;
1847         static constexpr bool can_partially_represent_native = true;
1848     };
1849     template <typename T>
1850     struct unsigned_integer_traits : integer_traits_base<T>
1851     {
1852         static constexpr bool is_losslessly_convertible_to_native =
1853             integer_limits<underlying_type<T>>::max <= 9223372036854775807ULL;
1854         static constexpr bool can_represent_native = false;
1855     };
1856     template <typename T>
1857     struct signed_integer_traits : integer_traits_base<T>
1858     {
1859         using native_type = int64_t;
1860         static constexpr bool is_losslessly_convertible_to_native =
1861             integer_limits<underlying_type<T>>::min >= (-9223372036854775807LL - 1LL)
1862             && integer_limits<underlying_type<T>>::max <= 9223372036854775807LL;
1863         static constexpr bool can_represent_native =
1864             integer_limits<underlying_type<T>>::min <= (-9223372036854775807LL - 1LL)
1865             && integer_limits<underlying_type<T>>::max >= 9223372036854775807LL;
1866     };
1867     template <typename T, bool S = integer_traits_base<T>::is_signed>
1868     struct integer_traits : signed_integer_traits<T>
1869     {};
1870     template <typename T>
1871     struct integer_traits<T, false> : unsigned_integer_traits<T>
1872     {};
1873     template <>
1874     struct value_traits<signed char> : integer_traits<signed char>
1875     {};
1876     template <>
1877     struct value_traits<unsigned char> : integer_traits<unsigned char>
1878     {};
1879     template <>
1880     struct value_traits<signed short> : integer_traits<signed short>
1881     {};
1882     template <>
1883     struct value_traits<unsigned short> : integer_traits<unsigned short>
1884     {};
1885     template <>
1886     struct value_traits<signed int> : integer_traits<signed int>
1887     {};
1888     template <>
1889     struct value_traits<unsigned int> : integer_traits<unsigned int>
1890     {};
1891     template <>
1892     struct value_traits<signed long> : integer_traits<signed long>
1893     {};
1894     template <>
1895     struct value_traits<unsigned long> : integer_traits<unsigned long>
1896     {};
1897     template <>
1898     struct value_traits<signed long long> : integer_traits<signed long long>
1899     {};
1900     template <>
1901     struct value_traits<unsigned long long> : integer_traits<unsigned long long>
1902     {};
1903     static_assert(value_traits<int64_t>::is_native);
1904     static_assert(value_traits<int64_t>::is_signed);
1905     static_assert(value_traits<int64_t>::is_losslessly_convertible_to_native);
1906     static_assert(value_traits<int64_t>::can_represent_native);
1907     static_assert(value_traits<int64_t>::can_partially_represent_native);
1908 
1909     // integer value_traits specializations - non-standard types
1910 #ifdef TOML_INT128
1911     template <>
1912     struct integer_limits<TOML_INT128>
1913     {
1914         static constexpr TOML_INT128 max =
1915             static_cast<TOML_INT128>((TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1);
1916         static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 };
1917     };
1918     template <>
1919     struct integer_limits<TOML_UINT128>
1920     {
1921         static constexpr TOML_UINT128 min = TOML_UINT128{};
1922         static constexpr TOML_UINT128 max = (2u * static_cast<TOML_UINT128>(integer_limits<TOML_INT128>::max)) + 1u;
1923     };
1924     template <>
1925     struct value_traits<TOML_INT128> : integer_traits<TOML_INT128>
1926     {};
1927     template <>
1928     struct value_traits<TOML_UINT128> : integer_traits<TOML_UINT128>
1929     {};
1930 #endif
1931 #ifdef TOML_SMALL_INT_TYPE
1932     template <>
1933     struct value_traits<TOML_SMALL_INT_TYPE> : signed_integer_traits<TOML_SMALL_INT_TYPE>
1934     {};
1935 #endif
1936 
1937     // floating-point traits base
1938     template <typename T, int MantissaDigits, int DecimalDigits>
1939     struct float_traits_base
1940     {
1941         static constexpr auto type      = node_type::floating_point;
1942         using native_type               = double;
1943         static constexpr bool is_native = std::is_same_v<T, native_type>;
1944         static constexpr bool is_signed = true;
1945 
1946         static constexpr int bits     = static_cast<int>(sizeof(T) * CHAR_BIT);
1947         static constexpr int digits   = MantissaDigits;
1948         static constexpr int digits10 = DecimalDigits;
1949 
1950         static constexpr bool is_losslessly_convertible_to_native = bits <= 64      //
1951                                                                  && digits <= 53    // DBL_MANT_DIG
1952                                                                  && digits10 <= 15; // DBL_DIG
1953 
1954         static constexpr bool can_represent_native = digits >= 53    // DBL_MANT_DIG
1955                                                   && digits10 >= 15; // DBL_DIG
1956 
1957         static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0;
1958     };
1959     template <typename T>
1960     struct float_traits : float_traits_base<T, std::numeric_limits<T>::digits, std::numeric_limits<T>::digits10>
1961     {};
1962 #if TOML_ENABLE_FLOAT16
1963     template <>
1964     struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__>
1965     {};
1966 #endif
1967 #ifdef TOML_FLOAT128
1968     template <>
1969     struct float_traits<TOML_FLOAT128> : float_traits_base<TOML_FLOAT128, __FLT128_MANT_DIG__, __FLT128_DIG__>
1970     {};
1971 #endif
1972 
1973     // floating-point traits
1974     template <>
1975     struct value_traits<float> : float_traits<float>
1976     {};
1977     template <>
1978     struct value_traits<double> : float_traits<double>
1979     {};
1980     template <>
1981     struct value_traits<long double> : float_traits<long double>
1982     {};
1983 #if TOML_ENABLE_FLOAT16
1984     template <>
1985     struct value_traits<_Float16> : float_traits<_Float16>
1986     {};
1987 #endif
1988 #ifdef TOML_FLOAT128
1989     template <>
1990     struct value_traits<TOML_FLOAT128> : float_traits<TOML_FLOAT128>
1991     {};
1992 #endif
1993 #ifdef TOML_SMALL_FLOAT_TYPE
1994     template <>
1995     struct value_traits<TOML_SMALL_FLOAT_TYPE> : float_traits<TOML_SMALL_FLOAT_TYPE>
1996     {};
1997 #endif
1998     static_assert(value_traits<double>::is_native);
1999     static_assert(value_traits<double>::is_losslessly_convertible_to_native);
2000     static_assert(value_traits<double>::can_represent_native);
2001     static_assert(value_traits<double>::can_partially_represent_native);
2002 
2003     // string value_traits specializations - char-based strings
2004     template <typename T>
2005     struct string_traits
2006     {
2007         using native_type                                         = std::string;
2008         static constexpr bool is_native                           = std::is_same_v<T, native_type>;
2009         static constexpr bool is_losslessly_convertible_to_native = true;
2010         static constexpr bool can_represent_native =
2011             !std::is_array_v<T> && (!std::is_pointer_v<T> || std::is_const_v<std::remove_pointer_t<T>>);
2012         static constexpr bool can_partially_represent_native = can_represent_native;
2013         static constexpr auto type                           = node_type::string;
2014     };
2015     template <>
2016     struct value_traits<std::string> : string_traits<std::string>
2017     {};
2018     template <>
2019     struct value_traits<std::string_view> : string_traits<std::string_view>
2020     {};
2021     template <>
2022     struct value_traits<const char*> : string_traits<const char*>
2023     {};
2024     template <size_t N>
2025     struct value_traits<const char[N]> : string_traits<const char[N]>
2026     {};
2027     template <>
2028     struct value_traits<char*> : string_traits<char*>
2029     {};
2030     template <size_t N>
2031     struct value_traits<char[N]> : string_traits<char[N]>
2032     {};
2033 
2034     // string value_traits specializations - char8_t-based strings
2035 #if TOML_HAS_CHAR8
2036     template <>
2037     struct value_traits<std::u8string> : string_traits<std::u8string>
2038     {};
2039     template <>
2040     struct value_traits<std::u8string_view> : string_traits<std::u8string_view>
2041     {};
2042     template <>
2043     struct value_traits<const char8_t*> : string_traits<const char8_t*>
2044     {};
2045     template <size_t N>
2046     struct value_traits<const char8_t[N]> : string_traits<const char8_t[N]>
2047     {};
2048     template <>
2049     struct value_traits<char8_t*> : string_traits<char8_t*>
2050     {};
2051     template <size_t N>
2052     struct value_traits<char8_t[N]> : string_traits<char8_t[N]>
2053     {};
2054 #endif
2055 
2056     // string value_traits specializations - wchar_t-based strings on Windows
2057 #if TOML_ENABLE_WINDOWS_COMPAT
2058     template <typename T>
2059     struct wstring_traits
2060     {
2061         using native_type                                         = std::string;
2062         static constexpr bool is_native                           = false;
2063         static constexpr bool is_losslessly_convertible_to_native = true;                            // narrow
2064         static constexpr bool can_represent_native                = std::is_same_v<T, std::wstring>; // widen
2065         static constexpr bool can_partially_represent_native      = can_represent_native;
2066         static constexpr auto type                                = node_type::string;
2067     };
2068     template <>
2069     struct value_traits<std::wstring> : wstring_traits<std::wstring>
2070     {};
2071     template <>
2072     struct value_traits<std::wstring_view> : wstring_traits<std::wstring_view>
2073     {};
2074     template <>
2075     struct value_traits<const wchar_t*> : wstring_traits<const wchar_t*>
2076     {};
2077     template <size_t N>
2078     struct value_traits<const wchar_t[N]> : wstring_traits<const wchar_t[N]>
2079     {};
2080     template <>
2081     struct value_traits<wchar_t*> : wstring_traits<wchar_t*>
2082     {};
2083     template <size_t N>
2084     struct value_traits<wchar_t[N]> : wstring_traits<wchar_t[N]>
2085     {};
2086 #endif
2087 
2088     // other 'native' value_traits specializations
2089     template <typename T, node_type NodeType>
2090     struct native_value_traits
2091     {
2092         using native_type                                         = T;
2093         static constexpr bool is_native                           = true;
2094         static constexpr bool is_losslessly_convertible_to_native = true;
2095         static constexpr bool can_represent_native                = true;
2096         static constexpr bool can_partially_represent_native      = true;
2097         static constexpr auto type                                = NodeType;
2098     };
2099     template <>
2100     struct value_traits<bool> : native_value_traits<bool, node_type::boolean>
2101     {};
2102     template <>
2103     struct value_traits<date> : native_value_traits<date, node_type::date>
2104     {};
2105     template <>
2106     struct value_traits<time> : native_value_traits<time, node_type::time>
2107     {};
2108     template <>
2109     struct value_traits<date_time> : native_value_traits<date_time, node_type::date_time>
2110     {};
2111 
2112     // native value category queries
2113     template <typename T>
2114     using native_type_of = typename value_traits<T>::native_type;
2115     template <typename T>
2116     inline constexpr bool is_native = value_traits<T>::is_native;
2117     template <typename T>
2118     inline constexpr bool can_represent_native = value_traits<T>::can_represent_native;
2119     template <typename T>
2120     inline constexpr bool can_partially_represent_native = value_traits<T>::can_partially_represent_native;
2121     template <typename T>
2122     inline constexpr bool is_losslessly_convertible_to_native = value_traits<T>::is_losslessly_convertible_to_native;
2123     template <typename T, typename... U>
2124     inline constexpr bool is_natively_one_of = is_one_of<native_type_of<T>, U...>;
2125 
2126     // native value types => nodes
2127     template <typename T>
2128     struct node_wrapper
2129     {
2130         using type = T;
2131     };
2132     template <typename T>
2133     struct node_wrapper<const T>
2134     {
2135         using type = std::add_const_t<typename node_wrapper<T>::type>;
2136     };
2137     template <typename T>
2138     struct node_wrapper<volatile T>
2139     {
2140         using type = std::add_volatile_t<typename node_wrapper<T>::type>;
2141     };
2142     template <typename T>
2143     struct node_wrapper<const volatile T>
2144     {
2145         using type = std::add_const_t<std::add_volatile_t<typename node_wrapper<T>::type>>;
2146     };
2147     template <>
2148     struct node_wrapper<std::string>
2149     {
2150         using type = value<std::string>;
2151     };
2152     template <>
2153     struct node_wrapper<int64_t>
2154     {
2155         using type = value<int64_t>;
2156     };
2157     template <>
2158     struct node_wrapper<double>
2159     {
2160         using type = value<double>;
2161     };
2162     template <>
2163     struct node_wrapper<bool>
2164     {
2165         using type = value<bool>;
2166     };
2167     template <>
2168     struct node_wrapper<date>
2169     {
2170         using type = value<date>;
2171     };
2172     template <>
2173     struct node_wrapper<time>
2174     {
2175         using type = value<time>;
2176     };
2177     template <>
2178     struct node_wrapper<date_time>
2179     {
2180         using type = value<date_time>;
2181     };
2182     template <typename T>
2183     using wrap_node = typename node_wrapper<std::remove_reference_t<T>>::type;
2184 
2185     // nodes => native value types
2186     template <typename T>
2187     struct node_unwrapper
2188     {
2189         using type = T;
2190     };
2191     template <typename T>
2192     struct node_unwrapper<value<T>>
2193     {
2194         using type = T;
2195     };
2196     template <typename T>
2197     struct node_unwrapper<const value<T>>
2198     {
2199         using type = std::add_const_t<T>;
2200     };
2201     template <typename T>
2202     struct node_unwrapper<volatile value<T>>
2203     {
2204         using type = std::add_volatile_t<T>;
2205     };
2206     template <typename T>
2207     struct node_unwrapper<const volatile value<T>>
2208     {
2209         using type = std::add_volatile_t<std::add_const_t<T>>;
2210     };
2211     template <typename T>
2212     using unwrap_node = typename node_unwrapper<std::remove_reference_t<T>>::type;
2213 
2214     template <typename T>
2215     struct node_type_getter
2216     {
2217         static constexpr auto value = value_traits<T>::type;
2218     };
2219     template <>
2220     struct node_type_getter<table>
2221     {
2222         static constexpr auto value = node_type::table;
2223     };
2224     template <>
2225     struct node_type_getter<array>
2226     {
2227         static constexpr auto value = node_type::array;
2228     };
2229     template <>
2230     struct node_type_getter<void>
2231     {
2232         static constexpr auto value = node_type::none;
2233     };
2234     template <typename T>
2235     inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref<T>>>::value;
2236 
2237     template <typename T, typename ConvertFrom>
2238     inline constexpr bool is_constructible_or_convertible = std::is_constructible_v<T, ConvertFrom> //
2239                                                          || std::is_convertible_v<ConvertFrom, T>;
2240 }
2241 TOML_IMPL_NAMESPACE_END;
2242 
2243 TOML_NAMESPACE_START
2244 {
2245     template <typename T>
2246     inline constexpr bool is_table = std::is_same_v<impl::remove_cvref<T>, table>;
2247 
2248     template <typename T>
2249     inline constexpr bool is_array = std::is_same_v<impl::remove_cvref<T>, array>;
2250 
2251     template <typename T>
2252     inline constexpr bool is_container = is_table<T> || is_array<T>;
2253 
2254     template <typename T>
2255     inline constexpr bool is_string = std::is_same_v<               //
2256         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2257         value<std::string>>;
2258 
2259     template <typename T>
2260     inline constexpr bool is_integer = std::is_same_v<              //
2261         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2262         value<int64_t>>;
2263 
2264     template <typename T>
2265     inline constexpr bool is_floating_point = std::is_same_v<       //
2266         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2267         value<double>>;
2268 
2269     template <typename T>
2270     inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
2271 
2272     template <typename T>
2273     inline constexpr bool is_boolean = std::is_same_v<              //
2274         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2275         value<bool>>;
2276 
2277     template <typename T>
2278     inline constexpr bool is_date = std::is_same_v<                 //
2279         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2280         value<date>>;
2281 
2282     template <typename T>
2283     inline constexpr bool is_time = std::is_same_v<                 //
2284         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2285         value<time>>;
2286 
2287     template <typename T>
2288     inline constexpr bool is_date_time = std::is_same_v<            //
2289         impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
2290         value<date_time>>;
2291 
2292     template <typename T>
2293     inline constexpr bool is_chronological = is_date<T> || is_time<T> || is_date_time<T>;
2294 
2295     template <typename T>
2296     inline constexpr bool is_value = is_string<T> || is_number<T> || is_boolean<T> || is_chronological<T>;
2297 
2298     template <typename T>
2299     inline constexpr bool is_node = std::is_same_v<toml::node, impl::remove_cvref<T>> //
2300                                  || std::is_base_of_v<toml::node, impl::remove_cvref<T>>;
2301 
2302     template <typename T>
2303     inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref<T>, node_view<node>, node_view<const node>>;
2304 }
2305 TOML_NAMESPACE_END;
2306 
2307 TOML_IMPL_NAMESPACE_START
2308 {
2309     template <typename T>
2310     TOML_CONST_INLINE_GETTER
2311     constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept
2312     {
2313         return static_cast<std::underlying_type_t<T>>(val);
2314     }
2315 
2316     // Q: "why not use std::fpclassify?"
2317     // A: Because it gets broken by -ffast-math and friends
2318     enum class TOML_CLOSED_ENUM fp_class : unsigned
2319     {
2320         ok,
2321         neg_inf,
2322         pos_inf,
2323         nan
2324     };
2325 
2326     TOML_PURE_GETTER
2327     inline fp_class fpclassify(const double& val) noexcept
2328     {
2329         static_assert(sizeof(uint64_t) == sizeof(double));
2330 
2331         static constexpr uint64_t sign     = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
2332         static constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
2333         static constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
2334 
2335         uint64_t val_bits;
2336         std::memcpy(&val_bits, &val, sizeof(val));
2337         if ((val_bits & exponent) != exponent)
2338             return fp_class::ok;
2339         if ((val_bits & mantissa))
2340             return fp_class::nan;
2341         return (val_bits & sign) ? fp_class::neg_inf : fp_class::pos_inf;
2342     }
2343 
2344     // Q: "why not use std::find and std::min?"
2345     // A: Because <algorithm> is _huge_ and these would be the only things I used from it.
2346     //    I don't want to impose such a heavy compile-time burden on users.
2347 
2348     template <typename Iterator, typename T>
2349     TOML_PURE_GETTER
2350     inline auto find(Iterator start, Iterator end, const T& needle) noexcept //
2351         ->decltype(&(*start))
2352     {
2353         for (; start != end; start++)
2354             if (*start == needle)
2355                 return &(*start);
2356         return nullptr;
2357     }
2358 
2359     template <typename T>
2360     TOML_PURE_INLINE_GETTER
2361     constexpr const T& min(const T& a, const T& b) noexcept //
2362     {
2363         return a < b ? a : b;
2364     }
2365 }
2366 TOML_IMPL_NAMESPACE_END;
2367 
2368 #ifdef _MSC_VER
2369 #pragma pop_macro("min")
2370 #pragma pop_macro("max")
2371 #ifndef __clang__
2372 #pragma inline_recursion(off)
2373 #endif
2374 #endif
2375 TOML_POP_WARNINGS;
2376 
2377 //********  impl/print_to_stream.hpp  **********************************************************************************
2378 
2379 TOML_PUSH_WARNINGS;
2380 #ifdef _MSC_VER
2381 #ifndef __clang__
2382 #pragma inline_recursion(on)
2383 #endif
2384 #pragma push_macro("min")
2385 #pragma push_macro("max")
2386 #undef min
2387 #undef max
2388 #endif
2389 
2390 TOML_IMPL_NAMESPACE_START
2391 {
2392     // Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
2393     // A: - I'm using <charconv> to format numerics. Faster and locale-independent.
2394     //    - I can (potentially) avoid forcing users to drag in <sstream> and <iomanip>.
2395     //    - Strings in C++. Honestly.
2396 
2397     TOML_EXPORTED_FREE_FUNCTION
2398     TOML_ATTR(nonnull)
2399     void TOML_CALLCONV print_to_stream(std::ostream&, const char*, size_t);
2400 
2401     TOML_EXPORTED_FREE_FUNCTION
2402     void TOML_CALLCONV print_to_stream(std::ostream&, std::string_view);
2403 
2404     TOML_EXPORTED_FREE_FUNCTION
2405     void TOML_CALLCONV print_to_stream(std::ostream&, const std::string&);
2406 
2407     TOML_EXPORTED_FREE_FUNCTION
2408     void TOML_CALLCONV print_to_stream(std::ostream&, char);
2409 
2410     TOML_EXPORTED_FREE_FUNCTION
2411     void TOML_CALLCONV print_to_stream(std::ostream&, signed char, value_flags = {}, size_t min_digits = 0);
2412 
2413     TOML_EXPORTED_FREE_FUNCTION
2414     void TOML_CALLCONV print_to_stream(std::ostream&, signed short, value_flags = {}, size_t min_digits = 0);
2415 
2416     TOML_EXPORTED_FREE_FUNCTION
2417     void TOML_CALLCONV print_to_stream(std::ostream&, signed int, value_flags = {}, size_t min_digits = 0);
2418 
2419     TOML_EXPORTED_FREE_FUNCTION
2420     void TOML_CALLCONV print_to_stream(std::ostream&, signed long, value_flags = {}, size_t min_digits = 0);
2421 
2422     TOML_EXPORTED_FREE_FUNCTION
2423     void TOML_CALLCONV print_to_stream(std::ostream&, signed long long, value_flags = {}, size_t min_digits = 0);
2424 
2425     TOML_EXPORTED_FREE_FUNCTION
2426     void TOML_CALLCONV print_to_stream(std::ostream&, unsigned char, value_flags = {}, size_t min_digits = 0);
2427 
2428     TOML_EXPORTED_FREE_FUNCTION
2429     void TOML_CALLCONV print_to_stream(std::ostream&, unsigned short, value_flags = {}, size_t min_digits = 0);
2430 
2431     TOML_EXPORTED_FREE_FUNCTION
2432     void TOML_CALLCONV print_to_stream(std::ostream&, unsigned int, value_flags = {}, size_t min_digits = 0);
2433 
2434     TOML_EXPORTED_FREE_FUNCTION
2435     void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long, value_flags = {}, size_t min_digits = 0);
2436 
2437     TOML_EXPORTED_FREE_FUNCTION
2438     void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long long, value_flags = {}, size_t min_digits = 0);
2439 
2440     TOML_EXPORTED_FREE_FUNCTION
2441     void TOML_CALLCONV print_to_stream(std::ostream&, float, value_flags = {}, bool relaxed_precision = false);
2442 
2443     TOML_EXPORTED_FREE_FUNCTION
2444     void TOML_CALLCONV print_to_stream(std::ostream&, double, value_flags = {}, bool relaxed_precision = false);
2445 
2446     TOML_EXPORTED_FREE_FUNCTION
2447     void TOML_CALLCONV print_to_stream(std::ostream&, bool);
2448 
2449     TOML_EXPORTED_FREE_FUNCTION
2450     void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date&);
2451 
2452     TOML_EXPORTED_FREE_FUNCTION
2453     void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time&);
2454 
2455     TOML_EXPORTED_FREE_FUNCTION
2456     void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time_offset&);
2457 
2458     TOML_EXPORTED_FREE_FUNCTION
2459     void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date_time&);
2460 
2461     TOML_EXPORTED_FREE_FUNCTION
2462     void TOML_CALLCONV print_to_stream(std::ostream&, const source_position&);
2463 
2464     TOML_EXPORTED_FREE_FUNCTION
2465     void TOML_CALLCONV print_to_stream(std::ostream&, const source_region&);
2466 
2467 #if TOML_ENABLE_FORMATTERS
2468 
2469     TOML_EXPORTED_FREE_FUNCTION
2470     void TOML_CALLCONV print_to_stream(std::ostream&, const array&);
2471 
2472     TOML_EXPORTED_FREE_FUNCTION
2473     void TOML_CALLCONV print_to_stream(std::ostream&, const table&);
2474 
2475     TOML_EXPORTED_FREE_FUNCTION
2476     void TOML_CALLCONV print_to_stream(std::ostream&, const value<std::string>&);
2477 
2478     TOML_EXPORTED_FREE_FUNCTION
2479     void TOML_CALLCONV print_to_stream(std::ostream&, const value<int64_t>&);
2480 
2481     TOML_EXPORTED_FREE_FUNCTION
2482     void TOML_CALLCONV print_to_stream(std::ostream&, const value<double>&);
2483 
2484     TOML_EXPORTED_FREE_FUNCTION
2485     void TOML_CALLCONV print_to_stream(std::ostream&, const value<bool>&);
2486 
2487     TOML_EXPORTED_FREE_FUNCTION
2488     void TOML_CALLCONV print_to_stream(std::ostream&, const value<date>&);
2489 
2490     TOML_EXPORTED_FREE_FUNCTION
2491     void TOML_CALLCONV print_to_stream(std::ostream&, const value<time>&);
2492 
2493     TOML_EXPORTED_FREE_FUNCTION
2494     void TOML_CALLCONV print_to_stream(std::ostream&, const value<date_time>&);
2495 
2496 #endif
2497 
2498     template <typename T, typename U>
2499     inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend)
2500     {
2501         print_to_stream(stream, bookend);
2502         print_to_stream(stream, val);
2503         print_to_stream(stream, bookend);
2504     }
2505 }
2506 TOML_IMPL_NAMESPACE_END;
2507 
2508 #ifdef _MSC_VER
2509 #pragma pop_macro("min")
2510 #pragma pop_macro("max")
2511 #ifndef __clang__
2512 #pragma inline_recursion(off)
2513 #endif
2514 #endif
2515 TOML_POP_WARNINGS;
2516 
2517 //********  impl/source_region.hpp  ************************************************************************************
2518 
2519 TOML_PUSH_WARNINGS;
2520 #ifdef _MSC_VER
2521 #ifndef __clang__
2522 #pragma inline_recursion(on)
2523 #endif
2524 #pragma push_macro("min")
2525 #pragma push_macro("max")
2526 #undef min
2527 #undef max
2528 #endif
2529 
2530 TOML_NAMESPACE_START
2531 {
2532     using source_index = uint32_t;
2533 
2534     using source_path_ptr = std::shared_ptr<const std::string>;
2535 
2536     struct TOML_TRIVIAL_ABI source_position
2537     {
2538         source_index line;
2539 
2540         source_index column;
2541 
2542         TOML_PURE_GETTER
2543         explicit constexpr operator bool() const noexcept
2544         {
2545             return line > source_index{} //
2546                 && column > source_index{};
2547         }
2548 
2549         TOML_PURE_GETTER
2550         friend constexpr bool operator==(const source_position& lhs, const source_position& rhs) noexcept
2551         {
2552             return lhs.line == rhs.line //
2553                 && lhs.column == rhs.column;
2554         }
2555 
2556         TOML_PURE_INLINE_GETTER
2557         friend constexpr bool operator!=(const source_position& lhs, const source_position& rhs) noexcept
2558         {
2559             return !(lhs == rhs);
2560         }
2561 
2562       private:
2563 
2564         TOML_PURE_GETTER
2565         static constexpr uint64_t pack(const source_position& pos) noexcept
2566         {
2567             return static_cast<uint64_t>(pos.line) << 32 | static_cast<uint64_t>(pos.column);
2568         }
2569 
2570       public:
2571 
2572         TOML_PURE_GETTER
2573         friend constexpr bool operator<(const source_position& lhs, const source_position& rhs) noexcept
2574         {
2575             return pack(lhs) < pack(rhs);
2576         }
2577 
2578         TOML_PURE_GETTER
2579         friend constexpr bool operator<=(const source_position& lhs, const source_position& rhs) noexcept
2580         {
2581             return pack(lhs) <= pack(rhs);
2582         }
2583 
2584         TOML_PURE_GETTER
2585         friend constexpr bool operator>(const source_position& lhs, const source_position& rhs) noexcept
2586         {
2587             return pack(lhs) > pack(rhs);
2588         }
2589 
2590         TOML_PURE_GETTER
2591         friend constexpr bool operator>=(const source_position& lhs, const source_position& rhs) noexcept
2592         {
2593             return pack(lhs) >= pack(rhs);
2594         }
2595 
2596         friend std::ostream& operator<<(std::ostream& lhs, const source_position& rhs)
2597         {
2598             impl::print_to_stream(lhs, rhs);
2599             return lhs;
2600         }
2601     };
2602 
2603     struct source_region
2604     {
2605         source_position begin;
2606 
2607         source_position end;
2608 
2609         source_path_ptr path;
2610 
2611 #if TOML_ENABLE_WINDOWS_COMPAT
2612 
2613         TOML_NODISCARD
2614         optional<std::wstring> wide_path() const
2615         {
2616             if (!path || path->empty())
2617                 return {};
2618             return { impl::widen(*path) };
2619         }
2620 
2621 #endif
2622 
2623         friend std::ostream& operator<<(std::ostream& lhs, const source_region& rhs)
2624         {
2625             impl::print_to_stream(lhs, rhs);
2626             return lhs;
2627         }
2628     };
2629 }
2630 TOML_NAMESPACE_END;
2631 
2632 #ifdef _MSC_VER
2633 #pragma pop_macro("min")
2634 #pragma pop_macro("max")
2635 #ifndef __clang__
2636 #pragma inline_recursion(off)
2637 #endif
2638 #endif
2639 TOML_POP_WARNINGS;
2640 
2641 //********  impl/date_time.hpp  ****************************************************************************************
2642 
2643 TOML_PUSH_WARNINGS;
2644 #ifdef _MSC_VER
2645 #ifndef __clang__
2646 #pragma inline_recursion(on)
2647 #endif
2648 #pragma push_macro("min")
2649 #pragma push_macro("max")
2650 #undef min
2651 #undef max
2652 #endif
2653 
2654 TOML_NAMESPACE_START
2655 {
2656     struct TOML_TRIVIAL_ABI date
2657     {
2658         uint16_t year;
2659 
2660         uint8_t month;
2661 
2662         uint8_t day;
2663 
2664         TOML_NODISCARD_CTOR
2665         date() noexcept = default;
2666 
2667         TOML_CONSTRAINED_TEMPLATE((impl::all_integral<Y, M, D>), typename Y, typename M, typename D)
2668         TOML_NODISCARD_CTOR
2669         constexpr date(Y y, M m, D d) noexcept //
2670             : year{ static_cast<uint16_t>(y) },
2671               month{ static_cast<uint8_t>(m) },
2672               day{ static_cast<uint8_t>(d) }
2673         {}
2674 
2675         TOML_PURE_GETTER
2676         friend constexpr bool operator==(const date& lhs, const date& rhs) noexcept
2677         {
2678             return lhs.year == rhs.year   //
2679                 && lhs.month == rhs.month //
2680                 && lhs.day == rhs.day;
2681         }
2682 
2683         TOML_PURE_INLINE_GETTER
2684         friend constexpr bool operator!=(const date& lhs, const date& rhs) noexcept
2685         {
2686             return !(lhs == rhs);
2687         }
2688 
2689       private:
2690 
2691         TOML_PURE_GETTER
2692         static constexpr uint32_t pack(const date& d) noexcept
2693         {
2694             return (static_cast<uint32_t>(d.year) << 16) | (static_cast<uint32_t>(d.month) << 8)
2695                  | static_cast<uint32_t>(d.day);
2696         }
2697 
2698       public:
2699 
2700         TOML_PURE_GETTER
2701         friend constexpr bool operator<(const date& lhs, const date& rhs) noexcept
2702         {
2703             return pack(lhs) < pack(rhs);
2704         }
2705 
2706         TOML_PURE_GETTER
2707         friend constexpr bool operator<=(const date& lhs, const date& rhs) noexcept
2708         {
2709             return pack(lhs) <= pack(rhs);
2710         }
2711 
2712         TOML_PURE_GETTER
2713         friend constexpr bool operator>(const date& lhs, const date& rhs) noexcept
2714         {
2715             return pack(lhs) > pack(rhs);
2716         }
2717 
2718         TOML_PURE_GETTER
2719         friend constexpr bool operator>=(const date& lhs, const date& rhs) noexcept
2720         {
2721             return pack(lhs) >= pack(rhs);
2722         }
2723 
2724         friend std::ostream& operator<<(std::ostream& lhs, const date& rhs)
2725         {
2726             impl::print_to_stream(lhs, rhs);
2727             return lhs;
2728         }
2729     };
2730 
2731     struct TOML_TRIVIAL_ABI time
2732     {
2733         uint8_t hour;
2734 
2735         uint8_t minute;
2736 
2737         uint8_t second;
2738 
2739         uint32_t nanosecond;
2740 
2741         TOML_NODISCARD_CTOR
2742         time() noexcept = default;
2743 
2744         TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M, S, NS>),
2745                                   typename H,
2746                                   typename M,
2747                                   typename S  = uint8_t,
2748                                   typename NS = uint32_t)
2749         TOML_NODISCARD_CTOR
2750         constexpr time(H h, M m, S s = S{}, NS ns = NS{}) noexcept //
2751             : hour{ static_cast<uint8_t>(h) },
2752               minute{ static_cast<uint8_t>(m) },
2753               second{ static_cast<uint8_t>(s) },
2754               nanosecond{ static_cast<uint32_t>(ns) }
2755         {}
2756 
2757         TOML_PURE_GETTER
2758         friend constexpr bool operator==(const time& lhs, const time& rhs) noexcept
2759         {
2760             return lhs.hour == rhs.hour     //
2761                 && lhs.minute == rhs.minute //
2762                 && lhs.second == rhs.second //
2763                 && lhs.nanosecond == rhs.nanosecond;
2764         }
2765 
2766         TOML_PURE_INLINE_GETTER
2767         friend constexpr bool operator!=(const time& lhs, const time& rhs) noexcept
2768         {
2769             return !(lhs == rhs);
2770         }
2771 
2772       private:
2773 
2774         TOML_PURE_GETTER
2775         static constexpr uint64_t pack(const time& t) noexcept
2776         {
2777             return static_cast<uint64_t>(t.hour) << 48 | static_cast<uint64_t>(t.minute) << 40
2778                  | static_cast<uint64_t>(t.second) << 32 | static_cast<uint64_t>(t.nanosecond);
2779         }
2780 
2781       public:
2782 
2783         TOML_PURE_GETTER
2784         friend constexpr bool operator<(const time& lhs, const time& rhs) noexcept
2785         {
2786             return pack(lhs) < pack(rhs);
2787         }
2788 
2789         TOML_PURE_GETTER
2790         friend constexpr bool operator<=(const time& lhs, const time& rhs) noexcept
2791         {
2792             return pack(lhs) <= pack(rhs);
2793         }
2794 
2795         TOML_PURE_GETTER
2796         friend constexpr bool operator>(const time& lhs, const time& rhs) noexcept
2797         {
2798             return pack(lhs) > pack(rhs);
2799         }
2800 
2801         TOML_PURE_GETTER
2802         friend constexpr bool operator>=(const time& lhs, const time& rhs) noexcept
2803         {
2804             return pack(lhs) >= pack(rhs);
2805         }
2806 
2807         friend std::ostream& operator<<(std::ostream& lhs, const time& rhs)
2808         {
2809             impl::print_to_stream(lhs, rhs);
2810             return lhs;
2811         }
2812     };
2813 
2814     struct TOML_TRIVIAL_ABI time_offset
2815     {
2816         int16_t minutes;
2817 
2818         TOML_NODISCARD_CTOR
2819         time_offset() noexcept = default;
2820 
2821         TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M>), typename H, typename M)
2822         TOML_NODISCARD_CTOR
2823         constexpr time_offset(H h, M m) noexcept //
2824             : minutes{ static_cast<int16_t>(static_cast<impl::common_signed_type<H, M>>(h)
2825                                                 * impl::common_signed_type<H, M>{ 60 }
2826                                             + static_cast<impl::common_signed_type<H, M>>(m)) }
2827         {}
2828 
2829         TOML_PURE_INLINE_GETTER
2830         friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
2831         {
2832             return lhs.minutes == rhs.minutes;
2833         }
2834 
2835         TOML_PURE_INLINE_GETTER
2836         friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
2837         {
2838             return lhs.minutes != rhs.minutes;
2839         }
2840 
2841         TOML_PURE_INLINE_GETTER
2842         friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
2843         {
2844             return lhs.minutes < rhs.minutes;
2845         }
2846 
2847         TOML_PURE_INLINE_GETTER
2848         friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
2849         {
2850             return lhs.minutes <= rhs.minutes;
2851         }
2852 
2853         TOML_PURE_INLINE_GETTER
2854         friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
2855         {
2856             return lhs.minutes > rhs.minutes;
2857         }
2858 
2859         TOML_PURE_INLINE_GETTER
2860         friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
2861         {
2862             return lhs.minutes >= rhs.minutes;
2863         }
2864 
2865         friend std::ostream& operator<<(std::ostream& lhs, const time_offset& rhs)
2866         {
2867             impl::print_to_stream(lhs, rhs);
2868             return lhs;
2869         }
2870     };
2871 
2872     TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt);
2873 
2874     struct date_time
2875     {
2876         toml::date date;
2877 
2878         toml::time time;
2879 
2880         optional<toml::time_offset> offset;
2881 
2882         TOML_NODISCARD_CTOR
2883         date_time() noexcept = default;
2884 
2885         TOML_NODISCARD_CTOR
2886         constexpr date_time(const toml::date& d, const toml::time& t) noexcept //
2887             : date{ d },
2888               time{ t },
2889               offset{} // TINAE - icc bugfix
2890         {}
2891 
2892         TOML_NODISCARD_CTOR
2893         explicit constexpr date_time(const toml::date& d) noexcept //
2894             : date{ d },
2895               time{},
2896               offset{} // TINAE - icc bugfix
2897         {}
2898 
2899         TOML_NODISCARD_CTOR
2900         explicit constexpr date_time(const toml::time& t) noexcept //
2901             : date{},
2902               time{ t },
2903               offset{} // TINAE - icc bugfix
2904         {}
2905 
2906         TOML_NODISCARD_CTOR
2907         constexpr date_time(const toml::date& d, const toml::time& t, const toml::time_offset& off) noexcept
2908             : date{ d },
2909               time{ t },
2910               offset{ off }
2911         {}
2912 
2913         TOML_PURE_INLINE_GETTER
2914         constexpr bool is_local() const noexcept
2915         {
2916             return !offset.has_value();
2917         }
2918 
2919         TOML_PURE_GETTER
2920         friend constexpr bool operator==(const date_time& lhs, const date_time& rhs) noexcept
2921         {
2922             return lhs.date == rhs.date //
2923                 && lhs.time == rhs.time //
2924                 && lhs.offset == rhs.offset;
2925         }
2926 
2927         TOML_PURE_INLINE_GETTER
2928         friend constexpr bool operator!=(const date_time& lhs, const date_time& rhs) noexcept
2929         {
2930             return !(lhs == rhs);
2931         }
2932 
2933         TOML_PURE_GETTER
2934         friend constexpr bool operator<(const date_time& lhs, const date_time& rhs) noexcept
2935         {
2936             if (lhs.date != rhs.date)
2937                 return lhs.date < rhs.date;
2938             if (lhs.time != rhs.time)
2939                 return lhs.time < rhs.time;
2940             return lhs.offset < rhs.offset;
2941         }
2942 
2943         TOML_PURE_GETTER
2944         friend constexpr bool operator<=(const date_time& lhs, const date_time& rhs) noexcept
2945         {
2946             if (lhs.date != rhs.date)
2947                 return lhs.date < rhs.date;
2948             if (lhs.time != rhs.time)
2949                 return lhs.time < rhs.time;
2950             return lhs.offset <= rhs.offset;
2951         }
2952 
2953         TOML_PURE_INLINE_GETTER
2954         friend constexpr bool operator>(const date_time& lhs, const date_time& rhs) noexcept
2955         {
2956             return !(lhs <= rhs);
2957         }
2958 
2959         TOML_PURE_INLINE_GETTER
2960         friend constexpr bool operator>=(const date_time& lhs, const date_time& rhs) noexcept
2961         {
2962             return !(lhs < rhs);
2963         }
2964 
2965         friend std::ostream& operator<<(std::ostream& lhs, const date_time& rhs)
2966         {
2967             impl::print_to_stream(lhs, rhs);
2968             return lhs;
2969         }
2970     };
2971 
2972     TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
2973 }
2974 TOML_NAMESPACE_END;
2975 
2976 #ifdef _MSC_VER
2977 #pragma pop_macro("min")
2978 #pragma pop_macro("max")
2979 #ifndef __clang__
2980 #pragma inline_recursion(off)
2981 #endif
2982 #endif
2983 TOML_POP_WARNINGS;
2984 
2985 //********  impl/at_path.hpp  ******************************************************************************************
2986 
2987 TOML_IMPL_NAMESPACE_START
2988 {
2989     template <typename T>
2990     using parse_path_callback = bool(TOML_CALLCONV*)(void*, T);
2991 
2992     TOML_NODISCARD
2993     bool TOML_CALLCONV parse_path(std::string_view,
2994                                   void*,
2995                                   parse_path_callback<std::string_view>,
2996                                   parse_path_callback<size_t>);
2997 }
2998 TOML_IMPL_NAMESPACE_END;
2999 
3000 TOML_NAMESPACE_START
3001 {
3002     TOML_NODISCARD
3003     TOML_EXPORTED_FREE_FUNCTION
3004     node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept;
3005 
3006     TOML_NODISCARD
3007     TOML_EXPORTED_FREE_FUNCTION
3008     node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept;
3009 
3010 #if TOML_ENABLE_WINDOWS_COMPAT
3011 
3012     TOML_NODISCARD
3013     TOML_EXPORTED_FREE_FUNCTION
3014     node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path);
3015 
3016     TOML_NODISCARD
3017     TOML_EXPORTED_FREE_FUNCTION
3018     node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path);
3019 
3020 #endif
3021 }
3022 TOML_NAMESPACE_END;
3023 
3024 //********  impl/std_vector.hpp  ***************************************************************************************
3025 
3026 TOML_DISABLE_WARNINGS;
3027 #include <vector>
3028 #include <iterator>
3029 TOML_ENABLE_WARNINGS;
3030 
3031 //********  impl/path.hpp  *********************************************************************************************
3032 
3033 TOML_PUSH_WARNINGS;
3034 #ifdef _MSC_VER
3035 #ifndef __clang__
3036 #pragma inline_recursion(on)
3037 #endif
3038 #pragma push_macro("min")
3039 #pragma push_macro("max")
3040 #undef min
3041 #undef max
3042 #endif
3043 
3044 TOML_NAMESPACE_START
3045 {
3046     enum class TOML_CLOSED_ENUM path_component_type : uint8_t
3047     {
3048         key         = 0x1,
3049         array_index = 0x2
3050     };
3051 
3052     class TOML_EXPORTED_CLASS path_component
3053     {
3054         struct storage_t
3055         {
3056             static constexpr size_t size =
3057                 (sizeof(size_t) < sizeof(std::string) ? sizeof(std::string) : sizeof(size_t));
3058             static constexpr size_t align =
3059                 (alignof(size_t) < alignof(std::string) ? alignof(std::string) : alignof(size_t));
3060 
3061             alignas(align) unsigned char bytes[size];
3062         };
3063         alignas(storage_t::align) mutable storage_t value_storage_;
3064 
3065         path_component_type type_;
3066 
3067         TOML_PURE_GETTER
3068         TOML_EXPORTED_STATIC_FUNCTION
3069         static bool TOML_CALLCONV equal(const path_component&, const path_component&) noexcept;
3070 
3071         template <typename Type>
3072         TOML_PURE_INLINE_GETTER
3073         static Type* get_as(storage_t& s) noexcept
3074         {
3075             return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
3076         }
3077 
3078         static void store_key(std::string_view key, storage_t& storage_)
3079         {
3080             ::new (static_cast<void*>(storage_.bytes)) std::string{ key };
3081         }
3082 
3083         static void store_index(size_t index, storage_t& storage_) noexcept
3084         {
3085             ::new (static_cast<void*>(storage_.bytes)) std::size_t{ index };
3086         }
3087 
3088         void destroy() noexcept
3089         {
3090             if (type_ == path_component_type::key)
3091                 get_as<std::string>(value_storage_)->~basic_string();
3092         }
3093 
3094         TOML_NODISCARD
3095         size_t& index_ref() noexcept
3096         {
3097             TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
3098             return *get_as<size_t>(value_storage_);
3099         }
3100 
3101         TOML_NODISCARD
3102         std::string& key_ref() noexcept
3103         {
3104             TOML_ASSERT_ASSUME(type_ == path_component_type::key);
3105             return *get_as<std::string>(value_storage_);
3106         }
3107 
3108       public:
3109 
3110         TOML_NODISCARD_CTOR
3111         TOML_EXPORTED_MEMBER_FUNCTION
3112         path_component();
3113 
3114         TOML_NODISCARD_CTOR
3115         TOML_EXPORTED_MEMBER_FUNCTION
3116         path_component(size_t index) noexcept;
3117 
3118         TOML_NODISCARD_CTOR
3119         TOML_EXPORTED_MEMBER_FUNCTION
3120         path_component(std::string_view key);
3121 
3122 #if TOML_ENABLE_WINDOWS_COMPAT
3123 
3124         TOML_NODISCARD_CTOR
3125         TOML_EXPORTED_MEMBER_FUNCTION
3126         path_component(std::wstring_view key);
3127 
3128 #endif
3129 
3130         TOML_NODISCARD_CTOR
3131         TOML_EXPORTED_MEMBER_FUNCTION
3132         path_component(const path_component& pc);
3133 
3134         TOML_NODISCARD_CTOR
3135         TOML_EXPORTED_MEMBER_FUNCTION
3136         path_component(path_component&& pc) noexcept;
3137 
3138         TOML_EXPORTED_MEMBER_FUNCTION
3139         path_component& operator=(const path_component& rhs);
3140 
3141         TOML_EXPORTED_MEMBER_FUNCTION
3142         path_component& operator=(path_component&& rhs) noexcept;
3143 
3144         TOML_EXPORTED_MEMBER_FUNCTION
3145         path_component& operator=(size_t new_index) noexcept;
3146 
3147         TOML_EXPORTED_MEMBER_FUNCTION
3148         path_component& operator=(std::string_view new_key);
3149 
3150 #if TOML_ENABLE_WINDOWS_COMPAT
3151 
3152         TOML_EXPORTED_MEMBER_FUNCTION
3153         path_component& operator=(std::wstring_view new_key);
3154 
3155 #endif
3156 
3157         ~path_component() noexcept
3158         {
3159             destroy();
3160         }
3161 
3162         TOML_PURE_GETTER
3163         size_t index() const noexcept
3164         {
3165             TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
3166             return *get_as<const size_t>(value_storage_);
3167         }
3168 
3169         TOML_PURE_INLINE_GETTER
3170         explicit operator size_t() const noexcept
3171         {
3172             return index();
3173         }
3174 
3175         TOML_PURE_GETTER
3176         const std::string& key() const noexcept
3177         {
3178             TOML_ASSERT_ASSUME(type_ == path_component_type::key);
3179             return *get_as<const std::string>(value_storage_);
3180         }
3181 
3182         TOML_PURE_INLINE_GETTER
3183         explicit operator const std::string&() const noexcept
3184         {
3185             return key();
3186         }
3187 
3188         TOML_PURE_INLINE_GETTER
3189         path_component_type type() const noexcept
3190         {
3191             return type_;
3192         }
3193 
3194         TOML_PURE_INLINE_GETTER
3195         friend bool operator==(const path_component& lhs, const path_component& rhs) noexcept
3196         {
3197             return equal(lhs, rhs);
3198         }
3199 
3200         TOML_PURE_INLINE_GETTER
3201         friend bool operator!=(const path_component& lhs, const path_component& rhs) noexcept
3202         {
3203             return !equal(lhs, rhs);
3204         }
3205     };
3206 
3207     class TOML_EXPORTED_CLASS path
3208     {
3209       private:
3210 
3211         std::vector<path_component> components_;
3212 
3213         TOML_EXPORTED_MEMBER_FUNCTION
3214         void print_to(std::ostream&) const;
3215 
3216         TOML_PURE_GETTER
3217         TOML_EXPORTED_STATIC_FUNCTION
3218         static bool TOML_CALLCONV equal(const path&, const path&) noexcept;
3219 
3220       public:
3221 
3222         TOML_NODISCARD_CTOR
3223         path() noexcept = default;
3224 
3225         TOML_NODISCARD_CTOR
3226         TOML_EXPORTED_MEMBER_FUNCTION
3227         explicit path(std::string_view);
3228 
3229 #if TOML_ENABLE_WINDOWS_COMPAT
3230 
3231         TOML_NODISCARD_CTOR
3232         TOML_EXPORTED_MEMBER_FUNCTION
3233         explicit path(std::wstring_view);
3234 
3235 #endif
3236 
3237         ~path() noexcept = default;
3238 
3239         TOML_NODISCARD_CTOR
3240         path(const path&) = default;
3241 
3242         TOML_NODISCARD_CTOR
3243         path(path&&) noexcept = default;
3244 
3245         TOML_PURE_INLINE_GETTER
3246         size_t size() const noexcept
3247         {
3248             return components_.size();
3249         }
3250 
3251         TOML_PURE_INLINE_GETTER
3252         explicit operator bool() const noexcept
3253         {
3254             return !components_.empty();
3255         }
3256 
3257         TOML_PURE_INLINE_GETTER
3258         bool empty() const noexcept
3259         {
3260             return components_.empty();
3261         }
3262 
3263         TOML_PURE_INLINE_GETTER
3264         path_component& operator[](size_t index) noexcept
3265         {
3266             TOML_ASSERT(index < size());
3267             return components_[index];
3268         }
3269 
3270         TOML_PURE_INLINE_GETTER
3271         const path_component& operator[](size_t index) const noexcept
3272         {
3273             TOML_ASSERT(index < size());
3274             return components_[index];
3275         }
3276 
3277         path& operator=(const path&) = default;
3278 
3279         path& operator=(path&&) noexcept = default;
3280 
3281         TOML_EXPORTED_MEMBER_FUNCTION
3282         path& operator=(std::string_view);
3283 
3284 #if TOML_ENABLE_WINDOWS_COMPAT
3285 
3286         TOML_EXPORTED_MEMBER_FUNCTION
3287         path& operator=(std::wstring_view);
3288 
3289 #endif
3290 
3291         TOML_ALWAYS_INLINE
3292         path& assign(const path& p)
3293         {
3294             return *this = p;
3295         }
3296 
3297         TOML_ALWAYS_INLINE
3298         path& assign(path&& p) noexcept
3299         {
3300             return *this = std::move(p);
3301         }
3302 
3303         TOML_ALWAYS_INLINE
3304         path& assign(std::string_view str)
3305         {
3306             return *this = str;
3307         }
3308 
3309 #if TOML_ENABLE_WINDOWS_COMPAT
3310 
3311         TOML_ALWAYS_INLINE
3312         path& assign(std::wstring_view str)
3313         {
3314             return *this = str;
3315         }
3316 
3317 #endif
3318 
3319         TOML_EXPORTED_MEMBER_FUNCTION
3320         path& operator+=(const path&);
3321 
3322         TOML_EXPORTED_MEMBER_FUNCTION
3323         path& operator+=(path&&);
3324 
3325         TOML_EXPORTED_MEMBER_FUNCTION
3326         path& operator+=(std::string_view);
3327 
3328 #if TOML_ENABLE_WINDOWS_COMPAT
3329 
3330         TOML_EXPORTED_MEMBER_FUNCTION
3331         path& operator+=(std::wstring_view);
3332 
3333 #endif
3334 
3335         TOML_ALWAYS_INLINE
3336         path& append(const path& p)
3337         {
3338             return *this += p;
3339         }
3340 
3341         TOML_ALWAYS_INLINE
3342         path& append(path&& p)
3343         {
3344             return *this += std::move(p);
3345         }
3346 
3347         TOML_ALWAYS_INLINE
3348         path& append(std::string_view str)
3349         {
3350             return *this += str;
3351         }
3352 
3353 #if TOML_ENABLE_WINDOWS_COMPAT
3354 
3355         TOML_ALWAYS_INLINE
3356         path& append(std::wstring_view str)
3357         {
3358             return *this += str;
3359         }
3360 
3361 #endif
3362 
3363         TOML_EXPORTED_MEMBER_FUNCTION
3364         path& prepend(const path&);
3365 
3366         TOML_EXPORTED_MEMBER_FUNCTION
3367         path& prepend(path&&);
3368 
3369         TOML_EXPORTED_MEMBER_FUNCTION
3370         path& prepend(std::string_view);
3371 
3372 #if TOML_ENABLE_WINDOWS_COMPAT
3373 
3374         TOML_EXPORTED_MEMBER_FUNCTION
3375         path& prepend(std::wstring_view);
3376 
3377 #endif
3378 
3379         TOML_NODISCARD
3380         friend path operator+(const path& lhs, const path& rhs)
3381         {
3382             path result = lhs;
3383             result += rhs;
3384             return result;
3385         }
3386 
3387         TOML_NODISCARD
3388         friend path operator+(const path& lhs, std::string_view rhs)
3389         {
3390             path result = lhs;
3391             result += rhs;
3392             return result;
3393         }
3394 
3395         TOML_NODISCARD
3396         friend path operator+(std::string_view lhs, const path& rhs)
3397         {
3398             path result = rhs;
3399             result.prepend(lhs);
3400             return result;
3401         }
3402 
3403 #if TOML_ENABLE_WINDOWS_COMPAT
3404 
3405         TOML_NODISCARD
3406         friend path operator+(const path& lhs, std::wstring_view rhs)
3407         {
3408             path result = lhs;
3409             result += rhs;
3410             return result;
3411         }
3412 
3413         TOML_NODISCARD
3414         friend path operator+(std::wstring_view lhs, const path& rhs)
3415         {
3416             path result = rhs;
3417             result.prepend(lhs);
3418             return result;
3419         }
3420 
3421 #endif
3422 
3423         TOML_ALWAYS_INLINE
3424         friend std::ostream& operator<<(std::ostream& os, const path& rhs)
3425         {
3426             rhs.print_to(os);
3427             return os;
3428         }
3429 
3430         TOML_NODISCARD
3431         TOML_EXPORTED_MEMBER_FUNCTION
3432         std::string str() const;
3433 
3434         TOML_NODISCARD
3435         TOML_ALWAYS_INLINE
3436         explicit operator std::string() const
3437         {
3438             return str();
3439         }
3440 
3441 #if TOML_ENABLE_WINDOWS_COMPAT
3442 
3443         TOML_NODISCARD
3444         TOML_EXPORTED_MEMBER_FUNCTION
3445         std::wstring wide_str() const;
3446 
3447         TOML_NODISCARD
3448         TOML_ALWAYS_INLINE
3449         explicit operator std::wstring() const
3450         {
3451             return wide_str();
3452         }
3453 
3454 #endif
3455 
3456         TOML_PURE_INLINE_GETTER
3457         friend bool operator==(const path& lhs, const path& rhs) noexcept
3458         {
3459             return equal(lhs, rhs);
3460         }
3461 
3462         TOML_PURE_INLINE_GETTER
3463         friend bool operator!=(const path& lhs, const path& rhs) noexcept
3464         {
3465             return !equal(lhs, rhs);
3466         }
3467 
3468         TOML_NODISCARD
3469         TOML_ALWAYS_INLINE
3470         friend bool operator==(const path& lhs, std::string_view rhs)
3471         {
3472             return lhs == path{ rhs };
3473         }
3474 
3475         TOML_NODISCARD
3476         TOML_ALWAYS_INLINE
3477         friend bool operator==(std::string_view lhs, const path& rhs)
3478         {
3479             return rhs == lhs;
3480         }
3481 
3482         TOML_NODISCARD
3483         TOML_ALWAYS_INLINE
3484         friend bool operator!=(const path& lhs, std::string_view rhs)
3485         {
3486             return lhs != path{ rhs };
3487         }
3488 
3489         TOML_NODISCARD
3490         TOML_ALWAYS_INLINE
3491         friend bool operator!=(std::string_view lhs, const path& rhs)
3492         {
3493             return rhs != lhs;
3494         }
3495 
3496 #if TOML_ENABLE_WINDOWS_COMPAT
3497 
3498         TOML_NODISCARD
3499         TOML_ALWAYS_INLINE
3500         friend bool operator==(const path& lhs, std::wstring_view rhs)
3501         {
3502             return lhs == path{ rhs };
3503         }
3504 
3505         TOML_NODISCARD
3506         TOML_ALWAYS_INLINE
3507         friend bool operator==(std::wstring_view lhs, const path& rhs)
3508         {
3509             return rhs == lhs;
3510         }
3511 
3512         TOML_NODISCARD
3513         TOML_ALWAYS_INLINE
3514         friend bool operator!=(const path& lhs, std::wstring_view rhs)
3515         {
3516             return lhs != path{ rhs };
3517         }
3518 
3519         TOML_NODISCARD
3520         TOML_ALWAYS_INLINE
3521         friend bool operator!=(std::wstring_view lhs, const path& rhs)
3522         {
3523             return rhs != lhs;
3524         }
3525 
3526 #endif // TOML_ENABLE_WINDOWS_COMPAT
3527 
3528         using iterator = std::vector<path_component>::iterator;
3529 
3530         using const_iterator = std::vector<path_component>::const_iterator;
3531 
3532         TOML_PURE_INLINE_GETTER
3533         iterator begin() noexcept
3534         {
3535             return components_.begin();
3536         }
3537 
3538         TOML_PURE_INLINE_GETTER
3539         iterator end() noexcept
3540         {
3541             return components_.end();
3542         }
3543 
3544         TOML_PURE_INLINE_GETTER
3545         const_iterator begin() const noexcept
3546         {
3547             return components_.begin();
3548         }
3549 
3550         TOML_PURE_INLINE_GETTER
3551         const_iterator end() const noexcept
3552         {
3553             return components_.end();
3554         }
3555 
3556         TOML_PURE_INLINE_GETTER
3557         const_iterator cbegin() const noexcept
3558         {
3559             return components_.begin();
3560         }
3561 
3562         TOML_PURE_INLINE_GETTER
3563         const_iterator cend() const noexcept
3564         {
3565             return components_.end();
3566         }
3567 
3568         TOML_EXPORTED_MEMBER_FUNCTION
3569         void clear() noexcept;
3570 
3571         TOML_EXPORTED_MEMBER_FUNCTION
3572         path& truncate(size_t n);
3573 
3574         TOML_NODISCARD
3575         TOML_EXPORTED_MEMBER_FUNCTION
3576         path truncated(size_t n) const;
3577 
3578         TOML_NODISCARD
3579         TOML_EXPORTED_MEMBER_FUNCTION
3580         path parent() const;
3581 
3582         TOML_NODISCARD
3583         TOML_EXPORTED_MEMBER_FUNCTION
3584         path leaf(size_t n = 1) const;
3585 
3586         TOML_NODISCARD
3587         TOML_EXPORTED_MEMBER_FUNCTION
3588         path subpath(const_iterator start, const_iterator end) const;
3589 
3590         TOML_NODISCARD
3591         TOML_EXPORTED_MEMBER_FUNCTION
3592         path subpath(size_t start, size_t length) const;
3593     };
3594 
3595     inline namespace literals
3596     {
3597         TOML_NODISCARD
3598         TOML_ALWAYS_INLINE
3599         path operator"" _tpath(const char* str, size_t len)
3600         {
3601             return path(std::string_view{ str, len });
3602         }
3603     }
3604 
3605     TOML_NODISCARD
3606     TOML_EXPORTED_FREE_FUNCTION
3607     node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept;
3608 
3609     TOML_NODISCARD
3610     TOML_EXPORTED_FREE_FUNCTION
3611     node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept;
3612 }
3613 TOML_NAMESPACE_END;
3614 
3615 #ifdef _MSC_VER
3616 #pragma pop_macro("min")
3617 #pragma pop_macro("max")
3618 #ifndef __clang__
3619 #pragma inline_recursion(off)
3620 #endif
3621 #endif
3622 TOML_POP_WARNINGS;
3623 
3624 //********  impl/std_utility.hpp  **************************************************************************************
3625 
3626 TOML_DISABLE_WARNINGS;
3627 #include <utility>
3628 TOML_ENABLE_WARNINGS;
3629 
3630 //********  impl/node.hpp  *********************************************************************************************
3631 
3632 TOML_PUSH_WARNINGS;
3633 #ifdef _MSC_VER
3634 #ifndef __clang__
3635 #pragma inline_recursion(on)
3636 #endif
3637 #pragma push_macro("min")
3638 #pragma push_macro("max")
3639 #undef min
3640 #undef max
3641 #endif
3642 
3643 // workaround for this: https://github.com/marzer/tomlplusplus/issues/220
3644 #if TOML_NVCC
3645 #define TOML_NVCC_WORKAROUND                                                                                           \
3646     {                                                                                                                  \
3647         return {};                                                                                                     \
3648     }
3649 #else
3650 #define TOML_NVCC_WORKAROUND = 0
3651 #endif
3652 
3653 TOML_NAMESPACE_START
3654 {
3655     class TOML_ABSTRACT_INTERFACE TOML_EXPORTED_CLASS node
3656     {
3657       private:
3658 
3659         friend class TOML_PARSER_TYPENAME;
3660         source_region source_{};
3661 
3662         template <typename T>
3663         TOML_NODISCARD
3664         decltype(auto) get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
3665 
3666         template <typename T, typename N>
3667         using ref_type_ = std::conditional_t<                                                   //
3668             std::is_reference_v<T>,                                                             //
3669             impl::copy_ref<impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>, T>, //
3670             impl::copy_cvref<impl::unwrap_node<T>, N>                                           //
3671             >;
3672 
3673         template <typename T, typename N>
3674         using ref_type = std::conditional_t<             //
3675             std::is_reference_v<N>,                      //
3676             ref_type_<T, N>,                             //
3677             ref_type_<T, std::add_lvalue_reference_t<N>> //
3678             >;
3679 
3680         template <typename T, typename N>
3681         TOML_PURE_GETTER
3682         static ref_type<T, N&&> do_ref(N&& n) noexcept
3683         {
3684             using unwrapped_type = impl::unwrap_node<T>;
3685             static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3686                           "The template type argument of node::ref() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3687 
3688             TOML_ASSERT_ASSUME(
3689                 n.template is<unwrapped_type>()
3690                 && "template type argument provided to toml::node::ref() didn't match the node's actual type");
3691 
3692             using node_ref = std::remove_volatile_t<std::remove_reference_t<N>>&;
3693             using val_type = std::remove_volatile_t<unwrapped_type>;
3694             using out_ref  = ref_type<T, N&&>;
3695             static_assert(std::is_reference_v<out_ref>);
3696 
3697             if constexpr (toml::is_value<unwrapped_type>)
3698                 return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>().get());
3699             else
3700                 return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>());
3701         }
3702 
3703       protected:
3704         TOML_EXPORTED_MEMBER_FUNCTION
3705         node() noexcept;
3706 
3707         TOML_EXPORTED_MEMBER_FUNCTION
3708         node(const node&) noexcept;
3709 
3710         TOML_EXPORTED_MEMBER_FUNCTION
3711         node(node&&) noexcept;
3712 
3713         TOML_EXPORTED_MEMBER_FUNCTION
3714         node& operator=(const node&) noexcept;
3715 
3716         TOML_EXPORTED_MEMBER_FUNCTION
3717         node& operator=(node&&) noexcept;
3718 
3719         template <typename T, typename N>
3720         using ref_cast_type_ = std::conditional_t<                                            //
3721             std::is_reference_v<T>,                                                           //
3722             impl::copy_ref<impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>, T>, //
3723             impl::copy_cvref<impl::wrap_node<T>, N>                                           //
3724             >;
3725 
3726         template <typename T, typename N>
3727         using ref_cast_type = std::conditional_t<             //
3728             std::is_reference_v<N>,                           //
3729             ref_cast_type_<T, N>,                             //
3730             ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
3731             >;
3732 
3733         template <typename T>
3734         TOML_PURE_INLINE_GETTER
3735         ref_cast_type<T, node&> ref_cast() & noexcept
3736         {
3737             using out_ref  = ref_cast_type<T, node&>;
3738             using out_type = std::remove_reference_t<out_ref>;
3739             return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3740         }
3741 
3742         template <typename T>
3743         TOML_PURE_INLINE_GETTER
3744         ref_cast_type<T, node&&> ref_cast() && noexcept
3745         {
3746             using out_ref  = ref_cast_type<T, node&&>;
3747             using out_type = std::remove_reference_t<out_ref>;
3748             return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3749         }
3750 
3751         template <typename T>
3752         TOML_PURE_INLINE_GETTER
3753         ref_cast_type<T, const node&> ref_cast() const& noexcept
3754         {
3755             using out_ref  = ref_cast_type<T, const node&>;
3756             using out_type = std::remove_reference_t<out_ref>;
3757             return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3758         }
3759 
3760         template <typename T>
3761         TOML_PURE_INLINE_GETTER
3762         ref_cast_type<T, const node&&> ref_cast() const&& noexcept
3763         {
3764             using out_ref  = ref_cast_type<T, const node&&>;
3765             using out_type = std::remove_reference_t<out_ref>;
3766             return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
3767         }
3768 
3769       public:
3770         TOML_EXPORTED_MEMBER_FUNCTION
3771         virtual ~node() noexcept;
3772 
3773         TOML_NODISCARD
3774         virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
3775 
3776         TOML_NODISCARD
3777         virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
3778 
3779         TOML_PURE_GETTER
3780         virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
3781 
3782         template <typename ElemType = void>
3783         TOML_PURE_GETTER
3784         bool is_homogeneous() const noexcept
3785         {
3786             using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
3787             static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
3788                           "The template type argument of node::is_homogeneous() must be void or one "
3789                           "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3790 
3791             return is_homogeneous(impl::node_type_of<type>);
3792         }
3793 
3794         TOML_PURE_GETTER
3795         virtual node_type type() const noexcept TOML_NVCC_WORKAROUND;
3796 
3797         TOML_PURE_GETTER
3798         virtual bool is_table() const noexcept TOML_NVCC_WORKAROUND;
3799 
3800         TOML_PURE_GETTER
3801         virtual bool is_array() const noexcept = 0;
3802 
3803         TOML_PURE_GETTER
3804         virtual bool is_array_of_tables() const noexcept TOML_NVCC_WORKAROUND;
3805 
3806         TOML_PURE_GETTER
3807         virtual bool is_value() const noexcept = 0;
3808 
3809         TOML_PURE_GETTER
3810         virtual bool is_string() const noexcept = 0;
3811 
3812         TOML_PURE_GETTER
3813         virtual bool is_integer() const noexcept = 0;
3814 
3815         TOML_PURE_GETTER
3816         virtual bool is_floating_point() const noexcept = 0;
3817 
3818         TOML_PURE_GETTER
3819         virtual bool is_number() const noexcept = 0;
3820 
3821         TOML_PURE_GETTER
3822         virtual bool is_boolean() const noexcept = 0;
3823 
3824         TOML_PURE_GETTER
3825         virtual bool is_date() const noexcept = 0;
3826 
3827         TOML_PURE_GETTER
3828         virtual bool is_time() const noexcept = 0;
3829 
3830         TOML_PURE_GETTER
3831         virtual bool is_date_time() const noexcept = 0;
3832 
3833         template <typename T>
3834         TOML_PURE_INLINE_GETTER
3835         bool is() const noexcept
3836         {
3837             using type = impl::remove_cvref<impl::unwrap_node<T>>;
3838             static_assert(toml::is_value<type> || toml::is_container<type>,
3839                           "The template type argument of node::is() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3840 
3841             if constexpr (std::is_same_v<type, table>)
3842                 return is_table();
3843             else if constexpr (std::is_same_v<type, array>)
3844                 return is_array();
3845             else if constexpr (std::is_same_v<type, std::string>)
3846                 return is_string();
3847             else if constexpr (std::is_same_v<type, int64_t>)
3848                 return is_integer();
3849             else if constexpr (std::is_same_v<type, double>)
3850                 return is_floating_point();
3851             else if constexpr (std::is_same_v<type, bool>)
3852                 return is_boolean();
3853             else if constexpr (std::is_same_v<type, date>)
3854                 return is_date();
3855             else if constexpr (std::is_same_v<type, time>)
3856                 return is_time();
3857             else if constexpr (std::is_same_v<type, date_time>)
3858                 return is_date_time();
3859 
3860             TOML_UNREACHABLE;
3861         }
3862 
3863         TOML_PURE_GETTER
3864         virtual table* as_table() noexcept = 0;
3865 
3866         TOML_PURE_GETTER
3867         virtual array* as_array() noexcept = 0;
3868 
3869         TOML_PURE_GETTER
3870         virtual toml::value<std::string>* as_string() noexcept = 0;
3871 
3872         TOML_PURE_GETTER
3873         virtual toml::value<int64_t>* as_integer() noexcept = 0;
3874 
3875         TOML_PURE_GETTER
3876         virtual toml::value<double>* as_floating_point() noexcept = 0;
3877 
3878         TOML_PURE_GETTER
3879         virtual toml::value<bool>* as_boolean() noexcept = 0;
3880 
3881         TOML_PURE_GETTER
3882         virtual toml::value<date>* as_date() noexcept = 0;
3883 
3884         TOML_PURE_GETTER
3885         virtual toml::value<time>* as_time() noexcept = 0;
3886 
3887         TOML_PURE_GETTER
3888         virtual toml::value<date_time>* as_date_time() noexcept = 0;
3889 
3890         TOML_PURE_GETTER
3891         virtual const table* as_table() const noexcept = 0;
3892 
3893         TOML_PURE_GETTER
3894         virtual const array* as_array() const noexcept = 0;
3895 
3896         TOML_PURE_GETTER
3897         virtual const toml::value<std::string>* as_string() const noexcept = 0;
3898 
3899         TOML_PURE_GETTER
3900         virtual const toml::value<int64_t>* as_integer() const noexcept = 0;
3901 
3902         TOML_PURE_GETTER
3903         virtual const toml::value<double>* as_floating_point() const noexcept = 0;
3904 
3905         TOML_PURE_GETTER
3906         virtual const toml::value<bool>* as_boolean() const noexcept = 0;
3907 
3908         TOML_PURE_GETTER
3909         virtual const toml::value<date>* as_date() const noexcept = 0;
3910 
3911         TOML_PURE_GETTER
3912         virtual const toml::value<time>* as_time() const noexcept = 0;
3913 
3914         TOML_PURE_GETTER
3915         virtual const toml::value<date_time>* as_date_time() const noexcept = 0;
3916 
3917         template <typename T>
3918         TOML_PURE_INLINE_GETTER
3919         impl::wrap_node<T>* as() noexcept
3920         {
3921             using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
3922             static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3923                           "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3924 
3925             if constexpr (std::is_same_v<unwrapped_type, table>)
3926                 return as_table();
3927             else if constexpr (std::is_same_v<unwrapped_type, array>)
3928                 return as_array();
3929             else if constexpr (std::is_same_v<unwrapped_type, std::string>)
3930                 return as_string();
3931             else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
3932                 return as_integer();
3933             else if constexpr (std::is_same_v<unwrapped_type, double>)
3934                 return as_floating_point();
3935             else if constexpr (std::is_same_v<unwrapped_type, bool>)
3936                 return as_boolean();
3937             else if constexpr (std::is_same_v<unwrapped_type, date>)
3938                 return as_date();
3939             else if constexpr (std::is_same_v<unwrapped_type, time>)
3940                 return as_time();
3941             else if constexpr (std::is_same_v<unwrapped_type, date_time>)
3942                 return as_date_time();
3943 
3944             TOML_UNREACHABLE;
3945         }
3946 
3947         template <typename T>
3948         TOML_PURE_INLINE_GETTER
3949         const impl::wrap_node<T>* as() const noexcept
3950         {
3951             using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
3952             static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
3953                           "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
3954 
3955             if constexpr (std::is_same_v<unwrapped_type, table>)
3956                 return as_table();
3957             else if constexpr (std::is_same_v<unwrapped_type, array>)
3958                 return as_array();
3959             else if constexpr (std::is_same_v<unwrapped_type, std::string>)
3960                 return as_string();
3961             else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
3962                 return as_integer();
3963             else if constexpr (std::is_same_v<unwrapped_type, double>)
3964                 return as_floating_point();
3965             else if constexpr (std::is_same_v<unwrapped_type, bool>)
3966                 return as_boolean();
3967             else if constexpr (std::is_same_v<unwrapped_type, date>)
3968                 return as_date();
3969             else if constexpr (std::is_same_v<unwrapped_type, time>)
3970                 return as_time();
3971             else if constexpr (std::is_same_v<unwrapped_type, date_time>)
3972                 return as_date_time();
3973 
3974             TOML_UNREACHABLE;
3975         }
3976 
3977         template <typename T>
3978         TOML_NODISCARD
3979         optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
3980 
3981         template <typename T>
3982         TOML_NODISCARD
3983         optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>);
3984 
3985         template <typename T>
3986         TOML_NODISCARD
3987         auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>);
3988 
3989         template <typename T>
3990         TOML_PURE_GETTER
3991         decltype(auto) ref() & noexcept
3992         {
3993             return do_ref<T>(*this);
3994         }
3995 
3996         template <typename T>
3997         TOML_PURE_GETTER
3998         decltype(auto) ref() && noexcept
3999         {
4000             return do_ref<T>(std::move(*this));
4001         }
4002 
4003         template <typename T>
4004         TOML_PURE_GETTER
4005         decltype(auto) ref() const& noexcept
4006         {
4007             return do_ref<T>(*this);
4008         }
4009 
4010         template <typename T>
4011         TOML_PURE_GETTER
4012         decltype(auto) ref() const&& noexcept
4013         {
4014             return do_ref<T>(std::move(*this));
4015         }
4016 
4017         TOML_PURE_INLINE_GETTER
4018         const source_region& source() const noexcept
4019         {
4020             return source_;
4021         }
4022 
4023       private:
4024 
4025         template <typename Func, typename Node, typename T>
4026         static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, Node>>;
4027 
4028         template <typename Func, typename Node, typename T>
4029         static constexpr bool can_visit_nothrow = std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>;
4030 
4031         template <typename Func, typename Node>
4032         static constexpr bool can_visit_any = can_visit<Func, Node, table>       //
4033                                            || can_visit<Func, Node, array>       //
4034                                            || can_visit<Func, Node, std::string> //
4035                                            || can_visit<Func, Node, int64_t>     //
4036                                            || can_visit<Func, Node, double>      //
4037                                            || can_visit<Func, Node, bool>        //
4038                                            || can_visit<Func, Node, date>        //
4039                                            || can_visit<Func, Node, time>        //
4040                                            || can_visit<Func, Node, date_time>;
4041 
4042         // clang-format off
4043 
4044         template <typename Func, typename Node>
4045         static constexpr bool can_visit_all = can_visit<Func, Node, table>       //
4046                                            && can_visit<Func, Node, array>       //
4047                                            && can_visit<Func, Node, std::string> //
4048                                            && can_visit<Func, Node, int64_t>     //
4049                                            && can_visit<Func, Node, double>      //
4050                                            && can_visit<Func, Node, bool>        //
4051                                            && can_visit<Func, Node, date>        //
4052                                            && can_visit<Func, Node, time>        //
4053                                            && can_visit<Func, Node, date_time>;
4054 
4055         template <typename Func, typename Node, typename T>
4056         static constexpr bool visit_is_nothrow_one = !can_visit<Func, Node, T> || can_visit_nothrow<Func, Node, T>;
4057 
4058         template <typename Func, typename Node>
4059         static constexpr bool visit_is_nothrow = visit_is_nothrow_one<Func, Node, table>       //
4060                                               && visit_is_nothrow_one<Func, Node, array>       //
4061                                               && visit_is_nothrow_one<Func, Node, std::string> //
4062                                               && visit_is_nothrow_one<Func, Node, int64_t>     //
4063                                               && visit_is_nothrow_one<Func, Node, double>      //
4064                                               && visit_is_nothrow_one<Func, Node, bool>        //
4065                                               && visit_is_nothrow_one<Func, Node, date>        //
4066                                               && visit_is_nothrow_one<Func, Node, time>        //
4067                                               && visit_is_nothrow_one<Func, Node, date_time>;
4068 
4069         // clang-format on
4070 
4071         template <typename Func, typename Node, typename T, bool = can_visit<Func, Node, T>>
4072         struct visit_return_type_
4073         {
4074             using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>()));
4075         };
4076         template <typename Func, typename Node, typename T>
4077         struct visit_return_type_<Func, Node, T, false>
4078         {
4079             using type = void;
4080         };
4081 
4082         template <typename Func, typename Node, typename T>
4083         using visit_return_type = typename visit_return_type_<Func, Node, T>::type;
4084 
4085         template <typename A, typename B>
4086         using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
4087 
4088         template <typename Func, typename Node>
4089         static decltype(auto) do_visit(Func&& visitor, Node&& n) noexcept(visit_is_nothrow<Func&&, Node&&>)
4090         {
4091             static_assert(can_visit_any<Func&&, Node&&>,
4092                           "TOML node visitors must be invocable for at least one of the toml::node "
4093                           "specializations:" TOML_SA_NODE_TYPE_LIST);
4094 
4095             switch (n.type())
4096             {
4097                 case node_type::table:
4098                     if constexpr (can_visit<Func&&, Node&&, table>)
4099                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<table>());
4100                     break;
4101 
4102                 case node_type::array:
4103                     if constexpr (can_visit<Func&&, Node&&, array>)
4104                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<array>());
4105                     break;
4106 
4107                 case node_type::string:
4108                     if constexpr (can_visit<Func&&, Node&&, std::string>)
4109                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<std::string>());
4110                     break;
4111 
4112                 case node_type::integer:
4113                     if constexpr (can_visit<Func&&, Node&&, int64_t>)
4114                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<int64_t>());
4115                     break;
4116 
4117                 case node_type::floating_point:
4118                     if constexpr (can_visit<Func&&, Node&&, double>)
4119                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<double>());
4120                     break;
4121 
4122                 case node_type::boolean:
4123                     if constexpr (can_visit<Func&&, Node&&, bool>)
4124                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<bool>());
4125                     break;
4126 
4127                 case node_type::date:
4128                     if constexpr (can_visit<Func&&, Node&&, date>)
4129                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date>());
4130                     break;
4131 
4132                 case node_type::time:
4133                     if constexpr (can_visit<Func&&, Node&&, time>)
4134                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<time>());
4135                     break;
4136 
4137                 case node_type::date_time:
4138                     if constexpr (can_visit<Func&&, Node&&, date_time>)
4139                         return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date_time>());
4140                     break;
4141 
4142                 case node_type::none: TOML_UNREACHABLE;
4143                 default: TOML_UNREACHABLE;
4144             }
4145 
4146             if constexpr (!can_visit_all<Func&&, Node&&>)
4147             {
4148                 // clang-format off
4149 
4150                 using return_type =
4151                     nonvoid<visit_return_type<Func&&, Node&&, table>,
4152                     nonvoid<visit_return_type<Func&&, Node&&, array>,
4153                     nonvoid<visit_return_type<Func&&, Node&&, std::string>,
4154                     nonvoid<visit_return_type<Func&&, Node&&, int64_t>,
4155                     nonvoid<visit_return_type<Func&&, Node&&, double>,
4156                     nonvoid<visit_return_type<Func&&, Node&&, bool>,
4157                     nonvoid<visit_return_type<Func&&, Node&&, date>,
4158                     nonvoid<visit_return_type<Func&&, Node&&, time>,
4159                             visit_return_type<Func&&, Node&&, date_time>
4160                 >>>>>>>>;
4161 
4162                 // clang-format on
4163 
4164                 if constexpr (!std::is_void_v<return_type>)
4165                 {
4166                     static_assert(std::is_default_constructible_v<return_type>,
4167                                   "Non-exhaustive visitors must return a default-constructible type, or void");
4168                     return return_type{};
4169                 }
4170             }
4171         }
4172 
4173       public:
4174 
4175         template <typename Func>
4176         decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>)
4177         {
4178             return do_visit(static_cast<Func&&>(visitor), *this);
4179         }
4180 
4181         template <typename Func>
4182         decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>)
4183         {
4184             return do_visit(static_cast<Func&&>(visitor), static_cast<node&&>(*this));
4185         }
4186 
4187         template <typename Func>
4188         decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>)
4189         {
4190             return do_visit(static_cast<Func&&>(visitor), *this);
4191         }
4192 
4193         template <typename Func>
4194         decltype(auto) visit(Func&& visitor) const&& noexcept(visit_is_nothrow<Func&&, const node&&>)
4195         {
4196             return do_visit(static_cast<Func&&>(visitor), static_cast<const node&&>(*this));
4197         }
4198 
4199         TOML_NODISCARD
4200         explicit operator node_view<node>() noexcept;
4201 
4202         TOML_NODISCARD
4203         explicit operator node_view<const node>() const noexcept;
4204 
4205         TOML_NODISCARD
4206         TOML_EXPORTED_MEMBER_FUNCTION
4207         node_view<node> at_path(std::string_view path) noexcept;
4208 
4209         TOML_NODISCARD
4210         TOML_EXPORTED_MEMBER_FUNCTION
4211         node_view<const node> at_path(std::string_view path) const noexcept;
4212 
4213         TOML_NODISCARD
4214         TOML_EXPORTED_MEMBER_FUNCTION
4215         node_view<node> at_path(const toml::path& path) noexcept;
4216 
4217         TOML_NODISCARD
4218         TOML_EXPORTED_MEMBER_FUNCTION
4219         node_view<const node> at_path(const toml::path& path) const noexcept;
4220 
4221 #if TOML_ENABLE_WINDOWS_COMPAT
4222 
4223         TOML_NODISCARD
4224         TOML_EXPORTED_MEMBER_FUNCTION
4225         node_view<node> at_path(std::wstring_view path);
4226 
4227         TOML_NODISCARD
4228         TOML_EXPORTED_MEMBER_FUNCTION
4229         node_view<const node> at_path(std::wstring_view path) const;
4230 
4231 #endif // TOML_ENABLE_WINDOWS_COMPAT
4232 
4233         TOML_NODISCARD
4234         TOML_EXPORTED_MEMBER_FUNCTION
4235         node_view<node> operator[](const toml::path& path) noexcept;
4236 
4237         TOML_NODISCARD
4238         TOML_EXPORTED_MEMBER_FUNCTION
4239         node_view<const node> operator[](const toml::path& path) const noexcept;
4240     };
4241 }
4242 TOML_NAMESPACE_END;
4243 
4244 TOML_IMPL_NAMESPACE_START
4245 {
4246     TOML_PURE_GETTER
4247     TOML_EXPORTED_FREE_FUNCTION
4248     bool TOML_CALLCONV node_deep_equality(const node*, const node*) noexcept;
4249 }
4250 TOML_IMPL_NAMESPACE_END;
4251 
4252 #undef TOML_NVCC_WORKAROUND
4253 
4254 #ifdef _MSC_VER
4255 #pragma pop_macro("min")
4256 #pragma pop_macro("max")
4257 #ifndef __clang__
4258 #pragma inline_recursion(off)
4259 #endif
4260 #endif
4261 TOML_POP_WARNINGS;
4262 
4263 //********  impl/std_initializer_list.hpp  *****************************************************************************
4264 
4265 TOML_DISABLE_WARNINGS;
4266 #include <initializer_list>
4267 TOML_ENABLE_WARNINGS;
4268 
4269 //********  impl/node_view.hpp  ****************************************************************************************
4270 
4271 TOML_PUSH_WARNINGS;
4272 #ifdef _MSC_VER
4273 #ifndef __clang__
4274 #pragma inline_recursion(on)
4275 #endif
4276 #pragma push_macro("min")
4277 #pragma push_macro("max")
4278 #undef min
4279 #undef max
4280 #endif
4281 
4282 TOML_DISABLE_ARITHMETIC_WARNINGS;
4283 
4284 TOML_NAMESPACE_START
4285 {
4286     template <typename ViewedType>
4287     class TOML_TRIVIAL_ABI node_view
4288     {
4289         static_assert(impl::is_one_of<ViewedType, toml::node, const toml::node>,
4290                       "A toml::node_view<> must wrap toml::node or const toml::node.");
4291 
4292       public:
4293 
4294         using viewed_type = ViewedType;
4295 
4296       private:
4297         template <typename T>
4298         friend class node_view;
4299 
4300         mutable viewed_type* node_ = nullptr;
4301 
4302       public:
4303 
4304         TOML_NODISCARD_CTOR
4305         node_view() noexcept = default;
4306 
4307         TOML_NODISCARD_CTOR
4308         explicit node_view(viewed_type* node) noexcept //
4309             : node_{ node }
4310         {}
4311 
4312         TOML_NODISCARD_CTOR
4313         explicit node_view(viewed_type& node) noexcept //
4314             : node_{ &node }
4315         {}
4316 
4317         TOML_NODISCARD_CTOR
4318         node_view(const node_view&) noexcept = default;
4319 
4320         TOML_NODISCARD_CTOR
4321         node_view(node_view&&) noexcept = default;
4322 
4323         node_view& operator=(const node_view&) & noexcept = default;
4324 
4325         node_view& operator=(node_view&&) & noexcept = default;
4326 
4327         TOML_PURE_INLINE_GETTER
4328         explicit operator bool() const noexcept
4329         {
4330             return node_ != nullptr;
4331         }
4332 
4333         TOML_PURE_INLINE_GETTER
4334         viewed_type* node() const noexcept
4335         {
4336             return node_;
4337         }
4338 
4339         TOML_PURE_GETTER
4340         node_type type() const noexcept
4341         {
4342             return node_ ? node_->type() : node_type::none;
4343         }
4344 
4345         TOML_PURE_GETTER
4346         bool is_table() const noexcept
4347         {
4348             return node_ && node_->is_table();
4349         }
4350 
4351         TOML_PURE_GETTER
4352         bool is_array() const noexcept
4353         {
4354             return node_ && node_->is_array();
4355         }
4356 
4357         TOML_PURE_GETTER
4358         bool is_value() const noexcept
4359         {
4360             return node_ && node_->is_value();
4361         }
4362 
4363         TOML_PURE_GETTER
4364         bool is_string() const noexcept
4365         {
4366             return node_ && node_->is_string();
4367         }
4368 
4369         TOML_PURE_GETTER
4370         bool is_integer() const noexcept
4371         {
4372             return node_ && node_->is_integer();
4373         }
4374 
4375         TOML_PURE_GETTER
4376         bool is_floating_point() const noexcept
4377         {
4378             return node_ && node_->is_floating_point();
4379         }
4380 
4381         TOML_PURE_GETTER
4382         bool is_number() const noexcept
4383         {
4384             return node_ && node_->is_number();
4385         }
4386 
4387         TOML_PURE_GETTER
4388         bool is_boolean() const noexcept
4389         {
4390             return node_ && node_->is_boolean();
4391         }
4392 
4393         TOML_PURE_GETTER
4394         bool is_date() const noexcept
4395         {
4396             return node_ && node_->is_date();
4397         }
4398 
4399         TOML_PURE_GETTER
4400         bool is_time() const noexcept
4401         {
4402             return node_ && node_->is_time();
4403         }
4404 
4405         TOML_PURE_GETTER
4406         bool is_date_time() const noexcept
4407         {
4408             return node_ && node_->is_date_time();
4409         }
4410 
4411         TOML_PURE_GETTER
4412         bool is_array_of_tables() const noexcept
4413         {
4414             return node_ && node_->is_array_of_tables();
4415         }
4416 
4417         template <typename T>
4418         TOML_PURE_GETTER
4419         bool is() const noexcept
4420         {
4421             return node_ ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>() : false;
4422         }
4423 
4424         TOML_NODISCARD
4425         bool is_homogeneous(node_type ntype, viewed_type*& first_nonmatch) const noexcept
4426         {
4427             if (!node_)
4428             {
4429                 first_nonmatch = {};
4430                 return false;
4431             }
4432             return node_->is_homogeneous(ntype, first_nonmatch);
4433         }
4434 
4435         TOML_PURE_GETTER
4436         bool is_homogeneous(node_type ntype) const noexcept
4437         {
4438             return node_ ? node_->is_homogeneous(ntype) : false;
4439         }
4440 
4441         template <typename ElemType = void>
4442         TOML_PURE_GETTER
4443         bool is_homogeneous() const noexcept
4444         {
4445             return node_ ? node_->template is_homogeneous<impl::unwrap_node<impl::remove_cvref<ElemType>>>() : false;
4446         }
4447 
4448         template <typename T>
4449         TOML_PURE_GETTER
4450         auto* as() const noexcept
4451         {
4452             return node_ ? node_->template as<T>() : nullptr;
4453         }
4454 
4455         TOML_PURE_GETTER
4456         auto* as_table() const noexcept
4457         {
4458             return as<table>();
4459         }
4460 
4461         TOML_PURE_GETTER
4462         auto* as_array() const noexcept
4463         {
4464             return as<array>();
4465         }
4466 
4467         TOML_PURE_GETTER
4468         auto* as_string() const noexcept
4469         {
4470             return as<std::string>();
4471         }
4472 
4473         TOML_PURE_GETTER
4474         auto* as_integer() const noexcept
4475         {
4476             return as<int64_t>();
4477         }
4478 
4479         TOML_PURE_GETTER
4480         auto* as_floating_point() const noexcept
4481         {
4482             return as<double>();
4483         }
4484 
4485         TOML_PURE_GETTER
4486         auto* as_boolean() const noexcept
4487         {
4488             return as<bool>();
4489         }
4490 
4491         TOML_PURE_GETTER
4492         auto* as_date() const noexcept
4493         {
4494             return as<date>();
4495         }
4496 
4497         TOML_PURE_GETTER
4498         auto* as_time() const noexcept
4499         {
4500             return as<time>();
4501         }
4502 
4503         TOML_PURE_GETTER
4504         auto* as_date_time() const noexcept
4505         {
4506             return as<date_time>();
4507         }
4508 
4509         template <typename T>
4510         TOML_NODISCARD
4511         optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
4512         {
4513             if (node_)
4514                 return node_->template value_exact<T>();
4515             return {};
4516         }
4517 
4518         template <typename T>
4519         TOML_NODISCARD
4520         optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>)
4521         {
4522             if (node_)
4523                 return node_->template value<T>();
4524             return {};
4525         }
4526 
4527         template <typename T>
4528         TOML_NODISCARD
4529         auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
4530         {
4531             using namespace ::toml::impl;
4532 
4533             static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
4534                           "Retrieving values as wide-character strings is only "
4535                           "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
4536 
4537             if constexpr (is_wide_string<T>)
4538             {
4539 #if TOML_ENABLE_WINDOWS_COMPAT
4540 
4541                 if (node_)
4542                     return node_->value_or(static_cast<T&&>(default_value));
4543                 return std::wstring{ static_cast<T&&>(default_value) };
4544 
4545 #else
4546 
4547                 static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
4548 
4549 #endif
4550             }
4551             else
4552             {
4553                 using value_type =
4554                     std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
4555                                        std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
4556                                        std::decay_t<T>>;
4557 
4558                 if (node_)
4559                     return node_->value_or(static_cast<T&&>(default_value));
4560                 if constexpr (std::is_pointer_v<value_type>)
4561                     return value_type{ default_value };
4562                 else
4563                     return static_cast<T&&>(default_value);
4564             }
4565         }
4566 
4567         template <typename T>
4568         TOML_PURE_INLINE_GETTER
4569         decltype(auto) ref() const noexcept
4570         {
4571             TOML_ASSERT_ASSUME(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
4572             return node_->template ref<T>();
4573         }
4574 
4575       private:
4576 
4577         template <typename Func>
4578         static constexpr bool visit_is_nothrow = noexcept(std::declval<viewed_type*>()->visit(std::declval<Func>()));
4579 
4580       public:
4581 
4582         template <typename Func>
4583         decltype(auto) visit(Func&& visitor) const noexcept(visit_is_nothrow<Func&&>)
4584         {
4585             using return_type = decltype(node_->visit(static_cast<Func&&>(visitor)));
4586             if (node_)
4587                 return node_->visit(static_cast<Func&&>(visitor));
4588             if constexpr (!std::is_void_v<return_type>)
4589                 return return_type{};
4590         }
4591 
4592       public:
4593 
4594         template <typename T>
4595         TOML_PURE_GETTER
4596         friend bool operator==(const node_view& lhs, const node_view<T>& rhs) noexcept
4597         {
4598             return impl::node_deep_equality(lhs.node_, rhs.node_);
4599         }
4600 
4601         template <typename T>
4602         TOML_PURE_GETTER
4603         friend bool operator!=(const node_view& lhs, const node_view<T>& rhs) noexcept
4604         {
4605             return !impl::node_deep_equality(lhs.node_, rhs.node_);
4606         }
4607 
4608         TOML_NODISCARD
4609         friend bool operator==(const node_view& lhs, const table& rhs) noexcept
4610         {
4611             if (lhs.node_ == &rhs)
4612                 return true;
4613             const auto tbl = lhs.as<table>();
4614             return tbl && *tbl == rhs;
4615         }
4616         TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const table&, );
4617 
4618         TOML_NODISCARD
4619         friend bool operator==(const node_view& lhs, const array& rhs) noexcept
4620         {
4621             if (lhs.node_ == &rhs)
4622                 return true;
4623             const auto arr = lhs.as<array>();
4624             return arr && *arr == rhs;
4625         }
4626         TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const array&, );
4627 
4628         template <typename T>
4629         TOML_NODISCARD
4630         friend bool operator==(const node_view& lhs, const toml::value<T>& rhs) noexcept
4631         {
4632             if (lhs.node_ == &rhs)
4633                 return true;
4634             const auto val = lhs.as<T>();
4635             return val && *val == rhs;
4636         }
4637         TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<T>&, template <typename T>);
4638 
4639         TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
4640         TOML_NODISCARD
4641         friend bool operator==(const node_view& lhs, const T& rhs) noexcept(!impl::is_wide_string<T>)
4642         {
4643             static_assert(!impl::is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
4644                           "Comparison with wide-character strings is only "
4645                           "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
4646 
4647             if constexpr (impl::is_wide_string<T>)
4648             {
4649 #if TOML_ENABLE_WINDOWS_COMPAT
4650                 return lhs == impl::narrow(rhs);
4651 #else
4652                 static_assert(impl::always_false<T>, "Evaluated unreachable branch!");
4653 #endif
4654             }
4655             else
4656             {
4657                 const auto val = lhs.as<impl::native_type_of<T>>();
4658                 return val && *val == rhs;
4659             }
4660         }
4661         TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&,
4662                                        const T&,
4663                                        TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>,
4664                                                                  typename T));
4665 
4666         template <typename T>
4667         TOML_NODISCARD
4668         friend bool operator==(const node_view& lhs,
4669                                const std::initializer_list<T>& rhs) noexcept(!impl::is_wide_string<T>)
4670         {
4671             const auto arr = lhs.as<array>();
4672             return arr && *arr == rhs;
4673         }
4674         TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<T>&, template <typename T>);
4675 
4676         template <typename T>
4677         TOML_NODISCARD
4678         friend bool operator==(const node_view& lhs, const std::vector<T>& rhs) noexcept(!impl::is_wide_string<T>)
4679         {
4680             const auto arr = lhs.as<array>();
4681             return arr && *arr == rhs;
4682         }
4683         TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<T>&, template <typename T>);
4684 
4685         TOML_NODISCARD
4686         node_view operator[](std::string_view key) const noexcept
4687         {
4688             if (auto tbl = this->as_table())
4689                 return node_view{ tbl->get(key) };
4690             return {};
4691         }
4692 
4693         TOML_NODISCARD
4694         node_view operator[](const toml::path& path) const noexcept
4695         {
4696             return node_ ? node_->at_path(path) : node_view{};
4697         }
4698 
4699         TOML_NODISCARD
4700         node_view at_path(std::string_view path) const noexcept
4701         {
4702             return node_ ? node_->at_path(path) : node_view{};
4703         }
4704 
4705         TOML_NODISCARD
4706         node_view at_path(const toml::path& path) const noexcept
4707         {
4708             return node_ ? node_->at_path(path) : node_view{};
4709         }
4710 
4711 #if TOML_ENABLE_WINDOWS_COMPAT
4712 
4713         TOML_NODISCARD
4714         node_view operator[](std::wstring_view key) const
4715         {
4716             if (auto tbl = this->as_table())
4717                 return node_view{ tbl->get(key) };
4718             return {};
4719         }
4720 
4721         TOML_NODISCARD
4722         node_view at_path(std::wstring_view path) const
4723         {
4724             return node_ ? node_->at_path(path) : node_view{};
4725         }
4726 
4727 #endif // TOML_ENABLE_WINDOWS_COMPAT
4728 
4729         TOML_NODISCARD
4730         node_view operator[](size_t index) const noexcept
4731         {
4732             if (auto arr = this->as_array())
4733                 return node_view{ arr->get(index) };
4734             return {};
4735         }
4736 
4737 #if TOML_ENABLE_FORMATTERS
4738 
4739         friend std::ostream& operator<<(std::ostream& os, const node_view& nv)
4740         {
4741             if (nv.node_)
4742                 nv.node_->visit([&os](const auto& n) { os << n; });
4743             return os;
4744         }
4745 
4746 #endif
4747     };
4748 
4749     template <typename T>
4750     node_view(const T&) -> node_view<const node>;
4751 
4752     template <typename T>
4753     node_view(const T*) -> node_view<const node>;
4754 
4755     template <typename T>
4756     node_view(T&) -> node_view<node>;
4757 
4758     template <typename T>
4759     node_view(T*) -> node_view<node>;
4760 }
4761 TOML_NAMESPACE_END;
4762 
4763 TOML_NAMESPACE_START
4764 {
4765     inline node::operator node_view<node>() noexcept
4766     {
4767         return node_view<node>{ this };
4768     }
4769 
4770     inline node::operator node_view<const node>() const noexcept
4771     {
4772         return node_view<const node>{ this };
4773     }
4774 }
4775 TOML_NAMESPACE_END;
4776 
4777 #ifdef _MSC_VER
4778 #pragma pop_macro("min")
4779 #pragma pop_macro("max")
4780 #ifndef __clang__
4781 #pragma inline_recursion(off)
4782 #endif
4783 #endif
4784 TOML_POP_WARNINGS;
4785 
4786 //********  impl/value.hpp  ********************************************************************************************
4787 
4788 TOML_PUSH_WARNINGS;
4789 #ifdef _MSC_VER
4790 #ifndef __clang__
4791 #pragma inline_recursion(on)
4792 #endif
4793 #pragma push_macro("min")
4794 #pragma push_macro("max")
4795 #undef min
4796 #undef max
4797 #endif
4798 
4799 TOML_DISABLE_ARITHMETIC_WARNINGS;
4800 
4801 // clang-format off
4802 
4803 #if TOML_ENABLE_WINDOWS_COMPAT
4804     #define TOML_SA_VALUE_MESSAGE_WSTRING           TOML_SA_LIST_SEP "std::wstring"
4805 #else
4806     #define TOML_SA_VALUE_MESSAGE_WSTRING
4807 #endif
4808 #if TOML_HAS_CHAR8
4809     #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW     TOML_SA_LIST_SEP "std::u8string_view"
4810     #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8       TOML_SA_LIST_SEP "const char8_t*"
4811 #else
4812     #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
4813     #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
4814 #endif
4815 
4816 #define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg)                                                          \
4817     "The " type_arg " must be one of:"                                                                      \
4818     TOML_SA_LIST_NEW "A native TOML value type"                                                             \
4819     TOML_SA_NATIVE_VALUE_TYPE_LIST                                                                          \
4820                                                                                                             \
4821     TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"          \
4822     TOML_SA_LIST_BEG "std::string"                                                                          \
4823     TOML_SA_VALUE_MESSAGE_WSTRING                                                                           \
4824     TOML_SA_LIST_SEP "any signed integer type >= 64 bits"                                                   \
4825     TOML_SA_LIST_SEP "any floating-point type >= 64 bits"                                                   \
4826     TOML_SA_LIST_END                                                                                        \
4827                                                                                                             \
4828     TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"                    \
4829     TOML_SA_LIST_BEG "std::string_view"                                                                     \
4830     TOML_SA_VALUE_MESSAGE_U8STRING_VIEW                                                                     \
4831     TOML_SA_LIST_SEP "const char*"                                                                          \
4832     TOML_SA_VALUE_MESSAGE_CONST_CHAR8                                                                       \
4833         TOML_SA_LIST_END
4834 
4835 #define TOML_SA_VALUE_FUNC_MESSAGE(type_arg)                                                                \
4836     "The " type_arg " must be one of:"                                                                      \
4837     TOML_SA_LIST_NEW "A native TOML value type"                                                             \
4838     TOML_SA_NATIVE_VALUE_TYPE_LIST                                                                          \
4839                                                                                                             \
4840     TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"          \
4841     TOML_SA_LIST_BEG "std::string"                                                                          \
4842     TOML_SA_VALUE_MESSAGE_WSTRING                                                                           \
4843     TOML_SA_LIST_SEP "any signed integer type >= 64 bits"                                                   \
4844     TOML_SA_LIST_SEP "any floating-point type >= 64 bits"                                                   \
4845     TOML_SA_LIST_END                                                                                        \
4846                                                                                                             \
4847     TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"        \
4848     TOML_SA_LIST_BEG "any other integral type"                                                              \
4849     TOML_SA_LIST_SEP "any floating-point type"                                                              \
4850     TOML_SA_LIST_END                                                                                        \
4851                                                                                                             \
4852     TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"                    \
4853     TOML_SA_LIST_BEG "std::string_view"                                                                     \
4854     TOML_SA_VALUE_MESSAGE_U8STRING_VIEW                                                                     \
4855     TOML_SA_LIST_SEP "const char*"                                                                          \
4856     TOML_SA_VALUE_MESSAGE_CONST_CHAR8                                                                       \
4857     TOML_SA_LIST_END
4858 
4859 // clang-format on
4860 TOML_IMPL_NAMESPACE_START
4861 {
4862     template <typename T, typename...>
4863     struct native_value_maker
4864     {
4865         template <typename... Args>
4866         TOML_NODISCARD
4867         static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
4868         {
4869             if constexpr (std::is_aggregate_v<T>)
4870                 return T{ static_cast<Args&&>(args)... };
4871             else
4872                 return T(static_cast<Args&&>(args)...);
4873         }
4874     };
4875 
4876     template <typename T>
4877     struct native_value_maker<T, T>
4878     {
4879         template <typename U>
4880         TOML_NODISCARD
4881         TOML_ALWAYS_INLINE
4882         static U&& make(U&& val) noexcept
4883         {
4884             return static_cast<U&&>(val);
4885         }
4886     };
4887 
4888 #if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
4889 
4890     struct string_maker
4891     {
4892         template <typename T>
4893         TOML_NODISCARD
4894         static std::string make(T&& arg)
4895         {
4896             using arg_type = std::decay_t<T>;
4897 #if TOML_HAS_CHAR8
4898             if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>)
4899             {
4900                 return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
4901             }
4902             if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>)
4903             {
4904                 return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())),
4905                                    arg.length());
4906             }
4907 #endif
4908 
4909 #if TOML_ENABLE_WINDOWS_COMPAT
4910             if constexpr (is_wide_string<arg_type>)
4911             {
4912                 return narrow(static_cast<T&&>(arg));
4913             }
4914 #endif
4915         }
4916     };
4917 
4918 #if TOML_HAS_CHAR8
4919     template <>
4920     struct native_value_maker<std::string, char8_t*> : string_maker
4921     {};
4922     template <>
4923     struct native_value_maker<std::string, const char8_t*> : string_maker
4924     {};
4925     template <>
4926     struct native_value_maker<std::string, std::u8string> : string_maker
4927     {};
4928     template <>
4929     struct native_value_maker<std::string, std::u8string_view> : string_maker
4930     {};
4931 #endif // TOML_HAS_CHAR8
4932 
4933 #if TOML_ENABLE_WINDOWS_COMPAT
4934     template <>
4935     struct native_value_maker<std::string, wchar_t*> : string_maker
4936     {};
4937     template <>
4938     struct native_value_maker<std::string, const wchar_t*> : string_maker
4939     {};
4940     template <>
4941     struct native_value_maker<std::string, std::wstring> : string_maker
4942     {};
4943     template <>
4944     struct native_value_maker<std::string, std::wstring_view> : string_maker
4945     {};
4946 #endif // TOML_ENABLE_WINDOWS_COMPAT
4947 
4948 #endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
4949 
4950     template <typename T>
4951     TOML_CONST_GETTER
4952     inline optional<T> node_integer_cast(int64_t val) noexcept
4953     {
4954         static_assert(node_type_of<T> == node_type::integer);
4955         static_assert(!is_cvref<T>);
4956 
4957         using traits = value_traits<T>;
4958         if constexpr (!traits::is_signed)
4959         {
4960             if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
4961             {
4962                 using common_t = decltype(int64_t{} + T{});
4963                 if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
4964                     return {};
4965             }
4966             else
4967             {
4968                 if (val < int64_t{})
4969                     return {};
4970             }
4971         }
4972         else
4973         {
4974             if (val < traits::min || val > traits::max)
4975                 return {};
4976         }
4977         return { static_cast<T>(val) };
4978     }
4979 
4980     template <typename...>
4981     struct value_variadic_ctor_allowed : std::true_type
4982     {};
4983 
4984     template <typename T, typename... Args>
4985     struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type
4986     {};
4987 }
4988 TOML_IMPL_NAMESPACE_END;
4989 
4990 TOML_NAMESPACE_START
4991 {
4992     template <typename ValueType>
4993     class value : public node
4994     {
4995         static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
4996                       "A toml::value<> must model one of the native TOML value types:" TOML_SA_NATIVE_VALUE_TYPE_LIST);
4997 
4998       private:
4999 
5000         friend class TOML_PARSER_TYPENAME;
5001 
5002         template <typename T, typename U>
5003         TOML_CONST_INLINE_GETTER
5004         static auto as_value([[maybe_unused]] U* ptr) noexcept
5005         {
5006             if constexpr (std::is_same_v<value_type, T>)
5007                 return ptr;
5008             else
5009                 return nullptr;
5010         }
5011 
5012         ValueType val_;
5013         value_flags flags_ = value_flags::none;
5014 
5015       public:
5016 
5017         using value_type = ValueType;
5018 
5019         using value_arg = POXY_IMPLEMENTATION_DETAIL(
5020             std::conditional_t<
5021                 std::is_same_v<value_type, std::string>,
5022                 std::string_view,
5023                 std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>>);
5024 
5025         TOML_HIDDEN_CONSTRAINT(
5026             (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value),
5027             typename... Args)
5028         TOML_NODISCARD_CTOR
5029         explicit value(Args&&... args) noexcept(noexcept(value_type(
5030             impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))))
5031             : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))
5032         {
5033 #if TOML_LIFETIME_HOOKS
5034             TOML_VALUE_CREATED;
5035 #endif
5036         }
5037 
5038         TOML_NODISCARD_CTOR
5039         value(const value& other) noexcept //
5040             : node(other),
5041               val_{ other.val_ },
5042               flags_{ other.flags_ }
5043         {
5044 #if TOML_LIFETIME_HOOKS
5045             TOML_VALUE_CREATED;
5046 #endif
5047         }
5048 
5049         TOML_NODISCARD_CTOR
5050         value(const value& other, value_flags flags) noexcept //
5051             : node(other),
5052               val_{ other.val_ },
5053               flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
5054         {
5055 #if TOML_LIFETIME_HOOKS
5056             TOML_VALUE_CREATED;
5057 #endif
5058         }
5059 
5060         TOML_NODISCARD_CTOR
5061         value(value&& other) noexcept //
5062             : node(std::move(other)),
5063               val_{ std::move(other.val_) },
5064               flags_{ std::exchange(other.flags_, value_flags{}) }
5065         {
5066 #if TOML_LIFETIME_HOOKS
5067             TOML_VALUE_CREATED;
5068 #endif
5069         }
5070 
5071         TOML_NODISCARD_CTOR
5072         value(value&& other, value_flags flags) noexcept //
5073             : node(std::move(other)),
5074               val_{ std::move(other.val_) },
5075               flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
5076         {
5077 #if TOML_LIFETIME_HOOKS
5078             TOML_VALUE_CREATED;
5079 #endif
5080             other.flags_ = {};
5081         }
5082 
5083         value& operator=(const value& rhs) noexcept
5084         {
5085             node::operator=(rhs);
5086             val_   = rhs.val_;
5087             flags_ = rhs.flags_;
5088             return *this;
5089         }
5090 
5091         value& operator=(value&& rhs) noexcept
5092         {
5093             if (&rhs != this)
5094             {
5095                 node::operator=(std::move(rhs));
5096                 val_   = std::move(rhs.val_);
5097                 flags_ = std::exchange(rhs.flags_, value_flags{});
5098             }
5099             return *this;
5100         }
5101 
5102 #if TOML_LIFETIME_HOOKS
5103         ~value() noexcept
5104         {
5105             TOML_VALUE_DESTROYED;
5106         }
5107 #endif
5108 
5109         TOML_CONST_INLINE_GETTER
5110         node_type type() const noexcept final
5111         {
5112             return impl::node_type_of<value_type>;
5113         }
5114 
5115         TOML_PURE_GETTER
5116         bool is_homogeneous(node_type ntype) const noexcept final
5117         {
5118             return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
5119         }
5120 
5121         TOML_NODISCARD
5122         bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final
5123         {
5124             if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
5125             {
5126                 first_nonmatch = this;
5127                 return false;
5128             }
5129             return true;
5130         }
5131 
5132         TOML_NODISCARD
5133         bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final
5134         {
5135             if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
5136             {
5137                 first_nonmatch = this;
5138                 return false;
5139             }
5140             return true;
5141         }
5142 
5143         template <typename ElemType = void>
5144         TOML_PURE_GETTER
5145         bool is_homogeneous() const noexcept
5146         {
5147             using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
5148             static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
5149                           "The template type argument of value::is_homogeneous() must be void or one "
5150                           "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
5151 
5152             if constexpr (std::is_void_v<type>)
5153                 return true;
5154             else
5155                 return impl::node_type_of<type> == impl::node_type_of<value_type>;
5156         }
5157         TOML_CONST_INLINE_GETTER
5158         bool is_table() const noexcept final
5159         {
5160             return false;
5161         }
5162 
5163         TOML_CONST_INLINE_GETTER
5164         bool is_array() const noexcept final
5165         {
5166             return false;
5167         }
5168 
5169         TOML_CONST_INLINE_GETTER
5170         bool is_array_of_tables() const noexcept final
5171         {
5172             return false;
5173         }
5174 
5175         TOML_CONST_INLINE_GETTER
5176         bool is_value() const noexcept final
5177         {
5178             return true;
5179         }
5180 
5181         TOML_CONST_INLINE_GETTER
5182         bool is_string() const noexcept final
5183         {
5184             return std::is_same_v<value_type, std::string>;
5185         }
5186 
5187         TOML_CONST_INLINE_GETTER
5188         bool is_integer() const noexcept final
5189         {
5190             return std::is_same_v<value_type, int64_t>;
5191         }
5192 
5193         TOML_CONST_INLINE_GETTER
5194         bool is_floating_point() const noexcept final
5195         {
5196             return std::is_same_v<value_type, double>;
5197         }
5198 
5199         TOML_CONST_INLINE_GETTER
5200         bool is_number() const noexcept final
5201         {
5202             return impl::is_one_of<value_type, int64_t, double>;
5203         }
5204 
5205         TOML_CONST_INLINE_GETTER
5206         bool is_boolean() const noexcept final
5207         {
5208             return std::is_same_v<value_type, bool>;
5209         }
5210 
5211         TOML_CONST_INLINE_GETTER
5212         bool is_date() const noexcept final
5213         {
5214             return std::is_same_v<value_type, date>;
5215         }
5216 
5217         TOML_CONST_INLINE_GETTER
5218         bool is_time() const noexcept final
5219         {
5220             return std::is_same_v<value_type, time>;
5221         }
5222 
5223         TOML_CONST_INLINE_GETTER
5224         bool is_date_time() const noexcept final
5225         {
5226             return std::is_same_v<value_type, date_time>;
5227         }
5228 
5229         TOML_CONST_INLINE_GETTER
5230         table* as_table() noexcept final
5231         {
5232             return nullptr;
5233         }
5234 
5235         TOML_CONST_INLINE_GETTER
5236         array* as_array() noexcept final
5237         {
5238             return nullptr;
5239         }
5240 
5241         TOML_CONST_INLINE_GETTER
5242         value<std::string>* as_string() noexcept final
5243         {
5244             return as_value<std::string>(this);
5245         }
5246 
5247         TOML_CONST_INLINE_GETTER
5248         value<int64_t>* as_integer() noexcept final
5249         {
5250             return as_value<int64_t>(this);
5251         }
5252 
5253         TOML_CONST_INLINE_GETTER
5254         value<double>* as_floating_point() noexcept final
5255         {
5256             return as_value<double>(this);
5257         }
5258 
5259         TOML_CONST_INLINE_GETTER
5260         value<bool>* as_boolean() noexcept final
5261         {
5262             return as_value<bool>(this);
5263         }
5264 
5265         TOML_CONST_INLINE_GETTER
5266         value<date>* as_date() noexcept final
5267         {
5268             return as_value<date>(this);
5269         }
5270 
5271         TOML_CONST_INLINE_GETTER
5272         value<time>* as_time() noexcept final
5273         {
5274             return as_value<time>(this);
5275         }
5276 
5277         TOML_CONST_INLINE_GETTER
5278         value<date_time>* as_date_time() noexcept final
5279         {
5280             return as_value<date_time>(this);
5281         }
5282 
5283         TOML_CONST_INLINE_GETTER
5284         const table* as_table() const noexcept final
5285         {
5286             return nullptr;
5287         }
5288 
5289         TOML_CONST_INLINE_GETTER
5290         const array* as_array() const noexcept final
5291         {
5292             return nullptr;
5293         }
5294 
5295         TOML_CONST_INLINE_GETTER
5296         const value<std::string>* as_string() const noexcept final
5297         {
5298             return as_value<std::string>(this);
5299         }
5300 
5301         TOML_CONST_INLINE_GETTER
5302         const value<int64_t>* as_integer() const noexcept final
5303         {
5304             return as_value<int64_t>(this);
5305         }
5306 
5307         TOML_CONST_INLINE_GETTER
5308         const value<double>* as_floating_point() const noexcept final
5309         {
5310             return as_value<double>(this);
5311         }
5312 
5313         TOML_CONST_INLINE_GETTER
5314         const value<bool>* as_boolean() const noexcept final
5315         {
5316             return as_value<bool>(this);
5317         }
5318 
5319         TOML_CONST_INLINE_GETTER
5320         const value<date>* as_date() const noexcept final
5321         {
5322             return as_value<date>(this);
5323         }
5324 
5325         TOML_CONST_INLINE_GETTER
5326         const value<time>* as_time() const noexcept final
5327         {
5328             return as_value<time>(this);
5329         }
5330 
5331         TOML_CONST_INLINE_GETTER
5332         const value<date_time>* as_date_time() const noexcept final
5333         {
5334             return as_value<date_time>(this);
5335         }
5336 
5337         TOML_PURE_INLINE_GETTER
5338         value_type& get() & noexcept
5339         {
5340             return val_;
5341         }
5342 
5343         TOML_PURE_INLINE_GETTER
5344         value_type&& get() && noexcept
5345         {
5346             return static_cast<value_type&&>(val_);
5347         }
5348 
5349         TOML_PURE_INLINE_GETTER
5350         const value_type& get() const& noexcept
5351         {
5352             return val_;
5353         }
5354 
5355         TOML_PURE_INLINE_GETTER
5356         const value_type&& get() const&& noexcept
5357         {
5358             return static_cast<const value_type&&>(val_);
5359         }
5360 
5361         TOML_PURE_INLINE_GETTER
5362         value_type& operator*() & noexcept
5363         {
5364             return val_;
5365         }
5366 
5367         TOML_PURE_INLINE_GETTER
5368         value_type&& operator*() && noexcept
5369         {
5370             return static_cast<value_type&&>(val_);
5371         }
5372 
5373         TOML_PURE_INLINE_GETTER
5374         const value_type& operator*() const& noexcept
5375         {
5376             return val_;
5377         }
5378 
5379         TOML_PURE_INLINE_GETTER
5380         const value_type&& operator*() const&& noexcept
5381         {
5382             return static_cast<const value_type&&>(val_);
5383         }
5384 
5385         TOML_PURE_INLINE_GETTER
5386         explicit operator value_type&() & noexcept
5387         {
5388             return val_;
5389         }
5390 
5391         TOML_PURE_INLINE_GETTER
5392         explicit operator value_type&&() && noexcept
5393         {
5394             return static_cast<value_type&&>(val_);
5395         }
5396 
5397         TOML_PURE_INLINE_GETTER
5398         explicit operator const value_type&() const& noexcept
5399         {
5400             return val_;
5401         }
5402 
5403         TOML_PURE_INLINE_GETTER
5404         explicit operator const value_type&&() && noexcept
5405         {
5406             return static_cast<const value_type&&>(val_);
5407         }
5408 
5409         TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
5410         TOML_PURE_INLINE_GETTER
5411         value_type* operator->() noexcept
5412         {
5413             return &val_;
5414         }
5415 
5416         TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
5417         TOML_PURE_INLINE_GETTER
5418         const value_type* operator->() const noexcept
5419         {
5420             return &val_;
5421         }
5422 
5423         TOML_NODISCARD
5424         value_flags flags() const noexcept
5425         {
5426             return flags_;
5427         }
5428 
5429         value& flags(value_flags new_flags) noexcept
5430         {
5431             flags_ = new_flags;
5432             return *this;
5433         }
5434 
5435         value& operator=(value_arg rhs) noexcept
5436         {
5437             if constexpr (std::is_same_v<value_type, std::string>)
5438                 val_.assign(rhs);
5439             else
5440                 val_ = rhs;
5441             return *this;
5442         }
5443 
5444         TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type)
5445         value& operator=(std::string&& rhs) noexcept
5446         {
5447             val_ = std::move(rhs);
5448             return *this;
5449         }
5450 
5451         TOML_PURE_GETTER
5452         friend bool operator==(const value& lhs, value_arg rhs) noexcept
5453         {
5454             if constexpr (std::is_same_v<value_type, double>)
5455             {
5456                 const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan;
5457                 const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan;
5458                 if (lhs_nan != rhs_nan)
5459                     return false;
5460                 if (lhs_nan)
5461                     return true;
5462             }
5463             return lhs.val_ == rhs;
5464         }
5465         TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, );
5466 
5467         TOML_PURE_GETTER
5468         friend bool operator<(const value& lhs, value_arg rhs) noexcept
5469         {
5470             return lhs.val_ < rhs;
5471         }
5472 
5473         TOML_PURE_GETTER
5474         friend bool operator<(value_arg lhs, const value& rhs) noexcept
5475         {
5476             return lhs < rhs.val_;
5477         }
5478 
5479         TOML_PURE_GETTER
5480         friend bool operator<=(const value& lhs, value_arg rhs) noexcept
5481         {
5482             return lhs.val_ <= rhs;
5483         }
5484 
5485         TOML_PURE_GETTER
5486         friend bool operator<=(value_arg lhs, const value& rhs) noexcept
5487         {
5488             return lhs <= rhs.val_;
5489         }
5490 
5491         TOML_PURE_GETTER
5492         friend bool operator>(const value& lhs, value_arg rhs) noexcept
5493         {
5494             return lhs.val_ > rhs;
5495         }
5496 
5497         TOML_PURE_GETTER
5498         friend bool operator>(value_arg lhs, const value& rhs) noexcept
5499         {
5500             return lhs > rhs.val_;
5501         }
5502 
5503         TOML_PURE_GETTER
5504         friend bool operator>=(const value& lhs, value_arg rhs) noexcept
5505         {
5506             return lhs.val_ >= rhs;
5507         }
5508 
5509         TOML_PURE_GETTER
5510         friend bool operator>=(value_arg lhs, const value& rhs) noexcept
5511         {
5512             return lhs >= rhs.val_;
5513         }
5514 
5515         template <typename T>
5516         TOML_PURE_GETTER
5517         friend bool operator==(const value& lhs, const value<T>& rhs) noexcept
5518         {
5519             if constexpr (std::is_same_v<value_type, T>)
5520                 return lhs == rhs.val_; // calls asymmetrical value-equality operator defined above
5521             else
5522                 return false;
5523         }
5524 
5525         template <typename T>
5526         TOML_PURE_INLINE_GETTER
5527         friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept
5528         {
5529             return !(lhs == rhs);
5530         }
5531 
5532         template <typename T>
5533         TOML_PURE_GETTER
5534         friend bool operator<(const value& lhs, const value<T>& rhs) noexcept
5535         {
5536             if constexpr (std::is_same_v<value_type, T>)
5537                 return lhs.val_ < rhs.val_;
5538             else
5539                 return impl::node_type_of<value_type> < impl::node_type_of<T>;
5540         }
5541 
5542         template <typename T>
5543         TOML_PURE_GETTER
5544         friend bool operator<=(const value& lhs, const value<T>& rhs) noexcept
5545         {
5546             if constexpr (std::is_same_v<value_type, T>)
5547                 return lhs.val_ <= rhs.val_;
5548             else
5549                 return impl::node_type_of<value_type> <= impl::node_type_of<T>;
5550         }
5551 
5552         template <typename T>
5553         TOML_PURE_GETTER
5554         friend bool operator>(const value& lhs, const value<T>& rhs) noexcept
5555         {
5556             if constexpr (std::is_same_v<value_type, T>)
5557                 return lhs.val_ > rhs.val_;
5558             else
5559                 return impl::node_type_of<value_type> > impl::node_type_of<T>;
5560         }
5561 
5562         template <typename T>
5563         TOML_PURE_GETTER
5564         friend bool operator>=(const value& lhs, const value<T>& rhs) noexcept
5565         {
5566             if constexpr (std::is_same_v<value_type, T>)
5567                 return lhs.val_ >= rhs.val_;
5568             else
5569                 return impl::node_type_of<value_type> >= impl::node_type_of<T>;
5570         }
5571 
5572 #if TOML_ENABLE_FORMATTERS
5573 
5574         friend std::ostream& operator<<(std::ostream& lhs, const value& rhs)
5575         {
5576             impl::print_to_stream(lhs, rhs);
5577             return lhs;
5578         }
5579 
5580 #endif
5581     };
5582 
5583     template <typename T>
5584     value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
5585     template <typename T>
5586     value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
5587 
5588     template <typename T>
5589     TOML_NODISCARD
5590     inline decltype(auto) node::get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
5591     {
5592         using namespace impl;
5593 
5594         static_assert(node_type_of<T> != node_type::none);
5595         static_assert(node_type_of<T> != node_type::table);
5596         static_assert(node_type_of<T> != node_type::array);
5597         static_assert(is_native<T> || can_represent_native<T>);
5598         static_assert(!is_cvref<T>);
5599         TOML_ASSERT(this->type() == node_type_of<T>);
5600 
5601         if constexpr (node_type_of<T> == node_type::string)
5602         {
5603             const auto& str = *ref_cast<std::string>();
5604             if constexpr (std::is_same_v<T, std::string>)
5605                 return str;
5606             else if constexpr (std::is_same_v<T, std::string_view>)
5607                 return T{ str };
5608             else if constexpr (std::is_same_v<T, const char*>)
5609                 return str.c_str();
5610 
5611             else if constexpr (std::is_same_v<T, std::wstring>)
5612             {
5613 #if TOML_ENABLE_WINDOWS_COMPAT
5614                 return widen(str);
5615 #else
5616                 static_assert(always_false<T>, "Evaluated unreachable branch!");
5617 #endif
5618             }
5619 
5620 #if TOML_HAS_CHAR8
5621 
5622             // char -> char8_t (potentially unsafe - the feature is 'experimental'!)
5623             else if constexpr (is_one_of<T, std::u8string, std::u8string_view>)
5624                 return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length());
5625             else if constexpr (std::is_same_v<T, const char8_t*>)
5626                 return reinterpret_cast<const char8_t*>(str.c_str());
5627             else
5628                 static_assert(always_false<T>, "Evaluated unreachable branch!");
5629 
5630 #endif
5631         }
5632         else
5633             return static_cast<T>(*ref_cast<native_type_of<T>>());
5634     }
5635 
5636     template <typename T>
5637     TOML_NODISCARD
5638     inline optional<T> node::value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
5639     {
5640         using namespace impl;
5641 
5642         static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
5643                       "Retrieving values as wide-character strings with node::value_exact() is only "
5644                       "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5645 
5646         static_assert((is_native<T> || can_represent_native<T>) && !is_cvref<T>,
5647                       TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()"));
5648 
5649         // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
5650         if constexpr ((is_native<T> || can_represent_native<T>) && !is_cvref<T>)
5651         {
5652             if (type() == node_type_of<T>)
5653                 return { this->get_value_exact<T>() };
5654             else
5655                 return {};
5656         }
5657     }
5658 
5659     template <typename T>
5660     TOML_NODISCARD
5661     inline optional<T> node::value() const noexcept(impl::value_retrieval_is_nothrow<T>)
5662     {
5663         using namespace impl;
5664 
5665         static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
5666                       "Retrieving values as wide-character strings with node::value() is only "
5667                       "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5668         static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
5669                       TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
5670 
5671         // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
5672         // semantics to be mindful of so the exact retrieval is enough.
5673         if constexpr (is_natively_one_of<T, std::string, time, date, date_time>)
5674         {
5675             if (type() == node_type_of<T>)
5676                 return { this->get_value_exact<T>() };
5677             else
5678                 return {};
5679         }
5680 
5681         // everything else requires a bit of logicking.
5682         else
5683         {
5684             switch (type())
5685             {
5686                 // int -> *
5687                 case node_type::integer:
5688                 {
5689                     // int -> int
5690                     if constexpr (is_natively_one_of<T, int64_t>)
5691                     {
5692                         if constexpr (is_native<T> || can_represent_native<T>)
5693                             return static_cast<T>(*ref_cast<int64_t>());
5694                         else
5695                             return node_integer_cast<T>(*ref_cast<int64_t>());
5696                     }
5697 
5698                     // int -> float
5699                     else if constexpr (is_natively_one_of<T, double>)
5700                     {
5701                         const int64_t val = *ref_cast<int64_t>();
5702                         if constexpr (std::numeric_limits<T>::digits < 64)
5703                         {
5704                             constexpr auto largest_whole_float = (int64_t{ 1 } << std::numeric_limits<T>::digits);
5705                             if (val < -largest_whole_float || val > largest_whole_float)
5706                                 return {};
5707                         }
5708                         return static_cast<T>(val);
5709                     }
5710 
5711                     // int -> bool
5712                     else if constexpr (is_natively_one_of<T, bool>)
5713                         return static_cast<bool>(*ref_cast<int64_t>());
5714 
5715                     // int -> anything else
5716                     else
5717                         return {};
5718                 }
5719 
5720                 // float -> *
5721                 case node_type::floating_point:
5722                 {
5723                     // float -> float
5724                     if constexpr (is_natively_one_of<T, double>)
5725                     {
5726                         if constexpr (is_native<T> || can_represent_native<T>)
5727                             return { static_cast<T>(*ref_cast<double>()) };
5728                         else
5729                         {
5730                             const double val = *ref_cast<double>();
5731                             if (impl::fpclassify(val) == fp_class::ok
5732                                 && (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)()))
5733                                 return {};
5734                             return { static_cast<T>(val) };
5735                         }
5736                     }
5737 
5738                     // float -> int
5739                     else if constexpr (is_natively_one_of<T, int64_t>)
5740                     {
5741                         const double val = *ref_cast<double>();
5742                         if (impl::fpclassify(val) == fp_class::ok
5743                             && static_cast<double>(static_cast<int64_t>(val)) == val)
5744                             return node_integer_cast<T>(static_cast<int64_t>(val));
5745                         else
5746                             return {};
5747                     }
5748 
5749                     // float -> anything else
5750                     else
5751                         return {};
5752                 }
5753 
5754                 // bool -> *
5755                 case node_type::boolean:
5756                 {
5757                     // bool -> bool
5758                     if constexpr (is_natively_one_of<T, bool>)
5759                         return { *ref_cast<bool>() };
5760 
5761                     // bool -> int
5762                     else if constexpr (is_natively_one_of<T, int64_t>)
5763                         return { static_cast<T>(*ref_cast<bool>()) };
5764 
5765                     // bool -> anything else
5766                     else
5767                         return {};
5768                 }
5769             }
5770 
5771             // non-values, or 'exact' types covered above
5772             return {};
5773         }
5774     }
5775 
5776     template <typename T>
5777     TOML_NODISCARD
5778     inline auto node::value_or(T && default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
5779     {
5780         using namespace impl;
5781 
5782         static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
5783                       "Retrieving values as wide-character strings with node::value_or() is only "
5784                       "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5785 
5786         if constexpr (is_wide_string<T>)
5787         {
5788 #if TOML_ENABLE_WINDOWS_COMPAT
5789 
5790             if (type() == node_type::string)
5791                 return widen(*ref_cast<std::string>());
5792             return std::wstring{ static_cast<T&&>(default_value) };
5793 
5794 #else
5795 
5796             static_assert(always_false<T>, "Evaluated unreachable branch!");
5797 
5798 #endif
5799         }
5800         else
5801         {
5802             using value_type =
5803                 std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
5804                                    std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
5805                                    std::decay_t<T>>;
5806             using traits = value_traits<value_type>;
5807 
5808             // clang-format off
5809 
5810             static_assert(
5811                 traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
5812                 "The default value type of node::value_or() must be one of:"
5813                 TOML_SA_LIST_NEW "A native TOML value type"
5814                 TOML_SA_NATIVE_VALUE_TYPE_LIST
5815 
5816                 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
5817                 TOML_SA_LIST_BEG "std::string"
5818                 #if TOML_ENABLE_WINDOWS_COMPAT
5819                 TOML_SA_LIST_SEP "std::wstring"
5820                 #endif
5821                 TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
5822                 TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
5823                 TOML_SA_LIST_END
5824 
5825                 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
5826                 TOML_SA_LIST_BEG "any other integral type"
5827                 TOML_SA_LIST_SEP "any floating-point type"
5828                 TOML_SA_LIST_END
5829 
5830                 TOML_SA_LIST_NXT "A compatible view type"
5831                 TOML_SA_LIST_BEG "std::string_view"
5832                 #if TOML_HAS_CHAR8
5833                 TOML_SA_LIST_SEP "std::u8string_view"
5834                 #endif
5835                 #if TOML_ENABLE_WINDOWS_COMPAT
5836                 TOML_SA_LIST_SEP "std::wstring_view"
5837                 #endif
5838                 TOML_SA_LIST_SEP "const char*"
5839                 #if TOML_HAS_CHAR8
5840                 TOML_SA_LIST_SEP "const char8_t*"
5841                 #endif
5842                 #if TOML_ENABLE_WINDOWS_COMPAT
5843                 TOML_SA_LIST_SEP "const wchar_t*"
5844                 #endif
5845                 TOML_SA_LIST_END
5846             );
5847 
5848             // clang-format on
5849 
5850             // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
5851             if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
5852             {
5853                 if constexpr (traits::is_native)
5854                 {
5855                     if (type() == node_type_of<value_type>)
5856                         return *ref_cast<typename traits::native_type>();
5857                 }
5858                 if (auto val = this->value<value_type>())
5859                     return *val;
5860                 if constexpr (std::is_pointer_v<value_type>)
5861                     return value_type{ default_value };
5862                 else
5863                     return static_cast<T&&>(default_value);
5864             }
5865         }
5866     }
5867 }
5868 TOML_NAMESPACE_END;
5869 
5870 #ifdef _MSC_VER
5871 #pragma pop_macro("min")
5872 #pragma pop_macro("max")
5873 #ifndef __clang__
5874 #pragma inline_recursion(off)
5875 #endif
5876 #endif
5877 TOML_POP_WARNINGS;
5878 
5879 //********  impl/make_node.hpp  ****************************************************************************************
5880 
5881 TOML_PUSH_WARNINGS;
5882 #ifdef _MSC_VER
5883 #ifndef __clang__
5884 #pragma inline_recursion(on)
5885 #endif
5886 #pragma push_macro("min")
5887 #pragma push_macro("max")
5888 #undef min
5889 #undef max
5890 #endif
5891 
5892 TOML_IMPL_NAMESPACE_START
5893 {
5894     template <typename T>
5895     TOML_NODISCARD
5896     TOML_ATTR(returns_nonnull)
5897     auto* make_node_impl_specialized(T && val, [[maybe_unused]] value_flags flags)
5898     {
5899         using unwrapped_type = unwrap_node<remove_cvref<T>>;
5900         static_assert(!std::is_same_v<unwrapped_type, node>);
5901         static_assert(!is_node_view<unwrapped_type>);
5902 
5903         // arrays + tables - invoke copy/move ctor
5904         if constexpr (is_one_of<unwrapped_type, array, table>)
5905         {
5906             return new unwrapped_type(static_cast<T&&>(val));
5907         }
5908 
5909         // values
5910         else
5911         {
5912             using native_type = native_type_of<unwrapped_type>;
5913             using value_type  = value<native_type>;
5914 
5915             value_type* out;
5916 
5917             // copy/move ctor
5918             if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
5919             {
5920                 out = new value_type{ static_cast<T&&>(val), flags };
5921             }
5922 
5923             // creating from raw value
5924             else
5925             {
5926                 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
5927                               "Instantiating values from wide-character strings is only "
5928                               "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
5929 
5930                 if constexpr (!is_losslessly_convertible_to_native<unwrapped_type>)
5931                 {
5932                     if constexpr (std::is_same_v<native_type, int64_t>)
5933                         static_assert(always_false<T>,
5934                                       "Integral value initializers must be losslessly convertible to int64_t");
5935                     else if constexpr (std::is_same_v<native_type, double>)
5936                         static_assert(always_false<T>,
5937                                       "Floating-point value initializers must be losslessly convertible to double");
5938                     else
5939                         static_assert(
5940                             always_false<T>,
5941                             "Value initializers must be losslessly convertible to one of the TOML value types");
5942                 }
5943 
5944                 if constexpr (is_wide_string<T>)
5945                 {
5946 #if TOML_ENABLE_WINDOWS_COMPAT
5947                     out = new value_type{ narrow(static_cast<T&&>(val)) };
5948 #else
5949                     static_assert(always_false<T>, "Evaluated unreachable branch!");
5950 #endif
5951                 }
5952                 else
5953                     out = new value_type{ static_cast<T&&>(val) };
5954 
5955                 if (flags != preserve_source_value_flags)
5956                     out->flags(flags);
5957             }
5958 
5959             return out;
5960         }
5961     }
5962 
5963     template <typename T>
5964     TOML_NODISCARD
5965     auto* make_node_impl(T && val, value_flags flags = preserve_source_value_flags)
5966     {
5967         using unwrapped_type = unwrap_node<remove_cvref<T>>;
5968         if constexpr (std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>)
5969         {
5970             if constexpr (is_node_view<unwrapped_type>)
5971             {
5972                 if (!val)
5973                     return static_cast<toml::node*>(nullptr);
5974             }
5975 
5976             return static_cast<T&&>(val).visit(
5977                 [flags](auto&& concrete) {
5978                     return static_cast<toml::node*>(
5979                         make_node_impl_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
5980                 });
5981         }
5982         else
5983             return make_node_impl_specialized(static_cast<T&&>(val), flags);
5984     }
5985 
5986     template <typename T>
5987     TOML_NODISCARD
5988     auto* make_node_impl(inserter<T> && val, value_flags flags = preserve_source_value_flags)
5989     {
5990         return make_node_impl(static_cast<T&&>(val.value), flags);
5991     }
5992 
5993     template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
5994     struct inserted_type_of_
5995     {
5996         using type = std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
5997     };
5998 
5999     template <typename T>
6000     struct inserted_type_of_<inserter<T>, false>
6001     {
6002         using type = typename inserted_type_of_<remove_cvref<T>>::type;
6003     };
6004 
6005     template <typename T>
6006     struct inserted_type_of_<T, false>
6007     {
6008         using type = void;
6009     };
6010 
6011     template <typename T>
6012     TOML_NODISCARD
6013     node_ptr make_node(T && val, value_flags flags = preserve_source_value_flags)
6014     {
6015         return node_ptr{ make_node_impl(static_cast<T&&>(val), flags) };
6016     }
6017 
6018     template <typename... T>
6019     struct emplaced_type_of_
6020     {
6021         using type = void;
6022     };
6023 
6024     template <typename T>
6025     struct emplaced_type_of_<T>
6026     {
6027         using type = std::conditional_t<is_one_of<T, node, node_view<node>, node_view<const node>>,
6028                                         void,
6029                                         typename inserted_type_of_<T>::type>;
6030     };
6031 
6032     template <typename T>
6033     struct emplaced_type_of_<inserter<T>>
6034     {
6035         using type = typename emplaced_type_of_<remove_cvref<T>>::type;
6036     };
6037 
6038     template <typename... T>
6039     using emplaced_type_of = typename emplaced_type_of_<remove_cvref<T>...>::type;
6040 }
6041 TOML_IMPL_NAMESPACE_END;
6042 
6043 TOML_NAMESPACE_START
6044 {
6045     template <typename T>
6046     using inserted_type_of = POXY_IMPLEMENTATION_DETAIL(typename impl::inserted_type_of_<impl::remove_cvref<T>>::type);
6047 }
6048 TOML_NAMESPACE_END;
6049 
6050 #ifdef _MSC_VER
6051 #pragma pop_macro("min")
6052 #pragma pop_macro("max")
6053 #ifndef __clang__
6054 #pragma inline_recursion(off)
6055 #endif
6056 #endif
6057 TOML_POP_WARNINGS;
6058 
6059 //********  impl/array.hpp  ********************************************************************************************
6060 
6061 TOML_PUSH_WARNINGS;
6062 #ifdef _MSC_VER
6063 #ifndef __clang__
6064 #pragma inline_recursion(on)
6065 #endif
6066 #pragma push_macro("min")
6067 #pragma push_macro("max")
6068 #undef min
6069 #undef max
6070 #endif
6071 
6072 #ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
6073 #if TOML_GCC && TOML_GCC <= 7
6074 #define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1
6075 #else
6076 #define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0
6077 #endif
6078 #endif
6079 
6080 #if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
6081 #define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE                                                                  \
6082     "If you're seeing this error it's because you're using one of toml++'s for_each() functions on a compiler with "   \
6083     "known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or bool-convertible) value from the "  \
6084     "for_each() callable causes spurious compilation failures, while returning nothing (void) works fine. "            \
6085     "If you believe this message is incorrect for your compiler, you can try your luck by #defining "                  \
6086     "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know at "                 \
6087     "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for early-exiting from " \
6088     "for_each(), you can suppress this error by #defining TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED "         \
6089     "and moving on with your life."
6090 #endif
6091 
6092 TOML_IMPL_NAMESPACE_START
6093 {
6094     template <bool IsConst>
6095     class TOML_TRIVIAL_ABI array_iterator
6096     {
6097       private:
6098         template <bool>
6099         friend class array_iterator;
6100 
6101         using mutable_vector_iterator = std::vector<node_ptr>::iterator;
6102         using const_vector_iterator   = std::vector<node_ptr>::const_iterator;
6103         using vector_iterator         = std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
6104 
6105         mutable vector_iterator iter_;
6106 
6107       public:
6108         using value_type        = std::conditional_t<IsConst, const node, node>;
6109         using reference         = value_type&;
6110         using pointer           = value_type*;
6111         using difference_type   = ptrdiff_t;
6112         using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;
6113 
6114         TOML_NODISCARD_CTOR
6115         array_iterator() noexcept = default;
6116 
6117         TOML_NODISCARD_CTOR
6118         explicit array_iterator(mutable_vector_iterator iter) noexcept //
6119             : iter_{ iter }
6120         {}
6121 
6122         TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
6123         TOML_NODISCARD_CTOR
6124         explicit array_iterator(const_vector_iterator iter) noexcept //
6125             : iter_{ iter }
6126         {}
6127 
6128         TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
6129         TOML_NODISCARD_CTOR
6130         array_iterator(const array_iterator<false>& other) noexcept //
6131             : iter_{ other.iter_ }
6132         {}
6133 
6134         TOML_NODISCARD_CTOR
6135         array_iterator(const array_iterator&) noexcept = default;
6136 
6137         array_iterator& operator=(const array_iterator&) noexcept = default;
6138 
6139         array_iterator& operator++() noexcept // ++pre
6140         {
6141             ++iter_;
6142             return *this;
6143         }
6144 
6145         array_iterator operator++(int) noexcept // post++
6146         {
6147             array_iterator out{ iter_ };
6148             ++iter_;
6149             return out;
6150         }
6151 
6152         array_iterator& operator--() noexcept // --pre
6153         {
6154             --iter_;
6155             return *this;
6156         }
6157 
6158         array_iterator operator--(int) noexcept // post--
6159         {
6160             array_iterator out{ iter_ };
6161             --iter_;
6162             return out;
6163         }
6164 
6165         TOML_PURE_INLINE_GETTER
6166         reference operator*() const noexcept
6167         {
6168             return *iter_->get();
6169         }
6170 
6171         TOML_PURE_INLINE_GETTER
6172         pointer operator->() const noexcept
6173         {
6174             return iter_->get();
6175         }
6176 
6177         TOML_PURE_INLINE_GETTER
6178         explicit operator const vector_iterator&() const noexcept
6179         {
6180             return iter_;
6181         }
6182 
6183         TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
6184         TOML_PURE_INLINE_GETTER
6185         explicit operator const const_vector_iterator() const noexcept
6186         {
6187             return iter_;
6188         }
6189 
6190         array_iterator& operator+=(ptrdiff_t rhs) noexcept
6191         {
6192             iter_ += rhs;
6193             return *this;
6194         }
6195 
6196         array_iterator& operator-=(ptrdiff_t rhs) noexcept
6197         {
6198             iter_ -= rhs;
6199             return *this;
6200         }
6201 
6202         TOML_NODISCARD
6203         friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept
6204         {
6205             return array_iterator{ lhs.iter_ + rhs };
6206         }
6207 
6208         TOML_NODISCARD
6209         friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept
6210         {
6211             return array_iterator{ rhs.iter_ + lhs };
6212         }
6213 
6214         TOML_NODISCARD
6215         friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept
6216         {
6217             return array_iterator{ lhs.iter_ - rhs };
6218         }
6219 
6220         TOML_PURE_INLINE_GETTER
6221         friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept
6222         {
6223             return lhs.iter_ - rhs.iter_;
6224         }
6225 
6226         TOML_PURE_INLINE_GETTER
6227         friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept
6228         {
6229             return lhs.iter_ == rhs.iter_;
6230         }
6231 
6232         TOML_PURE_INLINE_GETTER
6233         friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept
6234         {
6235             return lhs.iter_ != rhs.iter_;
6236         }
6237 
6238         TOML_PURE_INLINE_GETTER
6239         friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept
6240         {
6241             return lhs.iter_ < rhs.iter_;
6242         }
6243 
6244         TOML_PURE_INLINE_GETTER
6245         friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept
6246         {
6247             return lhs.iter_ <= rhs.iter_;
6248         }
6249 
6250         TOML_PURE_INLINE_GETTER
6251         friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept
6252         {
6253             return lhs.iter_ > rhs.iter_;
6254         }
6255 
6256         TOML_PURE_INLINE_GETTER
6257         friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept
6258         {
6259             return lhs.iter_ >= rhs.iter_;
6260         }
6261 
6262         TOML_PURE_INLINE_GETTER
6263         reference operator[](ptrdiff_t idx) const noexcept
6264         {
6265             return *(iter_ + idx)->get();
6266         }
6267     };
6268 
6269     struct array_init_elem
6270     {
6271         mutable node_ptr value;
6272 
6273         template <typename T>
6274         TOML_NODISCARD_CTOR
6275         array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) //
6276             : value{ make_node(static_cast<T&&>(val), flags) }
6277         {}
6278     };
6279 }
6280 TOML_IMPL_NAMESPACE_END;
6281 
6282 TOML_NAMESPACE_START
6283 {
6284     using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);
6285 
6286     using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);
6287 
6288     class TOML_EXPORTED_CLASS array : public node
6289     {
6290       private:
6291 
6292         using vector_type           = std::vector<impl::node_ptr>;
6293         using vector_iterator       = typename vector_type::iterator;
6294         using const_vector_iterator = typename vector_type::const_iterator;
6295         vector_type elems_;
6296 
6297         TOML_NODISCARD_CTOR
6298         TOML_EXPORTED_MEMBER_FUNCTION
6299         array(const impl::array_init_elem*, const impl::array_init_elem*);
6300 
6301         TOML_NODISCARD_CTOR
6302         array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
6303             : array{ elems.begin(), elems.end() }
6304         {}
6305 
6306         TOML_EXPORTED_MEMBER_FUNCTION
6307         void preinsertion_resize(size_t idx, size_t count);
6308 
6309         TOML_EXPORTED_MEMBER_FUNCTION
6310         void insert_at_back(impl::node_ptr&&);
6311 
6312         TOML_EXPORTED_MEMBER_FUNCTION
6313         vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&);
6314 
6315         template <typename T>
6316         void emplace_back_if_not_empty_view(T&& val, value_flags flags)
6317         {
6318             if constexpr (is_node_view<T>)
6319             {
6320                 if (!val)
6321                     return;
6322             }
6323             insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
6324         }
6325 
6326         TOML_NODISCARD
6327         TOML_EXPORTED_MEMBER_FUNCTION
6328         size_t total_leaf_count() const noexcept;
6329 
6330         TOML_EXPORTED_MEMBER_FUNCTION
6331         void flatten_child(array&& child, size_t& dest_index) noexcept;
6332 
6333       public:
6334         using value_type      = node;
6335         using size_type       = size_t;
6336         using difference_type = ptrdiff_t;
6337         using reference       = node&;
6338         using const_reference = const node&;
6339 
6340         TOML_NODISCARD_CTOR
6341         TOML_EXPORTED_MEMBER_FUNCTION
6342         array() noexcept;
6343 
6344         TOML_EXPORTED_MEMBER_FUNCTION
6345         ~array() noexcept;
6346 
6347         TOML_NODISCARD_CTOR
6348         TOML_EXPORTED_MEMBER_FUNCTION
6349         array(const array&);
6350 
6351         TOML_NODISCARD_CTOR
6352         TOML_EXPORTED_MEMBER_FUNCTION
6353         array(array&& other) noexcept;
6354 
6355         TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0 || !std::is_same_v<impl::remove_cvref<ElemType>, array>),
6356                                   typename ElemType,
6357                                   typename... ElemTypes)
6358         TOML_NODISCARD_CTOR
6359         explicit array(ElemType&& val, ElemTypes&&... vals)
6360             : array{ std::false_type{},
6361                      std::initializer_list<impl::array_init_elem>{ static_cast<ElemType&&>(val),
6362                                                                    static_cast<ElemTypes&&>(vals)... } }
6363         {}
6364 
6365         TOML_EXPORTED_MEMBER_FUNCTION
6366         array& operator=(const array&);
6367 
6368         TOML_EXPORTED_MEMBER_FUNCTION
6369         array& operator=(array&& rhs) noexcept;
6370 
6371         TOML_CONST_INLINE_GETTER
6372         node_type type() const noexcept final
6373         {
6374             return node_type::array;
6375         }
6376 
6377         TOML_PURE_GETTER
6378         TOML_EXPORTED_MEMBER_FUNCTION
6379         bool is_homogeneous(node_type ntype) const noexcept final;
6380 
6381         TOML_NODISCARD
6382         TOML_EXPORTED_MEMBER_FUNCTION
6383         bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;
6384 
6385         TOML_NODISCARD
6386         TOML_EXPORTED_MEMBER_FUNCTION
6387         bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;
6388 
6389         template <typename ElemType = void>
6390         TOML_PURE_GETTER
6391         bool is_homogeneous() const noexcept
6392         {
6393             using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
6394             static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
6395                           "The template type argument of array::is_homogeneous() must be void or one "
6396                           "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
6397 
6398             return is_homogeneous(impl::node_type_of<type>);
6399         }
6400         TOML_CONST_INLINE_GETTER
6401         bool is_table() const noexcept final
6402         {
6403             return false;
6404         }
6405 
6406         TOML_CONST_INLINE_GETTER
6407         bool is_array() const noexcept final
6408         {
6409             return true;
6410         }
6411 
6412         TOML_PURE_GETTER
6413         bool is_array_of_tables() const noexcept final
6414         {
6415             return is_homogeneous(node_type::table);
6416         }
6417 
6418         TOML_CONST_INLINE_GETTER
6419         bool is_value() const noexcept final
6420         {
6421             return false;
6422         }
6423 
6424         TOML_CONST_INLINE_GETTER
6425         bool is_string() const noexcept final
6426         {
6427             return false;
6428         }
6429 
6430         TOML_CONST_INLINE_GETTER
6431         bool is_integer() const noexcept final
6432         {
6433             return false;
6434         }
6435 
6436         TOML_CONST_INLINE_GETTER
6437         bool is_floating_point() const noexcept final
6438         {
6439             return false;
6440         }
6441 
6442         TOML_CONST_INLINE_GETTER
6443         bool is_number() const noexcept final
6444         {
6445             return false;
6446         }
6447 
6448         TOML_CONST_INLINE_GETTER
6449         bool is_boolean() const noexcept final
6450         {
6451             return false;
6452         }
6453 
6454         TOML_CONST_INLINE_GETTER
6455         bool is_date() const noexcept final
6456         {
6457             return false;
6458         }
6459 
6460         TOML_CONST_INLINE_GETTER
6461         bool is_time() const noexcept final
6462         {
6463             return false;
6464         }
6465 
6466         TOML_CONST_INLINE_GETTER
6467         bool is_date_time() const noexcept final
6468         {
6469             return false;
6470         }
6471 
6472         TOML_CONST_INLINE_GETTER
6473         table* as_table() noexcept final
6474         {
6475             return nullptr;
6476         }
6477 
6478         TOML_CONST_INLINE_GETTER
6479         array* as_array() noexcept final
6480         {
6481             return this;
6482         }
6483 
6484         TOML_CONST_INLINE_GETTER
6485         toml::value<std::string>* as_string() noexcept final
6486         {
6487             return nullptr;
6488         }
6489 
6490         TOML_CONST_INLINE_GETTER
6491         toml::value<int64_t>* as_integer() noexcept final
6492         {
6493             return nullptr;
6494         }
6495 
6496         TOML_CONST_INLINE_GETTER
6497         toml::value<double>* as_floating_point() noexcept final
6498         {
6499             return nullptr;
6500         }
6501 
6502         TOML_CONST_INLINE_GETTER
6503         toml::value<bool>* as_boolean() noexcept final
6504         {
6505             return nullptr;
6506         }
6507 
6508         TOML_CONST_INLINE_GETTER
6509         toml::value<date>* as_date() noexcept final
6510         {
6511             return nullptr;
6512         }
6513 
6514         TOML_CONST_INLINE_GETTER
6515         toml::value<time>* as_time() noexcept final
6516         {
6517             return nullptr;
6518         }
6519 
6520         TOML_CONST_INLINE_GETTER
6521         toml::value<date_time>* as_date_time() noexcept final
6522         {
6523             return nullptr;
6524         }
6525 
6526         TOML_CONST_INLINE_GETTER
6527         const table* as_table() const noexcept final
6528         {
6529             return nullptr;
6530         }
6531 
6532         TOML_CONST_INLINE_GETTER
6533         const array* as_array() const noexcept final
6534         {
6535             return this;
6536         }
6537 
6538         TOML_CONST_INLINE_GETTER
6539         const toml::value<std::string>* as_string() const noexcept final
6540         {
6541             return nullptr;
6542         }
6543 
6544         TOML_CONST_INLINE_GETTER
6545         const toml::value<int64_t>* as_integer() const noexcept final
6546         {
6547             return nullptr;
6548         }
6549 
6550         TOML_CONST_INLINE_GETTER
6551         const toml::value<double>* as_floating_point() const noexcept final
6552         {
6553             return nullptr;
6554         }
6555 
6556         TOML_CONST_INLINE_GETTER
6557         const toml::value<bool>* as_boolean() const noexcept final
6558         {
6559             return nullptr;
6560         }
6561 
6562         TOML_CONST_INLINE_GETTER
6563         const toml::value<date>* as_date() const noexcept final
6564         {
6565             return nullptr;
6566         }
6567 
6568         TOML_CONST_INLINE_GETTER
6569         const toml::value<time>* as_time() const noexcept final
6570         {
6571             return nullptr;
6572         }
6573 
6574         TOML_CONST_INLINE_GETTER
6575         const toml::value<date_time>* as_date_time() const noexcept final
6576         {
6577             return nullptr;
6578         }
6579 
6580         TOML_PURE_INLINE_GETTER
6581         node* get(size_t index) noexcept
6582         {
6583             return index < elems_.size() ? elems_[index].get() : nullptr;
6584         }
6585 
6586         TOML_PURE_INLINE_GETTER
6587         const node* get(size_t index) const noexcept
6588         {
6589             return const_cast<array&>(*this).get(index);
6590         }
6591 
6592         template <typename ElemType>
6593         TOML_NODISCARD
6594         impl::wrap_node<ElemType>* get_as(size_t index) noexcept
6595         {
6596             if (auto val = get(index))
6597                 return val->template as<ElemType>();
6598             return nullptr;
6599         }
6600 
6601         template <typename ElemType>
6602         TOML_NODISCARD
6603         const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
6604         {
6605             return const_cast<array&>(*this).template get_as<ElemType>(index);
6606         }
6607 
6608         using node::operator[]; // inherit operator[toml::path]
6609         TOML_NODISCARD
6610         node& operator[](size_t index) noexcept
6611         {
6612             return *elems_[index];
6613         }
6614 
6615         TOML_NODISCARD
6616         const node& operator[](size_t index) const noexcept
6617         {
6618             return *elems_[index];
6619         }
6620 
6621         TOML_NODISCARD
6622         TOML_EXPORTED_MEMBER_FUNCTION
6623         node& at(size_t index);
6624 
6625         TOML_NODISCARD
6626         const node& at(size_t index) const
6627         {
6628             return const_cast<array&>(*this).at(index);
6629         }
6630 
6631         TOML_NODISCARD
6632         node& front() noexcept
6633         {
6634             return *elems_.front();
6635         }
6636 
6637         TOML_NODISCARD
6638         const node& front() const noexcept
6639         {
6640             return *elems_.front();
6641         }
6642 
6643         TOML_NODISCARD
6644         node& back() noexcept
6645         {
6646             return *elems_.back();
6647         }
6648 
6649         TOML_NODISCARD
6650         const node& back() const noexcept
6651         {
6652             return *elems_.back();
6653         }
6654 
6655         using iterator = array_iterator;
6656 
6657         using const_iterator = const_array_iterator;
6658 
6659         TOML_NODISCARD
6660         iterator begin() noexcept
6661         {
6662             return iterator{ elems_.begin() };
6663         }
6664 
6665         TOML_NODISCARD
6666         const_iterator begin() const noexcept
6667         {
6668             return const_iterator{ elems_.cbegin() };
6669         }
6670 
6671         TOML_NODISCARD
6672         const_iterator cbegin() const noexcept
6673         {
6674             return const_iterator{ elems_.cbegin() };
6675         }
6676 
6677         TOML_NODISCARD
6678         iterator end() noexcept
6679         {
6680             return iterator{ elems_.end() };
6681         }
6682 
6683         TOML_NODISCARD
6684         const_iterator end() const noexcept
6685         {
6686             return const_iterator{ elems_.cend() };
6687         }
6688 
6689         TOML_NODISCARD
6690         const_iterator cend() const noexcept
6691         {
6692             return const_iterator{ elems_.cend() };
6693         }
6694 
6695       private:
6696 
6697         template <typename T, typename Array>
6698         using for_each_elem_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;
6699 
6700         template <typename Func, typename Array, typename T>
6701         using can_for_each = std::disjunction<std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
6702                                               std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
6703                                               std::is_invocable<Func, for_each_elem_ref<T, Array>>>;
6704 
6705         template <typename Func, typename Array, typename T>
6706         using can_for_each_nothrow = std::conditional_t<
6707             // first form
6708             std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
6709             std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
6710             std::conditional_t<
6711                 // second form
6712                 std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
6713                 std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
6714                 std::conditional_t<
6715                     // third form
6716                     std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
6717                     std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>,
6718                     std::false_type>>>;
6719 
6720         template <typename Func, typename Array>
6721         using can_for_each_any = std::disjunction<can_for_each<Func, Array, table>,
6722                                                   can_for_each<Func, Array, array>,
6723                                                   can_for_each<Func, Array, std::string>,
6724                                                   can_for_each<Func, Array, int64_t>,
6725                                                   can_for_each<Func, Array, double>,
6726                                                   can_for_each<Func, Array, bool>,
6727                                                   can_for_each<Func, Array, date>,
6728                                                   can_for_each<Func, Array, time>,
6729                                                   can_for_each<Func, Array, date_time>>;
6730 
6731         template <typename Func, typename Array, typename T>
6732         using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Array, T>>, //
6733                                                          can_for_each_nothrow<Func, Array, T>>;
6734 
6735         template <typename Func, typename Array>
6736         using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Array, table>,
6737                                                      for_each_is_nothrow_one<Func, Array, array>,
6738                                                      for_each_is_nothrow_one<Func, Array, std::string>,
6739                                                      for_each_is_nothrow_one<Func, Array, int64_t>,
6740                                                      for_each_is_nothrow_one<Func, Array, double>,
6741                                                      for_each_is_nothrow_one<Func, Array, bool>,
6742                                                      for_each_is_nothrow_one<Func, Array, date>,
6743                                                      for_each_is_nothrow_one<Func, Array, time>,
6744                                                      for_each_is_nothrow_one<Func, Array, date_time>>;
6745 
6746         template <typename Func, typename Array>
6747         static void do_for_each(Func&& visitor, Array&& arr) //
6748             noexcept(for_each_is_nothrow<Func&&, Array&&>::value)
6749         {
6750             static_assert(can_for_each_any<Func&&, Array&&>::value,
6751                           "TOML array for_each visitors must be invocable for at least one of the toml::node "
6752                           "specializations:" TOML_SA_NODE_TYPE_LIST);
6753 
6754             for (size_t i = 0; i < arr.size(); i++)
6755             {
6756                 using node_ref = impl::copy_cvref<toml::node, Array&&>;
6757                 static_assert(std::is_reference_v<node_ref>);
6758 
6759 #if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
6760 
6761 #ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
6762                 static_assert(impl::always_false<Func, Array, node_ref>, //
6763                               TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
6764 #endif
6765 
6766                 static_cast<node_ref>(static_cast<Array&&>(arr)[i])
6767                     .visit(
6768                         [&]([[maybe_unused]] auto&& elem) //
6769                         noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
6770                         {
6771                             using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
6772                             static_assert(std::is_reference_v<elem_ref>);
6773 
6774                             // func(elem, i)
6775                             if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
6776                             {
6777                                 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
6778                             }
6779 
6780                             // func(i, elem)
6781                             else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
6782                             {
6783                                 static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
6784                             }
6785 
6786                             // func(elem)
6787                             else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
6788                             {
6789                                 static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
6790                             }
6791                         });
6792 
6793 #else
6794                 const auto keep_going =
6795                     static_cast<node_ref>(static_cast<Array&&>(arr)[i])
6796                         .visit(
6797                             [&]([[maybe_unused]] auto&& elem) //
6798                             noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
6799                             {
6800                                 using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
6801                                 static_assert(std::is_reference_v<elem_ref>);
6802 
6803                                 // func(elem, i)
6804                                 if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
6805                                 {
6806                                     using return_type =
6807                                         decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
6808 
6809                                     if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
6810                                     {
6811                                         return static_cast<bool>(
6812                                             static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
6813                                     }
6814                                     else
6815                                     {
6816                                         static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
6817                                         return true;
6818                                     }
6819                                 }
6820 
6821                                 // func(i, elem)
6822                                 else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
6823                                 {
6824                                     using return_type =
6825                                         decltype(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
6826 
6827                                     if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
6828                                     {
6829                                         return static_cast<bool>(
6830                                             static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
6831                                     }
6832                                     else
6833                                     {
6834                                         static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
6835                                         return true;
6836                                     }
6837                                 }
6838 
6839                                 // func(elem)
6840                                 else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
6841                                 {
6842                                     using return_type =
6843                                         decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
6844 
6845                                     if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
6846                                     {
6847                                         return static_cast<bool>(
6848                                             static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
6849                                     }
6850                                     else
6851                                     {
6852                                         static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
6853                                         return true;
6854                                     }
6855                                 }
6856 
6857                                 // visitor not compatible with this particular type
6858                                 else
6859                                     return true;
6860                             });
6861 
6862                 if (!keep_going)
6863                     return;
6864 #endif
6865             }
6866         }
6867 
6868       public:
6869 
6870         template <typename Func>
6871         array& for_each(Func&& visitor) & //
6872             noexcept(for_each_is_nothrow<Func&&, array&>::value)
6873         {
6874             do_for_each(static_cast<Func&&>(visitor), *this);
6875             return *this;
6876         }
6877 
6878         template <typename Func>
6879         array&& for_each(Func&& visitor) && //
6880             noexcept(for_each_is_nothrow<Func&&, array&&>::value)
6881         {
6882             do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
6883             return static_cast<array&&>(*this);
6884         }
6885 
6886         template <typename Func>
6887         const array& for_each(Func&& visitor) const& //
6888             noexcept(for_each_is_nothrow<Func&&, const array&>::value)
6889         {
6890             do_for_each(static_cast<Func&&>(visitor), *this);
6891             return *this;
6892         }
6893 
6894         template <typename Func>
6895         const array&& for_each(Func&& visitor) const&& //
6896             noexcept(for_each_is_nothrow<Func&&, const array&&>::value)
6897         {
6898             do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
6899             return static_cast<const array&&>(*this);
6900         }
6901 
6902         TOML_NODISCARD
6903         bool empty() const noexcept
6904         {
6905             return elems_.empty();
6906         }
6907 
6908         TOML_NODISCARD
6909         size_t size() const noexcept
6910         {
6911             return elems_.size();
6912         }
6913 
6914         TOML_NODISCARD
6915         size_t max_size() const noexcept
6916         {
6917             return elems_.max_size();
6918         }
6919 
6920         TOML_NODISCARD
6921         size_t capacity() const noexcept
6922         {
6923             return elems_.capacity();
6924         }
6925 
6926         TOML_EXPORTED_MEMBER_FUNCTION
6927         void reserve(size_t new_capacity);
6928 
6929         TOML_EXPORTED_MEMBER_FUNCTION
6930         void shrink_to_fit();
6931 
6932         TOML_EXPORTED_MEMBER_FUNCTION
6933         void truncate(size_t new_size);
6934 
6935         template <typename ElemType>
6936         void resize(size_t new_size,
6937                     ElemType&& default_init_val,
6938                     value_flags default_init_flags = preserve_source_value_flags)
6939         {
6940             static_assert(!is_node_view<ElemType>,
6941                           "The default element type argument to toml::array::resize may not be toml::node_view.");
6942 
6943             if (!new_size)
6944                 clear();
6945             else if (new_size > elems_.size())
6946                 insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
6947             else
6948                 truncate(new_size);
6949         }
6950 
6951         TOML_EXPORTED_MEMBER_FUNCTION
6952         iterator erase(const_iterator pos) noexcept;
6953 
6954         TOML_EXPORTED_MEMBER_FUNCTION
6955         iterator erase(const_iterator first, const_iterator last) noexcept;
6956 
6957         TOML_EXPORTED_MEMBER_FUNCTION
6958         array& flatten() &;
6959 
6960         array&& flatten() &&
6961         {
6962             return static_cast<toml::array&&>(this->flatten());
6963         }
6964 
6965         TOML_EXPORTED_MEMBER_FUNCTION
6966         array& prune(bool recursive = true) & noexcept;
6967 
6968         array&& prune(bool recursive = true) && noexcept
6969         {
6970             return static_cast<toml::array&&>(this->prune(recursive));
6971         }
6972 
6973         TOML_EXPORTED_MEMBER_FUNCTION
6974         void pop_back() noexcept;
6975 
6976         TOML_EXPORTED_MEMBER_FUNCTION
6977         void clear() noexcept;
6978 
6979         template <typename ElemType>
6980         iterator insert(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
6981         {
6982             if constexpr (is_node_view<ElemType>)
6983             {
6984                 if (!val)
6985                     return end();
6986             }
6987             return iterator{ insert_at(const_vector_iterator{ pos },
6988                                        impl::make_node(static_cast<ElemType&&>(val), flags)) };
6989         }
6990 
6991         template <typename ElemType>
6992         iterator insert(const_iterator pos,
6993                         size_t count,
6994                         ElemType&& val,
6995                         value_flags flags = preserve_source_value_flags)
6996         {
6997             if constexpr (is_node_view<ElemType>)
6998             {
6999                 if (!val)
7000                     return end();
7001             }
7002             switch (count)
7003             {
7004                 case 0: return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
7005                 case 1: return insert(pos, static_cast<ElemType&&>(val), flags);
7006                 default:
7007                 {
7008                     const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
7009                     preinsertion_resize(start_idx, count);
7010                     size_t i = start_idx;
7011                     for (size_t e = start_idx + count - 1u; i < e; i++)
7012                         elems_[i] = impl::make_node(val, flags);
7013 
7014                     elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
7015                     return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
7016                 }
7017             }
7018         }
7019 
7020         template <typename Iter>
7021         iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = preserve_source_value_flags)
7022         {
7023             const auto distance = std::distance(first, last);
7024             if (distance <= 0)
7025                 return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
7026             else
7027             {
7028                 auto count       = distance;
7029                 using deref_type = decltype(*first);
7030                 if constexpr (is_node_view<deref_type>)
7031                 {
7032                     for (auto it = first; it != last; it++)
7033                         if (!(*it))
7034                             count--;
7035                     if (!count)
7036                         return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
7037                 }
7038                 const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
7039                 preinsertion_resize(start_idx, static_cast<size_t>(count));
7040                 size_t i = start_idx;
7041                 for (auto it = first; it != last; it++)
7042                 {
7043                     if constexpr (is_node_view<deref_type>)
7044                     {
7045                         if (!(*it))
7046                             continue;
7047                     }
7048                     if constexpr (std::is_rvalue_reference_v<deref_type>)
7049                         elems_[i++] = impl::make_node(std::move(*it), flags);
7050                     else
7051                         elems_[i++] = impl::make_node(*it, flags);
7052                 }
7053                 return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
7054             }
7055         }
7056 
7057         template <typename ElemType>
7058         iterator insert(const_iterator pos,
7059                         std::initializer_list<ElemType> ilist,
7060                         value_flags flags = preserve_source_value_flags)
7061         {
7062             return insert(pos, ilist.begin(), ilist.end(), flags);
7063         }
7064 
7065         template <typename ElemType = void, typename... Args>
7066         iterator emplace(const_iterator pos, Args&&... args)
7067         {
7068             using raw_elem_type = impl::remove_cvref<ElemType>;
7069             using elem_type     = std::conditional_t<std::is_void_v<raw_elem_type>, //
7070                                                      impl::emplaced_type_of<Args&&...>,
7071                                                      raw_elem_type>;
7072 
7073             using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
7074             static_assert(impl::is_native<type> || impl::is_one_of<type, table, array>,
7075                           "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
7076 
7077             return iterator{ insert_at(const_vector_iterator{ pos },
7078                                        impl::node_ptr{ new impl::wrap_node<type>{ static_cast<Args&&>(args)... } }) };
7079         }
7080 
7081         template <typename ElemType>
7082         iterator replace(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
7083         {
7084             TOML_ASSERT(pos >= cbegin() && pos < cend());
7085 
7086             if constexpr (is_node_view<ElemType>)
7087             {
7088                 if (!val)
7089                     return end();
7090             }
7091 
7092             const auto it = elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin());
7093             *it           = impl::make_node(static_cast<ElemType&&>(val), flags);
7094             return iterator{ it };
7095         }
7096 
7097         template <typename ElemType>
7098         void push_back(ElemType&& val, value_flags flags = preserve_source_value_flags)
7099         {
7100             emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
7101         }
7102 
7103         template <typename ElemType = void, typename... Args>
7104         decltype(auto) emplace_back(Args&&... args)
7105         {
7106             using raw_elem_type = impl::remove_cvref<ElemType>;
7107             using elem_type     = std::conditional_t<std::is_void_v<raw_elem_type>, //
7108                                                      impl::emplaced_type_of<Args&&...>,
7109                                                      raw_elem_type>;
7110 
7111             static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
7112                                                  && sizeof...(Args) == 1u                     //
7113                                                  && impl::first_is_same<impl::node_ptr&&, Args&&...>;
7114 
7115             using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
7116 
7117             static_assert(
7118                 moving_node_ptr                                       //
7119                     || impl::is_native<unwrapped_type>                //
7120                     || impl::is_one_of<unwrapped_type, table, array>, //
7121                 "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
7122 
7123             if constexpr (moving_node_ptr)
7124             {
7125                 insert_at_back(static_cast<Args&&>(args)...);
7126                 return *elems_.back();
7127             }
7128             else
7129             {
7130                 auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<Args&&>(args)... };
7131                 insert_at_back(impl::node_ptr{ ptr });
7132                 return *ptr;
7133             }
7134         }
7135 
7136       private:
7137 
7138         TOML_NODISCARD
7139         TOML_EXPORTED_STATIC_FUNCTION
7140         static bool TOML_CALLCONV equal(const array&, const array&) noexcept;
7141 
7142         template <typename T>
7143         TOML_NODISCARD
7144         static bool equal_to_container(const array& lhs, const T& rhs) noexcept
7145         {
7146             using element_type = std::remove_const_t<typename T::value_type>;
7147             static_assert(impl::is_losslessly_convertible_to_native<element_type>,
7148                           "Container element type must be losslessly convertible one of the native TOML value types");
7149 
7150             if (lhs.size() != rhs.size())
7151                 return false;
7152             if (rhs.size() == 0u)
7153                 return true;
7154 
7155             size_t i{};
7156             for (auto& list_elem : rhs)
7157             {
7158                 const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
7159                 if (!elem || *elem != list_elem)
7160                     return false;
7161             }
7162 
7163             return true;
7164         }
7165 
7166       public:
7167 
7168         TOML_NODISCARD
7169         friend bool operator==(const array& lhs, const array& rhs) noexcept
7170         {
7171             return equal(lhs, rhs);
7172         }
7173 
7174         TOML_NODISCARD
7175         friend bool operator!=(const array& lhs, const array& rhs) noexcept
7176         {
7177             return !equal(lhs, rhs);
7178         }
7179 
7180         template <typename T>
7181         TOML_NODISCARD
7182         friend bool operator==(const array& lhs, const std::initializer_list<T>& rhs) noexcept
7183         {
7184             return equal_to_container(lhs, rhs);
7185         }
7186         TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>);
7187 
7188         template <typename T>
7189         TOML_NODISCARD
7190         friend bool operator==(const array& lhs, const std::vector<T>& rhs) noexcept
7191         {
7192             return equal_to_container(lhs, rhs);
7193         }
7194         TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>);
7195 
7196 #if TOML_ENABLE_FORMATTERS
7197 
7198         friend std::ostream& operator<<(std::ostream& lhs, const array& rhs)
7199         {
7200             impl::print_to_stream(lhs, rhs);
7201             return lhs;
7202         }
7203 
7204 #endif
7205     };
7206 }
7207 TOML_NAMESPACE_END;
7208 
7209 #ifdef _MSC_VER
7210 #pragma pop_macro("min")
7211 #pragma pop_macro("max")
7212 #ifndef __clang__
7213 #pragma inline_recursion(off)
7214 #endif
7215 #endif
7216 TOML_POP_WARNINGS;
7217 
7218 //********  impl/key.hpp  **********************************************************************************************
7219 
7220 TOML_PUSH_WARNINGS;
7221 #ifdef _MSC_VER
7222 #ifndef __clang__
7223 #pragma inline_recursion(on)
7224 #endif
7225 #pragma push_macro("min")
7226 #pragma push_macro("max")
7227 #undef min
7228 #undef max
7229 #endif
7230 
7231 TOML_NAMESPACE_START
7232 {
7233     class key
7234     {
7235       private:
7236         std::string key_;
7237         source_region source_;
7238 
7239       public:
7240 
7241         TOML_NODISCARD_CTOR
7242         key() noexcept = default;
7243 
7244         TOML_NODISCARD_CTOR
7245         explicit key(std::string_view k, source_region&& src = {}) //
7246             : key_{ k },
7247               source_{ std::move(src) }
7248         {}
7249 
7250         TOML_NODISCARD_CTOR
7251         explicit key(std::string_view k, const source_region& src) //
7252             : key_{ k },
7253               source_{ src }
7254         {}
7255 
7256         TOML_NODISCARD_CTOR
7257         explicit key(std::string&& k, source_region&& src = {}) noexcept //
7258             : key_{ std::move(k) },
7259               source_{ std::move(src) }
7260         {}
7261 
7262         TOML_NODISCARD_CTOR
7263         explicit key(std::string&& k, const source_region& src) noexcept //
7264             : key_{ std::move(k) },
7265               source_{ src }
7266         {}
7267 
7268         TOML_NODISCARD_CTOR
7269         explicit key(const char* k, source_region&& src = {}) //
7270             : key_{ k },
7271               source_{ std::move(src) }
7272         {}
7273 
7274         TOML_NODISCARD_CTOR
7275         explicit key(const char* k, const source_region& src) //
7276             : key_{ k },
7277               source_{ src }
7278         {}
7279 
7280 #if TOML_ENABLE_WINDOWS_COMPAT
7281 
7282         TOML_NODISCARD_CTOR
7283         explicit key(std::wstring_view k, source_region&& src = {}) //
7284             : key_{ impl::narrow(k) },
7285               source_{ std::move(src) }
7286         {}
7287 
7288         TOML_NODISCARD_CTOR
7289         explicit key(std::wstring_view k, const source_region& src) //
7290             : key_{ impl::narrow(k) },
7291               source_{ src }
7292         {}
7293 
7294 #endif
7295 
7296         TOML_PURE_INLINE_GETTER
7297         std::string_view str() const noexcept
7298         {
7299             return std::string_view{ key_ };
7300         }
7301 
7302         TOML_PURE_INLINE_GETTER
7303         /*implicit*/ operator std::string_view() const noexcept
7304         {
7305             return str();
7306         }
7307 
7308         TOML_PURE_INLINE_GETTER
7309         bool empty() const noexcept
7310         {
7311             return key_.empty();
7312         }
7313 
7314         TOML_PURE_INLINE_GETTER
7315         const char* data() const noexcept
7316         {
7317             return key_.data();
7318         }
7319 
7320         TOML_PURE_INLINE_GETTER
7321         size_t length() const noexcept
7322         {
7323             return key_.length();
7324         }
7325 
7326         TOML_PURE_INLINE_GETTER
7327         const source_region& source() const noexcept
7328         {
7329             return source_;
7330         }
7331 
7332         TOML_PURE_INLINE_GETTER
7333         friend bool operator==(const key& lhs, const key& rhs) noexcept
7334         {
7335             return lhs.key_ == rhs.key_;
7336         }
7337 
7338         TOML_PURE_INLINE_GETTER
7339         friend bool operator!=(const key& lhs, const key& rhs) noexcept
7340         {
7341             return lhs.key_ != rhs.key_;
7342         }
7343 
7344         TOML_PURE_INLINE_GETTER
7345         friend bool operator<(const key& lhs, const key& rhs) noexcept
7346         {
7347             return lhs.key_ < rhs.key_;
7348         }
7349 
7350         TOML_PURE_INLINE_GETTER
7351         friend bool operator<=(const key& lhs, const key& rhs) noexcept
7352         {
7353             return lhs.key_ <= rhs.key_;
7354         }
7355 
7356         TOML_PURE_INLINE_GETTER
7357         friend bool operator>(const key& lhs, const key& rhs) noexcept
7358         {
7359             return lhs.key_ > rhs.key_;
7360         }
7361 
7362         TOML_PURE_INLINE_GETTER
7363         friend bool operator>=(const key& lhs, const key& rhs) noexcept
7364         {
7365             return lhs.key_ >= rhs.key_;
7366         }
7367 
7368         TOML_PURE_INLINE_GETTER
7369         friend bool operator==(const key& lhs, std::string_view rhs) noexcept
7370         {
7371             return lhs.key_ == rhs;
7372         }
7373 
7374         TOML_PURE_INLINE_GETTER
7375         friend bool operator!=(const key& lhs, std::string_view rhs) noexcept
7376         {
7377             return lhs.key_ != rhs;
7378         }
7379 
7380         TOML_PURE_INLINE_GETTER
7381         friend bool operator<(const key& lhs, std::string_view rhs) noexcept
7382         {
7383             return lhs.key_ < rhs;
7384         }
7385 
7386         TOML_PURE_INLINE_GETTER
7387         friend bool operator<=(const key& lhs, std::string_view rhs) noexcept
7388         {
7389             return lhs.key_ <= rhs;
7390         }
7391 
7392         TOML_PURE_INLINE_GETTER
7393         friend bool operator>(const key& lhs, std::string_view rhs) noexcept
7394         {
7395             return lhs.key_ > rhs;
7396         }
7397 
7398         TOML_PURE_INLINE_GETTER
7399         friend bool operator>=(const key& lhs, std::string_view rhs) noexcept
7400         {
7401             return lhs.key_ >= rhs;
7402         }
7403 
7404         TOML_PURE_INLINE_GETTER
7405         friend bool operator==(std::string_view lhs, const key& rhs) noexcept
7406         {
7407             return lhs == rhs.key_;
7408         }
7409 
7410         TOML_PURE_INLINE_GETTER
7411         friend bool operator!=(std::string_view lhs, const key& rhs) noexcept
7412         {
7413             return lhs != rhs.key_;
7414         }
7415 
7416         TOML_PURE_INLINE_GETTER
7417         friend bool operator<(std::string_view lhs, const key& rhs) noexcept
7418         {
7419             return lhs < rhs.key_;
7420         }
7421 
7422         TOML_PURE_INLINE_GETTER
7423         friend bool operator<=(std::string_view lhs, const key& rhs) noexcept
7424         {
7425             return lhs <= rhs.key_;
7426         }
7427 
7428         TOML_PURE_INLINE_GETTER
7429         friend bool operator>(std::string_view lhs, const key& rhs) noexcept
7430         {
7431             return lhs > rhs.key_;
7432         }
7433 
7434         TOML_PURE_INLINE_GETTER
7435         friend bool operator>=(std::string_view lhs, const key& rhs) noexcept
7436         {
7437             return lhs >= rhs.key_;
7438         }
7439 
7440         using const_iterator = const char*;
7441 
7442         using iterator = const_iterator;
7443 
7444         TOML_PURE_INLINE_GETTER
7445         const_iterator begin() const noexcept
7446         {
7447             return key_.data();
7448         }
7449 
7450         TOML_PURE_INLINE_GETTER
7451         const_iterator end() const noexcept
7452         {
7453             return key_.data() + key_.length();
7454         }
7455 
7456         friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
7457         {
7458             impl::print_to_stream(lhs, rhs.key_);
7459             return lhs;
7460         }
7461     };
7462 
7463     template <typename T>
7464     inline constexpr bool is_key = std::is_same_v<impl::remove_cvref<T>, toml::key>;
7465 
7466     template <typename T>
7467     inline constexpr bool is_key_or_convertible = is_key<T> //
7468                                                || impl::is_constructible_or_convertible<toml::key, T>;
7469 }
7470 TOML_NAMESPACE_END;
7471 
7472 #ifdef _MSC_VER
7473 #pragma pop_macro("min")
7474 #pragma pop_macro("max")
7475 #ifndef __clang__
7476 #pragma inline_recursion(off)
7477 #endif
7478 #endif
7479 TOML_POP_WARNINGS;
7480 
7481 //********  impl/std_map.hpp  ******************************************************************************************
7482 
7483 TOML_DISABLE_WARNINGS;
7484 #include <map>
7485 #include <iterator>
7486 TOML_ENABLE_WARNINGS;
7487 
7488 //********  impl/table.hpp  ********************************************************************************************
7489 
7490 TOML_PUSH_WARNINGS;
7491 #ifdef _MSC_VER
7492 #ifndef __clang__
7493 #pragma inline_recursion(on)
7494 #endif
7495 #pragma push_macro("min")
7496 #pragma push_macro("max")
7497 #undef min
7498 #undef max
7499 #endif
7500 
7501 TOML_IMPL_NAMESPACE_START
7502 {
7503     template <bool IsConst>
7504     struct table_proxy_pair
7505     {
7506         using value_type = std::conditional_t<IsConst, const node, node>;
7507 
7508         const toml::key& first;
7509         value_type& second;
7510     };
7511 
7512     template <bool IsConst>
7513     class table_iterator
7514     {
7515       private:
7516         template <bool>
7517         friend class table_iterator;
7518 
7519         using proxy_type           = table_proxy_pair<IsConst>;
7520         using mutable_map_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator;
7521         using const_map_iterator   = std::map<toml::key, node_ptr, std::less<>>::const_iterator;
7522         using map_iterator         = std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>;
7523 
7524         mutable map_iterator iter_;
7525         alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)];
7526         mutable bool proxy_instantiated_ = false;
7527 
7528         TOML_NODISCARD
7529         proxy_type* get_proxy() const noexcept
7530         {
7531             if (!proxy_instantiated_)
7532             {
7533                 auto p = ::new (static_cast<void*>(proxy_)) proxy_type{ iter_->first, *iter_->second.get() };
7534                 proxy_instantiated_ = true;
7535                 return p;
7536             }
7537             else
7538                 return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_));
7539         }
7540 
7541       public:
7542         TOML_NODISCARD_CTOR
7543         table_iterator() noexcept = default;
7544 
7545         TOML_NODISCARD_CTOR
7546         explicit table_iterator(mutable_map_iterator iter) noexcept //
7547             : iter_{ iter }
7548         {}
7549 
7550         TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
7551         TOML_NODISCARD_CTOR
7552         explicit table_iterator(const_map_iterator iter) noexcept //
7553             : iter_{ iter }
7554         {}
7555 
7556         TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
7557         TOML_NODISCARD_CTOR
7558         table_iterator(const table_iterator<false>& other) noexcept //
7559             : iter_{ other.iter_ }
7560         {}
7561 
7562         TOML_NODISCARD_CTOR
7563         table_iterator(const table_iterator& other) noexcept //
7564             : iter_{ other.iter_ }
7565         {}
7566 
7567         table_iterator& operator=(const table_iterator& rhs) noexcept
7568         {
7569             iter_               = rhs.iter_;
7570             proxy_instantiated_ = false;
7571             return *this;
7572         }
7573 
7574         using value_type        = table_proxy_pair<IsConst>;
7575         using reference         = value_type&;
7576         using pointer           = value_type*;
7577         using difference_type   = typename std::iterator_traits<map_iterator>::difference_type;
7578         using iterator_category = typename std::iterator_traits<map_iterator>::iterator_category;
7579 
7580         table_iterator& operator++() noexcept // ++pre
7581         {
7582             ++iter_;
7583             proxy_instantiated_ = false;
7584             return *this;
7585         }
7586 
7587         table_iterator operator++(int) noexcept // post++
7588         {
7589             table_iterator out{ iter_ };
7590             ++iter_;
7591             proxy_instantiated_ = false;
7592             return out;
7593         }
7594 
7595         table_iterator& operator--() noexcept // --pre
7596         {
7597             --iter_;
7598             proxy_instantiated_ = false;
7599             return *this;
7600         }
7601 
7602         table_iterator operator--(int) noexcept // post--
7603         {
7604             table_iterator out{ iter_ };
7605             --iter_;
7606             proxy_instantiated_ = false;
7607             return out;
7608         }
7609 
7610         TOML_PURE_INLINE_GETTER
7611         reference operator*() const noexcept
7612         {
7613             return *get_proxy();
7614         }
7615 
7616         TOML_PURE_INLINE_GETTER
7617         pointer operator->() const noexcept
7618         {
7619             return get_proxy();
7620         }
7621 
7622         TOML_PURE_INLINE_GETTER
7623         explicit operator const map_iterator&() const noexcept
7624         {
7625             return iter_;
7626         }
7627 
7628         TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
7629         TOML_PURE_INLINE_GETTER
7630         explicit operator const const_map_iterator() const noexcept
7631         {
7632             return iter_;
7633         }
7634 
7635         TOML_PURE_INLINE_GETTER
7636         friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept
7637         {
7638             return lhs.iter_ == rhs.iter_;
7639         }
7640 
7641         TOML_PURE_INLINE_GETTER
7642         friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept
7643         {
7644             return lhs.iter_ != rhs.iter_;
7645         }
7646     };
7647 
7648     struct table_init_pair
7649     {
7650         mutable toml::key key;
7651         mutable node_ptr value;
7652 
7653         template <typename K, typename V>
7654         TOML_NODISCARD_CTOR
7655         table_init_pair(K&& k, V&& v, value_flags flags = preserve_source_value_flags) //
7656             : key{ static_cast<K&&>(k) },
7657               value{ make_node(static_cast<V&&>(v), flags) }
7658         {}
7659     };
7660 }
7661 TOML_IMPL_NAMESPACE_END;
7662 
7663 TOML_NAMESPACE_START
7664 {
7665     using table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>);
7666 
7667     using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>);
7668 
7669     class TOML_EXPORTED_CLASS table : public node
7670     {
7671       private:
7672 
7673         using map_type           = std::map<toml::key, impl::node_ptr, std::less<>>;
7674         using map_pair           = std::pair<const toml::key, impl::node_ptr>;
7675         using map_iterator       = typename map_type::iterator;
7676         using const_map_iterator = typename map_type::const_iterator;
7677         map_type map_;
7678 
7679         bool inline_ = false;
7680 
7681         TOML_NODISCARD_CTOR
7682         TOML_EXPORTED_MEMBER_FUNCTION
7683         table(const impl::table_init_pair*, const impl::table_init_pair*);
7684 
7685       public:
7686 
7687         TOML_NODISCARD_CTOR
7688         TOML_EXPORTED_MEMBER_FUNCTION
7689         table() noexcept;
7690 
7691         TOML_EXPORTED_MEMBER_FUNCTION
7692         ~table() noexcept;
7693 
7694         TOML_NODISCARD_CTOR
7695         TOML_EXPORTED_MEMBER_FUNCTION
7696         table(const table&);
7697 
7698         TOML_NODISCARD_CTOR
7699         TOML_EXPORTED_MEMBER_FUNCTION
7700         table(table&& other) noexcept;
7701 
7702         TOML_NODISCARD_CTOR
7703         TOML_EXPORTED_MEMBER_FUNCTION
7704         explicit table(std::initializer_list<impl::table_init_pair> kvps) //
7705             : table(kvps.begin(), kvps.end())
7706         {}
7707 
7708         TOML_EXPORTED_MEMBER_FUNCTION
7709         table& operator=(const table&);
7710 
7711         TOML_EXPORTED_MEMBER_FUNCTION
7712         table& operator=(table&& rhs) noexcept;
7713 
7714         TOML_CONST_INLINE_GETTER
7715         node_type type() const noexcept final
7716         {
7717             return node_type::table;
7718         }
7719 
7720         TOML_PURE_GETTER
7721         TOML_EXPORTED_MEMBER_FUNCTION
7722         bool is_homogeneous(node_type ntype) const noexcept final;
7723 
7724         TOML_NODISCARD
7725         TOML_EXPORTED_MEMBER_FUNCTION
7726         bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;
7727 
7728         TOML_NODISCARD
7729         TOML_EXPORTED_MEMBER_FUNCTION
7730         bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;
7731 
7732         template <typename ElemType = void>
7733         TOML_PURE_GETTER
7734         bool is_homogeneous() const noexcept
7735         {
7736             using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
7737             static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
7738                           "The template type argument of table::is_homogeneous() must be void or one "
7739                           "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
7740 
7741             return is_homogeneous(impl::node_type_of<type>);
7742         }
7743         TOML_CONST_INLINE_GETTER
7744         bool is_table() const noexcept final
7745         {
7746             return true;
7747         }
7748 
7749         TOML_CONST_INLINE_GETTER
7750         bool is_array() const noexcept final
7751         {
7752             return false;
7753         }
7754 
7755         TOML_PURE_GETTER
7756         bool is_array_of_tables() const noexcept final
7757         {
7758             return false;
7759         }
7760 
7761         TOML_CONST_INLINE_GETTER
7762         bool is_value() const noexcept final
7763         {
7764             return false;
7765         }
7766 
7767         TOML_CONST_INLINE_GETTER
7768         bool is_string() const noexcept final
7769         {
7770             return false;
7771         }
7772 
7773         TOML_CONST_INLINE_GETTER
7774         bool is_integer() const noexcept final
7775         {
7776             return false;
7777         }
7778 
7779         TOML_CONST_INLINE_GETTER
7780         bool is_floating_point() const noexcept final
7781         {
7782             return false;
7783         }
7784 
7785         TOML_CONST_INLINE_GETTER
7786         bool is_number() const noexcept final
7787         {
7788             return false;
7789         }
7790 
7791         TOML_CONST_INLINE_GETTER
7792         bool is_boolean() const noexcept final
7793         {
7794             return false;
7795         }
7796 
7797         TOML_CONST_INLINE_GETTER
7798         bool is_date() const noexcept final
7799         {
7800             return false;
7801         }
7802 
7803         TOML_CONST_INLINE_GETTER
7804         bool is_time() const noexcept final
7805         {
7806             return false;
7807         }
7808 
7809         TOML_CONST_INLINE_GETTER
7810         bool is_date_time() const noexcept final
7811         {
7812             return false;
7813         }
7814 
7815         TOML_CONST_INLINE_GETTER
7816         table* as_table() noexcept final
7817         {
7818             return this;
7819         }
7820 
7821         TOML_CONST_INLINE_GETTER
7822         array* as_array() noexcept final
7823         {
7824             return nullptr;
7825         }
7826 
7827         TOML_CONST_INLINE_GETTER
7828         toml::value<std::string>* as_string() noexcept final
7829         {
7830             return nullptr;
7831         }
7832 
7833         TOML_CONST_INLINE_GETTER
7834         toml::value<int64_t>* as_integer() noexcept final
7835         {
7836             return nullptr;
7837         }
7838 
7839         TOML_CONST_INLINE_GETTER
7840         toml::value<double>* as_floating_point() noexcept final
7841         {
7842             return nullptr;
7843         }
7844 
7845         TOML_CONST_INLINE_GETTER
7846         toml::value<bool>* as_boolean() noexcept final
7847         {
7848             return nullptr;
7849         }
7850 
7851         TOML_CONST_INLINE_GETTER
7852         toml::value<date>* as_date() noexcept final
7853         {
7854             return nullptr;
7855         }
7856 
7857         TOML_CONST_INLINE_GETTER
7858         toml::value<time>* as_time() noexcept final
7859         {
7860             return nullptr;
7861         }
7862 
7863         TOML_CONST_INLINE_GETTER
7864         toml::value<date_time>* as_date_time() noexcept final
7865         {
7866             return nullptr;
7867         }
7868 
7869         TOML_CONST_INLINE_GETTER
7870         const table* as_table() const noexcept final
7871         {
7872             return this;
7873         }
7874 
7875         TOML_CONST_INLINE_GETTER
7876         const array* as_array() const noexcept final
7877         {
7878             return nullptr;
7879         }
7880 
7881         TOML_CONST_INLINE_GETTER
7882         const toml::value<std::string>* as_string() const noexcept final
7883         {
7884             return nullptr;
7885         }
7886 
7887         TOML_CONST_INLINE_GETTER
7888         const toml::value<int64_t>* as_integer() const noexcept final
7889         {
7890             return nullptr;
7891         }
7892 
7893         TOML_CONST_INLINE_GETTER
7894         const toml::value<double>* as_floating_point() const noexcept final
7895         {
7896             return nullptr;
7897         }
7898 
7899         TOML_CONST_INLINE_GETTER
7900         const toml::value<bool>* as_boolean() const noexcept final
7901         {
7902             return nullptr;
7903         }
7904 
7905         TOML_CONST_INLINE_GETTER
7906         const toml::value<date>* as_date() const noexcept final
7907         {
7908             return nullptr;
7909         }
7910 
7911         TOML_CONST_INLINE_GETTER
7912         const toml::value<time>* as_time() const noexcept final
7913         {
7914             return nullptr;
7915         }
7916 
7917         TOML_CONST_INLINE_GETTER
7918         const toml::value<date_time>* as_date_time() const noexcept final
7919         {
7920             return nullptr;
7921         }
7922 
7923         TOML_PURE_INLINE_GETTER
7924         bool is_inline() const noexcept
7925         {
7926             return inline_;
7927         }
7928 
7929         void is_inline(bool val) noexcept
7930         {
7931             inline_ = val;
7932         }
7933 
7934         TOML_PURE_GETTER
7935         TOML_EXPORTED_MEMBER_FUNCTION
7936         node* get(std::string_view key) noexcept;
7937 
7938         TOML_PURE_INLINE_GETTER
7939         const node* get(std::string_view key) const noexcept
7940         {
7941             return const_cast<table&>(*this).get(key);
7942         }
7943 
7944 #if TOML_ENABLE_WINDOWS_COMPAT
7945 
7946         TOML_NODISCARD
7947         node* get(std::wstring_view key)
7948         {
7949             if (empty())
7950                 return nullptr;
7951 
7952             return get(impl::narrow(key));
7953         }
7954 
7955         TOML_NODISCARD
7956         const node* get(std::wstring_view key) const
7957         {
7958             return const_cast<table&>(*this).get(key);
7959         }
7960 
7961 #endif // TOML_ENABLE_WINDOWS_COMPAT
7962 
7963         template <typename T>
7964         TOML_PURE_GETTER
7965         impl::wrap_node<T>* get_as(std::string_view key) noexcept
7966         {
7967             const auto n = this->get(key);
7968             return n ? n->template as<T>() : nullptr;
7969         }
7970 
7971         template <typename T>
7972         TOML_PURE_GETTER
7973         const impl::wrap_node<T>* get_as(std::string_view key) const noexcept
7974         {
7975             return const_cast<table&>(*this).template get_as<T>(key);
7976         }
7977 
7978 #if TOML_ENABLE_WINDOWS_COMPAT
7979 
7980         template <typename T>
7981         TOML_NODISCARD
7982         impl::wrap_node<T>* get_as(std::wstring_view key)
7983         {
7984             if (empty())
7985                 return nullptr;
7986 
7987             return get_as<T>(impl::narrow(key));
7988         }
7989 
7990         template <typename T>
7991         TOML_NODISCARD
7992         const impl::wrap_node<T>* get_as(std::wstring_view key) const
7993         {
7994             return const_cast<table&>(*this).template get_as<T>(key);
7995         }
7996 
7997 #endif // TOML_ENABLE_WINDOWS_COMPAT
7998 
7999         TOML_NODISCARD
8000         TOML_EXPORTED_MEMBER_FUNCTION
8001         node& at(std::string_view key);
8002 
8003         TOML_NODISCARD
8004         const node& at(std::string_view key) const
8005         {
8006             return const_cast<table&>(*this).at(key);
8007         }
8008 
8009 #if TOML_ENABLE_WINDOWS_COMPAT
8010 
8011         TOML_NODISCARD
8012         node& at(std::wstring_view key)
8013         {
8014             return at(impl::narrow(key));
8015         }
8016 
8017         TOML_NODISCARD
8018         const node& at(std::wstring_view key) const
8019         {
8020             return const_cast<table&>(*this).at(key);
8021         }
8022 
8023 #endif // TOML_ENABLE_WINDOWS_COMPAT
8024 
8025         using iterator = toml::table_iterator;
8026 
8027         using const_iterator = toml::const_table_iterator;
8028 
8029         TOML_PURE_INLINE_GETTER
8030         iterator begin() noexcept
8031         {
8032             return iterator{ map_.begin() };
8033         }
8034 
8035         TOML_PURE_INLINE_GETTER
8036         const_iterator begin() const noexcept
8037         {
8038             return const_iterator{ map_.cbegin() };
8039         }
8040 
8041         TOML_PURE_INLINE_GETTER
8042         const_iterator cbegin() const noexcept
8043         {
8044             return const_iterator{ map_.cbegin() };
8045         }
8046 
8047         TOML_PURE_INLINE_GETTER
8048         iterator end() noexcept
8049         {
8050             return iterator{ map_.end() };
8051         }
8052 
8053         TOML_PURE_INLINE_GETTER
8054         const_iterator end() const noexcept
8055         {
8056             return const_iterator{ map_.cend() };
8057         }
8058 
8059         TOML_PURE_INLINE_GETTER
8060         const_iterator cend() const noexcept
8061         {
8062             return const_iterator{ map_.cend() };
8063         }
8064 
8065       private:
8066 
8067         template <typename T, typename Table>
8068         using for_each_value_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Table>;
8069 
8070         template <typename Func, typename Table, typename T>
8071         using can_for_each = std::disjunction<std::is_invocable<Func, const key&, for_each_value_ref<T, Table>>, //
8072                                               std::is_invocable<Func, for_each_value_ref<T, Table>>>;
8073 
8074         template <typename Func, typename Table, typename T>
8075         using can_for_each_nothrow = std::conditional_t<
8076             // first form
8077             std::is_invocable_v<Func, const key&, for_each_value_ref<T, Table>>,
8078             std::is_nothrow_invocable<Func, const key&, for_each_value_ref<T, Table>>,
8079             std::conditional_t<
8080                 // second form
8081                 std::is_invocable_v<Func, for_each_value_ref<T, Table>>,
8082                 std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>,
8083                 std::false_type>>;
8084 
8085         template <typename Func, typename Table>
8086         using can_for_each_any = std::disjunction<can_for_each<Func, Table, table>,
8087                                                   can_for_each<Func, Table, array>,
8088                                                   can_for_each<Func, Table, std::string>,
8089                                                   can_for_each<Func, Table, int64_t>,
8090                                                   can_for_each<Func, Table, double>,
8091                                                   can_for_each<Func, Table, bool>,
8092                                                   can_for_each<Func, Table, date>,
8093                                                   can_for_each<Func, Table, time>,
8094                                                   can_for_each<Func, Table, date_time>>;
8095 
8096         template <typename Func, typename Table, typename T>
8097         using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Table, T>>, //
8098                                                          can_for_each_nothrow<Func, Table, T>>;
8099 
8100         template <typename Func, typename Table>
8101         using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Table, table>,
8102                                                      for_each_is_nothrow_one<Func, Table, array>,
8103                                                      for_each_is_nothrow_one<Func, Table, std::string>,
8104                                                      for_each_is_nothrow_one<Func, Table, int64_t>,
8105                                                      for_each_is_nothrow_one<Func, Table, double>,
8106                                                      for_each_is_nothrow_one<Func, Table, bool>,
8107                                                      for_each_is_nothrow_one<Func, Table, date>,
8108                                                      for_each_is_nothrow_one<Func, Table, time>,
8109                                                      for_each_is_nothrow_one<Func, Table, date_time>>;
8110 
8111         template <typename Func, typename Table>
8112         static void do_for_each(Func&& visitor, Table&& tbl) //
8113             noexcept(for_each_is_nothrow<Func&&, Table&&>::value)
8114         {
8115             static_assert(can_for_each_any<Func&&, Table&&>::value,
8116                           "TOML table for_each visitors must be invocable for at least one of the toml::node "
8117                           "specializations:" TOML_SA_NODE_TYPE_LIST);
8118 
8119             using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>;
8120 
8121             for (kvp_type& kvp : tbl.map_)
8122             {
8123                 using node_ref = impl::copy_cvref<toml::node, Table&&>;
8124                 static_assert(std::is_reference_v<node_ref>);
8125 
8126 #if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
8127 
8128 #ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
8129                 static_assert(impl::always_false<Func, Table, kvp_type, node_ref>, //
8130                               TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
8131 #endif
8132 
8133                 static_cast<node_ref>(*kvp.second)
8134                     .visit(
8135                         [&]([[maybe_unused]] auto&& v) //
8136                         noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value)
8137                         {
8138                             using value_ref = for_each_value_ref<decltype(v), Table&&>;
8139                             static_assert(std::is_reference_v<value_ref>);
8140 
8141                             // func(key, val)
8142                             if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>)
8143                             {
8144                                 static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first),
8145                                                              static_cast<value_ref>(v));
8146                             }
8147 
8148                             // func(val)
8149                             else if constexpr (std::is_invocable_v<Func&&, value_ref>)
8150                             {
8151                                 static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
8152                             }
8153                         });
8154 
8155 #else
8156                 const auto keep_going =
8157                     static_cast<node_ref>(*kvp.second)
8158                         .visit(
8159                             [&]([[maybe_unused]] auto&& v) //
8160                             noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value)
8161                             {
8162                                 using value_ref = for_each_value_ref<decltype(v), Table&&>;
8163                                 static_assert(std::is_reference_v<value_ref>);
8164 
8165                                 // func(key, val)
8166                                 if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>)
8167                                 {
8168                                     using return_type = decltype(static_cast<Func&&>(
8169                                         visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v)));
8170 
8171                                     if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
8172                                     {
8173                                         return static_cast<bool>(static_cast<Func&&>(
8174                                             visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v)));
8175                                     }
8176                                     else
8177                                     {
8178                                         static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first),
8179                                                                      static_cast<value_ref>(v));
8180                                         return true;
8181                                     }
8182                                 }
8183 
8184                                 // func(val)
8185                                 else if constexpr (std::is_invocable_v<Func&&, value_ref>)
8186                                 {
8187                                     using return_type =
8188                                         decltype(static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
8189 
8190                                     if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
8191                                     {
8192                                         return static_cast<bool>(
8193                                             static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
8194                                     }
8195                                     else
8196                                     {
8197                                         static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
8198                                         return true;
8199                                     }
8200                                 }
8201 
8202                                 // visitor not compatible with this particular type
8203                                 else
8204                                     return true;
8205                             });
8206 
8207                 if (!keep_going)
8208                     return;
8209 #endif
8210             }
8211         }
8212 
8213       public:
8214 
8215         template <typename Func>
8216         table& for_each(Func&& visitor) & //
8217             noexcept(for_each_is_nothrow<Func&&, table&>::value)
8218         {
8219             do_for_each(static_cast<Func&&>(visitor), *this);
8220             return *this;
8221         }
8222 
8223         template <typename Func>
8224         table&& for_each(Func&& visitor) && //
8225             noexcept(for_each_is_nothrow<Func&&, table&&>::value)
8226         {
8227             do_for_each(static_cast<Func&&>(visitor), static_cast<table&&>(*this));
8228             return static_cast<table&&>(*this);
8229         }
8230 
8231         template <typename Func>
8232         const table& for_each(Func&& visitor) const& //
8233             noexcept(for_each_is_nothrow<Func&&, const table&>::value)
8234         {
8235             do_for_each(static_cast<Func&&>(visitor), *this);
8236             return *this;
8237         }
8238 
8239         template <typename Func>
8240         const table&& for_each(Func&& visitor) const&& //
8241             noexcept(for_each_is_nothrow<Func&&, const table&&>::value)
8242         {
8243             do_for_each(static_cast<Func&&>(visitor), static_cast<const table&&>(*this));
8244             return static_cast<const table&&>(*this);
8245         }
8246 
8247         TOML_PURE_INLINE_GETTER
8248         bool empty() const noexcept
8249         {
8250             return map_.empty();
8251         }
8252 
8253         TOML_PURE_INLINE_GETTER
8254         size_t size() const noexcept
8255         {
8256             return map_.size();
8257         }
8258 
8259       private:
8260 
8261         TOML_PURE_GETTER
8262         TOML_EXPORTED_MEMBER_FUNCTION
8263         map_iterator get_lower_bound(std::string_view) noexcept;
8264 
8265       public:
8266 
8267         TOML_PURE_GETTER
8268         iterator lower_bound(std::string_view key) noexcept
8269         {
8270             return iterator{ get_lower_bound(key) };
8271         }
8272 
8273         TOML_PURE_GETTER
8274         const_iterator lower_bound(std::string_view key) const noexcept
8275         {
8276             return const_iterator{ const_cast<table&>(*this).get_lower_bound(key) };
8277         }
8278 
8279 #if TOML_ENABLE_WINDOWS_COMPAT
8280 
8281         TOML_NODISCARD
8282         iterator lower_bound(std::wstring_view key)
8283         {
8284             if (empty())
8285                 return end();
8286 
8287             return lower_bound(impl::narrow(key));
8288         }
8289 
8290         TOML_NODISCARD
8291         const_iterator lower_bound(std::wstring_view key) const
8292         {
8293             if (empty())
8294                 return end();
8295 
8296             return lower_bound(impl::narrow(key));
8297         }
8298 
8299 #endif // TOML_ENABLE_WINDOWS_COMPAT
8300 
8301         TOML_PURE_GETTER
8302         TOML_EXPORTED_MEMBER_FUNCTION
8303         iterator find(std::string_view key) noexcept;
8304 
8305         TOML_PURE_GETTER
8306         TOML_EXPORTED_MEMBER_FUNCTION
8307         const_iterator find(std::string_view key) const noexcept;
8308 
8309         TOML_PURE_GETTER
8310         bool contains(std::string_view key) const noexcept
8311         {
8312             return get(key) != nullptr;
8313         }
8314 
8315 #if TOML_ENABLE_WINDOWS_COMPAT
8316 
8317         TOML_NODISCARD
8318         iterator find(std::wstring_view key)
8319         {
8320             if (empty())
8321                 return end();
8322 
8323             return find(impl::narrow(key));
8324         }
8325 
8326         TOML_NODISCARD
8327         const_iterator find(std::wstring_view key) const
8328         {
8329             return find(impl::narrow(key));
8330         }
8331 
8332         TOML_NODISCARD
8333         bool contains(std::wstring_view key) const
8334         {
8335             return contains(impl::narrow(key));
8336         }
8337 
8338 #endif // TOML_ENABLE_WINDOWS_COMPAT
8339 
8340       private:
8341 
8342         TOML_EXPORTED_MEMBER_FUNCTION
8343         map_iterator erase(const_map_iterator) noexcept;
8344 
8345         TOML_EXPORTED_MEMBER_FUNCTION
8346         map_iterator erase(const_map_iterator, const_map_iterator) noexcept;
8347 
8348       public:
8349 
8350         iterator erase(iterator pos) noexcept
8351         {
8352             return iterator{ erase(const_map_iterator{ pos }) };
8353         }
8354 
8355         iterator erase(const_iterator pos) noexcept
8356         {
8357             return iterator{ erase(const_map_iterator{ pos }) };
8358         }
8359 
8360         iterator erase(const_iterator begin, const_iterator end) noexcept
8361         {
8362             return iterator{ erase(const_map_iterator{ begin }, const_map_iterator{ end }) };
8363         }
8364 
8365         TOML_EXPORTED_MEMBER_FUNCTION
8366         size_t erase(std::string_view key) noexcept;
8367 
8368 #if TOML_ENABLE_WINDOWS_COMPAT
8369 
8370         size_t erase(std::wstring_view key)
8371         {
8372             if (empty())
8373                 return false;
8374 
8375             return erase(impl::narrow(key));
8376         }
8377 
8378 #endif // TOML_ENABLE_WINDOWS_COMPAT
8379 
8380         TOML_EXPORTED_MEMBER_FUNCTION
8381         table& prune(bool recursive = true) & noexcept;
8382 
8383         table&& prune(bool recursive = true) && noexcept
8384         {
8385             return static_cast<toml::table&&>(this->prune(recursive));
8386         }
8387 
8388         TOML_EXPORTED_MEMBER_FUNCTION
8389         void clear() noexcept;
8390 
8391       private:
8392 
8393         TOML_EXPORTED_MEMBER_FUNCTION
8394         map_iterator insert_with_hint(const_iterator, key&&, impl::node_ptr&&);
8395 
8396       public:
8397 
8398         TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
8399                                   typename ValueType = void,
8400                                   typename KeyType,
8401                                   typename... ValueArgs)
8402         iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args)
8403         {
8404             static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8405                           "Emplacement using wide-character keys is only supported on Windows with "
8406                           "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8407 
8408             using raw_value_type = impl::remove_cvref<ValueType>;
8409             using value_type     = std::
8410                 conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
8411 
8412             if constexpr (impl::is_wide_string<KeyType>)
8413             {
8414 #if TOML_ENABLE_WINDOWS_COMPAT
8415                 return emplace_hint<value_type>(hint,
8416                                                 impl::narrow(static_cast<KeyType&&>(key)),
8417                                                 static_cast<ValueArgs&&>(args)...);
8418 #else
8419                 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8420 #endif
8421             }
8422             else
8423             {
8424                 static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
8425                                                      && sizeof...(ValueArgs) == 1u                 //
8426                                                      && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
8427                 using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
8428 
8429                 static_assert(moving_node_ptr                                       //
8430                                   || impl::is_native<unwrapped_type>                //
8431                                   || impl::is_one_of<unwrapped_type, table, array>, //
8432                               "ValueType argument of table::emplace_hint() must be one "
8433                               "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
8434 
8435                 map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr);
8436 
8437                 // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
8438                 // so now we have to construct the actual value
8439                 if (!ipos->second)
8440                 {
8441                     if constexpr (moving_node_ptr)
8442                         ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
8443                     else
8444                     {
8445 #if TOML_COMPILER_HAS_EXCEPTIONS
8446                         try
8447                         {
8448 #endif
8449                             ipos->second.reset(
8450                                 new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
8451 #if TOML_COMPILER_HAS_EXCEPTIONS
8452                         }
8453                         catch (...)
8454                         {
8455                             erase(const_map_iterator{ ipos }); // strong exception guarantee
8456                             throw;
8457                         }
8458 #endif
8459                     }
8460                 }
8461                 return iterator{ ipos };
8462             }
8463 
8464             TOML_UNREACHABLE;
8465         }
8466 
8467         TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
8468                                   typename KeyType,
8469                                   typename ValueType)
8470         std::pair<iterator, bool> insert(KeyType&& key,
8471                                          ValueType&& val,
8472                                          value_flags flags = preserve_source_value_flags)
8473         {
8474             static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8475                           "Insertion using wide-character keys is only supported on Windows with "
8476                           "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8477 
8478             if constexpr (is_node_view<ValueType>)
8479             {
8480                 if (!val)
8481                     return { end(), false };
8482             }
8483 
8484             if constexpr (impl::is_wide_string<KeyType>)
8485             {
8486 #if TOML_ENABLE_WINDOWS_COMPAT
8487                 return insert(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), flags);
8488 #else
8489                 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8490 #endif
8491             }
8492             else
8493             {
8494                 const auto key_view = std::string_view{ key };
8495                 map_iterator ipos   = get_lower_bound(key_view);
8496                 if (ipos == map_.end() || ipos->first != key_view)
8497                 {
8498                     ipos = insert_with_hint(const_iterator{ ipos },
8499                                             toml::key{ static_cast<KeyType&&>(key) },
8500                                             impl::make_node(static_cast<ValueType&&>(val), flags));
8501                     return { iterator{ ipos }, true };
8502                 }
8503                 return { iterator{ ipos }, false };
8504             }
8505         }
8506 
8507         TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), typename Iter)
8508         void insert(Iter begin, Iter end, value_flags flags = preserve_source_value_flags)
8509         {
8510             if (begin == end)
8511                 return;
8512             for (auto it = begin; it != end; it++)
8513             {
8514                 if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
8515                     insert(std::move((*it).first), std::move((*it).second), flags);
8516                 else
8517                     insert((*it).first, (*it).second, flags);
8518             }
8519         }
8520 
8521         TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
8522                                   typename KeyType,
8523                                   typename ValueType)
8524         std::pair<iterator, bool> insert_or_assign(KeyType&& key,
8525                                                    ValueType&& val,
8526                                                    value_flags flags = preserve_source_value_flags)
8527         {
8528             static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8529                           "Insertion using wide-character keys is only supported on Windows with "
8530                           "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8531 
8532             if constexpr (is_node_view<ValueType>)
8533             {
8534                 if (!val)
8535                     return { end(), false };
8536             }
8537 
8538             if constexpr (impl::is_wide_string<KeyType>)
8539             {
8540 #if TOML_ENABLE_WINDOWS_COMPAT
8541                 return insert_or_assign(impl::narrow(static_cast<KeyType&&>(key)),
8542                                         static_cast<ValueType&&>(val),
8543                                         flags);
8544 #else
8545                 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8546 #endif
8547             }
8548             else
8549             {
8550                 const auto key_view = std::string_view{ key };
8551                 map_iterator ipos   = get_lower_bound(key_view);
8552                 if (ipos == map_.end() || ipos->first != key_view)
8553                 {
8554                     ipos = insert_with_hint(const_iterator{ ipos },
8555                                             toml::key{ static_cast<KeyType&&>(key) },
8556                                             impl::make_node(static_cast<ValueType&&>(val), flags));
8557                     return { iterator{ ipos }, true };
8558                 }
8559                 else
8560                 {
8561                     (*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags);
8562                     return { iterator{ ipos }, false };
8563                 }
8564             }
8565         }
8566 
8567         TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
8568                                   typename ValueType = void,
8569                                   typename KeyType,
8570                                   typename... ValueArgs)
8571         std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args)
8572         {
8573             static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
8574                           "Emplacement using wide-character keys is only supported on Windows with "
8575                           "TOML_ENABLE_WINDOWS_COMPAT enabled.");
8576 
8577             using raw_value_type = impl::remove_cvref<ValueType>;
8578             using value_type     = std::
8579                 conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
8580 
8581             if constexpr (impl::is_wide_string<KeyType>)
8582             {
8583 #if TOML_ENABLE_WINDOWS_COMPAT
8584                 return emplace<value_type>(impl::narrow(static_cast<KeyType&&>(key)),
8585                                            static_cast<ValueArgs&&>(args)...);
8586 #else
8587                 static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
8588 #endif
8589             }
8590             else
8591             {
8592                 using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
8593                 static_assert((impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
8594                               "ValueType argument of table::emplace() must be one "
8595                               "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
8596 
8597                 const auto key_view = std::string_view{ key };
8598                 auto ipos           = get_lower_bound(key_view);
8599                 if (ipos == map_.end() || ipos->first != key_view)
8600                 {
8601                     ipos = insert_with_hint(
8602                         const_iterator{ ipos },
8603                         toml::key{ static_cast<KeyType&&>(key) },
8604                         impl::node_ptr{ new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... } });
8605                     return { iterator{ ipos }, true };
8606                 }
8607                 return { iterator{ ipos }, false };
8608             }
8609         }
8610 
8611         using node::operator[]; // inherit operator[toml::path]
8612 
8613         TOML_NODISCARD
8614         node_view<node> operator[](std::string_view key) noexcept
8615         {
8616             return node_view<node>{ get(key) };
8617         }
8618 
8619         TOML_NODISCARD
8620         node_view<const node> operator[](std::string_view key) const noexcept
8621         {
8622             return node_view<const node>{ get(key) };
8623         }
8624 
8625 #if TOML_ENABLE_WINDOWS_COMPAT
8626 
8627         TOML_NODISCARD
8628         node_view<node> operator[](std::wstring_view key)
8629         {
8630             return node_view<node>{ get(key) };
8631         }
8632 
8633         TOML_NODISCARD
8634         node_view<const node> operator[](std::wstring_view key) const
8635         {
8636             return node_view<const node>{ get(key) };
8637         }
8638 
8639 #endif // TOML_ENABLE_WINDOWS_COMPAT
8640 
8641       private:
8642 
8643         TOML_PURE_GETTER
8644         TOML_EXPORTED_STATIC_FUNCTION
8645         static bool TOML_CALLCONV equal(const table&, const table&) noexcept;
8646 
8647       public:
8648 
8649         TOML_NODISCARD
8650         friend bool operator==(const table& lhs, const table& rhs) noexcept
8651         {
8652             return equal(lhs, rhs);
8653         }
8654 
8655         TOML_NODISCARD
8656         friend bool operator!=(const table& lhs, const table& rhs) noexcept
8657         {
8658             return !equal(lhs, rhs);
8659         }
8660 
8661 #if TOML_ENABLE_FORMATTERS
8662 
8663         friend std::ostream& operator<<(std::ostream& lhs, const table& rhs)
8664         {
8665             impl::print_to_stream(lhs, rhs);
8666             return lhs;
8667         }
8668 
8669 #endif
8670     };
8671 }
8672 TOML_NAMESPACE_END;
8673 
8674 #ifdef _MSC_VER
8675 #pragma pop_macro("min")
8676 #pragma pop_macro("max")
8677 #ifndef __clang__
8678 #pragma inline_recursion(off)
8679 #endif
8680 #endif
8681 TOML_POP_WARNINGS;
8682 
8683 //********  impl/unicode_autogenerated.hpp  ****************************************************************************
8684 
8685 TOML_PUSH_WARNINGS;
8686 #ifdef _MSC_VER
8687 #ifndef __clang__
8688 #pragma inline_recursion(on)
8689 #endif
8690 #pragma push_macro("min")
8691 #pragma push_macro("max")
8692 #undef min
8693 #undef max
8694 #endif
8695 
8696 #if TOML_GCC && TOML_GCC < 9
8697 #pragma GCC push_options
8698 #pragma GCC optimize("O1") // codegen bugs
8699 #endif
8700 
8701 // the functions in this namespace block are automatically generated by a tool - they are not meant to be hand-edited
8702 
8703 TOML_IMPL_NAMESPACE_START
8704 {
8705     TOML_CONST_GETTER
8706     constexpr bool is_ascii_horizontal_whitespace(char32_t c) noexcept
8707     {
8708         return c == U'\t' || c == U' ';
8709     }
8710 
8711     TOML_CONST_GETTER
8712     constexpr bool is_non_ascii_horizontal_whitespace(char32_t c) noexcept
8713     {
8714         // 20 code units from 8 ranges (spanning a search area of 65120)
8715 
8716         if (c < U'\xA0' || c > U'\uFEFF')
8717             return false;
8718 
8719         const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xA0ull) / 0x3FAull;
8720         if ((1ull << child_index_0) & 0x7FFFFFFFFFFFF75Eull)
8721             return false;
8722         if (c == U'\xA0' || c == U'\u3000' || c == U'\uFEFF')
8723             return true;
8724         switch (child_index_0)
8725         {
8726             case 0x05: return c == U'\u1680' || c == U'\u180E';
8727             case 0x07:
8728                 return (U'\u2000' <= c && c <= U'\u200B') || (U'\u205F' <= c && c <= U'\u2060') || c == U'\u202F';
8729             default: TOML_UNREACHABLE;
8730         }
8731 
8732         TOML_UNREACHABLE;
8733     }
8734 
8735     TOML_CONST_GETTER
8736     constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept
8737     {
8738         return c >= U'\n' && c <= U'\r';
8739     }
8740 
8741     TOML_CONST_GETTER
8742     constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept
8743     {
8744         return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
8745     }
8746 
8747     TOML_CONST_GETTER
8748     constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
8749     {
8750 #if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
8751         if TOML_UNLIKELY(c == U'+')
8752             return true;
8753 #endif
8754         // 64 code units from 5 ranges (spanning a search area of 78)
8755 
8756         if (c < U'-' || c > U'z')
8757             return false;
8758 
8759         return (((static_cast<uint_least64_t>(c) - 0x2Dull) / 0x40ull) != 0ull)
8760             || ((1ull << (static_cast<uint_least64_t>(c) - 0x2Dull)) & 0xFFF43FFFFFF01FF9ull);
8761     }
8762 
8763 #if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
8764 
8765     TOML_CONST_GETTER
8766     constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept
8767     {
8768         // 971732 code units from 16 ranges (spanning a search area of 982862)
8769 
8770         if (c < U'\xB2' || c > U'\U000EFFFF')
8771             return false;
8772 
8773         const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xB2ull) / 0x3BFEull;
8774         if ((1ull << child_index_0) & 0xFFFFFFFFFFFFFFE6ull)
8775             return true;
8776         switch (child_index_0)
8777         {
8778             case 0x00: // [0] 00B2 - 3CAF
8779             {
8780                 // 12710 code units from 13 ranges (spanning a search area of 15358)
8781 
8782                 TOML_ASSUME(c >= U'\xB2' && c <= U'\u3CAF');
8783 
8784                 constexpr uint_least64_t bitmask_table_1[] = {
8785                     0xFFFFFFDFFFFFDC83u, 0xFFFFFFFFFFFFFFDFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8786                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8787                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFEFFFu,
8788                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8789                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8790                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8791                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8792                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8793                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8794                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8795                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8796                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8797                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8798                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8799                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8800                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8801                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8802                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8803                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8804                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8805                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8806                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8807                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8808                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8809                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8810                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8811                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8812                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8813                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8814                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8815                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8816                     0xFFFFFFFFFFFFFFFFu, 0x000000000C003FFFu, 0xC000000000006000u, 0xFFFFFFFFFFFFFFFFu,
8817                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000000003FFFFFFFu,
8818                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8819                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8820                     0x0000000000000000u, 0x0000000000000000u, 0xFFFFC00000000000u, 0xFFFFFFFFFFFFFFFFu,
8821                     0xFFFFFFFFFFFFFFFFu, 0x0000000000003FFFu, 0x0000000000000000u, 0x0000000000000000u,
8822                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8823                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8824                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8825                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8826                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8827                     0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
8828                     0x0000000000000000u, 0xFFFFFFFFFFFFC000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8829                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8830                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8831                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8832                     0x3FFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFF8000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8833                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8834                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8835                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8836                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8837                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8838                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8839                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8840                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8841                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8842                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8843                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
8844                     0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu,
8845                 };
8846                 return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xB2ull) / 0x40ull]
8847                      & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xB2ull) % 0x40ull));
8848             }
8849             case 0x03: return c <= U'\uD7FF';
8850             case 0x04:
8851                 return (U'\uF900' <= c && c <= U'\uFDCF') || (U'\uFDF0' <= c && c <= U'\uFFFD') || U'\U00010000' <= c;
8852             default: TOML_UNREACHABLE;
8853         }
8854 
8855         TOML_UNREACHABLE;
8856     }
8857 
8858 #endif // TOML_LANG_UNRELEASED
8859 }
8860 TOML_IMPL_NAMESPACE_END;
8861 
8862 #if TOML_GCC && TOML_GCC < 9
8863 #pragma GCC pop_options
8864 #endif
8865 
8866 #ifdef _MSC_VER
8867 #pragma pop_macro("min")
8868 #pragma pop_macro("max")
8869 #ifndef __clang__
8870 #pragma inline_recursion(off)
8871 #endif
8872 #endif
8873 TOML_POP_WARNINGS;
8874 
8875 //********  impl/unicode.hpp  ******************************************************************************************
8876 
8877 TOML_PUSH_WARNINGS;
8878 #ifdef _MSC_VER
8879 #ifndef __clang__
8880 #pragma inline_recursion(on)
8881 #endif
8882 #pragma push_macro("min")
8883 #pragma push_macro("max")
8884 #undef min
8885 #undef max
8886 #endif
8887 
8888 TOML_IMPL_NAMESPACE_START
8889 {
8890     TOML_CONST_GETTER
8891     constexpr bool is_string_delimiter(char32_t c) noexcept
8892     {
8893         return c == U'"' || c == U'\'';
8894     }
8895 
8896     TOML_CONST_GETTER
8897     constexpr bool is_ascii_letter(char32_t c) noexcept
8898     {
8899         return (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z');
8900     }
8901 
8902     TOML_CONST_GETTER
8903     constexpr bool is_binary_digit(char32_t c) noexcept
8904     {
8905         return c == U'0' || c == U'1';
8906     }
8907 
8908     TOML_CONST_GETTER
8909     constexpr bool is_octal_digit(char32_t c) noexcept
8910     {
8911         return (c >= U'0' && c <= U'7');
8912     }
8913 
8914     TOML_CONST_GETTER
8915     constexpr bool is_decimal_digit(char32_t c) noexcept
8916     {
8917         return (c >= U'0' && c <= U'9');
8918     }
8919 
8920     TOML_CONST_GETTER
8921     constexpr bool is_hexadecimal_digit(char32_t c) noexcept
8922     {
8923         return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
8924     }
8925 
8926     template <typename T>
8927     TOML_CONST_GETTER
8928     constexpr uint_least32_t hex_to_dec(const T c) noexcept
8929     {
8930         if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
8931             return c >= 0x41u                    // >= 'A'
8932                      ? 10u + (c | 0x20u) - 0x61u // - 'a'
8933                      : c - 0x30u                 // - '0'
8934                 ;
8935         else
8936             return hex_to_dec(static_cast<uint_least32_t>(c));
8937     }
8938 
8939     TOML_CONST_GETTER
8940     constexpr bool is_horizontal_whitespace(char32_t c) noexcept
8941     {
8942         return is_ascii_horizontal_whitespace(c) || is_non_ascii_horizontal_whitespace(c);
8943     }
8944 
8945     TOML_CONST_GETTER
8946     constexpr bool is_vertical_whitespace(char32_t c) noexcept
8947     {
8948         return is_ascii_vertical_whitespace(c) || is_non_ascii_vertical_whitespace(c);
8949     }
8950 
8951     TOML_CONST_GETTER
8952     constexpr bool is_whitespace(char32_t c) noexcept
8953     {
8954         return is_horizontal_whitespace(c) || is_vertical_whitespace(c);
8955     }
8956 
8957     TOML_CONST_GETTER
8958     constexpr bool is_bare_key_character(char32_t c) noexcept
8959     {
8960         return is_ascii_bare_key_character(c)
8961 #if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
8962             || is_non_ascii_bare_key_character(c)
8963 #endif
8964             ;
8965     }
8966 
8967     TOML_CONST_GETTER
8968     constexpr bool is_value_terminator(char32_t c) noexcept
8969     {
8970         return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
8971     }
8972 
8973     TOML_CONST_GETTER
8974     constexpr bool is_control_character(char c) noexcept
8975     {
8976         return c <= '\u001F' || c == '\u007F';
8977     }
8978 
8979     TOML_CONST_GETTER
8980     constexpr bool is_control_character(char32_t c) noexcept
8981     {
8982         return c <= U'\u001F' || c == U'\u007F';
8983     }
8984 
8985     TOML_CONST_GETTER
8986     constexpr bool is_nontab_control_character(char32_t c) noexcept
8987     {
8988         return c <= U'\u0008' || (c >= U'\u000A' && c <= U'\u001F') || c == U'\u007F';
8989     }
8990 
8991     TOML_CONST_GETTER
8992     constexpr bool is_unicode_surrogate(char32_t c) noexcept
8993     {
8994         return c >= 0xD800u && c <= 0xDFFF;
8995     }
8996 
8997     struct utf8_decoder
8998     {
8999         // utf8_decoder based on this: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
9000         // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
9001 
9002         uint_least32_t state{};
9003         char32_t codepoint{};
9004 
9005         static constexpr uint8_t state_table[]{
9006             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
9007             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
9008             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
9009             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
9010             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,
9011             1,  1,  1,  1,  1,  1,  1,  1,  1,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  7,  7,
9012             7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
9013             7,  7,  7,  8,  8,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
9014             2,  2,  2,  2,  2,  2,  2,  2,  10, 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  4,  3,  3,  11, 6,  6,
9015             6,  5,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
9016             0,  12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0,  12,
9017             12, 12, 12, 12, 0,  12, 0,  12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12,
9018             12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12,
9019             36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
9020         };
9021 
9022         TOML_PURE_INLINE_GETTER
9023         constexpr bool error() const noexcept
9024         {
9025             return state == uint_least32_t{ 12u };
9026         }
9027 
9028         TOML_PURE_INLINE_GETTER
9029         constexpr bool has_code_point() const noexcept
9030         {
9031             return state == uint_least32_t{};
9032         }
9033 
9034         TOML_PURE_INLINE_GETTER
9035         constexpr bool needs_more_input() const noexcept
9036         {
9037             return !has_code_point() && !error();
9038         }
9039 
9040         constexpr void operator()(uint8_t byte) noexcept
9041         {
9042             TOML_ASSERT_ASSUME(!error());
9043 
9044             const auto type = state_table[byte];
9045 
9046             codepoint = static_cast<char32_t>(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte
9047                                                                : (byte & uint_least32_t{ 63u })
9048                                                                      | (static_cast<uint_least32_t>(codepoint) << 6));
9049 
9050             state = state_table[state + uint_least32_t{ 256u } + type];
9051         }
9052 
9053         TOML_ALWAYS_INLINE
9054         constexpr void operator()(char c) noexcept
9055         {
9056             operator()(static_cast<uint8_t>(c));
9057         }
9058 
9059         TOML_ALWAYS_INLINE
9060         constexpr void reset() noexcept
9061         {
9062             state = {};
9063         }
9064     };
9065 
9066     TOML_PURE_GETTER
9067     TOML_ATTR(nonnull)
9068     bool is_ascii(const char* str, size_t len) noexcept;
9069 }
9070 TOML_IMPL_NAMESPACE_END;
9071 
9072 #ifdef _MSC_VER
9073 #pragma pop_macro("min")
9074 #pragma pop_macro("max")
9075 #ifndef __clang__
9076 #pragma inline_recursion(off)
9077 #endif
9078 #endif
9079 TOML_POP_WARNINGS;
9080 
9081 //********  impl/parse_error.hpp  **************************************************************************************
9082 
9083 #if TOML_ENABLE_PARSER
9084 
9085 //********  impl/std_except.hpp  ***************************************************************************************
9086 
9087 TOML_DISABLE_WARNINGS;
9088 #if TOML_EXCEPTIONS
9089 #include <stdexcept>
9090 #endif
9091 TOML_ENABLE_WARNINGS;
9092 
9093 //********  impl/parse_error.hpp  **************************************************************************************
9094 
9095 TOML_PUSH_WARNINGS;
9096 #ifdef _MSC_VER
9097 #ifndef __clang__
9098 #pragma inline_recursion(on)
9099 #endif
9100 #pragma push_macro("min")
9101 #pragma push_macro("max")
9102 #undef min
9103 #undef max
9104 #endif
9105 
9106 #if TOML_DOXYGEN || !TOML_EXCEPTIONS
9107 #define TOML_PARSE_ERROR_BASE
9108 #else
9109 #define TOML_PARSE_ERROR_BASE    : public std::runtime_error
9110 #endif
9111 
9112 TOML_NAMESPACE_START
9113 {
9114     TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
9115 
9116     class parse_error TOML_PARSE_ERROR_BASE
9117     {
9118       private:
9119 #if !TOML_EXCEPTIONS
9120         std::string description_;
9121 #endif
9122         source_region source_;
9123 
9124       public:
9125 #if TOML_EXCEPTIONS
9126 
9127         TOML_NODISCARD_CTOR
9128         TOML_ATTR(nonnull)
9129         parse_error(const char* desc, source_region&& src) noexcept //
9130             : std::runtime_error{ desc },
9131               source_{ std::move(src) }
9132         {}
9133 
9134         TOML_NODISCARD_CTOR
9135         TOML_ATTR(nonnull)
9136         parse_error(const char* desc, const source_region& src) noexcept //
9137             : parse_error{ desc, source_region{ src } }
9138         {}
9139 
9140         TOML_NODISCARD_CTOR
9141         TOML_ATTR(nonnull)
9142         parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept
9143             : parse_error{ desc, source_region{ position, position, path } }
9144         {}
9145 
9146 #else
9147 
9148         TOML_NODISCARD_CTOR
9149         parse_error(std::string&& desc, source_region&& src) noexcept //
9150             : description_{ std::move(desc) },
9151               source_{ std::move(src) }
9152         {}
9153 
9154         TOML_NODISCARD_CTOR
9155         parse_error(std::string&& desc, const source_region& src) noexcept //
9156             : parse_error{ std::move(desc), source_region{ src } }
9157         {}
9158 
9159         TOML_NODISCARD_CTOR
9160         parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
9161             : parse_error{ std::move(desc), source_region{ position, position, path } }
9162         {}
9163 
9164 #endif
9165 
9166         TOML_NODISCARD
9167         std::string_view description() const noexcept
9168         {
9169 #if TOML_EXCEPTIONS
9170             return std::string_view{ what() };
9171 #else
9172             return description_;
9173 #endif
9174         }
9175 
9176         TOML_NODISCARD
9177         const source_region& source() const noexcept
9178         {
9179             return source_;
9180         }
9181 
9182         friend std::ostream& operator<<(std::ostream& lhs, const parse_error& rhs)
9183         {
9184             impl::print_to_stream(lhs, rhs.description());
9185             impl::print_to_stream(lhs, "\n\t(error occurred at "sv);
9186             impl::print_to_stream(lhs, rhs.source());
9187             impl::print_to_stream(lhs, ")"sv);
9188             return lhs;
9189         }
9190     };
9191 
9192     TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9193 }
9194 TOML_NAMESPACE_END;
9195 
9196 #undef TOML_PARSE_ERROR_BASE
9197 
9198 #ifdef _MSC_VER
9199 #pragma pop_macro("min")
9200 #pragma pop_macro("max")
9201 #ifndef __clang__
9202 #pragma inline_recursion(off)
9203 #endif
9204 #endif
9205 TOML_POP_WARNINGS;
9206 
9207 #endif // TOML_ENABLE_PARSER
9208 
9209 //********  impl/parse_result.hpp  *************************************************************************************
9210 
9211 #if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
9212 
9213 TOML_PUSH_WARNINGS;
9214 #ifdef _MSC_VER
9215 #ifndef __clang__
9216 #pragma inline_recursion(on)
9217 #endif
9218 #pragma push_macro("min")
9219 #pragma push_macro("max")
9220 #undef min
9221 #undef max
9222 #endif
9223 
9224 TOML_NAMESPACE_START
9225 {
9226     TOML_ABI_NAMESPACE_START(noex);
9227 
9228     class parse_result
9229     {
9230       private:
9231         struct storage_t
9232         {
9233             static constexpr size_t size =
9234                 (sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(toml::table));
9235             static constexpr size_t align =
9236                 (alignof(toml::table) < alignof(parse_error) ? alignof(parse_error) : alignof(toml::table));
9237 
9238             alignas(align) unsigned char bytes[size];
9239         };
9240 
9241         alignas(storage_t::align) mutable storage_t storage_;
9242         bool err_;
9243 
9244         template <typename Type>
9245         TOML_NODISCARD
9246         TOML_ALWAYS_INLINE
9247         static Type* get_as(storage_t& s) noexcept
9248         {
9249             return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
9250         }
9251 
9252         void destroy() noexcept
9253         {
9254             if (err_)
9255                 get_as<parse_error>(storage_)->~parse_error();
9256             else
9257                 get_as<toml::table>(storage_)->~table();
9258         }
9259 
9260       public:
9261 
9262         TOML_NODISCARD_CTOR
9263         parse_result() noexcept //
9264             : err_{ true }
9265         {
9266             ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::string{}, source_region{} };
9267         }
9268 
9269         TOML_NODISCARD_CTOR
9270         explicit parse_result(toml::table&& tbl) noexcept //
9271             : err_{ false }
9272         {
9273             ::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(tbl) };
9274         }
9275 
9276         TOML_NODISCARD_CTOR
9277         explicit parse_result(parse_error&& err) noexcept //
9278             : err_{ true }
9279         {
9280             ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(err) };
9281         }
9282 
9283         TOML_NODISCARD_CTOR
9284         parse_result(parse_result&& res) noexcept //
9285             : err_{ res.err_ }
9286         {
9287             if (err_)
9288                 ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(res).error() };
9289             else
9290                 ::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(res).table() };
9291         }
9292 
9293         parse_result& operator=(parse_result&& rhs) noexcept
9294         {
9295             if (err_ != rhs.err_)
9296             {
9297                 destroy();
9298                 err_ = rhs.err_;
9299                 if (err_)
9300                     ::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(rhs).error() };
9301                 else
9302                     ::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(rhs).table() };
9303             }
9304             else
9305             {
9306                 if (err_)
9307                     error() = std::move(rhs).error();
9308                 else
9309                     table() = std::move(rhs).table();
9310             }
9311             return *this;
9312         }
9313 
9314         ~parse_result() noexcept
9315         {
9316             destroy();
9317         }
9318 
9319         TOML_NODISCARD
9320         bool succeeded() const noexcept
9321         {
9322             return !err_;
9323         }
9324 
9325         TOML_NODISCARD
9326         bool failed() const noexcept
9327         {
9328             return err_;
9329         }
9330 
9331         TOML_NODISCARD
9332         explicit operator bool() const noexcept
9333         {
9334             return !err_;
9335         }
9336 
9337         TOML_NODISCARD
9338         toml::table& table() & noexcept
9339         {
9340             TOML_ASSERT_ASSUME(!err_);
9341             return *get_as<toml::table>(storage_);
9342         }
9343 
9344         TOML_NODISCARD
9345         toml::table&& table() && noexcept
9346         {
9347             TOML_ASSERT_ASSUME(!err_);
9348             return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
9349         }
9350 
9351         TOML_NODISCARD
9352         const toml::table& table() const& noexcept
9353         {
9354             TOML_ASSERT_ASSUME(!err_);
9355             return *get_as<const toml::table>(storage_);
9356         }
9357 
9358         TOML_NODISCARD
9359         /* implicit */ operator toml::table&() noexcept
9360         {
9361             return table();
9362         }
9363 
9364         TOML_NODISCARD
9365         /* implicit */ operator toml::table&&() noexcept
9366         {
9367             return std::move(table());
9368         }
9369 
9370         TOML_NODISCARD
9371         /* implicit */ operator const toml::table&() const noexcept
9372         {
9373             return table();
9374         }
9375 
9376         TOML_NODISCARD
9377         parse_error& error() & noexcept
9378         {
9379             TOML_ASSERT_ASSUME(err_);
9380             return *get_as<parse_error>(storage_);
9381         }
9382 
9383         TOML_NODISCARD
9384         parse_error&& error() && noexcept
9385         {
9386             TOML_ASSERT_ASSUME(err_);
9387             return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
9388         }
9389 
9390         TOML_NODISCARD
9391         const parse_error& error() const& noexcept
9392         {
9393             TOML_ASSERT_ASSUME(err_);
9394             return *get_as<const parse_error>(storage_);
9395         }
9396 
9397         TOML_NODISCARD
9398         explicit operator parse_error&() noexcept
9399         {
9400             return error();
9401         }
9402 
9403         TOML_NODISCARD
9404         explicit operator parse_error&&() noexcept
9405         {
9406             return std::move(error());
9407         }
9408 
9409         TOML_NODISCARD
9410         explicit operator const parse_error&() const noexcept
9411         {
9412             return error();
9413         }
9414 
9415         using iterator = table_iterator;
9416 
9417         using const_iterator = const_table_iterator;
9418 
9419         TOML_NODISCARD
9420         table_iterator begin() noexcept
9421         {
9422             return err_ ? table_iterator{} : table().begin();
9423         }
9424 
9425         TOML_NODISCARD
9426         const_table_iterator begin() const noexcept
9427         {
9428             return err_ ? const_table_iterator{} : table().begin();
9429         }
9430 
9431         TOML_NODISCARD
9432         const_table_iterator cbegin() const noexcept
9433         {
9434             return err_ ? const_table_iterator{} : table().cbegin();
9435         }
9436 
9437         TOML_NODISCARD
9438         table_iterator end() noexcept
9439         {
9440             return err_ ? table_iterator{} : table().end();
9441         }
9442 
9443         TOML_NODISCARD
9444         const_table_iterator end() const noexcept
9445         {
9446             return err_ ? const_table_iterator{} : table().end();
9447         }
9448 
9449         TOML_NODISCARD
9450         const_table_iterator cend() const noexcept
9451         {
9452             return err_ ? const_table_iterator{} : table().cend();
9453         }
9454 
9455         TOML_NODISCARD
9456         node_view<node> at_path(std::string_view path) noexcept
9457         {
9458             return err_ ? node_view<node>{} : table().at_path(path);
9459         }
9460 
9461         TOML_NODISCARD
9462         node_view<const node> at_path(std::string_view path) const noexcept
9463         {
9464             return err_ ? node_view<const node>{} : table().at_path(path);
9465         }
9466 
9467         TOML_NODISCARD
9468         node_view<node> at_path(const toml::path& path) noexcept
9469         {
9470             return err_ ? node_view<node>{} : table().at_path(path);
9471         }
9472 
9473         TOML_NODISCARD
9474         node_view<const node> at_path(const toml::path& path) const noexcept
9475         {
9476             return err_ ? node_view<const node>{} : table().at_path(path);
9477         }
9478 
9479 #if TOML_ENABLE_WINDOWS_COMPAT
9480 
9481         TOML_NODISCARD
9482         node_view<node> at_path(std::wstring_view path)
9483         {
9484             return err_ ? node_view<node>{} : table().at_path(path);
9485         }
9486 
9487         TOML_NODISCARD
9488         node_view<const node> at_path(std::wstring_view path) const
9489         {
9490             return err_ ? node_view<const node>{} : table().at_path(path);
9491         }
9492 
9493 #endif
9494 
9495         TOML_NODISCARD
9496         node_view<node> operator[](const toml::path& path) noexcept
9497         {
9498             return err_ ? node_view<node>{} : table()[path];
9499         }
9500 
9501         TOML_NODISCARD
9502         node_view<const node> operator[](const toml::path& path) const noexcept
9503         {
9504             return err_ ? node_view<const node>{} : table()[path];
9505         }
9506 
9507         TOML_NODISCARD
9508         node_view<node> operator[](std::string_view key) noexcept
9509         {
9510             return err_ ? node_view<node>{} : table()[key];
9511         }
9512 
9513         TOML_NODISCARD
9514         node_view<const node> operator[](std::string_view key) const noexcept
9515         {
9516             return err_ ? node_view<const node>{} : table()[key];
9517         }
9518 
9519 #if TOML_ENABLE_WINDOWS_COMPAT
9520 
9521         TOML_NODISCARD
9522         node_view<node> operator[](std::wstring_view key)
9523         {
9524             return err_ ? node_view<node>{} : table()[key];
9525         }
9526 
9527         TOML_NODISCARD
9528         node_view<const node> operator[](std::wstring_view key) const
9529         {
9530             return err_ ? node_view<const node>{} : table()[key];
9531         }
9532 
9533 #endif // TOML_ENABLE_WINDOWS_COMPAT
9534 
9535 #if TOML_ENABLE_FORMATTERS
9536 
9537         friend std::ostream& operator<<(std::ostream& os, const parse_result& result)
9538         {
9539             return result.err_ ? (os << result.error()) : (os << result.table());
9540         }
9541 
9542 #endif
9543     };
9544 
9545     TOML_ABI_NAMESPACE_END;
9546 }
9547 TOML_NAMESPACE_END;
9548 
9549 #ifdef _MSC_VER
9550 #pragma pop_macro("min")
9551 #pragma pop_macro("max")
9552 #ifndef __clang__
9553 #pragma inline_recursion(off)
9554 #endif
9555 #endif
9556 TOML_POP_WARNINGS;
9557 
9558 #endif // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
9559 
9560 //********  impl/parser.hpp  *******************************************************************************************
9561 
9562 #if TOML_ENABLE_PARSER
9563 
9564 TOML_PUSH_WARNINGS;
9565 #ifdef _MSC_VER
9566 #ifndef __clang__
9567 #pragma inline_recursion(on)
9568 #endif
9569 #pragma push_macro("min")
9570 #pragma push_macro("max")
9571 #undef min
9572 #undef max
9573 #endif
9574 
9575 TOML_NAMESPACE_START
9576 {
9577     TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
9578 
9579     TOML_NODISCARD
9580     TOML_EXPORTED_FREE_FUNCTION
9581     parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path = {});
9582 
9583     TOML_NODISCARD
9584     TOML_EXPORTED_FREE_FUNCTION
9585     parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path);
9586 
9587     TOML_NODISCARD
9588     TOML_EXPORTED_FREE_FUNCTION
9589     parse_result TOML_CALLCONV parse_file(std::string_view file_path);
9590 
9591 #if TOML_HAS_CHAR8
9592 
9593     TOML_NODISCARD
9594     TOML_EXPORTED_FREE_FUNCTION
9595     parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path = {});
9596 
9597     TOML_NODISCARD
9598     TOML_EXPORTED_FREE_FUNCTION
9599     parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path);
9600 
9601     TOML_NODISCARD
9602     TOML_EXPORTED_FREE_FUNCTION
9603     parse_result TOML_CALLCONV parse_file(std::u8string_view file_path);
9604 
9605 #endif // TOML_HAS_CHAR8
9606 
9607 #if TOML_ENABLE_WINDOWS_COMPAT
9608 
9609     TOML_NODISCARD
9610     TOML_EXPORTED_FREE_FUNCTION
9611     parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path);
9612 
9613     TOML_NODISCARD
9614     TOML_EXPORTED_FREE_FUNCTION
9615     parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path);
9616 
9617     TOML_NODISCARD
9618     TOML_EXPORTED_FREE_FUNCTION
9619     parse_result TOML_CALLCONV parse_file(std::wstring_view file_path);
9620 
9621 #endif // TOML_ENABLE_WINDOWS_COMPAT
9622 
9623 #if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
9624 
9625     TOML_NODISCARD
9626     TOML_EXPORTED_FREE_FUNCTION
9627     parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path);
9628 
9629 #endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
9630 
9631     TOML_NODISCARD
9632     TOML_EXPORTED_FREE_FUNCTION
9633     parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path = {});
9634 
9635     TOML_NODISCARD
9636     TOML_EXPORTED_FREE_FUNCTION
9637     parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path);
9638 
9639     TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9640 
9641     inline namespace literals
9642     {
9643         TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex);
9644 
9645         TOML_NODISCARD
9646         TOML_ALWAYS_INLINE
9647         parse_result operator"" _toml(const char* str, size_t len)
9648         {
9649             return parse(std::string_view{ str, len });
9650         }
9651 
9652 #if TOML_HAS_CHAR8
9653 
9654         TOML_NODISCARD
9655         TOML_ALWAYS_INLINE
9656         parse_result operator"" _toml(const char8_t* str, size_t len)
9657         {
9658             return parse(std::u8string_view{ str, len });
9659         }
9660 
9661 #endif // TOML_HAS_CHAR8
9662 
9663         TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
9664     }
9665 }
9666 TOML_NAMESPACE_END;
9667 
9668 #ifdef _MSC_VER
9669 #pragma pop_macro("min")
9670 #pragma pop_macro("max")
9671 #ifndef __clang__
9672 #pragma inline_recursion(off)
9673 #endif
9674 #endif
9675 TOML_POP_WARNINGS;
9676 
9677 #endif // TOML_ENABLE_PARSER
9678 
9679 //********  impl/formatter.hpp  ****************************************************************************************
9680 
9681 #if TOML_ENABLE_FORMATTERS
9682 
9683 TOML_PUSH_WARNINGS;
9684 #ifdef _MSC_VER
9685 #ifndef __clang__
9686 #pragma inline_recursion(on)
9687 #endif
9688 #pragma push_macro("min")
9689 #pragma push_macro("max")
9690 #undef min
9691 #undef max
9692 #endif
9693 
9694 TOML_IMPL_NAMESPACE_START
9695 {
9696     struct formatter_constants
9697     {
9698         format_flags mandatory_flags;
9699         format_flags ignored_flags;
9700 
9701         std::string_view float_pos_inf;
9702         std::string_view float_neg_inf;
9703         std::string_view float_nan;
9704 
9705         std::string_view bool_true;
9706         std::string_view bool_false;
9707     };
9708 
9709     struct formatter_config
9710     {
9711         format_flags flags;
9712         std::string_view indent;
9713     };
9714 
9715     class TOML_EXPORTED_CLASS formatter
9716     {
9717       private:
9718         const node* source_;
9719 #if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
9720         const parse_result* result_;
9721 #endif
9722         const formatter_constants* constants_;
9723         formatter_config config_;
9724         size_t indent_columns_;
9725         format_flags int_format_mask_;
9726         std::ostream* stream_; //
9727         int indent_;           // these are set in attach()
9728         bool naked_newline_;   //
9729 
9730       protected:
9731         TOML_PURE_INLINE_GETTER
9732         const node& source() const noexcept
9733         {
9734             return *source_;
9735         }
9736 
9737         TOML_PURE_INLINE_GETTER
9738         std::ostream& stream() const noexcept
9739         {
9740             return *stream_;
9741         }
9742 
9743         TOML_PURE_INLINE_GETTER
9744         int indent() const noexcept
9745         {
9746             return indent_;
9747         }
9748 
9749         void indent(int level) noexcept
9750         {
9751             indent_ = level;
9752         }
9753 
9754         void increase_indent() noexcept
9755         {
9756             indent_++;
9757         }
9758 
9759         void decrease_indent() noexcept
9760         {
9761             indent_--;
9762         }
9763 
9764         TOML_PURE_INLINE_GETTER
9765         size_t indent_columns() const noexcept
9766         {
9767             return indent_columns_;
9768         }
9769 
9770         TOML_PURE_INLINE_GETTER
9771         bool indent_array_elements() const noexcept
9772         {
9773             return !!(config_.flags & format_flags::indent_array_elements);
9774         }
9775 
9776         TOML_PURE_INLINE_GETTER
9777         bool indent_sub_tables() const noexcept
9778         {
9779             return !!(config_.flags & format_flags::indent_sub_tables);
9780         }
9781 
9782         TOML_PURE_INLINE_GETTER
9783         bool literal_strings_allowed() const noexcept
9784         {
9785             return !!(config_.flags & format_flags::allow_literal_strings);
9786         }
9787 
9788         TOML_PURE_INLINE_GETTER
9789         bool multi_line_strings_allowed() const noexcept
9790         {
9791             return !!(config_.flags & format_flags::allow_multi_line_strings);
9792         }
9793 
9794         TOML_PURE_INLINE_GETTER
9795         bool real_tabs_in_strings_allowed() const noexcept
9796         {
9797             return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
9798         }
9799 
9800         TOML_PURE_INLINE_GETTER
9801         bool unicode_strings_allowed() const noexcept
9802         {
9803             return !!(config_.flags & format_flags::allow_unicode_strings);
9804         }
9805 
9806         TOML_PURE_INLINE_GETTER
9807         bool terse_kvps() const noexcept
9808         {
9809             return !!(config_.flags & format_flags::terse_key_value_pairs);
9810         }
9811 
9812         TOML_EXPORTED_MEMBER_FUNCTION
9813         void attach(std::ostream& stream) noexcept;
9814 
9815         TOML_EXPORTED_MEMBER_FUNCTION
9816         void detach() noexcept;
9817 
9818         TOML_EXPORTED_MEMBER_FUNCTION
9819         void print_newline(bool force = false);
9820 
9821         TOML_EXPORTED_MEMBER_FUNCTION
9822         void print_indent();
9823 
9824         TOML_EXPORTED_MEMBER_FUNCTION
9825         void print_unformatted(char);
9826 
9827         TOML_EXPORTED_MEMBER_FUNCTION
9828         void print_unformatted(std::string_view);
9829 
9830         TOML_EXPORTED_MEMBER_FUNCTION
9831         void print_string(std::string_view str,
9832                           bool allow_multi_line         = true,
9833                           bool allow_bare               = false,
9834                           bool allow_literal_whitespace = true);
9835 
9836         TOML_EXPORTED_MEMBER_FUNCTION
9837         void print(const value<std::string>&);
9838 
9839         TOML_EXPORTED_MEMBER_FUNCTION
9840         void print(const value<int64_t>&);
9841 
9842         TOML_EXPORTED_MEMBER_FUNCTION
9843         void print(const value<double>&);
9844 
9845         TOML_EXPORTED_MEMBER_FUNCTION
9846         void print(const value<bool>&);
9847 
9848         TOML_EXPORTED_MEMBER_FUNCTION
9849         void print(const value<date>&);
9850 
9851         TOML_EXPORTED_MEMBER_FUNCTION
9852         void print(const value<time>&);
9853 
9854         TOML_EXPORTED_MEMBER_FUNCTION
9855         void print(const value<date_time>&);
9856 
9857         TOML_EXPORTED_MEMBER_FUNCTION
9858         void print_value(const node&, node_type);
9859 
9860         TOML_NODISCARD
9861         TOML_EXPORTED_MEMBER_FUNCTION
9862         bool dump_failed_parse_result();
9863 
9864         TOML_NODISCARD_CTOR
9865         TOML_EXPORTED_MEMBER_FUNCTION
9866         formatter(const node*, const parse_result*, const formatter_constants&, const formatter_config&) noexcept;
9867     };
9868 }
9869 TOML_IMPL_NAMESPACE_END;
9870 
9871 #ifdef _MSC_VER
9872 #pragma pop_macro("min")
9873 #pragma pop_macro("max")
9874 #ifndef __clang__
9875 #pragma inline_recursion(off)
9876 #endif
9877 #endif
9878 TOML_POP_WARNINGS;
9879 
9880 #endif // TOML_ENABLE_FORMATTERS
9881 
9882 //********  impl/toml_formatter.hpp  ***********************************************************************************
9883 
9884 #if TOML_ENABLE_FORMATTERS
9885 
9886 TOML_PUSH_WARNINGS;
9887 #ifdef _MSC_VER
9888 #ifndef __clang__
9889 #pragma inline_recursion(on)
9890 #endif
9891 #pragma push_macro("min")
9892 #pragma push_macro("max")
9893 #undef min
9894 #undef max
9895 #endif
9896 
9897 TOML_NAMESPACE_START
9898 {
9899     class TOML_EXPORTED_CLASS toml_formatter : impl::formatter
9900     {
9901       private:
9902 
9903         using base = impl::formatter;
9904         std::vector<const key*> key_path_;
9905         bool pending_table_separator_ = false;
9906 
9907         TOML_EXPORTED_MEMBER_FUNCTION
9908         void print_pending_table_separator();
9909 
9910         TOML_EXPORTED_MEMBER_FUNCTION
9911         void print(const key&);
9912 
9913         TOML_EXPORTED_MEMBER_FUNCTION
9914         void print_inline(const toml::table&);
9915 
9916         TOML_EXPORTED_MEMBER_FUNCTION
9917         void print(const toml::array&);
9918 
9919         TOML_EXPORTED_MEMBER_FUNCTION
9920         void print(const toml::table&);
9921 
9922         TOML_EXPORTED_MEMBER_FUNCTION
9923         void print();
9924 
9925         static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory
9926                                                                  format_flags::none, // ignored
9927                                                                  "inf"sv,
9928                                                                  "-inf"sv,
9929                                                                  "nan"sv,
9930                                                                  "true"sv,
9931                                                                  "false"sv };
9932 
9933       public:
9934 
9935         static constexpr format_flags default_flags = constants.mandatory_flags                //
9936                                                     | format_flags::allow_literal_strings      //
9937                                                     | format_flags::allow_multi_line_strings   //
9938                                                     | format_flags::allow_unicode_strings      //
9939                                                     | format_flags::allow_real_tabs_in_strings //
9940                                                     | format_flags::allow_binary_integers      //
9941                                                     | format_flags::allow_octal_integers       //
9942                                                     | format_flags::allow_hexadecimal_integers //
9943                                                     | format_flags::indentation;
9944 
9945         TOML_NODISCARD_CTOR
9946         explicit toml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
9947             : base{ &source, nullptr, constants, { flags, "    "sv } }
9948         {}
9949 
9950 #if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
9951 
9952         TOML_NODISCARD_CTOR
9953         explicit toml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
9954             : base{ nullptr, &result, constants, { flags, "    "sv } }
9955         {}
9956 
9957 #endif
9958 
9959         friend std::ostream& operator<<(std::ostream& lhs, toml_formatter& rhs)
9960         {
9961             rhs.attach(lhs);
9962             rhs.key_path_.clear();
9963             rhs.print();
9964             rhs.detach();
9965             return lhs;
9966         }
9967 
9968         friend std::ostream& operator<<(std::ostream& lhs, toml_formatter&& rhs)
9969         {
9970             return lhs << rhs; // as lvalue
9971         }
9972     };
9973 }
9974 TOML_NAMESPACE_END;
9975 
9976 #ifdef _MSC_VER
9977 #pragma pop_macro("min")
9978 #pragma pop_macro("max")
9979 #ifndef __clang__
9980 #pragma inline_recursion(off)
9981 #endif
9982 #endif
9983 TOML_POP_WARNINGS;
9984 
9985 #endif // TOML_ENABLE_FORMATTERS
9986 
9987 //********  impl/json_formatter.hpp  ***********************************************************************************
9988 
9989 #if TOML_ENABLE_FORMATTERS
9990 
9991 TOML_PUSH_WARNINGS;
9992 #ifdef _MSC_VER
9993 #ifndef __clang__
9994 #pragma inline_recursion(on)
9995 #endif
9996 #pragma push_macro("min")
9997 #pragma push_macro("max")
9998 #undef min
9999 #undef max
10000 #endif
10001 
10002 TOML_NAMESPACE_START
10003 {
10004     class TOML_EXPORTED_CLASS json_formatter : impl::formatter
10005     {
10006       private:
10007 
10008         using base = impl::formatter;
10009 
10010         TOML_EXPORTED_MEMBER_FUNCTION
10011         void print(const toml::table&);
10012 
10013         TOML_EXPORTED_MEMBER_FUNCTION
10014         void print(const toml::array&);
10015 
10016         TOML_EXPORTED_MEMBER_FUNCTION
10017         void print();
10018 
10019         static constexpr impl::formatter_constants constants = {
10020             format_flags::quote_dates_and_times,                                          // mandatory
10021             format_flags::allow_literal_strings | format_flags::allow_multi_line_strings, // ignored
10022             "Infinity"sv,
10023             "-Infinity"sv,
10024             "NaN"sv,
10025             "true"sv,
10026             "false"sv
10027         };
10028 
10029       public:
10030 
10031         static constexpr format_flags default_flags = constants.mandatory_flags               //
10032                                                     | format_flags::quote_infinities_and_nans //
10033                                                     | format_flags::allow_unicode_strings     //
10034                                                     | format_flags::indentation;
10035 
10036         TOML_NODISCARD_CTOR
10037         explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
10038             : base{ &source, nullptr, constants, { flags, "    "sv } }
10039         {}
10040 
10041 #if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
10042 
10043         TOML_NODISCARD_CTOR
10044         explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
10045             : base{ nullptr, &result, constants, { flags, "    "sv } }
10046         {}
10047 
10048 #endif
10049 
10050         friend std::ostream& operator<<(std::ostream& lhs, json_formatter& rhs)
10051         {
10052             rhs.attach(lhs);
10053             rhs.print();
10054             rhs.detach();
10055             return lhs;
10056         }
10057 
10058         friend std::ostream& operator<<(std::ostream& lhs, json_formatter&& rhs)
10059         {
10060             return lhs << rhs; // as lvalue
10061         }
10062     };
10063 }
10064 TOML_NAMESPACE_END;
10065 
10066 #ifdef _MSC_VER
10067 #pragma pop_macro("min")
10068 #pragma pop_macro("max")
10069 #ifndef __clang__
10070 #pragma inline_recursion(off)
10071 #endif
10072 #endif
10073 TOML_POP_WARNINGS;
10074 
10075 #endif // TOML_ENABLE_FORMATTERS
10076 
10077 //********  impl/yaml_formatter.hpp  ***********************************************************************************
10078 
10079 #if TOML_ENABLE_FORMATTERS
10080 
10081 TOML_PUSH_WARNINGS;
10082 #ifdef _MSC_VER
10083 #ifndef __clang__
10084 #pragma inline_recursion(on)
10085 #endif
10086 #pragma push_macro("min")
10087 #pragma push_macro("max")
10088 #undef min
10089 #undef max
10090 #endif
10091 
10092 TOML_NAMESPACE_START
10093 {
10094     class TOML_EXPORTED_CLASS yaml_formatter : impl::formatter
10095     {
10096       private:
10097 
10098         using base = impl::formatter;
10099 
10100         TOML_EXPORTED_MEMBER_FUNCTION
10101         void print_yaml_string(const value<std::string>&);
10102 
10103         TOML_EXPORTED_MEMBER_FUNCTION
10104         void print(const toml::table&, bool = false);
10105 
10106         TOML_EXPORTED_MEMBER_FUNCTION
10107         void print(const toml::array&, bool = false);
10108 
10109         TOML_EXPORTED_MEMBER_FUNCTION
10110         void print();
10111 
10112         static constexpr impl::formatter_constants constants = {
10113             //
10114             format_flags::quote_dates_and_times | format_flags::indentation, // mandatory
10115             format_flags::allow_multi_line_strings,                          // ignored
10116             ".inf"sv,
10117             "-.inf"sv,
10118             ".NAN"sv,
10119             "true"sv,
10120             "false"sv
10121         };
10122 
10123       public:
10124 
10125         static constexpr format_flags default_flags = constants.mandatory_flags           //
10126                                                     | format_flags::allow_literal_strings //
10127                                                     | format_flags::allow_unicode_strings //
10128                                                     | format_flags::allow_octal_integers  //
10129                                                     | format_flags::allow_hexadecimal_integers;
10130 
10131         TOML_NODISCARD_CTOR
10132         explicit yaml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
10133             : base{ &source, nullptr, constants, { flags, "  "sv } }
10134         {}
10135 
10136 #if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
10137 
10138         TOML_NODISCARD_CTOR
10139         explicit yaml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
10140             : base{ nullptr, &result, constants, { flags, "  "sv } }
10141         {}
10142 
10143 #endif
10144 
10145         friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter& rhs)
10146         {
10147             rhs.attach(lhs);
10148             rhs.print();
10149             rhs.detach();
10150             return lhs;
10151         }
10152 
10153         friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter&& rhs)
10154         {
10155             return lhs << rhs; // as lvalue
10156         }
10157     };
10158 }
10159 TOML_NAMESPACE_END;
10160 
10161 #ifdef _MSC_VER
10162 #pragma pop_macro("min")
10163 #pragma pop_macro("max")
10164 #ifndef __clang__
10165 #pragma inline_recursion(off)
10166 #endif
10167 #endif
10168 TOML_POP_WARNINGS;
10169 
10170 #endif // TOML_ENABLE_FORMATTERS
10171 
10172 #if TOML_IMPLEMENTATION
10173 
10174 //********  impl/std_string.inl  ***************************************************************************************
10175 
10176 #if TOML_WINDOWS
10177 
10178 #ifndef _WINDOWS_
10179 #if TOML_INCLUDE_WINDOWS_H
10180 #include <Windows.h>
10181 #else
10182 
10183 extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int CodePage,
10184                                                                    unsigned long dwFlags,
10185                                                                    const wchar_t* lpWideCharStr,
10186                                                                    int cchWideChar,
10187                                                                    char* lpMultiByteStr,
10188                                                                    int cbMultiByte,
10189                                                                    const char* lpDefaultChar,
10190                                                                    int* lpUsedDefaultChar);
10191 
10192 extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage,
10193                                                                    unsigned long dwFlags,
10194                                                                    const char* lpMultiByteStr,
10195                                                                    int cbMultiByte,
10196                                                                    wchar_t* lpWideCharStr,
10197                                                                    int cchWideChar);
10198 
10199 #endif // TOML_INCLUDE_WINDOWS_H
10200 #endif // _WINDOWS_
10201 
10202 TOML_PUSH_WARNINGS;
10203 #ifdef _MSC_VER
10204 #ifndef __clang__
10205 #pragma inline_recursion(on)
10206 #endif
10207 #pragma push_macro("min")
10208 #pragma push_macro("max")
10209 #undef min
10210 #undef max
10211 #endif
10212 
10213 TOML_IMPL_NAMESPACE_START
10214 {
10215     TOML_EXTERNAL_LINKAGE
10216     std::string narrow(std::wstring_view str)
10217     {
10218         if (str.empty())
10219             return {};
10220 
10221         std::string s;
10222         const auto len =
10223             ::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
10224         if (len)
10225         {
10226             s.resize(static_cast<size_t>(len));
10227             ::WideCharToMultiByte(65001,
10228                                   0,
10229                                   str.data(),
10230                                   static_cast<int>(str.length()),
10231                                   s.data(),
10232                                   len,
10233                                   nullptr,
10234                                   nullptr);
10235         }
10236         return s;
10237     }
10238 
10239     TOML_EXTERNAL_LINKAGE
10240     std::wstring widen(std::string_view str)
10241     {
10242         if (str.empty())
10243             return {};
10244 
10245         std::wstring s;
10246         const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
10247         if (len)
10248         {
10249             s.resize(static_cast<size_t>(len));
10250             ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
10251         }
10252         return s;
10253     }
10254 
10255 #if TOML_HAS_CHAR8
10256 
10257     TOML_EXTERNAL_LINKAGE
10258     std::wstring widen(std::u8string_view str)
10259     {
10260         if (str.empty())
10261             return {};
10262 
10263         return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
10264     }
10265 
10266 #endif // TOML_HAS_CHAR8
10267 }
10268 TOML_IMPL_NAMESPACE_END;
10269 
10270 #ifdef _MSC_VER
10271 #pragma pop_macro("min")
10272 #pragma pop_macro("max")
10273 #ifndef __clang__
10274 #pragma inline_recursion(off)
10275 #endif
10276 #endif
10277 TOML_POP_WARNINGS;
10278 
10279 #endif // TOML_WINDOWS
10280 
10281 //********  impl/print_to_stream.inl  **********************************************************************************
10282 
10283 TOML_DISABLE_WARNINGS;
10284 #include <ostream>
10285 #if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
10286 #include <charconv>
10287 #endif
10288 #if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
10289 #include <sstream>
10290 #endif
10291 #if !TOML_INT_CHARCONV
10292 #include <iomanip>
10293 #endif
10294 TOML_ENABLE_WARNINGS;
10295 TOML_PUSH_WARNINGS;
10296 #ifdef _MSC_VER
10297 #ifndef __clang__
10298 #pragma inline_recursion(on)
10299 #endif
10300 #pragma push_macro("min")
10301 #pragma push_macro("max")
10302 #undef min
10303 #undef max
10304 #endif
10305 
10306 TOML_ANON_NAMESPACE_START
10307 {
10308     template <typename T>
10309     inline constexpr size_t charconv_buffer_length = 0;
10310 
10311     template <>
10312     inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
10313 
10314     template <>
10315     inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
10316 
10317     template <>
10318     inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
10319 
10320     template <>
10321     inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
10322 
10323     template <>
10324     inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
10325 
10326     template <>
10327     inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
10328 
10329     template <>
10330     inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
10331 
10332     template <>
10333     inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
10334 
10335     template <>
10336     inline constexpr size_t charconv_buffer_length<float> = 64;
10337 
10338     template <>
10339     inline constexpr size_t charconv_buffer_length<double> = 64;
10340 
10341     template <typename T>
10342     TOML_INTERNAL_LINKAGE
10343     void print_integer_to_stream(std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0)
10344     {
10345         if (!val)
10346         {
10347             if (!min_digits)
10348                 min_digits = 1;
10349 
10350             for (size_t i = 0; i < min_digits; i++)
10351                 stream.put('0');
10352 
10353             return;
10354         }
10355 
10356         static constexpr auto value_flags_mask =
10357             value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
10358         format &= value_flags_mask;
10359 
10360         int base = 10;
10361         if (format != value_flags::none && val > T{})
10362         {
10363             switch (format)
10364             {
10365                 case value_flags::format_as_binary: base = 2; break;
10366                 case value_flags::format_as_octal: base = 8; break;
10367                 case value_flags::format_as_hexadecimal: base = 16; break;
10368                 default: break;
10369             }
10370         }
10371 
10372 #if TOML_INT_CHARCONV
10373 
10374         char buf[(sizeof(T) * CHAR_BIT)];
10375         const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
10376         const auto len = static_cast<size_t>(res.ptr - buf);
10377         for (size_t i = len; i < min_digits; i++)
10378             stream.put('0');
10379         if (base == 16)
10380         {
10381             for (size_t i = 0; i < len; i++)
10382                 if (buf[i] >= 'a')
10383                     buf[i] -= 32;
10384         }
10385         impl::print_to_stream(stream, buf, len);
10386 
10387 #else
10388 
10389         using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
10390         using cast_type     = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
10391 
10392         if (base == 2)
10393         {
10394             const auto len = sizeof(T) * CHAR_BIT;
10395             for (size_t i = len; i < min_digits; i++)
10396                 stream.put('0');
10397 
10398             bool found_one     = false;
10399             const auto v       = static_cast<unsigned_type>(val);
10400             unsigned_type mask = unsigned_type{ 1 } << (len - 1u);
10401             for (size_t i = 0; i < len; i++)
10402             {
10403                 if ((v & mask))
10404                 {
10405                     stream.put('1');
10406                     found_one = true;
10407                 }
10408                 else if (found_one)
10409                     stream.put('0');
10410                 mask >>= 1;
10411             }
10412         }
10413         else
10414         {
10415             std::ostringstream ss;
10416             ss.imbue(std::locale::classic());
10417             ss << std::uppercase << std::setbase(base);
10418             if (min_digits)
10419                 ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
10420             ss << static_cast<cast_type>(val);
10421             const auto str = std::move(ss).str();
10422             impl::print_to_stream(stream, str);
10423         }
10424 
10425 #endif
10426     }
10427 
10428     template <typename T>
10429     TOML_INTERNAL_LINKAGE
10430     void print_floating_point_to_stream(std::ostream & stream,
10431                                         T val,
10432                                         value_flags format,
10433                                         [[maybe_unused]] bool relaxed_precision)
10434     {
10435         switch (impl::fpclassify(val))
10436         {
10437             case impl::fp_class::neg_inf: impl::print_to_stream(stream, "-inf"sv); break;
10438 
10439             case impl::fp_class::pos_inf: impl::print_to_stream(stream, "inf"sv); break;
10440 
10441             case impl::fp_class::nan: impl::print_to_stream(stream, "nan"sv); break;
10442 
10443             case impl::fp_class::ok:
10444             {
10445                 static constexpr auto needs_decimal_point = [](auto&& s) noexcept
10446                 {
10447                     for (auto c : s)
10448                         if (c == '.' || c == 'E' || c == 'e')
10449                             return false;
10450                     return true;
10451                 };
10452 
10453 #if TOML_FLOAT_CHARCONV
10454 
10455                 const auto hex = !!(format & value_flags::format_as_hexadecimal);
10456                 char buf[charconv_buffer_length<T>];
10457                 auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
10458                                : std::to_chars(buf, buf + sizeof(buf), val);
10459                 auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
10460 
10461                 char buf2[charconv_buffer_length<T>];
10462                 if (!hex && relaxed_precision)
10463                 {
10464                     res             = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
10465                     const auto str2 = std::string_view{ buf2, static_cast<size_t>(res.ptr - buf2) };
10466                     if (str2.length() < str.length())
10467                         str = str2;
10468                 }
10469 
10470                 impl::print_to_stream(stream, str);
10471                 if (!hex && needs_decimal_point(str))
10472                     toml::impl::print_to_stream(stream, ".0"sv);
10473 
10474 #else
10475 
10476                 std::ostringstream ss;
10477                 ss.imbue(std::locale::classic());
10478                 if (!relaxed_precision)
10479                     ss.precision(std::numeric_limits<T>::max_digits10);
10480                 if (!!(format & value_flags::format_as_hexadecimal))
10481                     ss << std::hexfloat;
10482                 ss << val;
10483                 const auto str = std::move(ss).str();
10484                 impl::print_to_stream(stream, str);
10485                 if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
10486                     impl::print_to_stream(stream, ".0"sv);
10487 
10488 #endif
10489             }
10490             break;
10491 
10492             default: TOML_UNREACHABLE;
10493         }
10494     }
10495 }
10496 TOML_ANON_NAMESPACE_END;
10497 
10498 TOML_IMPL_NAMESPACE_START
10499 {
10500     TOML_EXTERNAL_LINKAGE
10501     TOML_ATTR(nonnull)
10502     void TOML_CALLCONV print_to_stream(std::ostream & stream, const char* val, size_t len)
10503     {
10504         stream.write(val, static_cast<std::streamsize>(len));
10505     }
10506 
10507     TOML_EXTERNAL_LINKAGE
10508     void TOML_CALLCONV print_to_stream(std::ostream & stream, std::string_view val)
10509     {
10510         stream.write(val.data(), static_cast<std::streamsize>(val.length()));
10511     }
10512 
10513     TOML_EXTERNAL_LINKAGE
10514     void TOML_CALLCONV print_to_stream(std::ostream & stream, const std::string& val)
10515     {
10516         stream.write(val.data(), static_cast<std::streamsize>(val.length()));
10517     }
10518 
10519     TOML_EXTERNAL_LINKAGE
10520     void TOML_CALLCONV print_to_stream(std::ostream & stream, char val)
10521     {
10522         stream.put(val);
10523     }
10524 
10525     TOML_EXTERNAL_LINKAGE
10526     void TOML_CALLCONV print_to_stream(std::ostream & stream, signed char val, value_flags format, size_t min_digits)
10527     {
10528         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10529     }
10530 
10531     TOML_EXTERNAL_LINKAGE
10532     void TOML_CALLCONV print_to_stream(std::ostream & stream, signed short val, value_flags format, size_t min_digits)
10533     {
10534         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10535     }
10536 
10537     TOML_EXTERNAL_LINKAGE
10538     void TOML_CALLCONV print_to_stream(std::ostream & stream, signed int val, value_flags format, size_t min_digits)
10539     {
10540         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10541     }
10542 
10543     TOML_EXTERNAL_LINKAGE
10544     void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long val, value_flags format, size_t min_digits)
10545     {
10546         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10547     }
10548 
10549     TOML_EXTERNAL_LINKAGE
10550     void TOML_CALLCONV print_to_stream(std::ostream & stream,
10551                                        signed long long val,
10552                                        value_flags format,
10553                                        size_t min_digits)
10554     {
10555         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10556     }
10557 
10558     TOML_EXTERNAL_LINKAGE
10559     void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned char val, value_flags format, size_t min_digits)
10560     {
10561         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10562     }
10563 
10564     TOML_EXTERNAL_LINKAGE
10565     void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned short val, value_flags format, size_t min_digits)
10566     {
10567         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10568     }
10569 
10570     TOML_EXTERNAL_LINKAGE
10571     void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned int val, value_flags format, size_t min_digits)
10572     {
10573         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10574     }
10575 
10576     TOML_EXTERNAL_LINKAGE
10577     void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long val, value_flags format, size_t min_digits)
10578     {
10579         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10580     }
10581 
10582     TOML_EXTERNAL_LINKAGE
10583     void TOML_CALLCONV print_to_stream(std::ostream & stream,
10584                                        unsigned long long val,
10585                                        value_flags format,
10586                                        size_t min_digits)
10587     {
10588         TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
10589     }
10590 
10591     TOML_EXTERNAL_LINKAGE
10592     void TOML_CALLCONV print_to_stream(std::ostream & stream, float val, value_flags format, bool relaxed_precision)
10593     {
10594         TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
10595     }
10596 
10597     TOML_EXTERNAL_LINKAGE
10598     void TOML_CALLCONV print_to_stream(std::ostream & stream, double val, value_flags format, bool relaxed_precision)
10599     {
10600         TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
10601     }
10602 
10603     TOML_EXTERNAL_LINKAGE
10604     void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val)
10605     {
10606         print_to_stream(stream, val ? "true"sv : "false"sv);
10607     }
10608 
10609     TOML_EXTERNAL_LINKAGE
10610     void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date& val)
10611     {
10612         print_to_stream(stream, val.year, {}, 4);
10613         stream.put('-');
10614         print_to_stream(stream, val.month, {}, 2);
10615         stream.put('-');
10616         print_to_stream(stream, val.day, {}, 2);
10617     }
10618 
10619     TOML_EXTERNAL_LINKAGE
10620     void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time& val)
10621     {
10622         print_to_stream(stream, val.hour, {}, 2);
10623         stream.put(':');
10624         print_to_stream(stream, val.minute, {}, 2);
10625         stream.put(':');
10626         print_to_stream(stream, val.second, {}, 2);
10627         if (val.nanosecond && val.nanosecond <= 999999999u)
10628         {
10629             stream.put('.');
10630             auto ns       = val.nanosecond;
10631             size_t digits = 9u;
10632             while (ns % 10u == 0u)
10633             {
10634                 ns /= 10u;
10635                 digits--;
10636             }
10637             print_to_stream(stream, ns, {}, digits);
10638         }
10639     }
10640 
10641     TOML_EXTERNAL_LINKAGE
10642     void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time_offset& val)
10643     {
10644         if (!val.minutes)
10645         {
10646             stream.put('Z');
10647             return;
10648         }
10649 
10650         auto mins = static_cast<int>(val.minutes);
10651         if (mins < 0)
10652         {
10653             stream.put('-');
10654             mins = -mins;
10655         }
10656         else
10657             stream.put('+');
10658         const auto hours = mins / 60;
10659         if (hours)
10660         {
10661             print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
10662             mins -= hours * 60;
10663         }
10664         else
10665             print_to_stream(stream, "00"sv);
10666         stream.put(':');
10667         print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
10668     }
10669 
10670     TOML_EXTERNAL_LINKAGE
10671     void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date_time& val)
10672     {
10673         print_to_stream(stream, val.date);
10674         stream.put('T');
10675         print_to_stream(stream, val.time);
10676         if (val.offset)
10677             print_to_stream(stream, *val.offset);
10678     }
10679 
10680     TOML_EXTERNAL_LINKAGE
10681     void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_position& val)
10682     {
10683         print_to_stream(stream, "line "sv);
10684         print_to_stream(stream, val.line);
10685         print_to_stream(stream, ", column "sv);
10686         print_to_stream(stream, val.column);
10687     }
10688 
10689     TOML_EXTERNAL_LINKAGE
10690     void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_region& val)
10691     {
10692         print_to_stream(stream, val.begin);
10693         if (val.path)
10694         {
10695             print_to_stream(stream, " of '"sv);
10696             print_to_stream(stream, *val.path);
10697             stream.put('\'');
10698         }
10699     }
10700 
10701 #if TOML_ENABLE_FORMATTERS
10702 
10703     TOML_EXTERNAL_LINKAGE
10704     void TOML_CALLCONV print_to_stream(std::ostream & stream, const array& arr)
10705     {
10706         stream << toml_formatter{ arr };
10707     }
10708 
10709     TOML_EXTERNAL_LINKAGE
10710     void TOML_CALLCONV print_to_stream(std::ostream & stream, const table& tbl)
10711     {
10712         stream << toml_formatter{ tbl };
10713     }
10714 
10715     TOML_EXTERNAL_LINKAGE
10716     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<std::string>& val)
10717     {
10718         stream << toml_formatter{ val };
10719     }
10720 
10721     TOML_EXTERNAL_LINKAGE
10722     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<int64_t>& val)
10723     {
10724         stream << toml_formatter{ val };
10725     }
10726 
10727     TOML_EXTERNAL_LINKAGE
10728     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<double>& val)
10729     {
10730         stream << toml_formatter{ val };
10731     }
10732 
10733     TOML_EXTERNAL_LINKAGE
10734     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<bool>& val)
10735     {
10736         stream << toml_formatter{ val };
10737     }
10738 
10739     TOML_EXTERNAL_LINKAGE
10740     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date>& val)
10741     {
10742         stream << toml_formatter{ val };
10743     }
10744 
10745     TOML_EXTERNAL_LINKAGE
10746     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<time>& val)
10747     {
10748         stream << toml_formatter{ val };
10749     }
10750 
10751     TOML_EXTERNAL_LINKAGE
10752     void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date_time>& val)
10753     {
10754         stream << toml_formatter{ val };
10755     }
10756 
10757 #endif
10758 }
10759 TOML_IMPL_NAMESPACE_END;
10760 
10761 #ifdef _MSC_VER
10762 #pragma pop_macro("min")
10763 #pragma pop_macro("max")
10764 #ifndef __clang__
10765 #pragma inline_recursion(off)
10766 #endif
10767 #endif
10768 TOML_POP_WARNINGS;
10769 
10770 //********  impl/node.inl  *********************************************************************************************
10771 
10772 TOML_PUSH_WARNINGS;
10773 #ifdef _MSC_VER
10774 #ifndef __clang__
10775 #pragma inline_recursion(on)
10776 #endif
10777 #pragma push_macro("min")
10778 #pragma push_macro("max")
10779 #undef min
10780 #undef max
10781 #endif
10782 
10783 TOML_NAMESPACE_START
10784 {
10785     TOML_EXTERNAL_LINKAGE
10786     node::node() noexcept = default;
10787 
10788     TOML_EXTERNAL_LINKAGE
10789     node::~node() noexcept = default;
10790 
10791     TOML_EXTERNAL_LINKAGE
10792     node::node(node && other) noexcept //
10793         : source_{ std::exchange(other.source_, {}) }
10794     {}
10795 
10796     TOML_EXTERNAL_LINKAGE
10797     node::node(const node& /*other*/) noexcept
10798     {
10799         // does not copy source information - this is not an error
10800         //
10801         // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
10802     }
10803 
10804     TOML_EXTERNAL_LINKAGE
10805     node& node::operator=(const node& /*rhs*/) noexcept
10806     {
10807         // does not copy source information - this is not an error
10808         //
10809         // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
10810 
10811         source_ = {};
10812         return *this;
10813     }
10814 
10815     TOML_EXTERNAL_LINKAGE
10816     node& node::operator=(node&& rhs) noexcept
10817     {
10818         if (&rhs != this)
10819             source_ = std::exchange(rhs.source_, {});
10820         return *this;
10821     }
10822 
10823     TOML_EXTERNAL_LINKAGE
10824     node_view<node> node::at_path(std::string_view path) noexcept
10825     {
10826         return toml::at_path(*this, path);
10827     }
10828 
10829     TOML_EXTERNAL_LINKAGE
10830     node_view<const node> node::at_path(std::string_view path) const noexcept
10831     {
10832         return toml::at_path(*this, path);
10833     }
10834 
10835     TOML_EXTERNAL_LINKAGE
10836     node_view<node> node::at_path(const path& p) noexcept
10837     {
10838         return toml::at_path(*this, p);
10839     }
10840 
10841     TOML_EXTERNAL_LINKAGE
10842     node_view<const node> node::at_path(const path& p) const noexcept
10843     {
10844         return toml::at_path(*this, p);
10845     }
10846 
10847 #if TOML_ENABLE_WINDOWS_COMPAT
10848 
10849     TOML_EXTERNAL_LINKAGE
10850     node_view<node> node::at_path(std::wstring_view path)
10851     {
10852         return toml::at_path(*this, path);
10853     }
10854 
10855     TOML_EXTERNAL_LINKAGE
10856     node_view<const node> node::at_path(std::wstring_view path) const
10857     {
10858         return toml::at_path(*this, path);
10859     }
10860 
10861 #endif // TOML_ENABLE_WINDOWS_COMPAT
10862 
10863     TOML_EXTERNAL_LINKAGE
10864     node_view<node> node::operator[](const path& p) noexcept
10865     {
10866         return toml::at_path(*this, p);
10867     }
10868 
10869     TOML_EXTERNAL_LINKAGE
10870     node_view<const node> node::operator[](const path& p) const noexcept
10871     {
10872         return toml::at_path(*this, p);
10873     }
10874 }
10875 TOML_NAMESPACE_END;
10876 
10877 TOML_IMPL_NAMESPACE_START
10878 {
10879     TOML_PURE_GETTER
10880     TOML_EXTERNAL_LINKAGE
10881     bool TOML_CALLCONV node_deep_equality(const node* lhs, const node* rhs) noexcept
10882     {
10883         // both same or both null
10884         if (lhs == rhs)
10885             return true;
10886 
10887         // lhs null != rhs null or different types
10888         if ((!lhs != !rhs) || lhs->type() != rhs->type())
10889             return false;
10890 
10891         return lhs->visit(
10892             [=](auto& l) noexcept
10893             {
10894                 using concrete_type = remove_cvref<decltype(l)>;
10895 
10896                 return l == *(rhs->as<concrete_type>());
10897             });
10898     }
10899 }
10900 TOML_IMPL_NAMESPACE_END;
10901 
10902 #ifdef _MSC_VER
10903 #pragma pop_macro("min")
10904 #pragma pop_macro("max")
10905 #ifndef __clang__
10906 #pragma inline_recursion(off)
10907 #endif
10908 #endif
10909 TOML_POP_WARNINGS;
10910 
10911 //********  impl/at_path.inl  ******************************************************************************************
10912 
10913 TOML_DISABLE_WARNINGS;
10914 #if TOML_INT_CHARCONV
10915 #include <charconv>
10916 #else
10917 #include <sstream>
10918 #endif
10919 TOML_ENABLE_WARNINGS;
10920 TOML_PUSH_WARNINGS;
10921 #ifdef _MSC_VER
10922 #ifndef __clang__
10923 #pragma inline_recursion(on)
10924 #endif
10925 #pragma push_macro("min")
10926 #pragma push_macro("max")
10927 #undef min
10928 #undef max
10929 #endif
10930 
10931 TOML_IMPL_NAMESPACE_START
10932 {
10933     TOML_EXTERNAL_LINKAGE
10934     bool TOML_CALLCONV parse_path(const std::string_view path,
10935                                   void* const data,
10936                                   const parse_path_callback<std::string_view> on_key,
10937                                   const parse_path_callback<size_t> on_index)
10938     {
10939         // a blank string is a valid path; it's just one component representing the "" key
10940         if (path.empty())
10941             return on_key(data, ""sv);
10942 
10943         size_t pos                  = 0;
10944         const auto end              = path.length();
10945         bool prev_was_array_indexer = false;
10946         bool prev_was_dot           = true; // invisible root 'dot'
10947 
10948         while (pos < end)
10949         {
10950             // start of an array indexer
10951             if (path[pos] == '[')
10952             {
10953                 // find first digit in index
10954                 size_t index_start = pos + 1u;
10955                 while (true)
10956                 {
10957                     if TOML_UNLIKELY(index_start >= path.length())
10958                         return false;
10959 
10960                     const auto c = path[index_start];
10961                     if TOML_LIKELY(c >= '0' && c <= '9')
10962                         break;
10963                     else if (c == ' ' || c == '\t')
10964                         index_start++;
10965                     else
10966                         return false;
10967                 }
10968                 TOML_ASSERT(path[index_start] >= '0');
10969                 TOML_ASSERT(path[index_start] <= '9');
10970 
10971                 // find end of index (first non-digit character)
10972                 size_t index_end = index_start + 1u;
10973                 while (true)
10974                 {
10975                     // if an array indexer is missing the trailing ']' at the end of the string, permissively accept it
10976                     if TOML_UNLIKELY(index_end >= path.length())
10977                         break;
10978 
10979                     const auto c = path[index_end];
10980                     if (c >= '0' && c <= '9')
10981                         index_end++;
10982                     else if (c == ']' || c == ' ' || c == '\t' || c == '.' || c == '[')
10983                         break;
10984                     else
10985                         return false;
10986                 }
10987                 TOML_ASSERT(path[index_end - 1u] >= '0');
10988                 TOML_ASSERT(path[index_end - 1u] <= '9');
10989 
10990                 // move pos to after indexer (char after closing ']' or permissively EOL/subkey '.'/next opening '[')
10991                 pos = index_end;
10992                 while (true)
10993                 {
10994                     if TOML_UNLIKELY(pos >= path.length())
10995                         break;
10996 
10997                     const auto c = path[pos];
10998                     if (c == ']')
10999                     {
11000                         pos++;
11001                         break;
11002                     }
11003                     else if TOML_UNLIKELY(c == '.' || c == '[')
11004                         break;
11005                     else if (c == '\t' || c == ' ')
11006                         pos++;
11007                     else
11008                         return false;
11009                 }
11010 
11011                 // get array index substring
11012                 auto index_str = path.substr(index_start, index_end - index_start);
11013 
11014                 // parse the actual array index to an integer type
11015                 size_t index;
11016                 if (index_str.length() == 1u)
11017                     index = static_cast<size_t>(index_str[0] - '0');
11018                 else
11019                 {
11020 #if TOML_INT_CHARCONV
11021 
11022                     auto fc_result = std::from_chars(index_str.data(), index_str.data() + index_str.length(), index);
11023                     if (fc_result.ec != std::errc{})
11024                         return false;
11025 
11026 #else
11027 
11028                     std::stringstream ss;
11029                     ss.imbue(std::locale::classic());
11030                     ss.write(index_str.data(), static_cast<std::streamsize>(index_str.length()));
11031                     if (!(ss >> index))
11032                         return false;
11033 
11034 #endif
11035                 }
11036 
11037                 prev_was_dot           = false;
11038                 prev_was_array_indexer = true;
11039 
11040                 if (!on_index(data, index))
11041                     return false;
11042             }
11043 
11044             // start of a new table child
11045             else if (path[pos] == '.')
11046             {
11047                 // a dot immediately following another dot (or at the beginning of the string) is as if we'd asked
11048                 // for an empty child in between, e.g.
11049                 //
11050                 //     foo..bar
11051                 //
11052                 // is equivalent to
11053                 //
11054                 //     "foo".""."bar"
11055                 //
11056                 if (prev_was_dot && !on_key(data, ""sv))
11057                     return false;
11058 
11059                 pos++;
11060                 prev_was_dot           = true;
11061                 prev_was_array_indexer = false;
11062             }
11063 
11064             // an errant closing ']'
11065             else if TOML_UNLIKELY(path[pos] == ']')
11066                 return false;
11067 
11068             // some regular subkey
11069             else
11070             {
11071                 const auto subkey_start = pos;
11072                 const auto subkey_len =
11073                     impl::min(path.find_first_of(".[]"sv, subkey_start + 1u), path.length()) - subkey_start;
11074                 const auto subkey = path.substr(subkey_start, subkey_len);
11075 
11076                 // a regular subkey segment immediately after an array indexer is OK if it was all whitespace, e.g.:
11077                 //
11078                 //     "foo[0]  .bar"
11079                 //            ^^ skip this
11080                 //
11081                 // otherwise its an error (since it would have to be preceeded by a dot)
11082                 if (prev_was_array_indexer)
11083                 {
11084                     auto non_ws = subkey.find_first_not_of(" \t");
11085                     if (non_ws == std::string_view::npos)
11086                     {
11087                         pos += subkey_len;
11088                         prev_was_dot           = false;
11089                         prev_was_array_indexer = false;
11090                         continue;
11091                     }
11092                     else
11093                         return false;
11094                 }
11095 
11096                 pos += subkey_len;
11097                 prev_was_dot           = false;
11098                 prev_was_array_indexer = false;
11099 
11100                 if (!on_key(data, subkey))
11101                     return false;
11102             }
11103         }
11104 
11105         // Last character was a '.', which implies an empty string key at the end of the path
11106         if (prev_was_dot && !on_key(data, ""sv))
11107             return false;
11108 
11109         return true;
11110     }
11111 }
11112 TOML_IMPL_NAMESPACE_END;
11113 
11114 TOML_NAMESPACE_START
11115 {
11116     TOML_EXTERNAL_LINKAGE
11117     node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept
11118     {
11119         // early-exit sanity-checks
11120         if (root.is_value())
11121             return {};
11122         if (auto tbl = root.as_table(); tbl && tbl->empty())
11123             return {};
11124         if (auto arr = root.as_array(); arr && arr->empty())
11125             return {};
11126 
11127         node* current = &root;
11128 
11129         static constexpr auto on_key = [](void* data, std::string_view key) noexcept -> bool
11130         {
11131             auto& curr = *static_cast<node**>(data);
11132             TOML_ASSERT_ASSUME(curr);
11133 
11134             const auto current_table = curr->as<table>();
11135             if (!current_table)
11136                 return false;
11137 
11138             curr = current_table->get(key);
11139             return curr != nullptr;
11140         };
11141 
11142         static constexpr auto on_index = [](void* data, size_t index) noexcept -> bool
11143         {
11144             auto& curr = *static_cast<node**>(data);
11145             TOML_ASSERT_ASSUME(curr);
11146 
11147             const auto current_array = curr->as<array>();
11148             if (!current_array)
11149                 return false;
11150 
11151             curr = current_array->get(index);
11152             return curr != nullptr;
11153         };
11154 
11155         if (!impl::parse_path(path, &current, on_key, on_index))
11156             current = nullptr;
11157 
11158         return node_view{ current };
11159     }
11160 
11161     TOML_EXTERNAL_LINKAGE
11162     node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept
11163     {
11164         return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
11165     }
11166 
11167 #if TOML_ENABLE_WINDOWS_COMPAT
11168 
11169     TOML_EXTERNAL_LINKAGE
11170     node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path)
11171     {
11172         // these are the same top-level checks from the narrow-string version;
11173         // they're hoisted up here to avoid doing the wide -> narrow conversion where it would not be necessary
11174         // (avoids an allocation)
11175         if (root.is_value())
11176             return {};
11177         if (auto tbl = root.as_table(); tbl && tbl->empty())
11178             return {};
11179         if (auto arr = root.as_array(); arr && arr->empty())
11180             return {};
11181 
11182         return at_path(root, impl::narrow(path));
11183     }
11184 
11185     TOML_EXTERNAL_LINKAGE
11186     node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path)
11187     {
11188         return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
11189     }
11190 
11191 #endif // TOML_ENABLE_WINDOWS_COMPAT
11192 }
11193 TOML_NAMESPACE_END;
11194 
11195 #ifdef _MSC_VER
11196 #pragma pop_macro("min")
11197 #pragma pop_macro("max")
11198 #ifndef __clang__
11199 #pragma inline_recursion(off)
11200 #endif
11201 #endif
11202 TOML_POP_WARNINGS;
11203 
11204 //********  impl/path.inl  *********************************************************************************************
11205 
11206 TOML_DISABLE_WARNINGS;
11207 #if TOML_INT_CHARCONV
11208 #include <charconv>
11209 #endif
11210 #include <sstream>
11211 TOML_ENABLE_WARNINGS;
11212 TOML_PUSH_WARNINGS;
11213 #ifdef _MSC_VER
11214 #ifndef __clang__
11215 #pragma inline_recursion(on)
11216 #endif
11217 #pragma push_macro("min")
11218 #pragma push_macro("max")
11219 #undef min
11220 #undef max
11221 #endif
11222 
11223 TOML_NAMESPACE_START
11224 {
11225     TOML_EXTERNAL_LINKAGE
11226     path_component::path_component() //
11227         : type_{ path_component_type::key }
11228     {
11229         store_key("", value_storage_);
11230     }
11231 
11232     TOML_EXTERNAL_LINKAGE
11233     path_component::path_component(size_t index) noexcept //
11234         : type_(path_component_type::array_index)
11235     {
11236         store_index(index, value_storage_);
11237     }
11238 
11239     TOML_EXTERNAL_LINKAGE
11240     path_component::path_component(std::string_view key) //
11241         : type_(path_component_type::key)
11242     {
11243         store_key(key, value_storage_);
11244     }
11245 
11246 #if TOML_ENABLE_WINDOWS_COMPAT
11247 
11248     TOML_EXTERNAL_LINKAGE
11249     path_component::path_component(std::wstring_view key) //
11250         : path_component(impl::narrow(key))
11251     {}
11252 
11253 #endif
11254 
11255     TOML_EXTERNAL_LINKAGE
11256     path_component::path_component(const path_component& pc) //
11257         : type_{ pc.type_ }
11258     {
11259         if (type_ == path_component_type::array_index)
11260             store_index(pc.index(), value_storage_);
11261         else
11262             store_key(pc.key(), value_storage_);
11263     }
11264 
11265     TOML_EXTERNAL_LINKAGE
11266     path_component::path_component(path_component && pc) noexcept //
11267         : type_{ pc.type_ }
11268     {
11269         if (type_ == path_component_type::array_index)
11270             store_index(pc.index_ref(), value_storage_);
11271         else
11272             store_key(std::move(pc.key_ref()), value_storage_);
11273     }
11274 
11275     TOML_EXTERNAL_LINKAGE
11276     path_component& path_component::operator=(const path_component& rhs)
11277     {
11278         if (type_ != rhs.type_)
11279         {
11280             destroy();
11281 
11282             type_ = rhs.type_;
11283             if (type_ == path_component_type::array_index)
11284                 store_index(rhs.index(), value_storage_);
11285             else
11286                 store_key(rhs.key(), value_storage_);
11287         }
11288         else
11289         {
11290             if (type_ == path_component_type::array_index)
11291                 index_ref() = rhs.index();
11292             else
11293                 key_ref() = rhs.key();
11294         }
11295         return *this;
11296     }
11297 
11298     TOML_EXTERNAL_LINKAGE
11299     path_component& path_component::operator=(path_component&& rhs) noexcept
11300     {
11301         if (type_ != rhs.type_)
11302         {
11303             destroy();
11304 
11305             type_ = rhs.type_;
11306             if (type_ == path_component_type::array_index)
11307                 store_index(rhs.index(), value_storage_);
11308             else
11309                 store_key(std::move(rhs.key_ref()), value_storage_);
11310         }
11311         else
11312         {
11313             if (type_ == path_component_type::array_index)
11314                 index_ref() = rhs.index();
11315             else
11316                 key_ref() = std::move(rhs.key_ref());
11317         }
11318         return *this;
11319     }
11320 
11321     TOML_PURE_GETTER
11322     TOML_EXTERNAL_LINKAGE
11323     bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept
11324     {
11325         // Different comparison depending on contents
11326         if (lhs.type_ != rhs.type_)
11327             return false;
11328 
11329         if (lhs.type_ == path_component_type::array_index)
11330             return lhs.index() == rhs.index();
11331         else // path_component_type::key
11332             return lhs.key() == rhs.key();
11333     }
11334 
11335     TOML_EXTERNAL_LINKAGE
11336     path_component& path_component::operator=(size_t new_index) noexcept
11337     {
11338         // If currently a key, string will need to be destroyed regardless
11339         destroy();
11340 
11341         type_ = path_component_type::array_index;
11342         store_index(new_index, value_storage_);
11343 
11344         return *this;
11345     }
11346 
11347     TOML_EXTERNAL_LINKAGE
11348     path_component& path_component::operator=(std::string_view new_key)
11349     {
11350         if (type_ == path_component_type::key)
11351             key_ref() = new_key;
11352         else
11353         {
11354             type_ = path_component_type::key;
11355             store_key(new_key, value_storage_);
11356         }
11357 
11358         return *this;
11359     }
11360 
11361 #if TOML_ENABLE_WINDOWS_COMPAT
11362 
11363     TOML_EXTERNAL_LINKAGE
11364     path_component& path_component::operator=(std::wstring_view new_key)
11365     {
11366         if (type_ == path_component_type::key)
11367             key_ref() = impl::narrow(new_key);
11368         else
11369         {
11370             type_ = path_component_type::key;
11371             store_key(impl::narrow(new_key), value_storage_);
11372         }
11373 
11374         return *this;
11375     }
11376 
11377 #endif
11378 }
11379 TOML_NAMESPACE_END;
11380 
11381 TOML_ANON_NAMESPACE_START
11382 {
11383     TOML_INTERNAL_LINKAGE
11384     bool parse_path_into(std::string_view path_str, std::vector<path_component> & components)
11385     {
11386         using components_type = std::remove_reference_t<decltype(components)>;
11387 
11388         const auto original_size = components.size();
11389 
11390         static constexpr auto on_key = [](void* data, std::string_view key) -> bool
11391         {
11392             auto& comps = *static_cast<components_type*>(data);
11393             comps.emplace_back(key);
11394             return true;
11395         };
11396 
11397         static constexpr auto on_index = [](void* data, size_t index) -> bool
11398         {
11399             auto& comps = *static_cast<components_type*>(data);
11400             comps.emplace_back(index);
11401             return true;
11402         };
11403 
11404         if (!impl::parse_path(path_str, &components, on_key, on_index))
11405         {
11406             components.resize(original_size);
11407             return false;
11408         }
11409 
11410         return true;
11411     }
11412 }
11413 TOML_ANON_NAMESPACE_END;
11414 
11415 TOML_NAMESPACE_START
11416 {
11417     TOML_EXTERNAL_LINKAGE
11418     void path::print_to(std::ostream & os) const
11419     {
11420         bool root = true;
11421         for (const auto& component : components_)
11422         {
11423             if (component.type() == path_component_type::key) // key
11424             {
11425                 if (!root)
11426                     impl::print_to_stream(os, '.');
11427                 impl::print_to_stream(os, component.key());
11428             }
11429             else if (component.type() == path_component_type::array_index) // array
11430             {
11431                 impl::print_to_stream(os, '[');
11432                 impl::print_to_stream(os, component.index());
11433                 impl::print_to_stream(os, ']');
11434             }
11435             root = false;
11436         }
11437     }
11438 
11439     TOML_PURE_GETTER
11440     TOML_EXTERNAL_LINKAGE
11441     bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept
11442     {
11443         return lhs.components_ == rhs.components_;
11444     }
11445 
11446     TOML_EXTERNAL_LINKAGE
11447     path::path(std::string_view str) //
11448     {
11449         TOML_ANON_NAMESPACE::parse_path_into(str, components_);
11450     }
11451 
11452 #if TOML_ENABLE_WINDOWS_COMPAT
11453 
11454     TOML_EXTERNAL_LINKAGE
11455     path::path(std::wstring_view str) //
11456         : path(impl::narrow(str))
11457     {}
11458 
11459 #endif
11460 
11461     TOML_EXTERNAL_LINKAGE
11462     path& path::operator=(std::string_view rhs)
11463     {
11464         components_.clear();
11465         TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
11466         return *this;
11467     }
11468 
11469 #if TOML_ENABLE_WINDOWS_COMPAT
11470 
11471     TOML_EXTERNAL_LINKAGE
11472     path& path::operator=(std::wstring_view rhs)
11473     {
11474         return assign(impl::narrow(rhs));
11475     }
11476 
11477 #endif
11478 
11479     TOML_EXTERNAL_LINKAGE
11480     path& path::operator+=(const path& rhs)
11481     {
11482         components_.insert(components_.cend(), rhs.begin(), rhs.end());
11483         return *this;
11484     }
11485 
11486     TOML_EXTERNAL_LINKAGE
11487     path& path::operator+=(path&& rhs)
11488     {
11489         components_.insert(components_.end(),
11490                            std::make_move_iterator(rhs.components_.begin()),
11491                            std::make_move_iterator(rhs.components_.end()));
11492         return *this;
11493     }
11494 
11495     TOML_EXTERNAL_LINKAGE
11496     path& path::operator+=(std::string_view str)
11497     {
11498         TOML_ANON_NAMESPACE::parse_path_into(str, components_);
11499         return *this;
11500     }
11501 
11502 #if TOML_ENABLE_WINDOWS_COMPAT
11503 
11504     TOML_EXTERNAL_LINKAGE
11505     path& path::operator+=(std::wstring_view str)
11506     {
11507         return *this += impl::narrow(str);
11508     }
11509 
11510 #endif
11511 
11512     TOML_EXTERNAL_LINKAGE
11513     path& path::prepend(const path& source)
11514     {
11515         components_.insert(components_.begin(), source.components_.begin(), source.components_.end());
11516         return *this;
11517     }
11518 
11519     TOML_EXTERNAL_LINKAGE
11520     path& path::prepend(path && source)
11521     {
11522         components_.insert(components_.begin(),
11523                            std::make_move_iterator(source.components_.begin()),
11524                            std::make_move_iterator(source.components_.end()));
11525         return *this;
11526     }
11527 
11528     TOML_EXTERNAL_LINKAGE
11529     path& path::prepend(std::string_view source)
11530     {
11531         return prepend(path{ source });
11532     }
11533 
11534 #if TOML_ENABLE_WINDOWS_COMPAT
11535 
11536     TOML_EXTERNAL_LINKAGE
11537     path& path::prepend(std::wstring_view source)
11538     {
11539         return prepend(impl::narrow(source));
11540     }
11541 
11542 #endif
11543 
11544     TOML_EXTERNAL_LINKAGE
11545     std::string path::str() const
11546     {
11547         if (empty())
11548             return "";
11549 
11550         std::ostringstream ss;
11551         print_to(ss);
11552         return std::move(ss).str();
11553     }
11554 
11555 #if TOML_ENABLE_WINDOWS_COMPAT
11556 
11557     TOML_EXTERNAL_LINKAGE
11558     std::wstring path::wide_str() const
11559     {
11560         return impl::widen(str());
11561     }
11562 
11563 #endif
11564 
11565     TOML_EXTERNAL_LINKAGE
11566     void path::clear() noexcept
11567     {
11568         components_.clear();
11569     }
11570 
11571     TOML_EXTERNAL_LINKAGE
11572     path& path::truncate(size_t n)
11573     {
11574         n = n > components_.size() ? components_.size() : n;
11575 
11576         auto it_end = components_.end();
11577         components_.erase(it_end - static_cast<int>(n), it_end);
11578 
11579         return *this;
11580     }
11581 
11582     TOML_EXTERNAL_LINKAGE
11583     path path::truncated(size_t n) const
11584     {
11585         path truncated_path{};
11586 
11587         n = n > components_.size() ? components_.size() : n;
11588 
11589         // Copy all components except one
11590         // Need at least two path components to have a parent, since if there is
11591         // only one path component, the parent is the root/null path ""
11592         truncated_path.components_.insert(truncated_path.components_.begin(),
11593                                           components_.begin(),
11594                                           components_.end() - static_cast<int>(n));
11595 
11596         return truncated_path;
11597     }
11598 
11599     TOML_EXTERNAL_LINKAGE
11600     path path::parent() const
11601     {
11602         return truncated(1);
11603     }
11604 
11605     TOML_EXTERNAL_LINKAGE
11606     path path::leaf(size_t n) const
11607     {
11608         path leaf_path{};
11609 
11610         n = n > components_.size() ? components_.size() : n;
11611 
11612         if (n > 0)
11613         {
11614             leaf_path.components_.insert(leaf_path.components_.begin(),
11615                                          components_.end() - static_cast<int>(n),
11616                                          components_.end());
11617         }
11618 
11619         return leaf_path;
11620     }
11621 
11622     TOML_EXTERNAL_LINKAGE
11623     path path::subpath(std::vector<path_component>::const_iterator start,
11624                        std::vector<path_component>::const_iterator end) const
11625     {
11626         if (start >= end)
11627             return {};
11628 
11629         path subpath;
11630         subpath.components_.insert(subpath.components_.begin(), start, end);
11631         return subpath;
11632     }
11633 
11634     TOML_EXTERNAL_LINKAGE
11635     path path::subpath(size_t start, size_t length) const
11636     {
11637         return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length));
11638     }
11639 }
11640 TOML_NAMESPACE_END;
11641 
11642 TOML_NAMESPACE_START
11643 {
11644     TOML_EXTERNAL_LINKAGE
11645     node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept
11646     {
11647         // early-exit sanity-checks
11648         if (root.is_value())
11649             return {};
11650         if (auto tbl = root.as_table(); tbl && tbl->empty())
11651             return {};
11652         if (auto arr = root.as_array(); arr && arr->empty())
11653             return {};
11654 
11655         node* current = &root;
11656 
11657         for (const auto& component : path)
11658         {
11659             auto type = component.type();
11660             if (type == path_component_type::array_index)
11661             {
11662                 const auto current_array = current->as<array>();
11663                 if (!current_array)
11664                     return {}; // not an array, using array index doesn't work
11665 
11666                 current = current_array->get(component.index());
11667             }
11668             else if (type == path_component_type::key)
11669             {
11670                 const auto current_table = current->as<table>();
11671                 if (!current_table)
11672                     return {};
11673 
11674                 current = current_table->get(component.key());
11675             }
11676             else
11677             {
11678                 // Error: invalid component
11679                 return {};
11680             }
11681 
11682             if (!current)
11683                 return {}; // not found
11684         }
11685 
11686         return node_view{ current };
11687     }
11688 
11689     TOML_EXTERNAL_LINKAGE
11690     node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept
11691     {
11692         return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
11693     }
11694 }
11695 TOML_NAMESPACE_END;
11696 
11697 #ifdef _MSC_VER
11698 #pragma pop_macro("min")
11699 #pragma pop_macro("max")
11700 #ifndef __clang__
11701 #pragma inline_recursion(off)
11702 #endif
11703 #endif
11704 TOML_POP_WARNINGS;
11705 
11706 //********  impl/array.inl  ********************************************************************************************
11707 
11708 TOML_PUSH_WARNINGS;
11709 #ifdef _MSC_VER
11710 #ifndef __clang__
11711 #pragma inline_recursion(on)
11712 #endif
11713 #pragma push_macro("min")
11714 #pragma push_macro("max")
11715 #undef min
11716 #undef max
11717 #endif
11718 
11719 TOML_NAMESPACE_START
11720 {
11721     TOML_EXTERNAL_LINKAGE
11722     array::array() noexcept
11723     {
11724 #if TOML_LIFETIME_HOOKS
11725         TOML_ARRAY_CREATED;
11726 #endif
11727     }
11728 
11729     TOML_EXTERNAL_LINKAGE
11730     array::~array() noexcept
11731     {
11732 #if TOML_LIFETIME_HOOKS
11733         TOML_ARRAY_DESTROYED;
11734 #endif
11735     }
11736 
11737     TOML_EXTERNAL_LINKAGE
11738     array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
11739     {
11740 #if TOML_LIFETIME_HOOKS
11741         TOML_ARRAY_CREATED;
11742 #endif
11743 
11744         TOML_ASSERT_ASSUME(b);
11745         TOML_ASSERT_ASSUME(e);
11746         TOML_ASSERT_ASSUME(b <= e);
11747 
11748         if TOML_UNLIKELY(b == e)
11749             return;
11750 
11751         size_t cap{};
11752         for (auto it = b; it != e; it++)
11753         {
11754             if (it->value)
11755                 cap++;
11756         }
11757         if TOML_UNLIKELY(!cap)
11758             return;
11759 
11760         elems_.reserve(cap);
11761         for (; b != e; b++)
11762         {
11763             if (b->value)
11764                 elems_.push_back(std::move(b->value));
11765         }
11766     }
11767 
11768     TOML_EXTERNAL_LINKAGE
11769     array::array(const array& other) //
11770         : node(other)
11771     {
11772         elems_.reserve(other.elems_.size());
11773         for (const auto& elem : other)
11774             elems_.emplace_back(impl::make_node(elem));
11775 
11776 #if TOML_LIFETIME_HOOKS
11777         TOML_ARRAY_CREATED;
11778 #endif
11779     }
11780 
11781     TOML_EXTERNAL_LINKAGE
11782     array::array(array && other) noexcept //
11783         : node(std::move(other)),
11784           elems_(std::move(other.elems_))
11785     {
11786 #if TOML_LIFETIME_HOOKS
11787         TOML_ARRAY_CREATED;
11788 #endif
11789     }
11790 
11791     TOML_EXTERNAL_LINKAGE
11792     array& array::operator=(const array& rhs)
11793     {
11794         if (&rhs != this)
11795         {
11796             node::operator=(rhs);
11797             elems_.clear();
11798             elems_.reserve(rhs.elems_.size());
11799             for (const auto& elem : rhs)
11800                 elems_.emplace_back(impl::make_node(elem));
11801         }
11802         return *this;
11803     }
11804 
11805     TOML_EXTERNAL_LINKAGE
11806     array& array::operator=(array&& rhs) noexcept
11807     {
11808         if (&rhs != this)
11809         {
11810             node::operator=(std::move(rhs));
11811             elems_ = std::move(rhs.elems_);
11812         }
11813         return *this;
11814     }
11815 
11816     TOML_EXTERNAL_LINKAGE
11817     void array::preinsertion_resize(size_t idx, size_t count)
11818     {
11819         TOML_ASSERT(idx <= elems_.size());
11820         TOML_ASSERT_ASSUME(count >= 1u);
11821         const auto old_size         = elems_.size();
11822         const auto new_size         = old_size + count;
11823         const auto inserting_at_end = idx == old_size;
11824         elems_.resize(new_size);
11825         if (!inserting_at_end)
11826         {
11827             for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
11828                 elems_[right] = std::move(elems_[left]);
11829         }
11830     }
11831 
11832     TOML_EXTERNAL_LINKAGE
11833     void array::insert_at_back(impl::node_ptr && elem)
11834     {
11835         TOML_ASSERT(elem);
11836         elems_.push_back(std::move(elem));
11837     }
11838 
11839     TOML_EXTERNAL_LINKAGE
11840     array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem)
11841     {
11842         return elems_.insert(pos, std::move(elem));
11843     }
11844 
11845     TOML_PURE_GETTER
11846     TOML_EXTERNAL_LINKAGE
11847     bool array::is_homogeneous(node_type ntype) const noexcept
11848     {
11849         if (elems_.empty())
11850             return false;
11851 
11852         if (ntype == node_type::none)
11853             ntype = elems_[0]->type();
11854 
11855         for (const auto& val : elems_)
11856             if (val->type() != ntype)
11857                 return false;
11858 
11859         return true;
11860     }
11861 
11862     TOML_NODISCARD
11863     TOML_EXTERNAL_LINKAGE
11864     bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
11865     {
11866         if (elems_.empty())
11867         {
11868             first_nonmatch = {};
11869             return false;
11870         }
11871         if (ntype == node_type::none)
11872             ntype = elems_[0]->type();
11873         for (const auto& val : elems_)
11874         {
11875             if (val->type() != ntype)
11876             {
11877                 first_nonmatch = val.get();
11878                 return false;
11879             }
11880         }
11881         return true;
11882     }
11883 
11884     TOML_NODISCARD
11885     TOML_EXTERNAL_LINKAGE
11886     bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
11887     {
11888         node* fnm         = nullptr;
11889         const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
11890         first_nonmatch    = fnm;
11891         return result;
11892     }
11893 
11894     TOML_EXTERNAL_LINKAGE
11895     node& array::at(size_t index)
11896     {
11897 #if TOML_COMPILER_HAS_EXCEPTIONS
11898 
11899         return *elems_.at(index);
11900 
11901 #else
11902 
11903         auto n = get(index);
11904         TOML_ASSERT_ASSUME(n && "element index not found in array!");
11905         return *n;
11906 
11907 #endif
11908     }
11909 
11910     TOML_EXTERNAL_LINKAGE
11911     void array::reserve(size_t new_capacity)
11912     {
11913         elems_.reserve(new_capacity);
11914     }
11915 
11916     TOML_EXTERNAL_LINKAGE
11917     void array::shrink_to_fit()
11918     {
11919         elems_.shrink_to_fit();
11920     }
11921 
11922     TOML_EXTERNAL_LINKAGE
11923     void array::truncate(size_t new_size)
11924     {
11925         if (new_size < elems_.size())
11926             elems_.resize(new_size);
11927     }
11928 
11929     TOML_EXTERNAL_LINKAGE
11930     array::iterator array::erase(const_iterator pos) noexcept
11931     {
11932         return iterator{ elems_.erase(const_vector_iterator{ pos }) };
11933     }
11934 
11935     TOML_EXTERNAL_LINKAGE
11936     array::iterator array::erase(const_iterator first, const_iterator last) noexcept
11937     {
11938         return iterator{ elems_.erase(const_vector_iterator{ first }, const_vector_iterator{ last }) };
11939     }
11940 
11941     TOML_EXTERNAL_LINKAGE
11942     size_t array::total_leaf_count() const noexcept
11943     {
11944         size_t leaves{};
11945         for (size_t i = 0, e = elems_.size(); i < e; i++)
11946         {
11947             auto arr = elems_[i]->as_array();
11948             leaves += arr ? arr->total_leaf_count() : size_t{ 1 };
11949         }
11950         return leaves;
11951     }
11952 
11953     TOML_EXTERNAL_LINKAGE
11954     void array::flatten_child(array && child, size_t & dest_index) noexcept
11955     {
11956         for (size_t i = 0, e = child.size(); i < e; i++)
11957         {
11958             auto type = child.elems_[i]->type();
11959             if (type == node_type::array)
11960             {
11961                 array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
11962                 if (!arr.empty())
11963                     flatten_child(std::move(arr), dest_index);
11964             }
11965             else
11966                 elems_[dest_index++] = std::move(child.elems_[i]);
11967         }
11968     }
11969 
11970     TOML_EXTERNAL_LINKAGE
11971     array& array::flatten()&
11972     {
11973         if (elems_.empty())
11974             return *this;
11975 
11976         bool requires_flattening     = false;
11977         size_t size_after_flattening = elems_.size();
11978         for (size_t i = elems_.size(); i-- > 0u;)
11979         {
11980             auto arr = elems_[i]->as_array();
11981             if (!arr)
11982                 continue;
11983             size_after_flattening--; // discount the array itself
11984             const auto leaf_count = arr->total_leaf_count();
11985             if (leaf_count > 0u)
11986             {
11987                 requires_flattening = true;
11988                 size_after_flattening += leaf_count;
11989             }
11990             else
11991                 elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
11992         }
11993 
11994         if (!requires_flattening)
11995             return *this;
11996 
11997         elems_.reserve(size_after_flattening);
11998 
11999         size_t i = 0;
12000         while (i < elems_.size())
12001         {
12002             auto arr = elems_[i]->as_array();
12003             if (!arr)
12004             {
12005                 i++;
12006                 continue;
12007             }
12008 
12009             impl::node_ptr arr_storage = std::move(elems_[i]);
12010             const auto leaf_count      = arr->total_leaf_count();
12011             if (leaf_count > 1u)
12012                 preinsertion_resize(i + 1u, leaf_count - 1u);
12013             flatten_child(std::move(*arr), i); // increments i
12014         }
12015 
12016         return *this;
12017     }
12018 
12019     TOML_EXTERNAL_LINKAGE
12020     array& array::prune(bool recursive)& noexcept
12021     {
12022         if (elems_.empty())
12023             return *this;
12024 
12025         for (size_t i = elems_.size(); i-- > 0u;)
12026         {
12027             if (auto arr = elems_[i]->as_array())
12028             {
12029                 if (recursive)
12030                     arr->prune(true);
12031                 if (arr->empty())
12032                     elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
12033             }
12034             else if (auto tbl = elems_[i]->as_table())
12035             {
12036                 if (recursive)
12037                     tbl->prune(true);
12038                 if (tbl->empty())
12039                     elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
12040             }
12041         }
12042 
12043         return *this;
12044     }
12045 
12046     TOML_EXTERNAL_LINKAGE
12047     void array::pop_back() noexcept
12048     {
12049         elems_.pop_back();
12050     }
12051 
12052     TOML_EXTERNAL_LINKAGE
12053     void array::clear() noexcept
12054     {
12055         elems_.clear();
12056     }
12057 
12058     TOML_EXTERNAL_LINKAGE
12059     bool TOML_CALLCONV array::equal(const array& lhs, const array& rhs) noexcept
12060     {
12061         if (&lhs == &rhs)
12062             return true;
12063         if (lhs.elems_.size() != rhs.elems_.size())
12064             return false;
12065         for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
12066         {
12067             const auto lhs_type = lhs.elems_[i]->type();
12068             const node& rhs_    = *rhs.elems_[i];
12069             const auto rhs_type = rhs_.type();
12070             if (lhs_type != rhs_type)
12071                 return false;
12072 
12073             const bool equal = lhs.elems_[i]->visit(
12074                 [&](const auto& lhs_) noexcept
12075                 { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
12076             if (!equal)
12077                 return false;
12078         }
12079         return true;
12080     }
12081 }
12082 TOML_NAMESPACE_END;
12083 
12084 #ifdef _MSC_VER
12085 #pragma pop_macro("min")
12086 #pragma pop_macro("max")
12087 #ifndef __clang__
12088 #pragma inline_recursion(off)
12089 #endif
12090 #endif
12091 TOML_POP_WARNINGS;
12092 
12093 //********  impl/table.inl  ********************************************************************************************
12094 
12095 TOML_PUSH_WARNINGS;
12096 #ifdef _MSC_VER
12097 #ifndef __clang__
12098 #pragma inline_recursion(on)
12099 #endif
12100 #pragma push_macro("min")
12101 #pragma push_macro("max")
12102 #undef min
12103 #undef max
12104 #endif
12105 
12106 TOML_NAMESPACE_START
12107 {
12108     TOML_EXTERNAL_LINKAGE
12109     table::table() noexcept
12110     {
12111 #if TOML_LIFETIME_HOOKS
12112         TOML_TABLE_CREATED;
12113 #endif
12114     }
12115 
12116     TOML_EXTERNAL_LINKAGE
12117     table::~table() noexcept
12118     {
12119 #if TOML_LIFETIME_HOOKS
12120         TOML_TABLE_DESTROYED;
12121 #endif
12122     }
12123 
12124     TOML_EXTERNAL_LINKAGE
12125     table::table(const impl::table_init_pair* b, const impl::table_init_pair* e)
12126     {
12127 #if TOML_LIFETIME_HOOKS
12128         TOML_TABLE_CREATED;
12129 #endif
12130 
12131         TOML_ASSERT_ASSUME(b);
12132         TOML_ASSERT_ASSUME(e);
12133         TOML_ASSERT_ASSUME(b <= e);
12134 
12135         if TOML_UNLIKELY(b == e)
12136             return;
12137 
12138         for (; b != e; b++)
12139         {
12140             if (!b->value) // empty node_views
12141                 continue;
12142 
12143             map_.insert_or_assign(std::move(b->key), std::move(b->value));
12144         }
12145     }
12146 
12147     TOML_EXTERNAL_LINKAGE
12148     table::table(const table& other) //
12149         : node(other),
12150           inline_{ other.inline_ }
12151     {
12152         for (auto&& [k, v] : other.map_)
12153             map_.emplace_hint(map_.end(), k, impl::make_node(*v));
12154 
12155 #if TOML_LIFETIME_HOOKS
12156         TOML_TABLE_CREATED;
12157 #endif
12158     }
12159 
12160     TOML_EXTERNAL_LINKAGE
12161     table::table(table && other) noexcept //
12162         : node(std::move(other)),
12163           map_{ std::move(other.map_) },
12164           inline_{ other.inline_ }
12165     {
12166 #if TOML_LIFETIME_HOOKS
12167         TOML_TABLE_CREATED;
12168 #endif
12169     }
12170 
12171     TOML_EXTERNAL_LINKAGE
12172     table& table::operator=(const table& rhs)
12173     {
12174         if (&rhs != this)
12175         {
12176             node::operator=(rhs);
12177             map_.clear();
12178             for (auto&& [k, v] : rhs.map_)
12179                 map_.emplace_hint(map_.end(), k, impl::make_node(*v));
12180             inline_ = rhs.inline_;
12181         }
12182         return *this;
12183     }
12184 
12185     TOML_EXTERNAL_LINKAGE
12186     table& table::operator=(table&& rhs) noexcept
12187     {
12188         if (&rhs != this)
12189         {
12190             node::operator=(std::move(rhs));
12191             map_    = std::move(rhs.map_);
12192             inline_ = rhs.inline_;
12193         }
12194         return *this;
12195     }
12196 
12197     TOML_PURE_GETTER
12198     TOML_EXTERNAL_LINKAGE
12199     bool table::is_homogeneous(node_type ntype) const noexcept
12200     {
12201         if (map_.empty())
12202             return false;
12203 
12204         if (ntype == node_type::none)
12205             ntype = map_.cbegin()->second->type();
12206 
12207         for (auto&& [k, v] : map_)
12208         {
12209             TOML_UNUSED(k);
12210             if (v->type() != ntype)
12211                 return false;
12212         }
12213 
12214         return true;
12215     }
12216 
12217     TOML_NODISCARD
12218     TOML_EXTERNAL_LINKAGE
12219     bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
12220     {
12221         if (map_.empty())
12222         {
12223             first_nonmatch = {};
12224             return false;
12225         }
12226         if (ntype == node_type::none)
12227             ntype = map_.cbegin()->second->type();
12228         for (const auto& [k, v] : map_)
12229         {
12230             TOML_UNUSED(k);
12231             if (v->type() != ntype)
12232             {
12233                 first_nonmatch = v.get();
12234                 return false;
12235             }
12236         }
12237         return true;
12238     }
12239 
12240     TOML_NODISCARD
12241     TOML_EXTERNAL_LINKAGE
12242     bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
12243     {
12244         node* fnm         = nullptr;
12245         const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
12246         first_nonmatch    = fnm;
12247         return result;
12248     }
12249 
12250     TOML_PURE_GETTER
12251     TOML_EXTERNAL_LINKAGE
12252     node* table::get(std::string_view key) noexcept
12253     {
12254         if (auto it = map_.find(key); it != map_.end())
12255             return it->second.get();
12256         return nullptr;
12257     }
12258 
12259     TOML_EXTERNAL_LINKAGE
12260     node& table::at(std::string_view key)
12261     {
12262         auto n = get(key);
12263 
12264 #if TOML_COMPILER_HAS_EXCEPTIONS
12265 
12266         if (!n)
12267         {
12268             auto err = "key '"s;
12269             err.append(key);
12270             err.append("' not found in table"sv);
12271             throw std::out_of_range{ err };
12272         }
12273 
12274 #else
12275 
12276         TOML_ASSERT_ASSUME(n && "key not found in table!");
12277 
12278 #endif
12279 
12280         return *n;
12281     }
12282 
12283     TOML_PURE_GETTER
12284     TOML_EXTERNAL_LINKAGE
12285     table::map_iterator table::get_lower_bound(std::string_view key) noexcept
12286     {
12287         return map_.lower_bound(key);
12288     }
12289 
12290     TOML_PURE_GETTER
12291     TOML_EXTERNAL_LINKAGE
12292     table::iterator table::find(std::string_view key) noexcept
12293     {
12294         return iterator{ map_.find(key) };
12295     }
12296 
12297     TOML_PURE_GETTER
12298     TOML_EXTERNAL_LINKAGE
12299     table::const_iterator table::find(std::string_view key) const noexcept
12300     {
12301         return const_iterator{ map_.find(key) };
12302     }
12303 
12304     TOML_EXTERNAL_LINKAGE
12305     table::map_iterator table::erase(const_map_iterator pos) noexcept
12306     {
12307         return map_.erase(pos);
12308     }
12309 
12310     TOML_EXTERNAL_LINKAGE
12311     table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept
12312     {
12313         return map_.erase(begin, end);
12314     }
12315 
12316     TOML_EXTERNAL_LINKAGE
12317     size_t table::erase(std::string_view key) noexcept
12318     {
12319         if (auto it = map_.find(key); it != map_.end())
12320         {
12321             map_.erase(it);
12322             return size_t{ 1 };
12323         }
12324         return size_t{};
12325     }
12326 
12327     TOML_EXTERNAL_LINKAGE
12328     table& table::prune(bool recursive)& noexcept
12329     {
12330         if (map_.empty())
12331             return *this;
12332 
12333         for (auto it = map_.begin(); it != map_.end();)
12334         {
12335             if (auto arr = it->second->as_array())
12336             {
12337                 if (recursive)
12338                     arr->prune(true);
12339 
12340                 if (arr->empty())
12341                 {
12342                     it = map_.erase(it);
12343                     continue;
12344                 }
12345             }
12346             else if (auto tbl = it->second->as_table())
12347             {
12348                 if (recursive)
12349                     tbl->prune(true);
12350 
12351                 if (tbl->empty())
12352                 {
12353                     it = map_.erase(it);
12354                     continue;
12355                 }
12356             }
12357             it++;
12358         }
12359 
12360         return *this;
12361     }
12362 
12363     TOML_EXTERNAL_LINKAGE
12364     void table::clear() noexcept
12365     {
12366         map_.clear();
12367     }
12368 
12369     TOML_EXTERNAL_LINKAGE
12370     table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v)
12371     {
12372         return map_.emplace_hint(const_map_iterator{ hint }, std::move(k), std::move(v));
12373     }
12374 
12375     TOML_PURE_GETTER
12376     TOML_EXTERNAL_LINKAGE
12377     bool TOML_CALLCONV table::equal(const table& lhs, const table& rhs) noexcept
12378     {
12379         if (&lhs == &rhs)
12380             return true;
12381         if (lhs.map_.size() != rhs.map_.size())
12382             return false;
12383 
12384         for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++)
12385         {
12386             if (l->first != r->first)
12387                 return false;
12388 
12389             const auto lhs_type = l->second->type();
12390             const node& rhs_    = *r->second;
12391             const auto rhs_type = rhs_.type();
12392             if (lhs_type != rhs_type)
12393                 return false;
12394 
12395             const bool equal = l->second->visit(
12396                 [&](const auto& lhs_) noexcept
12397                 { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
12398             if (!equal)
12399                 return false;
12400         }
12401         return true;
12402     }
12403 }
12404 TOML_NAMESPACE_END;
12405 
12406 #ifdef _MSC_VER
12407 #pragma pop_macro("min")
12408 #pragma pop_macro("max")
12409 #ifndef __clang__
12410 #pragma inline_recursion(off)
12411 #endif
12412 #endif
12413 TOML_POP_WARNINGS;
12414 
12415 //********  impl/simd.hpp  *********************************************************************************************
12416 
12417 #if TOML_ENABLE_SIMD
12418 
12419 #if defined(__SSE2__)                                                                                                  \
12420     || (defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))
12421 #define TOML_HAS_SSE2 1
12422 #endif
12423 
12424 #if defined(__SSE4_1__) || (defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__)))
12425 #define TOML_HAS_SSE4_1 1
12426 #endif
12427 
12428 #endif // TOML_ENABLE_SIMD
12429 
12430 #ifndef TOML_HAS_SSE2
12431 #define TOML_HAS_SSE2 0
12432 #endif
12433 #ifndef TOML_HAS_SSE4_1
12434 #define TOML_HAS_SSE4_1 0
12435 #endif
12436 
12437 TOML_DISABLE_WARNINGS;
12438 #if TOML_HAS_SSE4_1
12439 #include <smmintrin.h>
12440 #endif
12441 #if TOML_HAS_SSE2
12442 #include <emmintrin.h>
12443 #endif
12444 TOML_ENABLE_WARNINGS;
12445 
12446 //********  impl/unicode.inl  ******************************************************************************************
12447 
12448 TOML_PUSH_WARNINGS;
12449 #ifdef _MSC_VER
12450 #ifndef __clang__
12451 #pragma inline_recursion(on)
12452 #endif
12453 #pragma push_macro("min")
12454 #pragma push_macro("max")
12455 #undef min
12456 #undef max
12457 #endif
12458 
12459 TOML_IMPL_NAMESPACE_START
12460 {
12461     TOML_PURE_GETTER
12462     TOML_EXTERNAL_LINKAGE
12463     bool is_ascii(const char* str, size_t len) noexcept
12464     {
12465         const char* const end = str + len;
12466 
12467 #if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
12468         {
12469             constexpr size_t chars_per_vector = 128u / CHAR_BIT;
12470 
12471             if (const size_t simdable = len - (len % chars_per_vector))
12472             {
12473                 __m128i mask = _mm_setzero_si128();
12474                 for (const char* const e = str + simdable; str < e; str += chars_per_vector)
12475                 {
12476                     const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
12477                     mask                        = _mm_or_si128(mask, current_bytes);
12478                 }
12479                 const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
12480 
12481 #if TOML_HAS_SSE4_1
12482                 if (!_mm_testz_si128(has_error, has_error))
12483                     return false;
12484 #else
12485                 if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
12486                     return false;
12487 #endif
12488             }
12489         }
12490 #endif
12491 
12492         for (; str < end; str++)
12493             if (static_cast<unsigned char>(*str) > 127u)
12494                 return false;
12495 
12496         return true;
12497     }
12498 }
12499 TOML_IMPL_NAMESPACE_END;
12500 
12501 #ifdef _MSC_VER
12502 #pragma pop_macro("min")
12503 #pragma pop_macro("max")
12504 #ifndef __clang__
12505 #pragma inline_recursion(off)
12506 #endif
12507 #endif
12508 TOML_POP_WARNINGS;
12509 
12510 //********  impl/parser.inl  *******************************************************************************************
12511 
12512 #if TOML_ENABLE_PARSER
12513 
12514 TOML_DISABLE_WARNINGS;
12515 #include <istream>
12516 #include <fstream>
12517 #if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
12518 #include <charconv>
12519 #endif
12520 #if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
12521 #include <sstream>
12522 #endif
12523 #if !TOML_INT_CHARCONV
12524 #include <iomanip>
12525 #endif
12526 TOML_ENABLE_WARNINGS;
12527 TOML_PUSH_WARNINGS;
12528 #ifdef _MSC_VER
12529 #ifndef __clang__
12530 #pragma inline_recursion(on)
12531 #endif
12532 #pragma push_macro("min")
12533 #pragma push_macro("max")
12534 #undef min
12535 #undef max
12536 #endif
12537 
12538 TOML_ANON_NAMESPACE_START
12539 {
12540     template <typename T>
12541     class utf8_byte_stream;
12542 
12543     TOML_INTERNAL_LINKAGE
12544     constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
12545 
12546     template <typename Char>
12547     class utf8_byte_stream<std::basic_string_view<Char>>
12548     {
12549         static_assert(sizeof(Char) == 1);
12550 
12551       private:
12552         std::basic_string_view<Char> source_;
12553         size_t position_ = {};
12554 
12555       public:
12556         TOML_NODISCARD_CTOR
12557         explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept //
12558             : source_{ sv }
12559         {
12560             // skip bom
12561             if (source_.length() >= 3u && memcmp(utf8_byte_order_mark.data(), source_.data(), 3u) == 0)
12562                 position_ += 3u;
12563         }
12564 
12565         TOML_CONST_INLINE_GETTER
12566         constexpr bool error() const noexcept
12567         {
12568             return false;
12569         }
12570 
12571         TOML_PURE_INLINE_GETTER
12572         constexpr bool eof() const noexcept
12573         {
12574             return position_ >= source_.length();
12575         }
12576 
12577         TOML_PURE_INLINE_GETTER
12578         explicit constexpr operator bool() const noexcept
12579         {
12580             return !eof();
12581         }
12582 
12583         TOML_PURE_INLINE_GETTER
12584         constexpr bool peek_eof() const noexcept
12585         {
12586             return eof();
12587         }
12588 
12589         TOML_NODISCARD
12590         TOML_ATTR(nonnull)
12591         size_t operator()(void* dest, size_t num) noexcept
12592         {
12593             TOML_ASSERT_ASSUME(!eof());
12594 
12595             num = impl::min(position_ + num, source_.length()) - position_;
12596             std::memcpy(dest, source_.data() + position_, num);
12597             position_ += num;
12598             return num;
12599         }
12600     };
12601 
12602     template <>
12603     class utf8_byte_stream<std::istream>
12604     {
12605       private:
12606         std::istream* source_;
12607 
12608       public:
12609         TOML_NODISCARD_CTOR
12610         explicit utf8_byte_stream(std::istream& stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) //
12611             : source_{ &stream }
12612         {
12613             if (!*this) // eof, bad
12614                 return;
12615 
12616             const auto initial_pos = source_->tellg();
12617             char bom[3];
12618             source_->read(bom, 3);
12619             if (source_->bad() || (source_->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3u) == 0))
12620                 return;
12621 
12622             source_->clear();
12623             source_->seekg(initial_pos, std::istream::beg);
12624         }
12625 
12626         TOML_PURE_INLINE_GETTER
12627         bool error() const noexcept
12628         {
12629             return !!(source_->rdstate() & std::istream::badbit);
12630         }
12631 
12632         TOML_PURE_INLINE_GETTER
12633         bool eof() const noexcept
12634         {
12635             return !!(source_->rdstate() & std::istream::eofbit);
12636         }
12637 
12638         TOML_PURE_INLINE_GETTER
12639         explicit operator bool() const noexcept
12640         {
12641             return !(source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
12642         }
12643 
12644         TOML_NODISCARD
12645         bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
12646         {
12647             return eof() || source_->peek() == std::istream::traits_type::eof();
12648         }
12649 
12650         TOML_NODISCARD
12651         TOML_ATTR(nonnull)
12652         size_t operator()(void* dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
12653         {
12654             TOML_ASSERT(*this);
12655 
12656             source_->read(static_cast<char*>(dest), static_cast<std::streamsize>(num));
12657             return static_cast<size_t>(source_->gcount());
12658         }
12659     };
12660 
12661     struct utf8_codepoint
12662     {
12663         char32_t value;
12664         char bytes[4];
12665         size_t count;
12666         source_position position;
12667 
12668         TOML_PURE_INLINE_GETTER
12669         constexpr operator const char32_t&() const noexcept
12670         {
12671             return value;
12672         }
12673 
12674         TOML_PURE_INLINE_GETTER
12675         constexpr const char32_t& operator*() const noexcept
12676         {
12677             return value;
12678         }
12679     };
12680     static_assert(std::is_trivial_v<utf8_codepoint>);
12681     static_assert(std::is_standard_layout_v<utf8_codepoint>);
12682 
12683     struct TOML_ABSTRACT_INTERFACE utf8_reader_interface
12684     {
12685         TOML_NODISCARD
12686         virtual const source_path_ptr& source_path() const noexcept = 0;
12687 
12688         TOML_NODISCARD
12689         virtual const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
12690 
12691         TOML_NODISCARD
12692         virtual bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
12693 
12694 #if !TOML_EXCEPTIONS
12695 
12696         TOML_NODISCARD
12697         virtual optional<parse_error>&& error() noexcept = 0;
12698 
12699 #endif
12700 
12701         virtual ~utf8_reader_interface() noexcept = default;
12702     };
12703 
12704 #if TOML_EXCEPTIONS
12705 #define utf8_reader_error(...)              throw parse_error(__VA_ARGS__)
12706 #define utf8_reader_return_after_error(...) static_assert(true)
12707 #define utf8_reader_error_check(...)        static_assert(true)
12708 #else
12709 #define utf8_reader_error(...)              err_.emplace(__VA_ARGS__)
12710 #define utf8_reader_return_after_error(...) return __VA_ARGS__
12711 #define utf8_reader_error_check(...)                                                                                   \
12712     do                                                                                                                 \
12713     {                                                                                                                  \
12714         if TOML_UNLIKELY(err_)                                                                                         \
12715             return __VA_ARGS__;                                                                                        \
12716     }                                                                                                                  \
12717     while (false)
12718 
12719 #endif
12720 
12721 #if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
12722 #define TOML_OVERALIGNED
12723 #else
12724 #define TOML_OVERALIGNED alignas(32)
12725 #endif
12726 
12727     template <typename T>
12728     class TOML_EMPTY_BASES utf8_reader final : public utf8_reader_interface
12729     {
12730       private:
12731         static constexpr size_t block_capacity = 32;
12732         utf8_byte_stream<T> stream_;
12733         source_position next_pos_ = { 1, 1 };
12734 
12735         impl::utf8_decoder decoder_;
12736         struct currently_decoding_t
12737         {
12738             char bytes[4];
12739             size_t count;
12740         } currently_decoding_;
12741 
12742         struct codepoints_t
12743         {
12744             TOML_OVERALIGNED utf8_codepoint buffer[block_capacity];
12745             size_t current;
12746             size_t count;
12747         } codepoints_;
12748 
12749         source_path_ptr source_path_;
12750 
12751 #if !TOML_EXCEPTIONS
12752         optional<parse_error> err_;
12753 #endif
12754 
12755         bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
12756         {
12757             TOML_ASSERT(stream_);
12758 
12759             TOML_OVERALIGNED char raw_bytes[block_capacity];
12760             size_t raw_bytes_read;
12761 
12762             // read the next raw (encoded) block in from the stream
12763             if constexpr (noexcept(stream_(raw_bytes, block_capacity)) || !TOML_EXCEPTIONS)
12764             {
12765                 raw_bytes_read = stream_(raw_bytes, block_capacity);
12766             }
12767 #if TOML_EXCEPTIONS
12768             else
12769             {
12770                 try
12771                 {
12772                     raw_bytes_read = stream_(raw_bytes, block_capacity);
12773                 }
12774                 catch (const std::exception& exc)
12775                 {
12776                     throw parse_error{ exc.what(), next_pos_, source_path_ };
12777                 }
12778                 catch (...)
12779                 {
12780                     throw parse_error{ "An unspecified error occurred", next_pos_, source_path_ };
12781                 }
12782             }
12783 #endif // TOML_EXCEPTIONS
12784 
12785             // handle a zero-byte read
12786             if TOML_UNLIKELY(!raw_bytes_read)
12787             {
12788                 if (stream_.eof())
12789                 {
12790                     // EOF only sets the error state if the decoder wants more input, otherwise
12791                     // a zero-byte read might have just caused the underlying stream to realize it's exhaused and set
12792                     // the EOF flag, and that's totally fine
12793                     if (decoder_.needs_more_input())
12794                         utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
12795                                           next_pos_,
12796                                           source_path_);
12797                 }
12798                 else
12799                 {
12800                     utf8_reader_error("Reading from the underlying stream failed - zero bytes read",
12801                                       next_pos_,
12802                                       source_path_);
12803                 }
12804                 return false;
12805             }
12806 
12807             TOML_ASSERT_ASSUME(raw_bytes_read);
12808             std::memset(&codepoints_, 0, sizeof(codepoints_));
12809 
12810             // helper for calculating decoded codepoint line+cols
12811             const auto calc_positions = [&]() noexcept
12812             {
12813                 for (size_t i = 0; i < codepoints_.count; i++)
12814                 {
12815                     auto& cp    = codepoints_.buffer[i];
12816                     cp.position = next_pos_;
12817 
12818                     if (cp == U'\n')
12819                     {
12820                         next_pos_.line++;
12821                         next_pos_.column = source_index{ 1 };
12822                     }
12823                     else
12824                         next_pos_.column++;
12825                 }
12826             };
12827 
12828             // decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
12829             const auto ascii_fast_path = !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
12830 
12831             // ASCII fast-path
12832             if (ascii_fast_path)
12833             {
12834                 decoder_.reset();
12835                 currently_decoding_.count = {};
12836 
12837                 codepoints_.count = raw_bytes_read;
12838                 for (size_t i = 0; i < codepoints_.count; i++)
12839                 {
12840                     auto& cp    = codepoints_.buffer[i];
12841                     cp.value    = static_cast<char32_t>(raw_bytes[i]);
12842                     cp.bytes[0] = raw_bytes[i];
12843                     cp.count    = 1u;
12844                 }
12845             }
12846 
12847             // UTF-8 slow-path
12848             else
12849             {
12850                 // helper for getting precise error location
12851                 const auto error_pos = [&]() noexcept -> const source_position&
12852                 { //
12853                     return codepoints_.count ? codepoints_.buffer[codepoints_.count - 1u].position : next_pos_;
12854                 };
12855 
12856                 for (size_t i = 0; i < raw_bytes_read; i++)
12857                 {
12858                     decoder_(static_cast<uint8_t>(raw_bytes[i]));
12859                     if TOML_UNLIKELY(decoder_.error())
12860                     {
12861                         calc_positions();
12862                         utf8_reader_error("Encountered invalid utf-8 sequence", error_pos(), source_path_);
12863                         utf8_reader_return_after_error(false);
12864                     }
12865 
12866                     currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];
12867 
12868                     if (decoder_.has_code_point())
12869                     {
12870                         auto& cp = codepoints_.buffer[codepoints_.count++];
12871 
12872                         cp.value = decoder_.codepoint;
12873                         cp.count = currently_decoding_.count;
12874                         std::memcpy(cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
12875                         currently_decoding_.count = {};
12876                     }
12877                     else if TOML_UNLIKELY(currently_decoding_.count == 4u)
12878                     {
12879                         calc_positions();
12880                         utf8_reader_error("Encountered overlong utf-8 sequence", error_pos(), source_path_);
12881                         utf8_reader_return_after_error(false);
12882                     }
12883                 }
12884                 if TOML_UNLIKELY(decoder_.needs_more_input() && stream_.eof())
12885                 {
12886                     calc_positions();
12887                     utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
12888                                       error_pos(),
12889                                       source_path_);
12890                     utf8_reader_return_after_error(false);
12891                 }
12892             }
12893 
12894             TOML_ASSERT_ASSUME(codepoints_.count);
12895             calc_positions();
12896 
12897             // handle general I/O errors
12898             // (down here so the next_pos_ benefits from calc_positions())
12899             if TOML_UNLIKELY(stream_.error())
12900             {
12901                 utf8_reader_error("An I/O error occurred while reading from the underlying stream",
12902                                   next_pos_,
12903                                   source_path_);
12904                 utf8_reader_return_after_error(false);
12905             }
12906 
12907             return true;
12908         }
12909 
12910       public:
12911         template <typename U, typename String = std::string_view>
12912         TOML_NODISCARD_CTOR
12913         explicit utf8_reader(U&& source, String&& source_path = {}) noexcept(
12914             std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
12915             : stream_{ static_cast<U&&>(source) }
12916         {
12917             currently_decoding_.count = {};
12918 
12919             codepoints_.current = {};
12920             codepoints_.count   = {};
12921 
12922             if (!source_path.empty())
12923                 source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
12924         }
12925 
12926         TOML_PURE_INLINE_GETTER
12927         const source_path_ptr& source_path() const noexcept final
12928         {
12929             return source_path_;
12930         }
12931 
12932         TOML_NODISCARD
12933         const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
12934         {
12935             utf8_reader_error_check({});
12936 
12937             if (codepoints_.current == codepoints_.count)
12938             {
12939                 if TOML_UNLIKELY(!stream_ || !read_next_block())
12940                     return nullptr;
12941 
12942                 TOML_ASSERT_ASSUME(!codepoints_.current);
12943             }
12944             TOML_ASSERT_ASSUME(codepoints_.count);
12945             TOML_ASSERT_ASSUME(codepoints_.count <= block_capacity);
12946             TOML_ASSERT_ASSUME(codepoints_.current < codepoints_.count);
12947 
12948             return &codepoints_.buffer[codepoints_.current++];
12949         }
12950 
12951         TOML_NODISCARD
12952         bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
12953         {
12954             return stream_.peek_eof();
12955         }
12956 
12957 #if !TOML_EXCEPTIONS
12958 
12959         TOML_NODISCARD
12960         optional<parse_error>&& error() noexcept final
12961         {
12962             return std::move(err_);
12963         }
12964 
12965 #endif
12966     };
12967 
12968     template <typename Char>
12969     utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
12970     template <typename Char>
12971     utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
12972     template <typename Char>
12973     utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
12974     template <typename Char>
12975     utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
12976 
12977 #if TOML_EXCEPTIONS
12978 #define utf8_buffered_reader_error_check(...) static_assert(true)
12979 #else
12980 #define utf8_buffered_reader_error_check(...)                                                                          \
12981     do                                                                                                                 \
12982     {                                                                                                                  \
12983         if TOML_UNLIKELY(reader_.error())                                                                              \
12984             return __VA_ARGS__;                                                                                        \
12985     }                                                                                                                  \
12986     while (false)
12987 
12988 #endif
12989 
12990     class TOML_EMPTY_BASES utf8_buffered_reader
12991     {
12992       public:
12993         static constexpr size_t max_history_length = 128;
12994 
12995       private:
12996         static constexpr size_t history_buffer_size = max_history_length - 1; //'head' is stored in the reader
12997         utf8_reader_interface& reader_;
12998         struct
12999         {
13000             utf8_codepoint buffer[history_buffer_size];
13001             size_t count, first;
13002         } history_                  = {};
13003         const utf8_codepoint* head_ = {};
13004         size_t negative_offset_     = {};
13005 
13006       public:
13007         TOML_NODISCARD_CTOR
13008         explicit utf8_buffered_reader(utf8_reader_interface& reader) noexcept //
13009             : reader_{ reader }
13010         {}
13011 
13012         TOML_PURE_INLINE_GETTER
13013         const source_path_ptr& source_path() const noexcept
13014         {
13015             return reader_.source_path();
13016         }
13017 
13018         TOML_NODISCARD
13019         const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
13020         {
13021             utf8_buffered_reader_error_check({});
13022 
13023             if (negative_offset_)
13024             {
13025                 negative_offset_--;
13026 
13027                 // an entry negative offset of 1 just means "replay the current head"
13028                 if (!negative_offset_)
13029                     return head_;
13030 
13031                 // otherwise step back into the history buffer
13032                 else
13033                     return history_.buffer
13034                          + ((history_.first + history_.count - negative_offset_) % history_buffer_size);
13035             }
13036             else
13037             {
13038                 // first character read from stream
13039                 if TOML_UNLIKELY(!history_.count && !head_)
13040                     head_ = reader_.read_next();
13041 
13042                 // subsequent characters and not eof
13043                 else if (head_)
13044                 {
13045                     if TOML_UNLIKELY(history_.count < history_buffer_size)
13046                         history_.buffer[history_.count++] = *head_;
13047                     else
13048                         history_.buffer[(history_.first++ + history_buffer_size) % history_buffer_size] = *head_;
13049 
13050                     head_ = reader_.read_next();
13051                 }
13052 
13053                 return head_;
13054             }
13055         }
13056 
13057         TOML_NODISCARD
13058         const utf8_codepoint* step_back(size_t count) noexcept
13059         {
13060             utf8_buffered_reader_error_check({});
13061 
13062             TOML_ASSERT_ASSUME(history_.count);
13063             TOML_ASSERT_ASSUME(negative_offset_ + count <= history_.count);
13064 
13065             negative_offset_ += count;
13066 
13067             return negative_offset_
13068                      ? history_.buffer + ((history_.first + history_.count - negative_offset_) % history_buffer_size)
13069                      : head_;
13070         }
13071 
13072         TOML_NODISCARD
13073         bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
13074         {
13075             return reader_.peek_eof();
13076         }
13077 
13078 #if !TOML_EXCEPTIONS
13079 
13080         TOML_NODISCARD
13081         optional<parse_error>&& error() noexcept
13082         {
13083             return reader_.error();
13084         }
13085 
13086 #endif
13087     };
13088 }
13089 TOML_ANON_NAMESPACE_END;
13090 
13091 #if TOML_EXCEPTIONS
13092 #define TOML_RETURNS_BY_THROWING [[noreturn]]
13093 #else
13094 #define TOML_RETURNS_BY_THROWING
13095 #endif
13096 
13097 TOML_ANON_NAMESPACE_START
13098 {
13099     template <typename... T>
13100     TOML_CONST_GETTER
13101     TOML_INTERNAL_LINKAGE
13102     constexpr bool is_match(char32_t codepoint, T... vals) noexcept
13103     {
13104         static_assert((std::is_same_v<char32_t, T> && ...));
13105         return ((codepoint == vals) || ...);
13106     }
13107 
13108     template <uint64_t>
13109     struct parse_integer_traits;
13110     template <>
13111     struct parse_integer_traits<2>
13112     {
13113         static constexpr auto scope_qualifier  = "binary integer"sv;
13114         static constexpr auto is_digit         = impl::is_binary_digit;
13115         static constexpr auto is_signed        = false;
13116         static constexpr auto max_digits       = 63;
13117         static constexpr auto prefix_codepoint = U'b';
13118         static constexpr auto prefix           = "b"sv;
13119         static constexpr auto full_prefix      = "0b"sv;
13120     };
13121     template <>
13122     struct parse_integer_traits<8>
13123     {
13124         static constexpr auto scope_qualifier  = "octal integer"sv;
13125         static constexpr auto is_digit         = impl::is_octal_digit;
13126         static constexpr auto is_signed        = false;
13127         static constexpr auto max_digits       = 21; // strlen("777777777777777777777")
13128         static constexpr auto prefix_codepoint = U'o';
13129         static constexpr auto prefix           = "o"sv;
13130         static constexpr auto full_prefix      = "0o"sv;
13131     };
13132     template <>
13133     struct parse_integer_traits<10>
13134     {
13135         static constexpr auto scope_qualifier = "decimal integer"sv;
13136         static constexpr auto is_digit        = impl::is_decimal_digit;
13137         static constexpr auto is_signed       = true;
13138         static constexpr auto max_digits      = 19; // strlen("9223372036854775807")
13139         static constexpr auto full_prefix     = ""sv;
13140     };
13141     template <>
13142     struct parse_integer_traits<16>
13143     {
13144         static constexpr auto scope_qualifier  = "hexadecimal integer"sv;
13145         static constexpr auto is_digit         = impl::is_hexadecimal_digit;
13146         static constexpr auto is_signed        = false;
13147         static constexpr auto max_digits       = 16; // strlen("7FFFFFFFFFFFFFFF")
13148         static constexpr auto prefix_codepoint = U'x';
13149         static constexpr auto prefix           = "x"sv;
13150         static constexpr auto full_prefix      = "0x"sv;
13151     };
13152 
13153     TOML_PURE_GETTER
13154     TOML_INTERNAL_LINKAGE
13155     std::string_view to_sv(node_type val) noexcept
13156     {
13157         return impl::node_type_friendly_names[impl::unwrap_enum(val)];
13158     }
13159 
13160     TOML_PURE_GETTER
13161     TOML_INTERNAL_LINKAGE
13162     std::string_view to_sv(const std::string& str) noexcept
13163     {
13164         return std::string_view{ str };
13165     }
13166 
13167     TOML_CONST_GETTER
13168     TOML_INTERNAL_LINKAGE
13169     std::string_view to_sv(bool val) noexcept
13170     {
13171         using namespace std::string_view_literals;
13172 
13173         return val ? "true"sv : "false"sv;
13174     }
13175 
13176     TOML_PURE_GETTER
13177     TOML_INTERNAL_LINKAGE
13178     std::string_view to_sv(const utf8_codepoint& cp) noexcept
13179     {
13180         if (cp.value <= U'\x1F')
13181             return impl::control_char_escapes[cp.value];
13182         else if (cp.value == U'\x7F')
13183             return "\\u007F"sv;
13184         else
13185             return std::string_view{ cp.bytes, cp.count };
13186     }
13187 
13188     TOML_PURE_GETTER
13189     TOML_INTERNAL_LINKAGE
13190     std::string_view to_sv(const utf8_codepoint* cp) noexcept
13191     {
13192         if (cp)
13193             return to_sv(*cp);
13194         return ""sv;
13195     }
13196 
13197     struct escaped_codepoint
13198     {
13199         const utf8_codepoint& cp;
13200     };
13201 
13202     template <typename T>
13203     TOML_ATTR(nonnull)
13204     TOML_INTERNAL_LINKAGE
13205     void concatenate(char*& write_pos, char* const buf_end, const T& arg) noexcept
13206     {
13207         if TOML_UNLIKELY(write_pos >= buf_end)
13208             return;
13209 
13210         using arg_type = impl::remove_cvref<T>;
13211 
13212         // string views
13213         if constexpr (std::is_same_v<arg_type, std::string_view>)
13214         {
13215             const auto max_chars = static_cast<size_t>(buf_end - write_pos);
13216             const auto len       = max_chars < arg.length() ? max_chars : arg.length();
13217             std::memcpy(write_pos, arg.data(), len);
13218             write_pos += len;
13219         }
13220 
13221         // doubles
13222         else if constexpr (std::is_same_v<arg_type, double>)
13223         {
13224 #if TOML_FLOAT_CHARCONV
13225             const auto result = std::to_chars(write_pos, buf_end, arg);
13226             write_pos         = result.ptr;
13227 #else
13228             std::ostringstream ss;
13229             ss.imbue(std::locale::classic());
13230             ss.precision(std::numeric_limits<arg_type>::max_digits10);
13231             ss << arg;
13232             concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
13233 #endif
13234         }
13235 
13236         // 64-bit integers
13237         else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>)
13238         {
13239 #if TOML_INT_CHARCONV
13240             const auto result = std::to_chars(write_pos, buf_end, arg);
13241             write_pos         = result.ptr;
13242 #else
13243             std::ostringstream ss;
13244             ss.imbue(std::locale::classic());
13245             using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
13246             ss << static_cast<cast_type>(arg);
13247             concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
13248 #endif
13249         }
13250 
13251         // escaped_codepoint
13252         else if constexpr (std::is_same_v<arg_type, escaped_codepoint>)
13253         {
13254             if (arg.cp.value <= U'\x7F')
13255                 concatenate(write_pos, buf_end, to_sv(arg.cp));
13256             else
13257             {
13258                 auto val            = static_cast<uint_least32_t>(arg.cp.value);
13259                 const auto digits   = val > 0xFFFFu ? 8u : 4u;
13260                 constexpr auto mask = uint_least32_t{ 0xFu };
13261                 char buf[10]        = { '\\', digits > 4 ? 'U' : 'u' };
13262                 for (auto i = 2u + digits; i-- > 2u;)
13263                 {
13264                     const auto hexdig = val & mask;
13265                     buf[i]            = static_cast<char>(hexdig >= 0xAu ? ('A' + (hexdig - 0xAu)) : ('0' + hexdig));
13266                     val >>= 4;
13267                 }
13268                 concatenate(write_pos, buf_end, std::string_view{ buf, digits + 2u });
13269             }
13270         }
13271 
13272         // all other floats (fallback - coerce to double)
13273         else if constexpr (std::is_floating_point_v<arg_type>)
13274             concatenate(write_pos, buf_end, static_cast<double>(arg));
13275 
13276         // all other integers (fallback - coerce to (u)int64_t)
13277         else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>)
13278         {
13279             using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
13280             concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
13281         }
13282 
13283         else
13284         {
13285             static_assert(
13286                 impl::always_false<T>,
13287                 "concatenate() inputs are limited to std::string_views, integers, floats, and escaped_codepoint");
13288         }
13289     }
13290 
13291     struct error_builder
13292     {
13293         static constexpr std::size_t buf_size = 512;
13294         char buf[buf_size];
13295         char* write_pos           = buf;
13296         char* const max_write_pos = buf + (buf_size - std::size_t{ 1 }); // allow for null terminator
13297 
13298         TOML_NODISCARD_CTOR
13299         error_builder(std::string_view scope) noexcept
13300         {
13301             concatenate(write_pos, max_write_pos, "Error while parsing "sv);
13302             concatenate(write_pos, max_write_pos, scope);
13303             concatenate(write_pos, max_write_pos, ": "sv);
13304         }
13305 
13306         template <typename T>
13307         void append(const T& arg) noexcept
13308         {
13309             concatenate(write_pos, max_write_pos, arg);
13310         }
13311 
13312         TOML_RETURNS_BY_THROWING
13313         auto finish(const source_position& pos, const source_path_ptr& source_path) const
13314         {
13315             *write_pos = '\0';
13316 
13317 #if TOML_EXCEPTIONS
13318             throw parse_error{ buf, pos, source_path };
13319 #else
13320             return parse_error{ std::string(buf, static_cast<size_t>(write_pos - buf)), pos, source_path };
13321 #endif
13322         }
13323 
13324         TOML_DELETE_DEFAULTS(error_builder);
13325     };
13326 
13327     struct parse_scope
13328     {
13329         std::string_view& storage_;
13330         std::string_view parent_;
13331 
13332         TOML_NODISCARD_CTOR
13333         explicit parse_scope(std::string_view& current_scope, std::string_view new_scope) noexcept
13334             : storage_{ current_scope },
13335               parent_{ current_scope }
13336         {
13337             storage_ = new_scope;
13338         }
13339 
13340         ~parse_scope() noexcept
13341         {
13342             storage_ = parent_;
13343         }
13344 
13345         TOML_DELETE_DEFAULTS(parse_scope);
13346     };
13347 #define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
13348 #define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
13349 #define push_parse_scope(scope)         push_parse_scope_1(scope, __LINE__)
13350 
13351     struct parse_key_buffer
13352     {
13353         std::string buffer;
13354         std::vector<std::pair<size_t, size_t>> segments;
13355         std::vector<source_position> starts;
13356         std::vector<source_position> ends;
13357 
13358         void clear() noexcept
13359         {
13360             buffer.clear();
13361             segments.clear();
13362             starts.clear();
13363             ends.clear();
13364         }
13365 
13366         void push_back(std::string_view segment, source_position b, source_position e)
13367         {
13368             segments.push_back({ buffer.length(), segment.length() });
13369             buffer.append(segment);
13370             starts.push_back(b);
13371             ends.push_back(e);
13372         }
13373 
13374         TOML_PURE_INLINE_GETTER
13375         std::string_view operator[](size_t i) const noexcept
13376         {
13377             return std::string_view{ buffer.c_str() + segments[i].first, segments[i].second };
13378         }
13379 
13380         TOML_PURE_INLINE_GETTER
13381         std::string_view back() const noexcept
13382         {
13383             return (*this)[segments.size() - 1u];
13384         }
13385 
13386         TOML_PURE_INLINE_GETTER
13387         bool empty() const noexcept
13388         {
13389             return segments.empty();
13390         }
13391 
13392         TOML_PURE_INLINE_GETTER
13393         size_t size() const noexcept
13394         {
13395             return segments.size();
13396         }
13397     };
13398 
13399     struct depth_counter_scope
13400     {
13401         size_t& depth_;
13402 
13403         TOML_NODISCARD_CTOR
13404         explicit depth_counter_scope(size_t& depth) noexcept //
13405             : depth_{ depth }
13406         {
13407             depth_++;
13408         }
13409 
13410         ~depth_counter_scope() noexcept
13411         {
13412             depth_--;
13413         }
13414 
13415         TOML_DELETE_DEFAULTS(depth_counter_scope);
13416     };
13417 
13418     struct parsed_string
13419     {
13420         std::string_view value;
13421         bool was_multi_line;
13422     };
13423 
13424     struct table_vector_scope
13425     {
13426         std::vector<table*>& tables;
13427 
13428         TOML_NODISCARD_CTOR
13429         explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
13430             : tables{ tables_ }
13431         {
13432             tables.push_back(&tbl);
13433         }
13434 
13435         ~table_vector_scope() noexcept
13436         {
13437             tables.pop_back();
13438         }
13439 
13440         TOML_DELETE_DEFAULTS(table_vector_scope);
13441     };
13442 }
13443 TOML_ANON_NAMESPACE_END;
13444 
13445 #if 1 // parser helper macros
13446 
13447 // Q: "what the fuck is this? MACROS????"
13448 // A: The parser needs to work in exceptionless mode (returning error objects directly)
13449 //    and exception mode (reporting parse failures by throwing). Two totally different control flows.
13450 //    These macros encapsulate the differences between the two modes so I can write code code
13451 //    as though I was only targeting one mode and not want yeet myself into the sun.
13452 //    They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
13453 //    of toml++.
13454 
13455 #define is_eof()         !cp
13456 #define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
13457 #define return_if_eof(...)                                                                                             \
13458     do                                                                                                                 \
13459     {                                                                                                                  \
13460         if TOML_UNLIKELY(is_eof())                                                                                     \
13461             return __VA_ARGS__;                                                                                        \
13462     }                                                                                                                  \
13463     while (false)
13464 
13465 #if TOML_EXCEPTIONS
13466 #define is_error()                  false
13467 #define return_after_error(...)     TOML_UNREACHABLE
13468 #define assert_not_error()          static_assert(true)
13469 #define return_if_error(...)        static_assert(true)
13470 #define return_if_error_or_eof(...) return_if_eof(__VA_ARGS__)
13471 #else
13472 #define is_error()              !!err
13473 #define return_after_error(...) return __VA_ARGS__
13474 #define assert_not_error()      TOML_ASSERT(!is_error())
13475 #define return_if_error(...)                                                                                           \
13476     do                                                                                                                 \
13477     {                                                                                                                  \
13478         if TOML_UNLIKELY(is_error())                                                                                   \
13479             return __VA_ARGS__;                                                                                        \
13480     }                                                                                                                  \
13481     while (false)
13482 #define return_if_error_or_eof(...)                                                                                    \
13483     do                                                                                                                 \
13484     {                                                                                                                  \
13485         if TOML_UNLIKELY(is_eof() || is_error())                                                                       \
13486             return __VA_ARGS__;                                                                                        \
13487     }                                                                                                                  \
13488     while (false)
13489 #endif
13490 
13491 #if defined(TOML_BREAK_AT_PARSE_ERRORS) && TOML_BREAK_AT_PARSE_ERRORS
13492 #if defined(__has_builtin)
13493 #if __has_builtin(__builtin_debugtrap)
13494 #define parse_error_break() __builtin_debugtrap()
13495 #elif __has_builtin(__debugbreak)
13496 #define parse_error_break() __debugbreak()
13497 #endif
13498 #endif
13499 #ifndef parse_error_break
13500 #if TOML_MSVC || TOML_ICC
13501 #define parse_error_break() __debugbreak()
13502 #else
13503 #define parse_error_break() TOML_ASSERT(false)
13504 #endif
13505 #endif
13506 #else
13507 #define parse_error_break() static_assert(true)
13508 #endif
13509 
13510 #define set_error_and_return(ret, ...)                                                                                 \
13511     do                                                                                                                 \
13512     {                                                                                                                  \
13513         if (!is_error())                                                                                               \
13514             set_error(__VA_ARGS__);                                                                                    \
13515         return_after_error(ret);                                                                                       \
13516     }                                                                                                                  \
13517     while (false)
13518 
13519 #define set_error_and_return_default(...) set_error_and_return({}, __VA_ARGS__)
13520 
13521 #define set_error_and_return_if_eof(...)                                                                               \
13522     do                                                                                                                 \
13523     {                                                                                                                  \
13524         if TOML_UNLIKELY(is_eof())                                                                                     \
13525             set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv);                                            \
13526     }                                                                                                                  \
13527     while (false)
13528 
13529 #define advance_and_return_if_error(...)                                                                               \
13530     do                                                                                                                 \
13531     {                                                                                                                  \
13532         assert_not_eof();                                                                                              \
13533         advance();                                                                                                     \
13534         return_if_error(__VA_ARGS__);                                                                                  \
13535     }                                                                                                                  \
13536     while (false)
13537 
13538 #define advance_and_return_if_error_or_eof(...)                                                                        \
13539     do                                                                                                                 \
13540     {                                                                                                                  \
13541         assert_not_eof();                                                                                              \
13542         advance();                                                                                                     \
13543         return_if_error(__VA_ARGS__);                                                                                  \
13544         set_error_and_return_if_eof(__VA_ARGS__);                                                                      \
13545     }                                                                                                                  \
13546     while (false)
13547 
13548 #endif // parser helper macros
13549 
13550 TOML_IMPL_NAMESPACE_START
13551 {
13552     TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
13553 
13554     class parser
13555     {
13556       private:
13557         static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES;
13558 
13559         utf8_buffered_reader reader;
13560         table root;
13561         source_position prev_pos = { 1, 1 };
13562         const utf8_codepoint* cp = {};
13563         std::vector<table*> implicit_tables;
13564         std::vector<table*> dotted_key_tables;
13565         std::vector<table*> open_inline_tables;
13566         std::vector<array*> table_arrays;
13567         parse_key_buffer key_buffer;
13568         std::string string_buffer;
13569         std::string recording_buffer; // for diagnostics
13570         bool recording = false, recording_whitespace = true;
13571         std::string_view current_scope;
13572         size_t nested_values = {};
13573 #if !TOML_EXCEPTIONS
13574         mutable optional<parse_error> err;
13575 #endif
13576 
13577         TOML_NODISCARD
13578         source_position current_position(source_index fallback_offset = 0) const noexcept
13579         {
13580             if (!is_eof())
13581                 return cp->position;
13582             return { prev_pos.line, static_cast<source_index>(prev_pos.column + fallback_offset) };
13583         }
13584 
13585         template <typename... T>
13586         TOML_RETURNS_BY_THROWING
13587         TOML_NEVER_INLINE
13588         void set_error_at(source_position pos, const T&... reason) const
13589         {
13590             static_assert(sizeof...(T) > 0);
13591             return_if_error();
13592 
13593             error_builder builder{ current_scope };
13594             (builder.append(reason), ...);
13595 
13596             parse_error_break();
13597 
13598 #if TOML_EXCEPTIONS
13599             builder.finish(pos, reader.source_path());
13600 #else
13601             err.emplace(builder.finish(pos, reader.source_path()));
13602 #endif
13603         }
13604 
13605         template <typename... T>
13606         TOML_RETURNS_BY_THROWING
13607         void set_error(const T&... reason) const
13608         {
13609             set_error_at(current_position(1), reason...);
13610         }
13611 
13612         void go_back(size_t count = 1) noexcept
13613         {
13614             return_if_error();
13615             TOML_ASSERT_ASSUME(count);
13616 
13617             cp       = reader.step_back(count);
13618             prev_pos = cp->position;
13619         }
13620 
13621         void advance()
13622         {
13623             return_if_error();
13624             assert_not_eof();
13625 
13626             prev_pos = cp->position;
13627             cp       = reader.read_next();
13628 
13629 #if !TOML_EXCEPTIONS
13630             if (reader.error())
13631             {
13632                 err = std::move(reader.error());
13633                 return;
13634             }
13635 #endif
13636 
13637             if (recording && !is_eof())
13638             {
13639                 if (recording_whitespace || !is_whitespace(*cp))
13640                     recording_buffer.append(cp->bytes, cp->count);
13641             }
13642         }
13643 
13644         void start_recording(bool include_current = true) noexcept
13645         {
13646             return_if_error();
13647 
13648             recording            = true;
13649             recording_whitespace = true;
13650             recording_buffer.clear();
13651             if (include_current && !is_eof())
13652                 recording_buffer.append(cp->bytes, cp->count);
13653         }
13654 
13655         void stop_recording(size_t pop_bytes = 0) noexcept
13656         {
13657             return_if_error();
13658 
13659             recording = false;
13660             if (pop_bytes)
13661             {
13662                 if (pop_bytes >= recording_buffer.length())
13663                     recording_buffer.clear();
13664                 else if (pop_bytes == 1u)
13665                     recording_buffer.pop_back();
13666                 else
13667                     recording_buffer.erase(recording_buffer.begin()
13668                                                + static_cast<ptrdiff_t>(recording_buffer.length() - pop_bytes),
13669                                            recording_buffer.end());
13670             }
13671         }
13672 
13673         bool consume_leading_whitespace()
13674         {
13675             return_if_error_or_eof({});
13676 
13677             bool consumed = false;
13678             while (!is_eof() && is_horizontal_whitespace(*cp))
13679             {
13680                 if TOML_UNLIKELY(!is_ascii_horizontal_whitespace(*cp))
13681                     set_error_and_return_default("expected space or tab, saw '"sv, escaped_codepoint{ *cp }, "'"sv);
13682 
13683                 consumed = true;
13684                 advance_and_return_if_error({});
13685             }
13686             return consumed;
13687         }
13688 
13689         bool consume_line_break()
13690         {
13691             return_if_error_or_eof({});
13692 
13693             if TOML_UNLIKELY(is_match(*cp, U'\v', U'\f'))
13694                 set_error_and_return_default(
13695                     R"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);
13696 
13697             if (*cp == U'\r')
13698             {
13699                 advance_and_return_if_error({}); // skip \r
13700 
13701                 if TOML_UNLIKELY(is_eof())
13702                     set_error_and_return_default("expected '\\n' after '\\r', saw EOF"sv);
13703 
13704                 if TOML_UNLIKELY(*cp != U'\n')
13705                     set_error_and_return_default("expected '\\n' after '\\r', saw '"sv,
13706                                                  escaped_codepoint{ *cp },
13707                                                  "'"sv);
13708             }
13709             else if (*cp != U'\n')
13710                 return false;
13711 
13712             advance_and_return_if_error({}); // skip \n
13713             return true;
13714         }
13715 
13716         bool consume_rest_of_line()
13717         {
13718             return_if_error_or_eof({});
13719 
13720             do
13721             {
13722                 if (is_ascii_vertical_whitespace(*cp))
13723                     return consume_line_break();
13724                 else
13725                     advance();
13726                 return_if_error({});
13727             }
13728             while (!is_eof());
13729 
13730             return true;
13731         }
13732 
13733         bool consume_comment()
13734         {
13735             return_if_error_or_eof({});
13736 
13737             if (*cp != U'#')
13738                 return false;
13739 
13740             push_parse_scope("comment"sv);
13741 
13742             advance_and_return_if_error({}); // skip the '#'
13743 
13744             while (!is_eof())
13745             {
13746                 if (consume_line_break())
13747                     return true;
13748                 return_if_error({});
13749 
13750 #if TOML_LANG_AT_LEAST(1, 0, 0)
13751 
13752                 // toml/issues/567 (disallow non-TAB control characters in comments)
13753                 if TOML_UNLIKELY(is_nontab_control_character(*cp))
13754                     set_error_and_return_default(
13755                         "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv);
13756 
13757                 // toml/pull/720 (disallow surrogates in comments)
13758                 else if TOML_UNLIKELY(is_unicode_surrogate(*cp))
13759                     set_error_and_return_default(
13760                         "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
13761 #endif
13762 
13763                 advance_and_return_if_error({});
13764             }
13765 
13766             return true;
13767         }
13768 
13769         TOML_NODISCARD
13770         bool consume_expected_sequence(std::u32string_view seq)
13771         {
13772             return_if_error({});
13773             TOML_ASSERT(!seq.empty());
13774 
13775             for (auto c : seq)
13776             {
13777                 set_error_and_return_if_eof({});
13778                 if (*cp != c)
13779                     return false;
13780                 advance_and_return_if_error({});
13781             }
13782             return true;
13783         }
13784 
13785         template <typename T>
13786         TOML_NODISCARD
13787         bool consume_digit_sequence(T* digits, size_t len)
13788         {
13789             return_if_error({});
13790             TOML_ASSERT_ASSUME(digits);
13791             TOML_ASSERT_ASSUME(len);
13792 
13793             for (size_t i = 0; i < len; i++)
13794             {
13795                 set_error_and_return_if_eof({});
13796                 if (!is_decimal_digit(*cp))
13797                     return false;
13798 
13799                 digits[i] = static_cast<T>(*cp - U'0');
13800                 advance_and_return_if_error({});
13801             }
13802             return true;
13803         }
13804 
13805         template <typename T>
13806         TOML_NODISCARD
13807         size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len)
13808         {
13809             return_if_error({});
13810             TOML_ASSERT_ASSUME(buffer);
13811             TOML_ASSERT_ASSUME(max_len);
13812 
13813             size_t i = {};
13814             for (; i < max_len; i++)
13815             {
13816                 if (is_eof() || !is_decimal_digit(*cp))
13817                     break;
13818 
13819                 buffer[i] = static_cast<T>(*cp - U'0');
13820                 advance_and_return_if_error({});
13821             }
13822             return i;
13823         }
13824 
13825         TOML_NODISCARD
13826         TOML_NEVER_INLINE
13827         std::string_view parse_basic_string(bool multi_line)
13828         {
13829             return_if_error({});
13830             assert_not_eof();
13831             TOML_ASSERT_ASSUME(*cp == U'"');
13832             push_parse_scope("string"sv);
13833 
13834             // skip the '"'
13835             advance_and_return_if_error_or_eof({});
13836 
13837             // multi-line strings ignore a single line ending right at the beginning
13838             if (multi_line)
13839             {
13840                 consume_line_break();
13841                 return_if_error({});
13842                 set_error_and_return_if_eof({});
13843             }
13844 
13845             auto& str = string_buffer;
13846             str.clear();
13847             bool escaped             = false;
13848             bool skipping_whitespace = false;
13849             do
13850             {
13851                 if (escaped)
13852                 {
13853                     escaped = false;
13854 
13855                     // handle 'line ending slashes' in multi-line mode
13856                     if (multi_line && is_whitespace(*cp))
13857                     {
13858                         consume_leading_whitespace();
13859 
13860                         if TOML_UNLIKELY(!consume_line_break())
13861                             set_error_and_return_default(
13862                                 "line-ending backslashes must be the last non-whitespace character on the line"sv);
13863 
13864                         skipping_whitespace = true;
13865                         return_if_error({});
13866                         continue;
13867                     }
13868 
13869                     bool skip_escaped_codepoint = true;
13870                     assert_not_eof();
13871                     switch (const auto escaped_codepoint = *cp)
13872                     {
13873                         // 'regular' escape codes
13874                         case U'b': str += '\b'; break;
13875                         case U'f': str += '\f'; break;
13876                         case U'n': str += '\n'; break;
13877                         case U'r': str += '\r'; break;
13878                         case U't': str += '\t'; break;
13879                         case U'"': str += '"'; break;
13880                         case U'\\': str += '\\'; break;
13881 
13882 #if TOML_LANG_UNRELEASED // toml/pull/790 (\e shorthand for \x1B)
13883                         case U'e': str += '\x1B'; break;
13884 #else
13885                         case U'e':
13886                             set_error_and_return_default(
13887                                 "escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
13888 #endif
13889 
13890 #if TOML_LANG_UNRELEASED // toml/pull/796 (\xHH unicode scalar sequences)
13891                         case U'x': [[fallthrough]];
13892 #else
13893                         case U'x':
13894                             set_error_and_return_default(
13895                                 "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
13896 #endif
13897 
13898                         // unicode scalar sequences
13899                         case U'u': [[fallthrough]];
13900                         case U'U':
13901                         {
13902                             push_parse_scope("unicode scalar sequence"sv);
13903                             advance_and_return_if_error_or_eof({});
13904                             skip_escaped_codepoint = false;
13905 
13906                             uint32_t place_value =
13907                                 escaped_codepoint == U'U' ? 0x10000000u : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
13908                             uint32_t sequence_value{};
13909                             while (place_value)
13910                             {
13911                                 set_error_and_return_if_eof({});
13912 
13913                                 if TOML_UNLIKELY(!is_hexadecimal_digit(*cp))
13914                                     set_error_and_return_default("expected hex digit, saw '"sv, to_sv(*cp), "'"sv);
13915 
13916                                 sequence_value += place_value * hex_to_dec(*cp);
13917                                 place_value /= 16u;
13918                                 advance_and_return_if_error({});
13919                             }
13920 
13921                             if TOML_UNLIKELY(is_unicode_surrogate(sequence_value))
13922                                 set_error_and_return_default(
13923                                     "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
13924                             else if TOML_UNLIKELY(sequence_value > 0x10FFFFu)
13925                                 set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
13926 
13927                             if (sequence_value < 0x80)
13928                             {
13929                                 str += static_cast<char>(sequence_value);
13930                             }
13931                             else if (sequence_value < 0x800u)
13932                             {
13933                                 str += static_cast<char>((sequence_value >> 6) | 0xC0u);
13934                                 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
13935                             }
13936                             else if (sequence_value < 0x10000u)
13937                             {
13938                                 str += static_cast<char>((sequence_value >> 12) | 0xE0u);
13939                                 str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
13940                                 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
13941                             }
13942                             else if (sequence_value < 0x110000u)
13943                             {
13944                                 str += static_cast<char>((sequence_value >> 18) | 0xF0u);
13945                                 str += static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
13946                                 str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
13947                                 str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
13948                             }
13949                             break;
13950                         }
13951 
13952                             // ???
13953                             TOML_UNLIKELY_CASE
13954                         default: set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
13955                     }
13956 
13957                     if (skip_escaped_codepoint)
13958                         advance_and_return_if_error_or_eof({});
13959                 }
13960                 else
13961                 {
13962                     // handle closing delimiters
13963                     if (*cp == U'"')
13964                     {
13965                         if (multi_line)
13966                         {
13967                             size_t lookaheads             = {};
13968                             size_t consecutive_delimiters = 1;
13969                             do
13970                             {
13971                                 advance_and_return_if_error({});
13972                                 lookaheads++;
13973                                 if (!is_eof() && *cp == U'"')
13974                                     consecutive_delimiters++;
13975                                 else
13976                                     break;
13977                             }
13978                             while (lookaheads < 4u);
13979 
13980                             switch (consecutive_delimiters)
13981                             {
13982                                 // """ " (one quote somewhere in a ML string)
13983                                 case 1:
13984                                     str += '"';
13985                                     skipping_whitespace = false;
13986                                     continue;
13987 
13988                                 // """ "" (two quotes somewhere in a ML string)
13989                                 case 2:
13990                                     str.append("\"\""sv);
13991                                     skipping_whitespace = false;
13992                                     continue;
13993 
13994                                 // """ """ (the end of the string)
13995                                 case 3: return str;
13996 
13997                                 // """ """" (one at the end of the string)
13998                                 case 4: str += '"'; return str;
13999 
14000                                 // """ """"" (two quotes at the end of the string)
14001                                 case 5:
14002                                     str.append("\"\""sv);
14003                                     advance_and_return_if_error({}); // skip the last '"'
14004                                     return str;
14005 
14006                                 default: TOML_UNREACHABLE;
14007                             }
14008                         }
14009                         else
14010                         {
14011                             advance_and_return_if_error({}); // skip the closing delimiter
14012                             return str;
14013                         }
14014                     }
14015 
14016                     // handle escapes
14017                     else if (*cp == U'\\')
14018                     {
14019                         advance_and_return_if_error_or_eof({}); // skip the '\'
14020                         skipping_whitespace = false;
14021                         escaped             = true;
14022                         continue;
14023                     }
14024 
14025                     // handle line endings in multi-line mode
14026                     if (multi_line && is_ascii_vertical_whitespace(*cp))
14027                     {
14028                         consume_line_break();
14029                         return_if_error({});
14030                         if (!skipping_whitespace)
14031                             str += '\n';
14032                         continue;
14033                     }
14034 
14035                     // handle control characters
14036                     if TOML_UNLIKELY(is_nontab_control_character(*cp))
14037                         set_error_and_return_default(
14038                             "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv);
14039 
14040 #if TOML_LANG_AT_LEAST(1, 0, 0)
14041 
14042                     // handle surrogates in strings
14043                     if TOML_UNLIKELY(is_unicode_surrogate(*cp))
14044                         set_error_and_return_default(
14045                             "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
14046 #endif
14047 
14048                     if (multi_line)
14049                     {
14050                         if (!skipping_whitespace || !is_horizontal_whitespace(*cp))
14051                         {
14052                             skipping_whitespace = false;
14053                             str.append(cp->bytes, cp->count);
14054                         }
14055                     }
14056                     else
14057                         str.append(cp->bytes, cp->count);
14058 
14059                     advance_and_return_if_error({});
14060                 }
14061             }
14062             while (!is_eof());
14063 
14064             set_error_and_return_default("encountered end-of-file"sv);
14065         }
14066 
14067         TOML_NODISCARD
14068         TOML_NEVER_INLINE
14069         std::string_view parse_literal_string(bool multi_line)
14070         {
14071             return_if_error({});
14072             assert_not_eof();
14073             TOML_ASSERT_ASSUME(*cp == U'\'');
14074             push_parse_scope("literal string"sv);
14075 
14076             // skip the delimiter
14077             advance_and_return_if_error_or_eof({});
14078 
14079             // multi-line strings ignore a single line ending right at the beginning
14080             if (multi_line)
14081             {
14082                 consume_line_break();
14083                 return_if_error({});
14084                 set_error_and_return_if_eof({});
14085             }
14086 
14087             auto& str = string_buffer;
14088             str.clear();
14089             do
14090             {
14091                 return_if_error({});
14092 
14093                 // handle closing delimiters
14094                 if (*cp == U'\'')
14095                 {
14096                     if (multi_line)
14097                     {
14098                         size_t lookaheads             = {};
14099                         size_t consecutive_delimiters = 1;
14100                         do
14101                         {
14102                             advance_and_return_if_error({});
14103                             lookaheads++;
14104                             if (!is_eof() && *cp == U'\'')
14105                                 consecutive_delimiters++;
14106                             else
14107                                 break;
14108                         }
14109                         while (lookaheads < 4u);
14110 
14111                         switch (consecutive_delimiters)
14112                         {
14113                             // ''' ' (one quote somewhere in a ML string)
14114                             case 1: str += '\''; continue;
14115 
14116                             // ''' '' (two quotes somewhere in a ML string)
14117                             case 2: str.append("''"sv); continue;
14118 
14119                             // ''' ''' (the end of the string)
14120                             case 3: return str;
14121 
14122                             // ''' '''' (one at the end of the string)
14123                             case 4: str += '\''; return str;
14124 
14125                             // ''' ''''' (two quotes at the end of the string)
14126                             case 5:
14127                                 str.append("''"sv);
14128                                 advance_and_return_if_error({}); // skip the last '
14129                                 return str;
14130 
14131                             default: TOML_UNREACHABLE;
14132                         }
14133                     }
14134                     else
14135                     {
14136                         advance_and_return_if_error({}); // skip the closing delimiter
14137                         return str;
14138                     }
14139                 }
14140 
14141                 // handle line endings in multi-line mode
14142                 if (multi_line && is_ascii_vertical_whitespace(*cp))
14143                 {
14144                     consume_line_break();
14145                     return_if_error({});
14146                     str += '\n';
14147                     continue;
14148                 }
14149 
14150                 // handle control characters
14151                 if TOML_UNLIKELY(is_nontab_control_character(*cp))
14152                     set_error_and_return_default(
14153                         "control characters other than TAB (U+0009) are explicitly prohibited"sv);
14154 
14155 #if TOML_LANG_AT_LEAST(1, 0, 0)
14156 
14157                 // handle surrogates in strings
14158                 if TOML_UNLIKELY(is_unicode_surrogate(*cp))
14159                     set_error_and_return_default("unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
14160 #endif
14161 
14162                 str.append(cp->bytes, cp->count);
14163                 advance_and_return_if_error({});
14164             }
14165             while (!is_eof());
14166 
14167             set_error_and_return_default("encountered end-of-file"sv);
14168         }
14169 
14170         TOML_NODISCARD
14171         TOML_NEVER_INLINE
14172         parsed_string parse_string()
14173         {
14174             return_if_error({});
14175             assert_not_eof();
14176             TOML_ASSERT_ASSUME(is_string_delimiter(*cp));
14177             push_parse_scope("string"sv);
14178 
14179             // get the first three characters to determine the string type
14180             const auto first = cp->value;
14181             advance_and_return_if_error_or_eof({});
14182             const auto second = cp->value;
14183             advance_and_return_if_error({});
14184             const auto third = cp ? cp->value : U'\0';
14185 
14186             // if we were eof at the third character then first and second need to be
14187             // the same string character (otherwise it's an unterminated string)
14188             if (is_eof())
14189             {
14190                 if (second == first)
14191                     return {};
14192 
14193                 set_error_and_return_default("encountered end-of-file"sv);
14194             }
14195 
14196             // if the first three characters are all the same string delimiter then
14197             // it's a multi-line string.
14198             else if (first == second && first == third)
14199             {
14200                 return { first == U'\'' ? parse_literal_string(true) : parse_basic_string(true), true };
14201             }
14202 
14203             // otherwise it's just a regular string.
14204             else
14205             {
14206                 // step back two characters so that the current
14207                 // character is the string delimiter
14208                 go_back(2u);
14209 
14210                 return { first == U'\'' ? parse_literal_string(false) : parse_basic_string(false), false };
14211             }
14212         }
14213 
14214         TOML_NODISCARD
14215         TOML_NEVER_INLINE
14216         std::string_view parse_bare_key_segment()
14217         {
14218             return_if_error({});
14219             assert_not_eof();
14220             TOML_ASSERT_ASSUME(is_bare_key_character(*cp));
14221 
14222             string_buffer.clear();
14223 
14224             while (!is_eof())
14225             {
14226                 if (!is_bare_key_character(*cp))
14227                     break;
14228 
14229                 string_buffer.append(cp->bytes, cp->count);
14230                 advance_and_return_if_error({});
14231             }
14232 
14233             return string_buffer;
14234         }
14235 
14236         TOML_NODISCARD
14237         TOML_NEVER_INLINE
14238         bool parse_boolean()
14239         {
14240             return_if_error({});
14241             assert_not_eof();
14242             TOML_ASSERT_ASSUME(is_match(*cp, U't', U'f', U'T', U'F'));
14243             push_parse_scope("boolean"sv);
14244 
14245             start_recording(true);
14246             auto result = is_match(*cp, U't', U'T');
14247             if (!consume_expected_sequence(result ? U"true"sv : U"false"sv))
14248                 set_error_and_return_default("expected '"sv,
14249                                              to_sv(result),
14250                                              "', saw '"sv,
14251                                              to_sv(recording_buffer),
14252                                              "'"sv);
14253             stop_recording();
14254 
14255             if (cp && !is_value_terminator(*cp))
14256                 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14257 
14258             return result;
14259         }
14260 
14261         TOML_NODISCARD
14262         TOML_NEVER_INLINE
14263         double parse_inf_or_nan()
14264         {
14265             return_if_error({});
14266             assert_not_eof();
14267             TOML_ASSERT_ASSUME(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
14268             push_parse_scope("floating-point"sv);
14269 
14270             start_recording(true);
14271             const bool negative = *cp == U'-';
14272             if (negative || *cp == U'+')
14273                 advance_and_return_if_error_or_eof({});
14274 
14275             const bool inf = is_match(*cp, U'i', U'I');
14276             if (!consume_expected_sequence(inf ? U"inf"sv : U"nan"sv))
14277                 set_error_and_return_default("expected '"sv,
14278                                              inf ? "inf"sv : "nan"sv,
14279                                              "', saw '"sv,
14280                                              to_sv(recording_buffer),
14281                                              "'"sv);
14282             stop_recording();
14283 
14284             if (cp && !is_value_terminator(*cp))
14285                 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14286 
14287             return inf ? (negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity())
14288                        : std::numeric_limits<double>::quiet_NaN();
14289         }
14290 
14291         TOML_NODISCARD
14292         TOML_NEVER_INLINE
14293         double parse_float()
14294         {
14295             return_if_error({});
14296             assert_not_eof();
14297             TOML_ASSERT_ASSUME(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
14298             push_parse_scope("floating-point"sv);
14299 
14300             // sign
14301             const int sign = *cp == U'-' ? -1 : 1;
14302             if (is_match(*cp, U'+', U'-'))
14303                 advance_and_return_if_error_or_eof({});
14304 
14305             // consume value chars
14306             char chars[utf8_buffered_reader::max_history_length];
14307             size_t length              = {};
14308             const utf8_codepoint* prev = {};
14309             bool seen_decimal = false, seen_exponent = false;
14310             char first_integer_part = '\0';
14311             while (!is_eof() && !is_value_terminator(*cp))
14312             {
14313                 if (*cp == U'_')
14314                 {
14315                     if (!prev || !is_decimal_digit(*prev))
14316                         set_error_and_return_default("underscores may only follow digits"sv);
14317 
14318                     prev = cp;
14319                     advance_and_return_if_error_or_eof({});
14320                     continue;
14321                 }
14322                 else if TOML_UNLIKELY(prev && *prev == U'_' && !is_decimal_digit(*cp))
14323                     set_error_and_return_default("underscores must be followed by digits"sv);
14324                 else if TOML_UNLIKELY(length == sizeof(chars))
14325                     set_error_and_return_default("exceeds length limit of "sv,
14326                                                  sizeof(chars),
14327                                                  " digits"sv,
14328                                                  (seen_exponent ? ""sv : " (consider using exponent notation)"sv));
14329                 else if (*cp == U'.')
14330                 {
14331                     // .1
14332                     // -.1
14333                     // +.1 (no integer part)
14334                     if (!first_integer_part)
14335                         set_error_and_return_default("expected decimal digit, saw '.'"sv);
14336 
14337                     // 1.0e+.10 (exponent cannot have '.')
14338                     else if (seen_exponent)
14339                         set_error_and_return_default("expected exponent decimal digit or sign, saw '.'"sv);
14340 
14341                     // 1.0.e+.10
14342                     // 1..0
14343                     // (multiple '.')
14344                     else if (seen_decimal)
14345                         set_error_and_return_default("expected decimal digit or exponent, saw '.'"sv);
14346 
14347                     seen_decimal = true;
14348                 }
14349                 else if (is_match(*cp, U'e', U'E'))
14350                 {
14351                     if (prev && !is_decimal_digit(*prev))
14352                         set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14353 
14354                     // 1.0ee+10 (multiple 'e')
14355                     else if (seen_exponent)
14356                         set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14357 
14358                     seen_decimal  = true; // implied
14359                     seen_exponent = true;
14360                 }
14361                 else if (is_match(*cp, U'+', U'-'))
14362                 {
14363                     // 1.-0 (sign in mantissa)
14364                     if (!seen_exponent)
14365                         set_error_and_return_default("expected decimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14366 
14367                     // 1.0e1-0 (misplaced exponent sign)
14368                     else if (!is_match(*prev, U'e', U'E'))
14369                         set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
14370                 }
14371                 else if (is_decimal_digit(*cp))
14372                 {
14373                     if (!seen_decimal)
14374                     {
14375                         if (!first_integer_part)
14376                             first_integer_part = static_cast<char>(cp->bytes[0]);
14377                         else if (first_integer_part == '0')
14378                             set_error_and_return_default("leading zeroes are prohibited"sv);
14379                     }
14380                 }
14381                 else
14382                     set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14383 
14384                 chars[length++] = static_cast<char>(cp->bytes[0]);
14385                 prev            = cp;
14386                 advance_and_return_if_error({});
14387             }
14388 
14389             // sanity-check ending state
14390             if (prev)
14391             {
14392                 if (*prev == U'_')
14393                 {
14394                     set_error_and_return_if_eof({});
14395                     set_error_and_return_default("underscores must be followed by digits"sv);
14396                 }
14397                 else if (is_match(*prev, U'e', U'E', U'+', U'-', U'.'))
14398                 {
14399                     set_error_and_return_if_eof({});
14400                     set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
14401                 }
14402             }
14403 
14404             // convert to double
14405             double result;
14406 #if TOML_FLOAT_CHARCONV
14407             {
14408                 auto fc_result = std::from_chars(chars, chars + length, result);
14409                 switch (fc_result.ec)
14410                 {
14411                     TOML_LIKELY_CASE
14412                     case std::errc{}: // ok
14413                         return result * sign;
14414 
14415                     case std::errc::invalid_argument:
14416                         set_error_and_return_default("'"sv,
14417                                                      std::string_view{ chars, length },
14418                                                      "' could not be interpreted as a value"sv);
14419                         break;
14420 
14421                     case std::errc::result_out_of_range:
14422                         set_error_and_return_default("'"sv,
14423                                                      std::string_view{ chars, length },
14424                                                      "' is not representable in 64 bits"sv);
14425                         break;
14426 
14427                     default: //??
14428                         set_error_and_return_default("an unspecified error occurred while trying to interpret '"sv,
14429                                                      std::string_view{ chars, length },
14430                                                      "' as a value"sv);
14431                 }
14432             }
14433 #else
14434             {
14435                 std::stringstream ss;
14436                 ss.imbue(std::locale::classic());
14437                 ss.write(chars, static_cast<std::streamsize>(length));
14438                 if ((ss >> result))
14439                     return result * sign;
14440                 else
14441                     set_error_and_return_default("'"sv,
14442                                                  std::string_view{ chars, length },
14443                                                  "' could not be interpreted as a value"sv);
14444             }
14445 #endif
14446         }
14447 
14448         TOML_NODISCARD
14449         TOML_NEVER_INLINE
14450         double parse_hex_float()
14451         {
14452             return_if_error({});
14453             assert_not_eof();
14454             TOML_ASSERT_ASSUME(is_match(*cp, U'0', U'+', U'-'));
14455             push_parse_scope("hexadecimal floating-point"sv);
14456 
14457 #if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
14458 
14459             // sign
14460             const int sign = *cp == U'-' ? -1 : 1;
14461             if (is_match(*cp, U'+', U'-'))
14462                 advance_and_return_if_error_or_eof({});
14463 
14464             // '0'
14465             if (*cp != U'0')
14466                 set_error_and_return_default(" expected '0', saw '"sv, to_sv(*cp), "'"sv);
14467             advance_and_return_if_error_or_eof({});
14468 
14469             // 'x' or 'X'
14470             if (!is_match(*cp, U'x', U'X'))
14471                 set_error_and_return_default("expected 'x' or 'X', saw '"sv, to_sv(*cp), "'"sv);
14472             advance_and_return_if_error_or_eof({});
14473 
14474             // <HEX DIGITS> ([.]<HEX DIGITS>)? [pP] [+-]? <DEC DIGITS>
14475 
14476             // consume value fragments
14477             struct fragment
14478             {
14479                 char chars[24];
14480                 size_t length;
14481                 double value;
14482             };
14483             fragment fragments[] = {
14484                 {}, // mantissa, whole part
14485                 {}, // mantissa, fractional part
14486                 {}  // exponent
14487             };
14488             fragment* current_fragment = fragments;
14489             const utf8_codepoint* prev = {};
14490             int exponent_sign          = 1;
14491             while (!is_eof() && !is_value_terminator(*cp))
14492             {
14493                 if (*cp == U'_')
14494                 {
14495                     if (!prev || !is_hexadecimal_digit(*prev))
14496                         set_error_and_return_default("underscores may only follow digits"sv);
14497 
14498                     prev = cp;
14499                     advance_and_return_if_error_or_eof({});
14500                     continue;
14501                 }
14502                 else if (prev && *prev == U'_' && !is_hexadecimal_digit(*cp))
14503                     set_error_and_return_default("underscores must be followed by digits"sv);
14504                 else if (*cp == U'.')
14505                 {
14506                     // 0x10.0p-.0 (exponent cannot have '.')
14507                     if (current_fragment == fragments + 2)
14508                         set_error_and_return_default("expected exponent digit or sign, saw '.'"sv);
14509 
14510                     // 0x10.0.p-0 (multiple '.')
14511                     else if (current_fragment == fragments + 1)
14512                         set_error_and_return_default("expected hexadecimal digit or exponent, saw '.'"sv);
14513 
14514                     else
14515                         current_fragment++;
14516                 }
14517                 else if (is_match(*cp, U'p', U'P'))
14518                 {
14519                     // 0x10.0pp-0 (multiple 'p')
14520                     if (current_fragment == fragments + 2)
14521                         set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
14522 
14523                     // 0x.p-0 (mantissa is just '.')
14524                     else if (fragments[0].length == 0u && fragments[1].length == 0u)
14525                         set_error_and_return_default("expected hexadecimal digit, saw '"sv, to_sv(*cp), "'"sv);
14526 
14527                     else
14528                         current_fragment = fragments + 2;
14529                 }
14530                 else if (is_match(*cp, U'+', U'-'))
14531                 {
14532                     // 0x-10.0p-0 (sign in mantissa)
14533                     if (current_fragment != fragments + 2)
14534                         set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14535 
14536                     // 0x10.0p0- (misplaced exponent sign)
14537                     else if (!is_match(*prev, U'p', U'P'))
14538                         set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
14539 
14540                     else
14541                         exponent_sign = *cp == U'-' ? -1 : 1;
14542                 }
14543                 else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*cp))
14544                     set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14545                 else if (current_fragment == fragments + 2 && !is_decimal_digit(*cp))
14546                     set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
14547                 else if (current_fragment->length == sizeof(fragment::chars))
14548                     set_error_and_return_default("fragment exceeeds maximum length of "sv,
14549                                                  sizeof(fragment::chars),
14550                                                  " characters"sv);
14551                 else
14552                     current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
14553 
14554                 prev = cp;
14555                 advance_and_return_if_error({});
14556             }
14557 
14558             // sanity-check ending state
14559             if (current_fragment != fragments + 2 || current_fragment->length == 0u)
14560             {
14561                 set_error_and_return_if_eof({});
14562                 set_error_and_return_default("missing exponent"sv);
14563             }
14564             else if (prev && *prev == U'_')
14565             {
14566                 set_error_and_return_if_eof({});
14567                 set_error_and_return_default("underscores must be followed by digits"sv);
14568             }
14569 
14570             // calculate values for the three fragments
14571             for (int fragment_idx = 0; fragment_idx < 3; fragment_idx++)
14572             {
14573                 auto& f             = fragments[fragment_idx];
14574                 const uint32_t base = fragment_idx == 2 ? 10u : 16u;
14575 
14576                 // left-trim zeroes
14577                 const char* c = f.chars;
14578                 size_t sig    = {};
14579                 while (f.length && *c == '0')
14580                 {
14581                     f.length--;
14582                     c++;
14583                     sig++;
14584                 }
14585                 if (!f.length)
14586                     continue;
14587 
14588                 // calculate value
14589                 auto place = 1u;
14590                 for (size_t i = 0; i < f.length - 1u; i++)
14591                     place *= base;
14592                 uint32_t val{};
14593                 while (place)
14594                 {
14595                     if (base == 16)
14596                         val += place * hex_to_dec(*c);
14597                     else
14598                         val += place * static_cast<uint32_t>(*c - '0');
14599                     if (fragment_idx == 1)
14600                         sig++;
14601                     c++;
14602                     place /= base;
14603                 }
14604                 f.value = static_cast<double>(val);
14605 
14606                 // shift the fractional part
14607                 if (fragment_idx == 1)
14608                 {
14609                     while (sig--)
14610                         f.value /= base;
14611                 }
14612             }
14613 
14614             return (fragments[0].value + fragments[1].value) * pow(2.0, fragments[2].value * exponent_sign) * sign;
14615 
14616 #else // !TOML_LANG_UNRELEASED
14617 
14618             set_error_and_return_default("hexadecimal floating-point values are not supported "
14619                                          "in TOML 1.0.0 and earlier"sv);
14620 
14621 #endif // !TOML_LANG_UNRELEASED
14622         }
14623 
14624         template <uint64_t base>
14625         TOML_NODISCARD
14626         TOML_NEVER_INLINE
14627         int64_t parse_integer()
14628         {
14629             return_if_error({});
14630             assert_not_eof();
14631             using traits = parse_integer_traits<base>;
14632             push_parse_scope(traits::scope_qualifier);
14633 
14634             [[maybe_unused]] int64_t sign = 1;
14635             if constexpr (traits::is_signed)
14636             {
14637                 sign = *cp == U'-' ? -1 : 1;
14638                 if (is_match(*cp, U'+', U'-'))
14639                     advance_and_return_if_error_or_eof({});
14640             }
14641 
14642             if constexpr (base == 10)
14643             {
14644                 if (!traits::is_digit(*cp))
14645                     set_error_and_return_default("expected expected digit or sign, saw '"sv, to_sv(*cp), "'"sv);
14646             }
14647             else
14648             {
14649                 // '0'
14650                 if (*cp != U'0')
14651                     set_error_and_return_default("expected '0', saw '"sv, to_sv(*cp), "'"sv);
14652                 advance_and_return_if_error_or_eof({});
14653 
14654                 // 'b', 'o', 'x'
14655                 if (*cp != traits::prefix_codepoint)
14656                     set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
14657                 advance_and_return_if_error_or_eof({});
14658 
14659                 if (!traits::is_digit(*cp))
14660                     set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
14661             }
14662 
14663             // consume digits
14664             char digits[utf8_buffered_reader::max_history_length];
14665             size_t length              = {};
14666             const utf8_codepoint* prev = {};
14667             while (!is_eof() && !is_value_terminator(*cp))
14668             {
14669                 if (*cp == U'_')
14670                 {
14671                     if (!prev || !traits::is_digit(*prev))
14672                         set_error_and_return_default("underscores may only follow digits"sv);
14673 
14674                     prev = cp;
14675                     advance_and_return_if_error_or_eof({});
14676                     continue;
14677                 }
14678                 else if TOML_UNLIKELY(prev && *prev == U'_' && !traits::is_digit(*cp))
14679                     set_error_and_return_default("underscores must be followed by digits"sv);
14680                 else if TOML_UNLIKELY(!traits::is_digit(*cp))
14681                     set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
14682                 else if TOML_UNLIKELY(length == sizeof(digits))
14683                     set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
14684                 else
14685                     digits[length++] = static_cast<char>(cp->bytes[0]);
14686 
14687                 prev = cp;
14688                 advance_and_return_if_error({});
14689             }
14690 
14691             // sanity check ending state
14692             if (prev && *prev == U'_')
14693             {
14694                 set_error_and_return_if_eof({});
14695                 set_error_and_return_default("underscores must be followed by digits"sv);
14696             }
14697 
14698             // single digits can be converted trivially
14699             if (length == 1u)
14700             {
14701                 int64_t result;
14702 
14703                 if constexpr (base == 16)
14704                     result = static_cast<int64_t>(hex_to_dec(digits[0]));
14705                 else
14706                     result = static_cast<int64_t>(digits[0] - '0');
14707 
14708                 if constexpr (traits::is_signed)
14709                     result *= sign;
14710 
14711                 return result;
14712             }
14713 
14714             // bin, oct and hex allow leading zeroes so trim them first
14715             const char* end = digits + length;
14716             const char* msd = digits;
14717             if constexpr (base != 10)
14718             {
14719                 while (msd < end && *msd == '0')
14720                     msd++;
14721                 if (msd == end)
14722                     return 0ll;
14723             }
14724 
14725             // decimal integers do not allow leading zeroes
14726             else
14727             {
14728                 if TOML_UNLIKELY(digits[0] == '0')
14729                     set_error_and_return_default("leading zeroes are prohibited"sv);
14730             }
14731 
14732             // range check
14733             if TOML_UNLIKELY(static_cast<size_t>(end - msd) > traits::max_digits)
14734                 set_error_and_return_default("'"sv,
14735                                              traits::full_prefix,
14736                                              std::string_view{ digits, length },
14737                                              "' is not representable as a signed 64-bit integer"sv);
14738 
14739             // do the thing
14740             {
14741                 uint64_t result = {};
14742                 {
14743                     uint64_t power = 1;
14744                     while (--end >= msd)
14745                     {
14746                         if constexpr (base == 16)
14747                             result += power * hex_to_dec(*end);
14748                         else
14749                             result += power * static_cast<uint64_t>(*end - '0');
14750 
14751                         power *= base;
14752                     }
14753                 }
14754 
14755                 // range check
14756                 static constexpr auto i64_max = static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
14757                 if TOML_UNLIKELY(result > i64_max + (sign < 0 ? 1u : 0u))
14758                     set_error_and_return_default("'"sv,
14759                                                  traits::full_prefix,
14760                                                  std::string_view{ digits, length },
14761                                                  "' is not representable as a signed 64-bit integer"sv);
14762 
14763                 if constexpr (traits::is_signed)
14764                 {
14765                     // avoid signed multiply UB when parsing INT64_MIN
14766                     if TOML_UNLIKELY(sign < 0 && result == i64_max + 1u)
14767                         return (std::numeric_limits<int64_t>::min)();
14768 
14769                     return static_cast<int64_t>(result) * sign;
14770                 }
14771                 else
14772                     return static_cast<int64_t>(result);
14773             }
14774         }
14775 
14776         TOML_NODISCARD
14777         TOML_NEVER_INLINE
14778         date parse_date(bool part_of_datetime = false)
14779         {
14780             return_if_error({});
14781             assert_not_eof();
14782             TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
14783             push_parse_scope("date"sv);
14784 
14785             // "YYYY"
14786             uint32_t digits[4];
14787             if (!consume_digit_sequence(digits, 4u))
14788                 set_error_and_return_default("expected 4-digit year, saw '"sv, to_sv(cp), "'"sv);
14789             const auto year         = digits[3] + digits[2] * 10u + digits[1] * 100u + digits[0] * 1000u;
14790             const auto is_leap_year = (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
14791             set_error_and_return_if_eof({});
14792 
14793             // '-'
14794             if (*cp != U'-')
14795                 set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
14796             advance_and_return_if_error_or_eof({});
14797 
14798             // "MM"
14799             if (!consume_digit_sequence(digits, 2u))
14800                 set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
14801             const auto month = digits[1] + digits[0] * 10u;
14802             if (month == 0u || month > 12u)
14803                 set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv, month);
14804             const auto max_days_in_month = month == 2u
14805                                              ? (is_leap_year ? 29u : 28u)
14806                                              : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
14807             set_error_and_return_if_eof({});
14808 
14809             // '-'
14810             if (*cp != U'-')
14811                 set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
14812             advance_and_return_if_error_or_eof({});
14813 
14814             // "DD"
14815             if (!consume_digit_sequence(digits, 2u))
14816                 set_error_and_return_default("expected 2-digit day, saw '"sv, to_sv(cp), "'"sv);
14817             const auto day = digits[1] + digits[0] * 10u;
14818             if (day == 0u || day > max_days_in_month)
14819                 set_error_and_return_default("expected day between 1 and "sv,
14820                                              max_days_in_month,
14821                                              " (inclusive), saw "sv,
14822                                              day);
14823 
14824             if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
14825                 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14826 
14827             return { year, month, day };
14828         }
14829 
14830         TOML_NODISCARD
14831         TOML_NEVER_INLINE
14832         time parse_time(bool part_of_datetime = false)
14833         {
14834             return_if_error({});
14835             assert_not_eof();
14836             TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
14837             push_parse_scope("time"sv);
14838 
14839             static constexpr size_t max_digits = 64; // far more than necessary but needed to allow fractional
14840                                                      // millisecond truncation per the spec
14841             uint32_t digits[max_digits];
14842 
14843             // "HH"
14844             if (!consume_digit_sequence(digits, 2u))
14845                 set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
14846             const auto hour = digits[1] + digits[0] * 10u;
14847             if (hour > 23u)
14848                 set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv, hour);
14849             set_error_and_return_if_eof({});
14850 
14851             // ':'
14852             if (*cp != U':')
14853                 set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
14854             advance_and_return_if_error_or_eof({});
14855 
14856             // "MM"
14857             if (!consume_digit_sequence(digits, 2u))
14858                 set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
14859             const auto minute = digits[1] + digits[0] * 10u;
14860             if (minute > 59u)
14861                 set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
14862             auto time = toml::time{ hour, minute };
14863 
14864             // ':'
14865             if constexpr (TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
14866             {
14867                 if (is_eof() || is_value_terminator(*cp) || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
14868                     return time;
14869             }
14870             else
14871                 set_error_and_return_if_eof({});
14872             if (*cp != U':')
14873                 set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
14874             advance_and_return_if_error_or_eof({});
14875 
14876             // "SS"
14877             if (!consume_digit_sequence(digits, 2u))
14878                 set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
14879             const auto second = digits[1] + digits[0] * 10u;
14880             if (second > 59u)
14881                 set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv, second);
14882             time.second = static_cast<decltype(time.second)>(second);
14883 
14884             // '.' (early-exiting is allowed; fractional is optional)
14885             if (is_eof() || is_value_terminator(*cp) || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
14886                 return time;
14887             if (*cp != U'.')
14888                 set_error_and_return_default("expected '.', saw '"sv, to_sv(*cp), "'"sv);
14889             advance_and_return_if_error_or_eof({});
14890 
14891             // "FFFFFFFFF"
14892             size_t digit_count = consume_variable_length_digit_sequence(digits, max_digits);
14893             if (!digit_count)
14894             {
14895                 set_error_and_return_if_eof({});
14896                 set_error_and_return_default("expected fractional digits, saw '"sv, to_sv(*cp), "'"sv);
14897             }
14898             else if (!is_eof())
14899             {
14900                 if (digit_count == max_digits && is_decimal_digit(*cp))
14901                     set_error_and_return_default("fractional component exceeds maximum precision of "sv, max_digits);
14902                 else if (!part_of_datetime && !is_value_terminator(*cp))
14903                     set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14904             }
14905             uint32_t value = 0u;
14906             uint32_t place = 1u;
14907             for (auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;)
14908             {
14909                 value += digits[i] * place;
14910                 place *= 10u;
14911             }
14912             for (auto i = digit_count; i < 9u; i++) // implicit zeros
14913                 value *= 10u;
14914             time.nanosecond = value;
14915             return time;
14916         }
14917 
14918         TOML_NODISCARD
14919         TOML_NEVER_INLINE
14920         date_time parse_date_time()
14921         {
14922             return_if_error({});
14923             assert_not_eof();
14924             TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
14925             push_parse_scope("date-time"sv);
14926 
14927             // "YYYY-MM-DD"
14928             auto date = parse_date(true);
14929             set_error_and_return_if_eof({});
14930 
14931             // ' ', 'T' or 't'
14932             if (!is_match(*cp, U' ', U'T', U't'))
14933                 set_error_and_return_default("expected space, 'T' or 't', saw '"sv, to_sv(*cp), "'"sv);
14934             advance_and_return_if_error_or_eof({});
14935 
14936             // "HH:MM:SS.FFFFFFFFF"
14937             auto time = parse_time(true);
14938             return_if_error({});
14939 
14940             // no offset
14941             if (is_eof() || is_value_terminator(*cp))
14942                 return { date, time };
14943 
14944             // zero offset ('Z' or 'z')
14945             time_offset offset{};
14946             if (is_match(*cp, U'Z', U'z'))
14947                 advance_and_return_if_error({});
14948 
14949             // explicit offset ("+/-HH:MM")
14950             else if (is_match(*cp, U'+', U'-'))
14951             {
14952                 push_parse_scope("date-time offset"sv);
14953 
14954                 // sign
14955                 int sign = *cp == U'-' ? -1 : 1;
14956                 advance_and_return_if_error_or_eof({});
14957 
14958                 // "HH"
14959                 int digits[2];
14960                 if (!consume_digit_sequence(digits, 2u))
14961                     set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
14962                 const auto hour = digits[1] + digits[0] * 10;
14963                 if (hour > 23)
14964                     set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv, hour);
14965                 set_error_and_return_if_eof({});
14966 
14967                 // ':'
14968                 if (*cp != U':')
14969                     set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
14970                 advance_and_return_if_error_or_eof({});
14971 
14972                 // "MM"
14973                 if (!consume_digit_sequence(digits, 2u))
14974                     set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
14975                 const auto minute = digits[1] + digits[0] * 10;
14976                 if (minute > 59)
14977                     set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
14978                 offset.minutes = static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
14979             }
14980 
14981             if (!is_eof() && !is_value_terminator(*cp))
14982                 set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
14983 
14984             return { date, time, offset };
14985         }
14986 
14987         TOML_NODISCARD
14988         node_ptr parse_array();
14989 
14990         TOML_NODISCARD
14991         node_ptr parse_inline_table();
14992 
14993         TOML_NODISCARD
14994         node_ptr parse_value_known_prefixes()
14995         {
14996             return_if_error({});
14997             assert_not_eof();
14998             TOML_ASSERT_ASSUME(!is_control_character(*cp));
14999             TOML_ASSERT_ASSUME(*cp != U'_');
15000 
15001             switch (cp->value)
15002             {
15003                 // arrays
15004                 case U'[': return parse_array();
15005 
15006                 // inline tables
15007                 case U'{': return parse_inline_table();
15008 
15009                 // floats beginning with '.'
15010                 case U'.': return node_ptr{ new value{ parse_float() } };
15011 
15012                 // strings
15013                 case U'"': [[fallthrough]];
15014                 case U'\'': return node_ptr{ new value{ parse_string().value } };
15015 
15016                 default:
15017                 {
15018                     const auto cp_upper = static_cast<uint_least32_t>(cp->value) & ~0x20u;
15019 
15020                     // bools
15021                     if (cp_upper == 70u || cp_upper == 84u) // F or T
15022                         return node_ptr{ new value{ parse_boolean() } };
15023 
15024                     // inf/nan
15025                     else if (cp_upper == 73u || cp_upper == 78u) // I or N
15026                         return node_ptr{ new value{ parse_inf_or_nan() } };
15027 
15028                     else
15029                         return nullptr;
15030                 }
15031             }
15032             TOML_UNREACHABLE;
15033         }
15034 
15035         TOML_NODISCARD
15036         node_ptr parse_value()
15037         {
15038             return_if_error({});
15039             assert_not_eof();
15040             TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
15041             push_parse_scope("value"sv);
15042 
15043             const depth_counter_scope depth_counter{ nested_values };
15044             if TOML_UNLIKELY(nested_values > max_nested_values)
15045                 set_error_and_return_default("exceeded maximum nested value depth of "sv,
15046                                              max_nested_values,
15047                                              " (TOML_MAX_NESTED_VALUES)"sv);
15048 
15049             // check if it begins with some control character
15050             // (note that this will also fail for whitespace but we're assuming we've
15051             // called consume_leading_whitespace() before calling parse_value())
15052             if TOML_UNLIKELY(is_control_character(*cp))
15053                 set_error_and_return_default("unexpected control character"sv);
15054 
15055             // underscores at the beginning
15056             else if (*cp == U'_')
15057                 set_error_and_return_default("values may not begin with underscores"sv);
15058 
15059             const auto begin_pos = cp->position;
15060             node_ptr val;
15061 
15062             do
15063             {
15064                 TOML_ASSERT_ASSUME(!is_control_character(*cp));
15065                 TOML_ASSERT_ASSUME(*cp != U'_');
15066 
15067                 // detect the value type and parse accordingly,
15068                 // starting with value types that can be detected
15069                 // unambiguously from just one character.
15070 
15071                 val = parse_value_known_prefixes();
15072                 return_if_error({});
15073                 if (val)
15074                     break;
15075 
15076                 // value types from here down require more than one character to unambiguously identify
15077                 // so scan ahead and collect a set of value 'traits'.
15078                 enum TOML_CLOSED_FLAGS_ENUM value_traits : int
15079                 {
15080                     has_nothing  = 0,
15081                     has_digits   = 1,
15082                     has_b        = 1 << 1, // as second char only (0b)
15083                     has_e        = 1 << 2, // only float exponents
15084                     has_o        = 1 << 3, // as second char only (0o)
15085                     has_p        = 1 << 4, // only hexfloat exponents
15086                     has_t        = 1 << 5,
15087                     has_x        = 1 << 6, // as second or third char only (0x, -0x, +0x)
15088                     has_z        = 1 << 7,
15089                     has_colon    = 1 << 8,
15090                     has_plus     = 1 << 9,
15091                     has_minus    = 1 << 10,
15092                     has_dot      = 1 << 11,
15093                     begins_sign  = 1 << 12,
15094                     begins_digit = 1 << 13,
15095                     begins_zero  = 1 << 14,
15096                     signs_msk  = has_plus | has_minus,
15097                     bdigit_msk = has_digits | begins_digit,
15098                     bzero_msk  = bdigit_msk | begins_zero,
15099                 };
15100                 value_traits traits  = has_nothing;
15101                 const auto has_any   = [&](auto t) noexcept { return (traits & t) != has_nothing; };
15102                 const auto has_none  = [&](auto t) noexcept { return (traits & t) == has_nothing; };
15103                 const auto add_trait = [&](auto t) noexcept { traits = static_cast<value_traits>(traits | t); };
15104 
15105                 // examine the first character to get the 'begins with' traits
15106                 // (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
15107                 if (is_decimal_digit(*cp))
15108                 {
15109                     add_trait(begins_digit);
15110                     if (*cp == U'0')
15111                         add_trait(begins_zero);
15112                 }
15113                 else if (is_match(*cp, U'+', U'-'))
15114                     add_trait(begins_sign);
15115                 else
15116                     break;
15117 
15118                 // scan the rest of the value to determine the remaining traits
15119                 char32_t chars[utf8_buffered_reader::max_history_length];
15120                 size_t char_count = {}, advance_count = {};
15121                 bool eof_while_scanning = false;
15122                 const auto scan         = [&]() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
15123                 {
15124                     if (is_eof())
15125                         return;
15126                     TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
15127 
15128                     do
15129                     {
15130                         if (const auto c = **cp; c != U'_')
15131                         {
15132                             chars[char_count++] = c;
15133 
15134                             if (is_decimal_digit(c))
15135                                 add_trait(has_digits);
15136                             else if (is_ascii_letter(c))
15137                             {
15138                                 TOML_ASSERT_ASSUME((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
15139                                 switch (static_cast<char32_t>(c | 32u))
15140                                 {
15141                                     case U'b':
15142                                         if (char_count == 2u && has_any(begins_zero))
15143                                             add_trait(has_b);
15144                                         break;
15145 
15146                                     case U'e':
15147                                         if (char_count > 1u
15148                                             && has_none(has_b | has_o | has_p | has_t | has_x | has_z | has_colon)
15149                                             && (has_none(has_plus | has_minus) || has_any(begins_sign)))
15150                                             add_trait(has_e);
15151                                         break;
15152 
15153                                     case U'o':
15154                                         if (char_count == 2u && has_any(begins_zero))
15155                                             add_trait(has_o);
15156                                         break;
15157 
15158                                     case U'p':
15159                                         if (has_any(has_x))
15160                                             add_trait(has_p);
15161                                         break;
15162 
15163                                     case U'x':
15164                                         if ((char_count == 2u && has_any(begins_zero))
15165                                             || (char_count == 3u && has_any(begins_sign) && chars[1] == U'0'))
15166                                             add_trait(has_x);
15167                                         break;
15168 
15169                                     case U't': add_trait(has_t); break;
15170                                     case U'z': add_trait(has_z); break;
15171                                 }
15172                             }
15173                             else if (c <= U':')
15174                             {
15175                                 TOML_ASSERT_ASSUME(c < U'0' || c > U'9');
15176                                 switch (c)
15177                                 {
15178                                     case U'+': add_trait(has_plus); break;
15179                                     case U'-': add_trait(has_minus); break;
15180                                     case U'.': add_trait(has_dot); break;
15181                                     case U':': add_trait(has_colon); break;
15182                                 }
15183                             }
15184                         }
15185 
15186                         advance_and_return_if_error();
15187                         advance_count++;
15188                         eof_while_scanning = is_eof();
15189                     }
15190                     while (advance_count < (utf8_buffered_reader::max_history_length - 1u) && !is_eof()
15191                            && !is_value_terminator(*cp));
15192                 };
15193                 scan();
15194                 return_if_error({});
15195 
15196                 // force further scanning if this could have been a date-time with a space instead of a T
15197                 if (char_count == 10u                                    //
15198                     && (traits | begins_zero) == (bzero_msk | has_minus) //
15199                     && chars[4] == U'-'                                  //
15200                     && chars[7] == U'-'                                  //
15201                     && !is_eof()                                         //
15202                     && *cp == U' ')
15203                 {
15204                     const auto pre_advance_count = advance_count;
15205                     const auto pre_scan_traits   = traits;
15206                     chars[char_count++]          = *cp;
15207                     add_trait(has_t);
15208 
15209                     const auto backpedal = [&]() noexcept
15210                     {
15211                         go_back(advance_count - pre_advance_count);
15212                         advance_count = pre_advance_count;
15213                         traits        = pre_scan_traits;
15214                         char_count    = 10u;
15215                     };
15216 
15217                     advance_and_return_if_error({});
15218                     advance_count++;
15219 
15220                     if (is_eof() || !is_decimal_digit(*cp))
15221                         backpedal();
15222                     else
15223                     {
15224                         chars[char_count++] = *cp;
15225 
15226                         advance_and_return_if_error({});
15227                         advance_count++;
15228 
15229                         scan();
15230                         return_if_error({});
15231 
15232                         if (char_count == 12u)
15233                             backpedal();
15234                     }
15235                 }
15236 
15237                 // set the reader back to where we started
15238                 go_back(advance_count);
15239 
15240                 // if after scanning ahead we still only have one value character,
15241                 // the only valid value type is an integer.
15242                 if (char_count == 1u)
15243                 {
15244                     if (has_any(begins_digit))
15245                     {
15246                         val.reset(new value{ static_cast<int64_t>(chars[0] - U'0') });
15247                         advance(); // skip the digit
15248                         break;
15249                     }
15250 
15251                     // anything else would be ambiguous.
15252                     else
15253                         set_error_and_return_default(eof_while_scanning ? "encountered end-of-file"sv
15254                                                                         : "could not determine value type"sv);
15255                 }
15256 
15257                 // now things that can be identified from two or more characters
15258                 return_if_error({});
15259                 TOML_ASSERT_ASSUME(char_count >= 2u);
15260 
15261                 // do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
15262                 // typed parse functions to take over and show better diagnostics if there's an issue
15263                 // (as opposed to the fallback "could not determine type" message)
15264                 if (has_any(has_p))
15265                     val.reset(new value{ parse_hex_float() });
15266                 else if (has_any(has_x | has_o | has_b))
15267                 {
15268                     int64_t i;
15269                     value_flags flags;
15270                     if (has_any(has_x))
15271                     {
15272                         i     = parse_integer<16>();
15273                         flags = value_flags::format_as_hexadecimal;
15274                     }
15275                     else if (has_any(has_o))
15276                     {
15277                         i     = parse_integer<8>();
15278                         flags = value_flags::format_as_octal;
15279                     }
15280                     else // has_b
15281                     {
15282                         i     = parse_integer<2>();
15283                         flags = value_flags::format_as_binary;
15284                     }
15285                     return_if_error({});
15286 
15287                     val.reset(new value{ i });
15288                     val->ref_cast<int64_t>().flags(flags);
15289                 }
15290                 else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
15291                     val.reset(new value{ parse_float() });
15292                 else if (has_any(begins_sign))
15293                 {
15294                     // single-digit signed integers
15295                     if (char_count == 2u && has_any(has_digits))
15296                     {
15297                         val.reset(new value{ static_cast<int64_t>(chars[1] - U'0') * (chars[0] == U'-' ? -1LL : 1LL) });
15298                         advance(); // skip the sign
15299                         advance(); // skip the digit
15300                         break;
15301                     }
15302 
15303                     // simple signed floats (e.g. +1.0)
15304                     if (is_decimal_digit(chars[1]) && chars[2] == U'.')
15305                         val.reset(new value{ parse_float() });
15306 
15307                     // signed infinity or nan
15308                     else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
15309                         val.reset(new value{ parse_inf_or_nan() });
15310                 }
15311 
15312                 return_if_error({});
15313                 if (val)
15314                     break;
15315 
15316                 // match trait masks against what they can match exclusively.
15317                 // all correct value parses will come out of this list, so doing this as a switch is likely to
15318                 // be a better friend to the optimizer on the success path (failure path can be slow but that
15319                 // doesn't matter much).
15320                 switch (unwrap_enum(traits))
15321                 {
15322                     // binary integers
15323                     // 0b10
15324                     case bzero_msk | has_b:
15325                         val.reset(new value{ parse_integer<2>() });
15326                         val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
15327                         break;
15328 
15329                     // octal integers
15330                     // 0o10
15331                     case bzero_msk | has_o:
15332                         val.reset(new value{ parse_integer<8>() });
15333                         val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
15334                         break;
15335 
15336                     // decimal integers
15337                     // 00
15338                     // 10
15339                     // +10
15340                     // -10
15341                     case bzero_msk: [[fallthrough]];
15342                     case bdigit_msk: [[fallthrough]];
15343                     case begins_sign | has_digits | has_minus: [[fallthrough]];
15344                     case begins_sign | has_digits | has_plus:
15345                     {
15346                         // if the value was so long we exhausted the history buffer it's reasonable to assume
15347                         // there was more and the value's actual type is impossible to identify without making the
15348                         // buffer bigger (since it could have actually been a float), so emit an error.
15349                         //
15350                         // (this will likely only come up during fuzzing and similar scenarios)
15351                         static constexpr size_t max_numeric_value_length =
15352                             utf8_buffered_reader::max_history_length - 2u;
15353                         if TOML_UNLIKELY(!eof_while_scanning && advance_count > max_numeric_value_length)
15354                             set_error_and_return_default("numeric value too long to identify type - cannot exceed "sv,
15355                                                          max_numeric_value_length,
15356                                                          " characters"sv);
15357 
15358                         val.reset(new value{ parse_integer<10>() });
15359                         break;
15360                     }
15361 
15362                     // hexadecimal integers
15363                     // 0x10
15364                     case bzero_msk | has_x:
15365                         val.reset(new value{ parse_integer<16>() });
15366                         val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
15367                         break;
15368 
15369                     // decimal floats
15370                     // 0e1
15371                     // 0e-1
15372                     // 0e+1
15373                     // 0.0
15374                     // 0.0e1
15375                     // 0.0e-1
15376                     // 0.0e+1
15377                     case bzero_msk | has_e: [[fallthrough]];
15378                     case bzero_msk | has_e | has_minus: [[fallthrough]];
15379                     case bzero_msk | has_e | has_plus: [[fallthrough]];
15380                     case bzero_msk | has_dot: [[fallthrough]];
15381                     case bzero_msk | has_dot | has_e: [[fallthrough]];
15382                     case bzero_msk | has_dot | has_e | has_minus: [[fallthrough]];
15383                     case bzero_msk | has_dot | has_e | has_plus: [[fallthrough]];
15384                     // 1e1
15385                     // 1e-1
15386                     // 1e+1
15387                     // 1.0
15388                     // 1.0e1
15389                     // 1.0e-1
15390                     // 1.0e+1
15391                     case bdigit_msk | has_e: [[fallthrough]];
15392                     case bdigit_msk | has_e | has_minus: [[fallthrough]];
15393                     case bdigit_msk | has_e | has_plus: [[fallthrough]];
15394                     case bdigit_msk | has_dot: [[fallthrough]];
15395                     case bdigit_msk | has_dot | has_e: [[fallthrough]];
15396                     case bdigit_msk | has_dot | has_e | has_minus: [[fallthrough]];
15397                     case bdigit_msk | has_dot | has_e | has_plus: [[fallthrough]];
15398                     // +1e1
15399                     // +1.0
15400                     // +1.0e1
15401                     // +1.0e+1
15402                     // +1.0e-1
15403                     // -1.0e+1
15404                     case begins_sign | has_digits | has_e | has_plus: [[fallthrough]];
15405                     case begins_sign | has_digits | has_dot | has_plus: [[fallthrough]];
15406                     case begins_sign | has_digits | has_dot | has_e | has_plus: [[fallthrough]];
15407                     case begins_sign | has_digits | has_dot | has_e | signs_msk: [[fallthrough]];
15408                     // -1e1
15409                     // -1e+1
15410                     // +1e-1
15411                     // -1.0
15412                     // -1.0e1
15413                     // -1.0e-1
15414                     case begins_sign | has_digits | has_e | has_minus: [[fallthrough]];
15415                     case begins_sign | has_digits | has_e | signs_msk: [[fallthrough]];
15416                     case begins_sign | has_digits | has_dot | has_minus: [[fallthrough]];
15417                     case begins_sign | has_digits | has_dot | has_e | has_minus:
15418                         val.reset(new value{ parse_float() });
15419                         break;
15420 
15421                     // hexadecimal floats
15422                     // 0x10p0
15423                     // 0x10p-0
15424                     // 0x10p+0
15425                     case bzero_msk | has_x | has_p: [[fallthrough]];
15426                     case bzero_msk | has_x | has_p | has_minus: [[fallthrough]];
15427                     case bzero_msk | has_x | has_p | has_plus: [[fallthrough]];
15428                     // -0x10p0
15429                     // -0x10p-0
15430                     // +0x10p0
15431                     // +0x10p+0
15432                     // -0x10p+0
15433                     // +0x10p-0
15434                     case begins_sign | has_digits | has_x | has_p | has_minus: [[fallthrough]];
15435                     case begins_sign | has_digits | has_x | has_p | has_plus: [[fallthrough]];
15436                     case begins_sign | has_digits | has_x | has_p | signs_msk: [[fallthrough]];
15437                     // 0x10.1p0
15438                     // 0x10.1p-0
15439                     // 0x10.1p+0
15440                     case bzero_msk | has_x | has_dot | has_p: [[fallthrough]];
15441                     case bzero_msk | has_x | has_dot | has_p | has_minus: [[fallthrough]];
15442                     case bzero_msk | has_x | has_dot | has_p | has_plus: [[fallthrough]];
15443                     // -0x10.1p0
15444                     // -0x10.1p-0
15445                     // +0x10.1p0
15446                     // +0x10.1p+0
15447                     // -0x10.1p+0
15448                     // +0x10.1p-0
15449                     case begins_sign | has_digits | has_x | has_dot | has_p | has_minus: [[fallthrough]];
15450                     case begins_sign | has_digits | has_x | has_dot | has_p | has_plus: [[fallthrough]];
15451                     case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
15452                         val.reset(new value{ parse_hex_float() });
15453                         break;
15454 
15455                     // times
15456                     // HH:MM
15457                     // HH:MM:SS
15458                     // HH:MM:SS.FFFFFF
15459                     case bzero_msk | has_colon: [[fallthrough]];
15460                     case bzero_msk | has_colon | has_dot: [[fallthrough]];
15461                     case bdigit_msk | has_colon: [[fallthrough]];
15462                     case bdigit_msk | has_colon | has_dot: val.reset(new value{ parse_time() }); break;
15463 
15464                     // local dates
15465                     // YYYY-MM-DD
15466                     case bzero_msk | has_minus: [[fallthrough]];
15467                     case bdigit_msk | has_minus: val.reset(new value{ parse_date() }); break;
15468 
15469                     // date-times
15470                     // YYYY-MM-DDTHH:MM
15471                     // YYYY-MM-DDTHH:MM-HH:MM
15472                     // YYYY-MM-DDTHH:MM+HH:MM
15473                     // YYYY-MM-DD HH:MM
15474                     // YYYY-MM-DD HH:MM-HH:MM
15475                     // YYYY-MM-DD HH:MM+HH:MM
15476                     // YYYY-MM-DDTHH:MM:SS
15477                     // YYYY-MM-DDTHH:MM:SS-HH:MM
15478                     // YYYY-MM-DDTHH:MM:SS+HH:MM
15479                     // YYYY-MM-DD HH:MM:SS
15480                     // YYYY-MM-DD HH:MM:SS-HH:MM
15481                     // YYYY-MM-DD HH:MM:SS+HH:MM
15482                     case bzero_msk | has_minus | has_colon | has_t: [[fallthrough]];
15483                     case bzero_msk | signs_msk | has_colon | has_t: [[fallthrough]];
15484                     case bdigit_msk | has_minus | has_colon | has_t: [[fallthrough]];
15485                     case bdigit_msk | signs_msk | has_colon | has_t: [[fallthrough]];
15486                     // YYYY-MM-DDTHH:MM:SS.FFFFFF
15487                     // YYYY-MM-DDTHH:MM:SS.FFFFFF-HH:MM
15488                     // YYYY-MM-DDTHH:MM:SS.FFFFFF+HH:MM
15489                     // YYYY-MM-DD HH:MM:SS.FFFFFF
15490                     // YYYY-MM-DD HH:MM:SS.FFFFFF-HH:MM
15491                     // YYYY-MM-DD HH:MM:SS.FFFFFF+HH:MM
15492                     case bzero_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
15493                     case bzero_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
15494                     case bdigit_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
15495                     case bdigit_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
15496                     // YYYY-MM-DDTHH:MMZ
15497                     // YYYY-MM-DD HH:MMZ
15498                     // YYYY-MM-DDTHH:MM:SSZ
15499                     // YYYY-MM-DD HH:MM:SSZ
15500                     // YYYY-MM-DDTHH:MM:SS.FFFFFFZ
15501                     // YYYY-MM-DD HH:MM:SS.FFFFFFZ
15502                     case bzero_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
15503                     case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t: [[fallthrough]];
15504                     case bdigit_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
15505                     case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
15506                         val.reset(new value{ parse_date_time() });
15507                         break;
15508                 }
15509             }
15510             while (false);
15511 
15512             if (!val)
15513             {
15514                 set_error_at(begin_pos, "could not determine value type"sv);
15515                 return_after_error({});
15516             }
15517 
15518             val->source_ = { begin_pos, current_position(1), reader.source_path() };
15519             return val;
15520         }
15521 
15522         TOML_NEVER_INLINE
15523         bool parse_key()
15524         {
15525             return_if_error({});
15526             assert_not_eof();
15527             TOML_ASSERT_ASSUME(is_bare_key_character(*cp) || is_string_delimiter(*cp));
15528             push_parse_scope("key"sv);
15529 
15530             key_buffer.clear();
15531             recording_whitespace = false;
15532 
15533             while (!is_error())
15534             {
15535                 std::string_view key_segment;
15536                 const auto key_begin = current_position();
15537 
15538                 // bare_key_segment
15539                 if (is_bare_key_character(*cp))
15540                     key_segment = parse_bare_key_segment();
15541 
15542                 // "quoted key segment"
15543                 else if (is_string_delimiter(*cp))
15544                 {
15545                     const auto begin_pos = cp->position;
15546 
15547                     recording_whitespace = true;
15548                     parsed_string str    = parse_string();
15549                     recording_whitespace = false;
15550                     return_if_error({});
15551 
15552                     if (str.was_multi_line)
15553                     {
15554                         set_error_at(begin_pos,
15555                                      "multi-line strings are prohibited in "sv,
15556                                      key_buffer.empty() ? ""sv : "dotted "sv,
15557                                      "keys"sv);
15558                         return_after_error({});
15559                     }
15560                     else
15561                         key_segment = str.value;
15562                 }
15563 
15564                 // ???
15565                 else
15566                     set_error_and_return_default("expected bare key starting character or string delimiter, saw '"sv,
15567                                                  to_sv(*cp),
15568                                                  "'"sv);
15569 
15570                 const auto key_end = current_position();
15571 
15572                 // whitespace following the key segment
15573                 consume_leading_whitespace();
15574 
15575                 // store segment
15576                 key_buffer.push_back(key_segment, key_begin, key_end);
15577 
15578                 // eof or no more key to come
15579                 if (is_eof() || *cp != U'.')
15580                     break;
15581 
15582                 // was a dotted key - go around again
15583                 advance_and_return_if_error_or_eof({});
15584                 consume_leading_whitespace();
15585                 set_error_and_return_if_eof({});
15586             }
15587             return_if_error({});
15588 
15589             return true;
15590         }
15591 
15592         TOML_NODISCARD
15593         key make_key(size_t segment_index) const
15594         {
15595             TOML_ASSERT(key_buffer.size() > segment_index);
15596 
15597             return key{
15598                 key_buffer[segment_index],
15599                 source_region{ key_buffer.starts[segment_index], key_buffer.ends[segment_index], root.source().path }
15600             };
15601         }
15602 
15603         TOML_NODISCARD
15604         TOML_NEVER_INLINE
15605         table* parse_table_header()
15606         {
15607             return_if_error({});
15608             assert_not_eof();
15609             TOML_ASSERT_ASSUME(*cp == U'[');
15610             push_parse_scope("table header"sv);
15611 
15612             const source_position header_begin_pos = cp->position;
15613             source_position header_end_pos;
15614             bool is_arr = false;
15615 
15616             // parse header
15617             {
15618                 // skip first '['
15619                 advance_and_return_if_error_or_eof({});
15620 
15621                 // skip past any whitespace that followed the '['
15622                 const bool had_leading_whitespace = consume_leading_whitespace();
15623                 set_error_and_return_if_eof({});
15624 
15625                 // skip second '[' (if present)
15626                 if (*cp == U'[')
15627                 {
15628                     if (had_leading_whitespace)
15629                         set_error_and_return_default(
15630                             "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv);
15631 
15632                     is_arr = true;
15633                     advance_and_return_if_error_or_eof({});
15634 
15635                     // skip past any whitespace that followed the '['
15636                     consume_leading_whitespace();
15637                     set_error_and_return_if_eof({});
15638                 }
15639 
15640                 // check for a premature closing ']'
15641                 if (*cp == U']')
15642                     set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
15643 
15644                 // get the actual key
15645                 start_recording();
15646                 parse_key();
15647                 stop_recording(1u);
15648                 return_if_error({});
15649 
15650                 // skip past any whitespace that followed the key
15651                 consume_leading_whitespace();
15652                 return_if_error({});
15653                 set_error_and_return_if_eof({});
15654 
15655                 // consume the closing ']'
15656                 if (*cp != U']')
15657                     set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
15658                 if (is_arr)
15659                 {
15660                     advance_and_return_if_error_or_eof({});
15661                     if (*cp != U']')
15662                         set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
15663                 }
15664                 advance_and_return_if_error({});
15665                 header_end_pos = current_position(1);
15666 
15667                 // handle the rest of the line after the header
15668                 consume_leading_whitespace();
15669                 if (!is_eof() && !consume_comment() && !consume_line_break())
15670                     set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
15671             }
15672             TOML_ASSERT(!key_buffer.empty());
15673 
15674             // check if each parent is a table/table array, or can be created implicitly as a table.
15675             table* parent = &root;
15676             for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++)
15677             {
15678                 const std::string_view segment = key_buffer[i];
15679                 auto pit                       = parent->lower_bound(segment);
15680 
15681                 // parent already existed
15682                 if (pit != parent->end() && pit->first == segment)
15683                 {
15684                     node& p = pit->second;
15685 
15686                     if (auto tbl = p.as_table())
15687                     {
15688                         // adding to closed inline tables is illegal
15689                         if (tbl->is_inline() && !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
15690                             set_error_and_return_default("cannot insert '"sv,
15691                                                          to_sv(recording_buffer),
15692                                                          "' into existing inline table"sv);
15693 
15694                         parent = tbl;
15695                     }
15696                     else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
15697                     {
15698                         // table arrays are a special case;
15699                         // the spec dictates we select the most recently declared element in the array.
15700                         TOML_ASSERT(!arr->empty());
15701                         TOML_ASSERT(arr->back().is_table());
15702                         parent = &arr->back().ref_cast<table>();
15703                     }
15704                     else
15705                     {
15706                         if (!is_arr && p.type() == node_type::table)
15707                             set_error_and_return_default("cannot redefine existing table '"sv,
15708                                                          to_sv(recording_buffer),
15709                                                          "'"sv);
15710                         else
15711                             set_error_and_return_default("cannot redefine existing "sv,
15712                                                          to_sv(p.type()),
15713                                                          " '"sv,
15714                                                          to_sv(recording_buffer),
15715                                                          "' as "sv,
15716                                                          is_arr ? "array-of-tables"sv : "table"sv);
15717                     }
15718                 }
15719 
15720                 // need to create a new implicit table
15721                 else
15722                 {
15723                     pit       = parent->emplace_hint<table>(pit, make_key(i));
15724                     table& p  = pit->second.ref_cast<table>();
15725                     p.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15726 
15727                     implicit_tables.push_back(&p);
15728                     parent = &p;
15729                 }
15730             }
15731 
15732             const auto last_segment = key_buffer.back();
15733             auto it                 = parent->lower_bound(last_segment);
15734 
15735             // if there was already a matching node some sanity checking is necessary;
15736             // this is ok if we're making an array and the existing element is already an array (new element)
15737             // or if we're making a table and the existing element is an implicitly-created table (promote it),
15738             // otherwise this is a redefinition error.
15739             if (it != parent->end() && it->first == last_segment)
15740             {
15741                 node& matching_node = it->second;
15742                 if (auto arr = matching_node.as_array();
15743                     is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
15744                 {
15745                     table& tbl  = arr->emplace_back<table>();
15746                     tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15747                     return &tbl;
15748                 }
15749 
15750                 else if (auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty())
15751                 {
15752                     if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl); found)
15753                     {
15754                         bool ok = true;
15755                         if (!tbl->empty())
15756                         {
15757                             for (auto& [_, child] : *tbl)
15758                             {
15759                                 if (!child.is_table() && !child.is_array_of_tables())
15760                                 {
15761                                     ok = false;
15762                                     break;
15763                                 }
15764                             }
15765                         }
15766 
15767                         if (ok)
15768                         {
15769                             implicit_tables.erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
15770                             tbl->source_.begin = header_begin_pos;
15771                             tbl->source_.end   = header_end_pos;
15772                             return tbl;
15773                         }
15774                     }
15775                 }
15776 
15777                 // if we get here it's a redefinition error.
15778                 if (!is_arr && matching_node.type() == node_type::table)
15779                 {
15780                     set_error_at(header_begin_pos,
15781                                  "cannot redefine existing table '"sv,
15782                                  to_sv(recording_buffer),
15783                                  "'"sv);
15784                     return_after_error({});
15785                 }
15786                 else
15787                 {
15788                     set_error_at(header_begin_pos,
15789                                  "cannot redefine existing "sv,
15790                                  to_sv(matching_node.type()),
15791                                  " '"sv,
15792                                  to_sv(recording_buffer),
15793                                  "' as "sv,
15794                                  is_arr ? "array-of-tables"sv : "table"sv);
15795                     return_after_error({});
15796                 }
15797             }
15798 
15799             // there was no matching node, sweet - we can freely instantiate a new table/table array.
15800             else
15801             {
15802                 auto last_key = make_key(key_buffer.size() - 1u);
15803 
15804                 // if it's an array we need to make the array and it's first table element,
15805                 // set the starting regions, and return the table element
15806                 if (is_arr)
15807                 {
15808                     it             = parent->emplace_hint<array>(it, std::move(last_key));
15809                     array& tbl_arr = it->second.ref_cast<array>();
15810                     table_arrays.push_back(&tbl_arr);
15811                     tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15812 
15813                     table& tbl  = tbl_arr.emplace_back<table>();
15814                     tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15815                     return &tbl;
15816                 }
15817 
15818                 // otherwise we're just making a table
15819                 else
15820                 {
15821                     it          = parent->emplace_hint<table>(it, std::move(last_key));
15822                     table& tbl  = it->second.ref_cast<table>();
15823                     tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
15824                     return &tbl;
15825                 }
15826             }
15827         }
15828 
15829         TOML_NEVER_INLINE
15830         bool parse_key_value_pair_and_insert(table* tbl)
15831         {
15832             return_if_error({});
15833             assert_not_eof();
15834             TOML_ASSERT_ASSUME(is_string_delimiter(*cp) || is_bare_key_character(*cp));
15835             push_parse_scope("key-value pair"sv);
15836 
15837             // read the key into the key buffer
15838             start_recording();
15839             parse_key();
15840             stop_recording(1u);
15841             return_if_error({});
15842             TOML_ASSERT(key_buffer.size() >= 1u);
15843 
15844             // skip past any whitespace that followed the key
15845             consume_leading_whitespace();
15846             set_error_and_return_if_eof({});
15847 
15848             // '='
15849             if (*cp != U'=')
15850                 set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv);
15851             advance_and_return_if_error_or_eof({});
15852 
15853             // skip past any whitespace that followed the '='
15854             consume_leading_whitespace();
15855             return_if_error({});
15856             set_error_and_return_if_eof({});
15857 
15858             // check that the next character could actually be a value
15859             if (is_value_terminator(*cp))
15860                 set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
15861 
15862             // if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
15863             // and set the target table to the second-to-last one in the chain
15864             if (key_buffer.size() > 1u)
15865             {
15866                 for (size_t i = 0; i < key_buffer.size() - 1u; i++)
15867                 {
15868                     const std::string_view segment = key_buffer[i];
15869                     auto pit                       = tbl->lower_bound(segment);
15870 
15871                     // parent already existed
15872                     if (pit != tbl->end() && pit->first == segment)
15873                     {
15874                         table* p = pit->second.as_table();
15875 
15876                         // redefinition
15877                         if TOML_UNLIKELY(!p
15878                             || !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
15879                                  || impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
15880                         {
15881                             set_error_at(key_buffer.starts[i],
15882                                          "cannot redefine existing "sv,
15883                                          to_sv(pit->second.type()),
15884                                          " as dotted key-value pair"sv);
15885                             return_after_error({});
15886                         }
15887 
15888                         tbl = p;
15889                     }
15890 
15891                     // need to create a new implicit table
15892                     else
15893                     {
15894                         pit       = tbl->emplace_hint<table>(pit, make_key(i));
15895                         table& p  = pit->second.ref_cast<table>();
15896                         p.source_ = pit->first.source();
15897 
15898                         dotted_key_tables.push_back(&p);
15899                         tbl = &p;
15900                     }
15901                 }
15902             }
15903 
15904             // ensure this isn't a redefinition
15905             const std::string_view last_segment = key_buffer.back();
15906             auto it                             = tbl->lower_bound(last_segment);
15907             if (it != tbl->end() && it->first == last_segment)
15908             {
15909                 set_error("cannot redefine existing "sv,
15910                           to_sv(it->second.type()),
15911                           " '"sv,
15912                           to_sv(recording_buffer),
15913                           "'"sv);
15914                 return_after_error({});
15915             }
15916 
15917             // create the key first since the key buffer will likely get overwritten during value parsing (inline
15918             // tables)
15919             auto last_key = make_key(key_buffer.size() - 1u);
15920 
15921             // now we can actually parse the value
15922             node_ptr val = parse_value();
15923             return_if_error({});
15924 
15925             tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
15926             return true;
15927         }
15928 
15929         void parse_document()
15930         {
15931             assert_not_error();
15932             assert_not_eof();
15933             push_parse_scope("root table"sv);
15934 
15935             table* current_table = &root;
15936 
15937             do
15938             {
15939                 return_if_error();
15940 
15941                 // leading whitespace, line endings, comments
15942                 if (consume_leading_whitespace() || consume_line_break() || consume_comment())
15943                     continue;
15944                 return_if_error();
15945 
15946                 // [tables]
15947                 // [[table array]]
15948                 if (*cp == U'[')
15949                     current_table = parse_table_header();
15950 
15951                 // bare_keys
15952                 // dotted.keys
15953                 // "quoted keys"
15954                 else if (is_bare_key_character(*cp) || is_string_delimiter(*cp))
15955                 {
15956                     push_parse_scope("key-value pair"sv);
15957 
15958                     parse_key_value_pair_and_insert(current_table);
15959 
15960                     // handle the rest of the line after the kvp
15961                     // (this is not done in parse_key_value_pair() because that is also used for inline tables)
15962                     consume_leading_whitespace();
15963                     return_if_error();
15964                     if (!is_eof() && !consume_comment() && !consume_line_break())
15965                         set_error("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
15966                 }
15967 
15968                 else // ??
15969                     set_error("expected keys, tables, whitespace or comments, saw '"sv, to_sv(cp), "'"sv);
15970             }
15971             while (!is_eof());
15972 
15973             auto eof_pos     = current_position(1);
15974             root.source_.end = eof_pos;
15975             if (current_table && current_table != &root && current_table->source_.end <= current_table->source_.begin)
15976                 current_table->source_.end = eof_pos;
15977         }
15978 
15979         static void update_region_ends(node& nde) noexcept
15980         {
15981             const auto type = nde.type();
15982             if (type > node_type::array)
15983                 return;
15984 
15985             if (type == node_type::table)
15986             {
15987                 auto& tbl = nde.ref_cast<table>();
15988                 if (tbl.is_inline()) // inline tables (and all their inline descendants) are already correctly
15989                                      // terminated
15990                     return;
15991 
15992                 auto end = nde.source_.end;
15993                 for (auto&& [k, v] : tbl)
15994                 {
15995                     TOML_UNUSED(k);
15996                     update_region_ends(v);
15997                     if (end < v.source_.end)
15998                         end = v.source_.end;
15999                 }
16000             }
16001             else // arrays
16002             {
16003                 auto& arr = nde.ref_cast<array>();
16004                 auto end  = nde.source_.end;
16005                 for (auto&& v : arr)
16006                 {
16007                     update_region_ends(v);
16008                     if (end < v.source_.end)
16009                         end = v.source_.end;
16010                 }
16011                 nde.source_.end = end;
16012             }
16013         }
16014 
16015       public:
16016         parser(utf8_reader_interface&& reader_) //
16017             : reader{ reader_ }
16018         {
16019             root.source_ = { prev_pos, prev_pos, reader.source_path() };
16020 
16021             if (!reader.peek_eof())
16022             {
16023                 cp = reader.read_next();
16024 
16025 #if !TOML_EXCEPTIONS
16026                 if (reader.error())
16027                 {
16028                     err = std::move(reader.error());
16029                     return;
16030                 }
16031 #endif
16032 
16033                 if (cp)
16034                     parse_document();
16035             }
16036 
16037             update_region_ends(root);
16038         }
16039 
16040         TOML_NODISCARD
16041         operator parse_result() && noexcept
16042         {
16043 #if TOML_EXCEPTIONS
16044 
16045             return { std::move(root) };
16046 
16047 #else
16048 
16049             if (err)
16050                 return parse_result{ *std::move(err) };
16051             else
16052                 return parse_result{ std::move(root) };
16053 
16054 #endif
16055         }
16056     };
16057 
16058     TOML_EXTERNAL_LINKAGE
16059     node_ptr parser::parse_array()
16060     {
16061         return_if_error({});
16062         assert_not_eof();
16063         TOML_ASSERT_ASSUME(*cp == U'[');
16064         push_parse_scope("array"sv);
16065 
16066         // skip opening '['
16067         advance_and_return_if_error_or_eof({});
16068 
16069         node_ptr arr_ptr{ new array{} };
16070         array& arr = arr_ptr->ref_cast<array>();
16071         enum class TOML_CLOSED_ENUM parse_type : int
16072         {
16073             none,
16074             comma,
16075             val
16076         };
16077         parse_type prev = parse_type::none;
16078 
16079         while (!is_error())
16080         {
16081             while (consume_leading_whitespace() || consume_line_break() || consume_comment())
16082                 continue;
16083             set_error_and_return_if_eof({});
16084 
16085             // commas - only legal after a value
16086             if (*cp == U',')
16087             {
16088                 if (prev == parse_type::val)
16089                 {
16090                     prev = parse_type::comma;
16091                     advance_and_return_if_error_or_eof({});
16092                     continue;
16093                 }
16094                 set_error_and_return_default("expected value or closing ']', saw comma"sv);
16095             }
16096 
16097             // closing ']'
16098             else if (*cp == U']')
16099             {
16100                 advance_and_return_if_error({});
16101                 break;
16102             }
16103 
16104             // must be a value
16105             else
16106             {
16107                 if (prev == parse_type::val)
16108                 {
16109                     set_error_and_return_default("expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
16110                     continue;
16111                 }
16112                 prev = parse_type::val;
16113 
16114                 auto val = parse_value();
16115                 return_if_error({});
16116 
16117                 if (!arr.capacity())
16118                     arr.reserve(4u);
16119                 arr.emplace_back<node_ptr>(std::move(val));
16120             }
16121         }
16122 
16123         return_if_error({});
16124         return arr_ptr;
16125     }
16126 
16127     TOML_EXTERNAL_LINKAGE
16128     node_ptr parser::parse_inline_table()
16129     {
16130         return_if_error({});
16131         assert_not_eof();
16132         TOML_ASSERT_ASSUME(*cp == U'{');
16133         push_parse_scope("inline table"sv);
16134 
16135         // skip opening '{'
16136         advance_and_return_if_error_or_eof({});
16137 
16138         node_ptr tbl_ptr{ new table{} };
16139         table& tbl = tbl_ptr->ref_cast<table>();
16140         tbl.is_inline(true);
16141         table_vector_scope table_scope{ open_inline_tables, tbl };
16142 
16143         enum class TOML_CLOSED_ENUM parse_type : int
16144         {
16145             none,
16146             comma,
16147             kvp
16148         };
16149         parse_type prev = parse_type::none;
16150         while (!is_error())
16151         {
16152             if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
16153             {
16154                 while (consume_leading_whitespace() || consume_line_break() || consume_comment())
16155                     continue;
16156             }
16157             else
16158             {
16159                 while (consume_leading_whitespace())
16160                     continue;
16161             }
16162             return_if_error({});
16163             set_error_and_return_if_eof({});
16164 
16165             // commas - only legal after a key-value pair
16166             if (*cp == U',')
16167             {
16168                 if (prev == parse_type::kvp)
16169                 {
16170                     prev = parse_type::comma;
16171                     advance_and_return_if_error_or_eof({});
16172                 }
16173                 else
16174                     set_error_and_return_default("expected key-value pair or closing '}', saw comma"sv);
16175             }
16176 
16177             // closing '}'
16178             else if (*cp == U'}')
16179             {
16180                 if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
16181                 {
16182                     if (prev == parse_type::comma)
16183                     {
16184                         set_error_and_return_default("expected key-value pair, saw closing '}' (dangling comma)"sv);
16185                         continue;
16186                     }
16187                 }
16188                 advance_and_return_if_error({});
16189                 break;
16190             }
16191 
16192             // key-value pair
16193             else if (is_string_delimiter(*cp) || is_bare_key_character(*cp))
16194             {
16195                 if (prev == parse_type::kvp)
16196                     set_error_and_return_default("expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
16197                 else
16198                 {
16199                     prev = parse_type::kvp;
16200                     parse_key_value_pair_and_insert(&tbl);
16201                 }
16202             }
16203 
16204             else
16205                 set_error_and_return_default("expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
16206         }
16207 
16208         return_if_error({});
16209         return tbl_ptr;
16210     }
16211 
16212     TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
16213 }
16214 TOML_IMPL_NAMESPACE_END;
16215 
16216 #undef TOML_RETURNS_BY_THROWING
16217 #undef advance_and_return_if_error
16218 #undef advance_and_return_if_error_or_eof
16219 #undef assert_not_eof
16220 #undef assert_not_error
16221 #undef is_eof
16222 #undef is_error
16223 #undef parse_error_break
16224 #undef push_parse_scope
16225 #undef push_parse_scope_1
16226 #undef push_parse_scope_2
16227 #undef return_after_error
16228 #undef return_if_eof
16229 #undef return_if_error
16230 #undef return_if_error_or_eof
16231 #undef set_error_and_return
16232 #undef set_error_and_return_default
16233 #undef set_error_and_return_if_eof
16234 #undef utf8_buffered_reader_error_check
16235 #undef utf8_reader_error
16236 #undef utf8_reader_error_check
16237 #undef utf8_reader_return_after_error
16238 
16239 TOML_ANON_NAMESPACE_START
16240 {
16241     TOML_NODISCARD
16242     TOML_INTERNAL_LINKAGE
16243     parse_result do_parse(utf8_reader_interface && reader)
16244     {
16245         return impl::parser{ std::move(reader) };
16246     }
16247 
16248     TOML_NODISCARD
16249     TOML_INTERNAL_LINKAGE
16250     parse_result do_parse_file(std::string_view file_path)
16251     {
16252 #if TOML_EXCEPTIONS
16253 #define TOML_PARSE_FILE_ERROR(msg, path)                                                                               \
16254     throw parse_error(msg, source_position{}, std::make_shared<const std::string>(std::move(path)))
16255 #else
16256 #define TOML_PARSE_FILE_ERROR(msg, path)                                                                               \
16257     return parse_result(parse_error(msg, source_position{}, std::make_shared<const std::string>(std::move(path))))
16258 #endif
16259 
16260         std::string file_path_str(file_path);
16261 
16262         // open file with a custom-sized stack buffer
16263         std::ifstream file;
16264         TOML_OVERALIGNED char file_buffer[sizeof(void*) * 1024u];
16265         file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
16266 #if TOML_WINDOWS
16267         file.open(impl::widen(file_path_str).c_str(), std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
16268 #else
16269         file.open(file_path_str, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
16270 #endif
16271         if (!file.is_open())
16272             TOML_PARSE_FILE_ERROR("File could not be opened for reading", file_path_str);
16273 
16274         // get size
16275         const auto file_size = file.tellg();
16276         if (file_size == -1)
16277             TOML_PARSE_FILE_ERROR("Could not determine file size", file_path_str);
16278         file.seekg(0, std::ifstream::beg);
16279 
16280         // read the whole file into memory first if the file isn't too large
16281         constexpr auto large_file_threshold = 1024 * 1024 * 2; // 2 MB
16282         if (file_size <= large_file_threshold)
16283         {
16284             std::vector<char> file_data;
16285             file_data.resize(static_cast<size_t>(file_size));
16286             file.read(file_data.data(), static_cast<std::streamsize>(file_size));
16287             return parse(std::string_view{ file_data.data(), file_data.size() }, std::move(file_path_str));
16288         }
16289 
16290         // otherwise parse it using the streams
16291         else
16292             return parse(file, std::move(file_path_str));
16293 
16294 #undef TOML_PARSE_FILE_ERROR
16295     }
16296 }
16297 TOML_ANON_NAMESPACE_END;
16298 
16299 TOML_NAMESPACE_START
16300 {
16301     TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
16302 
16303     TOML_EXTERNAL_LINKAGE
16304     parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path)
16305     {
16306         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
16307     }
16308 
16309     TOML_EXTERNAL_LINKAGE
16310     parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path)
16311     {
16312         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
16313     }
16314 
16315     TOML_EXTERNAL_LINKAGE
16316     parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path)
16317     {
16318         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
16319     }
16320 
16321     TOML_EXTERNAL_LINKAGE
16322     parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path)
16323     {
16324         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
16325     }
16326 
16327     TOML_EXTERNAL_LINKAGE
16328     parse_result TOML_CALLCONV parse_file(std::string_view file_path)
16329     {
16330         return TOML_ANON_NAMESPACE::do_parse_file(file_path);
16331     }
16332 
16333 #if TOML_HAS_CHAR8
16334 
16335     TOML_EXTERNAL_LINKAGE
16336     parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path)
16337     {
16338         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
16339     }
16340 
16341     TOML_EXTERNAL_LINKAGE
16342     parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path)
16343     {
16344         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
16345     }
16346 
16347     TOML_EXTERNAL_LINKAGE
16348     parse_result TOML_CALLCONV parse_file(std::u8string_view file_path)
16349     {
16350         std::string file_path_str;
16351         file_path_str.resize(file_path.length());
16352         memcpy(file_path_str.data(), file_path.data(), file_path.length());
16353         return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
16354     }
16355 
16356 #endif // TOML_HAS_CHAR8
16357 
16358 #if TOML_ENABLE_WINDOWS_COMPAT
16359 
16360     TOML_EXTERNAL_LINKAGE
16361     parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path)
16362     {
16363         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
16364     }
16365 
16366     TOML_EXTERNAL_LINKAGE
16367     parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path)
16368     {
16369         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
16370     }
16371 
16372     TOML_EXTERNAL_LINKAGE
16373     parse_result TOML_CALLCONV parse_file(std::wstring_view file_path)
16374     {
16375         return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
16376     }
16377 
16378 #endif // TOML_ENABLE_WINDOWS_COMPAT
16379 
16380 #if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
16381 
16382     TOML_EXTERNAL_LINKAGE
16383     parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path)
16384     {
16385         return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
16386     }
16387 
16388 #endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
16389 
16390     TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
16391 }
16392 TOML_NAMESPACE_END;
16393 
16394 #undef TOML_OVERALIGNED
16395 
16396 #ifdef _MSC_VER
16397 #pragma pop_macro("min")
16398 #pragma pop_macro("max")
16399 #ifndef __clang__
16400 #pragma inline_recursion(off)
16401 #endif
16402 #endif
16403 TOML_POP_WARNINGS;
16404 
16405 #endif // TOML_ENABLE_PARSER
16406 
16407 //********  impl/formatter.inl  ****************************************************************************************
16408 
16409 #if TOML_ENABLE_FORMATTERS
16410 
16411 TOML_PUSH_WARNINGS;
16412 #ifdef _MSC_VER
16413 #ifndef __clang__
16414 #pragma inline_recursion(on)
16415 #endif
16416 #pragma push_macro("min")
16417 #pragma push_macro("max")
16418 #undef min
16419 #undef max
16420 #endif
16421 
16422 TOML_IMPL_NAMESPACE_START
16423 {
16424     enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
16425     {
16426         none,
16427         line_breaks   = 1u << 0, // \n
16428         tabs          = 1u << 1, // \t
16429         control_chars = 1u << 2, // also includes non-ascii vertical whitespace
16430         single_quotes = 1u << 3,
16431         non_bare      = 1u << 4, // anything not satisfying "is bare key character"
16432         non_ascii     = 1u << 5, // any codepoint >= 128
16433 
16434         all = (non_ascii << 1u) - 1u
16435     };
16436     TOML_MAKE_FLAGS(formatted_string_traits);
16437 
16438     TOML_EXTERNAL_LINKAGE
16439     formatter::formatter(const node* source_node,
16440                          const parse_result* source_pr,
16441                          const formatter_constants& constants,
16442                          const formatter_config& config) noexcept //
16443 #if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
16444         : source_{ source_pr && *source_pr ? &source_pr->table() : source_node },
16445           result_{ source_pr },
16446 #else
16447         : source_{ source_pr ? source_pr : source_node },
16448 #endif
16449           constants_{ &constants },
16450           config_{ config }
16451     {
16452         TOML_ASSERT_ASSUME(source_);
16453 
16454         config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
16455 
16456         indent_columns_ = {};
16457         for (auto c : config_.indent)
16458             indent_columns_ += c == '\t' ? 4u : 1u;
16459 
16460         int_format_mask_ = config_.flags
16461                          & (format_flags::allow_binary_integers | format_flags::allow_octal_integers
16462                             | format_flags::allow_hexadecimal_integers);
16463     }
16464 
16465     TOML_EXTERNAL_LINKAGE
16466     void formatter::attach(std::ostream & stream) noexcept
16467     {
16468         indent_        = {};
16469         naked_newline_ = true;
16470         stream_        = &stream;
16471     }
16472 
16473     TOML_EXTERNAL_LINKAGE
16474     void formatter::detach() noexcept
16475     {
16476         stream_ = nullptr;
16477     }
16478 
16479     TOML_EXTERNAL_LINKAGE
16480     void formatter::print_newline(bool force)
16481     {
16482         if (!naked_newline_ || force)
16483         {
16484             print_to_stream(*stream_, '\n');
16485             naked_newline_ = true;
16486         }
16487     }
16488 
16489     TOML_EXTERNAL_LINKAGE
16490     void formatter::print_indent()
16491     {
16492         for (int i = 0; i < indent_; i++)
16493         {
16494             print_to_stream(*stream_, config_.indent);
16495             naked_newline_ = false;
16496         }
16497     }
16498 
16499     TOML_EXTERNAL_LINKAGE
16500     void formatter::print_unformatted(char c)
16501     {
16502         print_to_stream(*stream_, c);
16503         naked_newline_ = false;
16504     }
16505 
16506     TOML_EXTERNAL_LINKAGE
16507     void formatter::print_unformatted(std::string_view str)
16508     {
16509         print_to_stream(*stream_, str);
16510         naked_newline_ = false;
16511     }
16512 
16513     TOML_EXTERNAL_LINKAGE
16514     void formatter::print_string(std::string_view str,
16515                                  bool allow_multi_line,
16516                                  bool allow_bare,
16517                                  bool allow_literal_whitespace)
16518     {
16519         if (str.empty())
16520         {
16521             print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
16522             return;
16523         }
16524 
16525         // pre-scan the string to determine how we should output it
16526         formatted_string_traits traits = {};
16527 
16528         if (!allow_bare)
16529             traits |= formatted_string_traits::non_bare;
16530         bool unicode_allowed = unicode_strings_allowed();
16531 
16532         // ascii fast path
16533         if (is_ascii(str.data(), str.length()))
16534         {
16535             for (auto c : str)
16536             {
16537                 switch (c)
16538                 {
16539                     case '\n': traits |= formatted_string_traits::line_breaks; break;
16540                     case '\t': traits |= formatted_string_traits::tabs; break;
16541                     case '\'': traits |= formatted_string_traits::single_quotes; break;
16542                     default:
16543                     {
16544                         if TOML_UNLIKELY(is_control_character(c))
16545                             traits |= formatted_string_traits::control_chars;
16546 
16547                         if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
16548                             traits |= formatted_string_traits::non_bare;
16549                         break;
16550                     }
16551                 }
16552 
16553                 static constexpr auto all_ascii_traits =
16554                     formatted_string_traits::all & ~formatted_string_traits::non_ascii;
16555                 if (traits == all_ascii_traits)
16556                     break;
16557             }
16558         }
16559 
16560         // unicode slow path
16561         else
16562         {
16563             traits |= formatted_string_traits::non_ascii;
16564             utf8_decoder decoder;
16565 
16566             // if the unicode is malformed just treat the string as a single-line non-literal and
16567             // escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
16568             const auto bad_unicode = [&]() noexcept
16569             {
16570                 traits &= ~formatted_string_traits::line_breaks;
16571                 traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
16572                 unicode_allowed = false;
16573             };
16574 
16575             for (auto c : str)
16576             {
16577                 decoder(c);
16578 
16579                 if TOML_UNLIKELY(decoder.error())
16580                 {
16581                     bad_unicode();
16582                     break;
16583                 }
16584 
16585                 if (!decoder.has_code_point())
16586                     continue;
16587 
16588                 switch (decoder.codepoint)
16589                 {
16590                     case U'\n': traits |= formatted_string_traits::line_breaks; break;
16591                     case U'\t': traits |= formatted_string_traits::tabs; break;
16592                     case U'\'': traits |= formatted_string_traits::single_quotes; break;
16593                     default:
16594                     {
16595                         if TOML_UNLIKELY(is_control_character(decoder.codepoint)
16596                             || is_non_ascii_vertical_whitespace(decoder.codepoint))
16597                             traits |= formatted_string_traits::control_chars;
16598 
16599                         if (!is_bare_key_character(decoder.codepoint))
16600                             traits |= formatted_string_traits::non_bare;
16601                         break;
16602                     }
16603                 }
16604             }
16605 
16606             if (decoder.needs_more_input())
16607                 bad_unicode();
16608         }
16609 
16610         // strings with line breaks, tabs, and single-quotes can't be bare
16611         if (!!(traits
16612                & (formatted_string_traits::line_breaks | formatted_string_traits::tabs
16613                   | formatted_string_traits::single_quotes)))
16614             traits |= formatted_string_traits::non_bare;
16615 
16616         // if the string meets the requirements of being 'bare' we can emit a bare string
16617         // (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
16618         if (!(traits & formatted_string_traits::non_bare)
16619             && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed))
16620         {
16621             print_unformatted(str);
16622             return;
16623         }
16624         const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
16625 
16626         // determine if this should be a multi-line string (triple-quotes)
16627         const auto multi_line = allow_literal_whitespace     //
16628                              && allow_multi_line             //
16629                              && multi_line_strings_allowed() //
16630                              && !!(traits & formatted_string_traits::line_breaks);
16631 
16632         // determine if this should be a literal string (single-quotes with no escaping)
16633         const auto literal = literal_strings_allowed()                                          //
16634                           && !(traits & formatted_string_traits::control_chars)                 //
16635                           && (!(traits & formatted_string_traits::single_quotes) || multi_line) //
16636                           && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed)   //
16637                           && (!(traits & formatted_string_traits::line_breaks) || multi_line)   //
16638                           && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
16639 
16640         // literal strings (single quotes, no escape codes)
16641         if (literal)
16642         {
16643             const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
16644             print_unformatted(quot);
16645             print_unformatted(str);
16646             print_unformatted(quot);
16647             return;
16648         }
16649 
16650         // anything from here down is a non-literal string, so requires iteration and escaping.
16651         print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
16652 
16653         // ascii fast path
16654         if (!(traits & formatted_string_traits::non_ascii))
16655         {
16656             for (auto c : str)
16657             {
16658                 switch (c)
16659                 {
16660                     case '"': print_to_stream(*stream_, R"(\")"sv); break;
16661                     case '\\': print_to_stream(*stream_, R"(\\)"sv); break;
16662                     case '\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
16663                     case '\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
16664                     case '\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
16665                     default:
16666                     {
16667                         // control characters from lookup table
16668                         if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
16669                             print_to_stream(*stream_, control_char_escapes[c]);
16670 
16671                         // regular characters
16672                         else
16673                             print_to_stream(*stream_, c);
16674                     }
16675                 }
16676             }
16677         }
16678 
16679         // unicode slow path
16680         else
16681         {
16682             utf8_decoder decoder;
16683             const char* cp_start = str.data();
16684             const char* cp_end   = cp_start;
16685             for (auto c : str)
16686             {
16687                 decoder(c);
16688                 cp_end++;
16689 
16690                 // if the decoder encounters malformed unicode just emit raw bytes and
16691                 if (decoder.error())
16692                 {
16693                     while (cp_start != cp_end)
16694                     {
16695                         print_to_stream(*stream_, R"(\u00)"sv);
16696                         print_to_stream(*stream_,
16697                                         static_cast<uint8_t>(*cp_start),
16698                                         value_flags::format_as_hexadecimal,
16699                                         2);
16700                         cp_start++;
16701                     }
16702                     decoder.reset();
16703                     continue;
16704                 }
16705 
16706                 if (!decoder.has_code_point())
16707                     continue;
16708 
16709                 switch (decoder.codepoint)
16710                 {
16711                     case U'"': print_to_stream(*stream_, R"(\")"sv); break;
16712                     case U'\\': print_to_stream(*stream_, R"(\\)"sv); break;
16713                     case U'\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
16714                     case U'\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
16715                     case U'\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
16716                     default:
16717                     {
16718                         // control characters from lookup table
16719                         if TOML_UNLIKELY(decoder.codepoint <= U'\x1F')
16720                             print_to_stream(*stream_,
16721                                             control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);
16722 
16723                         // escaped unicode characters
16724                         else if (decoder.codepoint > U'\x7F'
16725                                  && (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint)))
16726                         {
16727                             if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu)
16728                             {
16729                                 print_to_stream(*stream_, R"(\U)"sv);
16730                                 print_to_stream(*stream_,
16731                                                 static_cast<uint_least32_t>(decoder.codepoint),
16732                                                 value_flags::format_as_hexadecimal,
16733                                                 8);
16734                             }
16735                             else
16736                             {
16737                                 print_to_stream(*stream_, R"(\u)"sv);
16738                                 print_to_stream(*stream_,
16739                                                 static_cast<uint_least32_t>(decoder.codepoint),
16740                                                 value_flags::format_as_hexadecimal,
16741                                                 4);
16742                             }
16743                         }
16744 
16745                         // regular characters
16746                         else
16747                             print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
16748                     }
16749                 }
16750 
16751                 cp_start = cp_end;
16752             }
16753         }
16754 
16755         print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
16756     }
16757 
16758     TOML_EXTERNAL_LINKAGE
16759     void formatter::print(const value<std::string>& val)
16760     {
16761         print_string(val.get());
16762     }
16763 
16764     TOML_EXTERNAL_LINKAGE
16765     void formatter::print(const value<int64_t>& val)
16766     {
16767         naked_newline_ = false;
16768 
16769         if (*val >= 0 && !!int_format_mask_)
16770         {
16771             static constexpr auto value_flags_mask =
16772                 value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
16773 
16774             const auto fmt = val.flags() & value_flags_mask;
16775             switch (fmt)
16776             {
16777                 case value_flags::format_as_binary:
16778                     if (!!(int_format_mask_ & format_flags::allow_binary_integers))
16779                     {
16780                         print_to_stream(*stream_, "0b"sv);
16781                         print_to_stream(*stream_, *val, fmt);
16782                         return;
16783                     }
16784                     break;
16785 
16786                 case value_flags::format_as_octal:
16787                     if (!!(int_format_mask_ & format_flags::allow_octal_integers))
16788                     {
16789                         print_to_stream(*stream_, "0o"sv);
16790                         print_to_stream(*stream_, *val, fmt);
16791                         return;
16792                     }
16793                     break;
16794 
16795                 case value_flags::format_as_hexadecimal:
16796                     if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers))
16797                     {
16798                         print_to_stream(*stream_, "0x"sv);
16799                         print_to_stream(*stream_, *val, fmt);
16800                         return;
16801                     }
16802                     break;
16803 
16804                 default: break;
16805             }
16806         }
16807 
16808         // fallback to decimal
16809         print_to_stream(*stream_, *val);
16810     }
16811 
16812     TOML_EXTERNAL_LINKAGE
16813     void formatter::print(const value<double>& val)
16814     {
16815         const std::string_view* inf_nan = nullptr;
16816         switch (fpclassify(*val))
16817         {
16818             case fp_class::neg_inf: inf_nan = &constants_->float_neg_inf; break;
16819             case fp_class::pos_inf: inf_nan = &constants_->float_pos_inf; break;
16820             case fp_class::nan: inf_nan = &constants_->float_nan; break;
16821             case fp_class::ok:
16822                 print_to_stream(*stream_,
16823                                 *val,
16824                                 value_flags::none,
16825                                 !!(config_.flags & format_flags::relaxed_float_precision));
16826                 break;
16827             default: TOML_UNREACHABLE;
16828         }
16829 
16830         if (inf_nan)
16831         {
16832             if (!!(config_.flags & format_flags::quote_infinities_and_nans))
16833                 print_to_stream_bookended(*stream_, *inf_nan, '"');
16834             else
16835                 print_to_stream(*stream_, *inf_nan);
16836         }
16837 
16838         naked_newline_ = false;
16839     }
16840 
16841     TOML_EXTERNAL_LINKAGE
16842     void formatter::print(const value<bool>& val)
16843     {
16844         print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
16845     }
16846 
16847     TOML_EXTERNAL_LINKAGE
16848     void formatter::print(const value<date>& val)
16849     {
16850         if (!!(config_.flags & format_flags::quote_dates_and_times))
16851             print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
16852         else
16853             print_to_stream(*stream_, *val);
16854         naked_newline_ = false;
16855     }
16856 
16857     TOML_EXTERNAL_LINKAGE
16858     void formatter::print(const value<time>& val)
16859     {
16860         if (!!(config_.flags & format_flags::quote_dates_and_times))
16861             print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
16862         else
16863             print_to_stream(*stream_, *val);
16864         naked_newline_ = false;
16865     }
16866 
16867     TOML_EXTERNAL_LINKAGE
16868     void formatter::print(const value<date_time>& val)
16869     {
16870         if (!!(config_.flags & format_flags::quote_dates_and_times))
16871             print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
16872         else
16873             print_to_stream(*stream_, *val);
16874         naked_newline_ = false;
16875     }
16876 
16877     TOML_EXTERNAL_LINKAGE
16878     void formatter::print_value(const node& val_node, node_type type)
16879     {
16880         TOML_ASSUME(type > node_type::array);
16881         switch (type)
16882         {
16883             case node_type::string: print(*reinterpret_cast<const value<std::string>*>(&val_node)); break;
16884             case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
16885             case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
16886             case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
16887             case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
16888             case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
16889             case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
16890             default: TOML_UNREACHABLE;
16891         }
16892     }
16893 
16894 #if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
16895 
16896     TOML_EXTERNAL_LINKAGE
16897     bool formatter::dump_failed_parse_result()
16898     {
16899         if (result_ && !(*result_))
16900         {
16901             stream() << result_->error();
16902             return true;
16903         }
16904         return false;
16905     }
16906 
16907 #else
16908 
16909     TOML_EXTERNAL_LINKAGE
16910     TOML_ATTR(const)
16911     bool formatter::dump_failed_parse_result()
16912     {
16913         return false;
16914     }
16915 
16916 #endif
16917 }
16918 TOML_IMPL_NAMESPACE_END;
16919 
16920 #ifdef _MSC_VER
16921 #pragma pop_macro("min")
16922 #pragma pop_macro("max")
16923 #ifndef __clang__
16924 #pragma inline_recursion(off)
16925 #endif
16926 #endif
16927 TOML_POP_WARNINGS;
16928 
16929 #endif // TOML_ENABLE_FORMATTERS
16930 
16931 //********  impl/toml_formatter.inl  ***********************************************************************************
16932 
16933 #if TOML_ENABLE_FORMATTERS
16934 
16935 TOML_PUSH_WARNINGS;
16936 #ifdef _MSC_VER
16937 #ifndef __clang__
16938 #pragma inline_recursion(on)
16939 #endif
16940 #pragma push_macro("min")
16941 #pragma push_macro("max")
16942 #undef min
16943 #undef max
16944 #endif
16945 
16946 TOML_DISABLE_ARITHMETIC_WARNINGS;
16947 
16948 TOML_ANON_NAMESPACE_START
16949 {
16950     TOML_INTERNAL_LINKAGE
16951     size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept
16952     {
16953         switch (node.type())
16954         {
16955             case node_type::table:
16956             {
16957                 auto& tbl = *reinterpret_cast<const table*>(&node);
16958                 if (tbl.empty())
16959                     return 2u;      // "{}"
16960                 size_t weight = 3u; // "{ }"
16961                 for (auto&& [k, v] : tbl)
16962                 {
16963                     weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // +  ", "
16964                     if (weight >= line_wrap_cols)
16965                         break;
16966                 }
16967                 return weight;
16968             }
16969 
16970             case node_type::array:
16971             {
16972                 auto& arr = *reinterpret_cast<const array*>(&node);
16973                 if (arr.empty())
16974                     return 2u;      // "[]"
16975                 size_t weight = 3u; // "[ ]"
16976                 for (auto& elem : arr)
16977                 {
16978                     weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // +  ", "
16979                     if (weight >= line_wrap_cols)
16980                         break;
16981                 }
16982                 return weight;
16983             }
16984 
16985             case node_type::string:
16986             {
16987                 // todo: proper utf8 decoding?
16988                 // todo: tab awareness?
16989                 auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
16990                 return str.length() + 2u; // + ""
16991             }
16992 
16993             case node_type::integer:
16994             {
16995                 auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
16996                 if (!val)
16997                     return 1u;
16998                 size_t weight = {};
16999                 if (val < 0)
17000                 {
17001                     weight += 1u;
17002                     val *= -1;
17003                 }
17004                 return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
17005             }
17006 
17007             case node_type::floating_point:
17008             {
17009                 auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
17010                 if (val == 0.0)
17011                     return 3u;      // "0.0"
17012                 size_t weight = 2u; // ".0"
17013                 if (val < 0.0)
17014                 {
17015                     weight += 1u;
17016                     val *= -1.0;
17017                 }
17018                 return weight + static_cast<size_t>(log10(val)) + 1u;
17019             }
17020 
17021             case node_type::boolean: return 5u;
17022             case node_type::date: [[fallthrough]];
17023             case node_type::time: return 10u;
17024             case node_type::date_time: return 30u;
17025             case node_type::none: TOML_UNREACHABLE;
17026             default: TOML_UNREACHABLE;
17027         }
17028 
17029         TOML_UNREACHABLE;
17030     }
17031 
17032     TOML_INTERNAL_LINKAGE
17033     bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept
17034     {
17035         return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols;
17036     }
17037 }
17038 TOML_ANON_NAMESPACE_END;
17039 
17040 TOML_NAMESPACE_START
17041 {
17042     TOML_EXTERNAL_LINKAGE
17043     void toml_formatter::print_pending_table_separator()
17044     {
17045         if (pending_table_separator_)
17046         {
17047             print_newline(true);
17048             print_newline(true);
17049             pending_table_separator_ = false;
17050         }
17051     }
17052 
17053     TOML_EXTERNAL_LINKAGE
17054     void toml_formatter::print(const key& k)
17055     {
17056         print_string(k.str(), false, true, false);
17057     }
17058 
17059     TOML_EXTERNAL_LINKAGE
17060     void toml_formatter::print_inline(const table& tbl)
17061     {
17062         if (tbl.empty())
17063         {
17064             print_unformatted("{}"sv);
17065             return;
17066         }
17067 
17068         print_unformatted("{ "sv);
17069 
17070         bool first = false;
17071         for (auto&& [k, v] : tbl)
17072         {
17073             if (first)
17074                 print_unformatted(", "sv);
17075             first = true;
17076 
17077             print(k);
17078             if (terse_kvps())
17079                 print_unformatted("="sv);
17080             else
17081                 print_unformatted(" = "sv);
17082 
17083             const auto type = v.type();
17084             TOML_ASSUME(type != node_type::none);
17085             switch (type)
17086             {
17087                 case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
17088                 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17089                 default: print_value(v, type);
17090             }
17091         }
17092 
17093         print_unformatted(" }"sv);
17094     }
17095 
17096     TOML_EXTERNAL_LINKAGE
17097     void toml_formatter::print(const array& arr)
17098     {
17099         if (arr.empty())
17100         {
17101             print_unformatted("[]"sv);
17102             return;
17103         }
17104 
17105         const auto original_indent = indent();
17106         const auto multiline       = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
17107               arr,
17108               120u,
17109               indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
17110 
17111         print_unformatted("["sv);
17112 
17113         if (multiline)
17114         {
17115             if (original_indent < 0)
17116                 indent(0);
17117             if (indent_array_elements())
17118                 increase_indent();
17119         }
17120         else
17121             print_unformatted(' ');
17122 
17123         for (size_t i = 0; i < arr.size(); i++)
17124         {
17125             if (i > 0u)
17126             {
17127                 print_unformatted(',');
17128                 if (!multiline)
17129                     print_unformatted(' ');
17130             }
17131 
17132             if (multiline)
17133             {
17134                 print_newline(true);
17135                 print_indent();
17136             }
17137 
17138             auto& v         = arr[i];
17139             const auto type = v.type();
17140             TOML_ASSUME(type != node_type::none);
17141             switch (type)
17142             {
17143                 case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
17144                 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17145                 default: print_value(v, type);
17146             }
17147         }
17148         if (multiline)
17149         {
17150             indent(original_indent);
17151             print_newline(true);
17152             print_indent();
17153         }
17154         else
17155             print_unformatted(' ');
17156 
17157         print_unformatted("]"sv);
17158     }
17159 
17160     TOML_EXTERNAL_LINKAGE
17161     void toml_formatter::print(const table& tbl)
17162     {
17163         static constexpr auto is_non_inline_array_of_tables = [](const node& n) noexcept
17164         {
17165             const auto arr = n.as_array();
17166             if (!arr || !arr->is_array_of_tables())
17167                 return false;
17168 
17169             return !reinterpret_cast<const table*>(&(*arr)[0])->is_inline();
17170         };
17171 
17172         // values, arrays, and inline tables/table arrays
17173         for (auto&& [k, v] : tbl)
17174         {
17175             const auto type = v.type();
17176             if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
17177                 || (type == node_type::array && is_non_inline_array_of_tables(v)))
17178                 continue;
17179 
17180             pending_table_separator_ = true;
17181             print_newline();
17182             print_indent();
17183             print(k);
17184             if (terse_kvps())
17185                 print_unformatted("="sv);
17186             else
17187                 print_unformatted(" = "sv);
17188             TOML_ASSUME(type != node_type::none);
17189             switch (type)
17190             {
17191                 case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
17192                 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17193                 default: print_value(v, type);
17194             }
17195         }
17196 
17197         const auto print_key_path = [&]()
17198         {
17199             size_t i{};
17200             for (const auto k : key_path_)
17201             {
17202                 if (i++)
17203                     print_unformatted('.');
17204                 print(*k);
17205             }
17206         };
17207 
17208         // non-inline tables
17209         for (auto&& [k, v] : tbl)
17210         {
17211             const auto type = v.type();
17212             if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
17213                 continue;
17214             auto& child_tbl = *reinterpret_cast<const table*>(&v);
17215 
17216             // we can skip indenting and emitting the headers for tables that only contain other tables
17217             // (so we don't over-nest)
17218             size_t child_value_count{}; // includes inline tables and non-table arrays
17219             size_t child_table_count{};
17220             size_t child_table_array_count{};
17221             for (auto&& [child_k, child_v] : child_tbl)
17222             {
17223                 TOML_UNUSED(child_k);
17224                 const auto child_type = child_v.type();
17225                 TOML_ASSUME(child_type != node_type::none);
17226                 switch (child_type)
17227                 {
17228                     case node_type::table:
17229                         if (reinterpret_cast<const table*>(&child_v)->is_inline())
17230                             child_value_count++;
17231                         else
17232                             child_table_count++;
17233                         break;
17234 
17235                     case node_type::array:
17236                         if (is_non_inline_array_of_tables(child_v))
17237                             child_table_array_count++;
17238                         else
17239                             child_value_count++;
17240                         break;
17241 
17242                     default: child_value_count++;
17243                 }
17244             }
17245             bool skip_self = false;
17246             if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u))
17247                 skip_self = true;
17248 
17249             key_path_.push_back(&k);
17250 
17251             if (!skip_self)
17252             {
17253                 print_pending_table_separator();
17254                 if (indent_sub_tables())
17255                     increase_indent();
17256                 print_indent();
17257                 print_unformatted("["sv);
17258                 print_key_path();
17259                 print_unformatted("]"sv);
17260                 pending_table_separator_ = true;
17261             }
17262 
17263             print(child_tbl);
17264 
17265             key_path_.pop_back();
17266             if (!skip_self && indent_sub_tables())
17267                 decrease_indent();
17268         }
17269 
17270         // table arrays
17271         for (auto&& [k, v] : tbl)
17272         {
17273             if (!is_non_inline_array_of_tables(v))
17274                 continue;
17275             auto& arr = *reinterpret_cast<const array*>(&v);
17276 
17277             if (indent_sub_tables())
17278                 increase_indent();
17279             key_path_.push_back(&k);
17280 
17281             for (size_t i = 0; i < arr.size(); i++)
17282             {
17283                 print_pending_table_separator();
17284                 print_indent();
17285                 print_unformatted("[["sv);
17286                 print_key_path();
17287                 print_unformatted("]]"sv);
17288                 pending_table_separator_ = true;
17289                 print(*reinterpret_cast<const table*>(&arr[i]));
17290             }
17291 
17292             key_path_.pop_back();
17293             if (indent_sub_tables())
17294                 decrease_indent();
17295         }
17296     }
17297 
17298     TOML_EXTERNAL_LINKAGE
17299     void toml_formatter::print()
17300     {
17301         if (dump_failed_parse_result())
17302             return;
17303 
17304         switch (auto source_type = source().type())
17305         {
17306             case node_type::table:
17307             {
17308                 auto& tbl = *reinterpret_cast<const table*>(&source());
17309                 if (tbl.is_inline())
17310                     print_inline(tbl);
17311                 else
17312                 {
17313                     decrease_indent(); // so root kvps and tables have the same indent
17314                     print(tbl);
17315                 }
17316                 break;
17317             }
17318 
17319             case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
17320 
17321             default: print_value(source(), source_type);
17322         }
17323     }
17324 }
17325 TOML_NAMESPACE_END;
17326 
17327 #ifdef _MSC_VER
17328 #pragma pop_macro("min")
17329 #pragma pop_macro("max")
17330 #ifndef __clang__
17331 #pragma inline_recursion(off)
17332 #endif
17333 #endif
17334 TOML_POP_WARNINGS;
17335 
17336 #endif // TOML_ENABLE_FORMATTERS
17337 
17338 //********  impl/json_formatter.inl  ***********************************************************************************
17339 
17340 #if TOML_ENABLE_FORMATTERS
17341 
17342 TOML_PUSH_WARNINGS;
17343 #ifdef _MSC_VER
17344 #ifndef __clang__
17345 #pragma inline_recursion(on)
17346 #endif
17347 #pragma push_macro("min")
17348 #pragma push_macro("max")
17349 #undef min
17350 #undef max
17351 #endif
17352 
17353 TOML_NAMESPACE_START
17354 {
17355     TOML_EXTERNAL_LINKAGE
17356     void json_formatter::print(const toml::table& tbl)
17357     {
17358         if (tbl.empty())
17359         {
17360             print_unformatted("{}"sv);
17361             return;
17362         }
17363 
17364         print_unformatted('{');
17365 
17366         if (indent_sub_tables())
17367             increase_indent();
17368         bool first = false;
17369         for (auto&& [k, v] : tbl)
17370         {
17371             if (first)
17372                 print_unformatted(',');
17373             first = true;
17374             print_newline(true);
17375             print_indent();
17376 
17377             print_string(k.str(), false);
17378             if (terse_kvps())
17379                 print_unformatted(":"sv);
17380             else
17381                 print_unformatted(" : "sv);
17382 
17383             const auto type = v.type();
17384             TOML_ASSUME(type != node_type::none);
17385             switch (type)
17386             {
17387                 case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
17388                 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17389                 default: print_value(v, type);
17390             }
17391         }
17392         if (indent_sub_tables())
17393             decrease_indent();
17394         print_newline(true);
17395         print_indent();
17396 
17397         print_unformatted('}');
17398     }
17399 
17400     TOML_EXTERNAL_LINKAGE
17401     void json_formatter::print(const toml::array& arr)
17402     {
17403         if (arr.empty())
17404         {
17405             print_unformatted("[]"sv);
17406             return;
17407         }
17408 
17409         print_unformatted('[');
17410         if (indent_array_elements())
17411             increase_indent();
17412         for (size_t i = 0; i < arr.size(); i++)
17413         {
17414             if (i > 0u)
17415                 print_unformatted(',');
17416             print_newline(true);
17417             print_indent();
17418 
17419             auto& v         = arr[i];
17420             const auto type = v.type();
17421             TOML_ASSUME(type != node_type::none);
17422             switch (type)
17423             {
17424                 case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
17425                 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17426                 default: print_value(v, type);
17427             }
17428         }
17429         if (indent_array_elements())
17430             decrease_indent();
17431         print_newline(true);
17432         print_indent();
17433         print_unformatted(']');
17434     }
17435 
17436     TOML_EXTERNAL_LINKAGE
17437     void json_formatter::print()
17438     {
17439         if (dump_failed_parse_result())
17440             return;
17441 
17442         switch (auto source_type = source().type())
17443         {
17444             case node_type::table: print(*reinterpret_cast<const table*>(&source())); break;
17445             case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
17446             default: print_value(source(), source_type);
17447         }
17448     }
17449 }
17450 TOML_NAMESPACE_END;
17451 
17452 #ifdef _MSC_VER
17453 #pragma pop_macro("min")
17454 #pragma pop_macro("max")
17455 #ifndef __clang__
17456 #pragma inline_recursion(off)
17457 #endif
17458 #endif
17459 TOML_POP_WARNINGS;
17460 
17461 #endif // TOML_ENABLE_FORMATTERS
17462 
17463 //********  impl/yaml_formatter.inl  ***********************************************************************************
17464 
17465 #if TOML_ENABLE_FORMATTERS
17466 
17467 TOML_PUSH_WARNINGS;
17468 #ifdef _MSC_VER
17469 #ifndef __clang__
17470 #pragma inline_recursion(on)
17471 #endif
17472 #pragma push_macro("min")
17473 #pragma push_macro("max")
17474 #undef min
17475 #undef max
17476 #endif
17477 
17478 TOML_NAMESPACE_START
17479 {
17480     TOML_EXTERNAL_LINKAGE
17481     void yaml_formatter::print_yaml_string(const value<std::string>& str)
17482     {
17483         if (str->empty())
17484         {
17485             base::print(str);
17486             return;
17487         }
17488 
17489         bool contains_newline = false;
17490         for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
17491             contains_newline = *c == '\n';
17492 
17493         if (contains_newline)
17494         {
17495             print_unformatted("|-"sv);
17496 
17497             increase_indent();
17498 
17499             auto line_end  = str->c_str() - 1u;
17500             const auto end = str->c_str() + str->length();
17501             while (line_end != end)
17502             {
17503                 auto line_start = line_end + 1u;
17504                 line_end        = line_start;
17505                 for (; line_end != end && *line_end != '\n'; line_end++)
17506                     ;
17507 
17508                 if TOML_LIKELY(line_start != line_end || line_end != end)
17509                 {
17510                     print_newline();
17511                     print_indent();
17512                     print_unformatted(std::string_view{ line_start, static_cast<size_t>(line_end - line_start) });
17513                 }
17514             }
17515 
17516             decrease_indent();
17517         }
17518         else
17519             print_string(*str, false, true);
17520     }
17521 
17522     TOML_EXTERNAL_LINKAGE
17523     void yaml_formatter::print(const toml::table& tbl, bool parent_is_array)
17524     {
17525         if (tbl.empty())
17526         {
17527             print_unformatted("{}"sv);
17528             return;
17529         }
17530 
17531         increase_indent();
17532 
17533         for (auto&& [k, v] : tbl)
17534         {
17535             if (!parent_is_array)
17536             {
17537                 print_newline();
17538                 print_indent();
17539             }
17540             parent_is_array = false;
17541 
17542             print_string(k.str(), false, true);
17543             if (terse_kvps())
17544                 print_unformatted(":"sv);
17545             else
17546                 print_unformatted(": "sv);
17547 
17548             const auto type = v.type();
17549             TOML_ASSUME(type != node_type::none);
17550             switch (type)
17551             {
17552                 case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
17553                 case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
17554                 case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
17555                 default: print_value(v, type);
17556             }
17557         }
17558 
17559         decrease_indent();
17560     }
17561 
17562     TOML_EXTERNAL_LINKAGE
17563     void yaml_formatter::print(const toml::array& arr, bool parent_is_array)
17564     {
17565         if (arr.empty())
17566         {
17567             print_unformatted("[]"sv);
17568             return;
17569         }
17570 
17571         increase_indent();
17572 
17573         for (auto&& v : arr)
17574         {
17575             if (!parent_is_array)
17576             {
17577                 print_newline();
17578                 print_indent();
17579             }
17580             parent_is_array = false;
17581 
17582             print_unformatted("- "sv);
17583 
17584             const auto type = v.type();
17585             TOML_ASSUME(type != node_type::none);
17586             switch (type)
17587             {
17588                 case node_type::table: print(*reinterpret_cast<const table*>(&v), true); break;
17589                 case node_type::array: print(*reinterpret_cast<const array*>(&v), true); break;
17590                 case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
17591                 default: print_value(v, type);
17592             }
17593         }
17594 
17595         decrease_indent();
17596     }
17597 
17598     TOML_EXTERNAL_LINKAGE
17599     void yaml_formatter::print()
17600     {
17601         if (dump_failed_parse_result())
17602             return;
17603 
17604         switch (auto source_type = source().type())
17605         {
17606             case node_type::table:
17607                 decrease_indent(); // so root kvps and tables have the same indent
17608                 print(*reinterpret_cast<const table*>(&source()));
17609                 break;
17610 
17611             case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
17612 
17613             case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&source())); break;
17614 
17615             default: print_value(source(), source_type);
17616         }
17617     }
17618 }
17619 TOML_NAMESPACE_END;
17620 
17621 #ifdef _MSC_VER
17622 #pragma pop_macro("min")
17623 #pragma pop_macro("max")
17624 #ifndef __clang__
17625 #pragma inline_recursion(off)
17626 #endif
17627 #endif
17628 TOML_POP_WARNINGS;
17629 
17630 #endif // TOML_ENABLE_FORMATTERS
17631 
17632 #endif // TOML_IMPLEMENTATION
17633 
17634 TOML_POP_WARNINGS;
17635 
17636 // macro hygiene
17637 #if TOML_UNDEF_MACROS
17638 #undef TOML_ABI_NAMESPACE_BOOL
17639 #undef TOML_ABI_NAMESPACE_END
17640 #undef TOML_ABI_NAMESPACE_START
17641 #undef TOML_ABI_NAMESPACES
17642 #undef TOML_ABSTRACT_INTERFACE
17643 #undef TOML_ALWAYS_INLINE
17644 #undef TOML_ANON_NAMESPACE
17645 #undef TOML_ANON_NAMESPACE_END
17646 #undef TOML_ANON_NAMESPACE_START
17647 #undef TOML_ARCH_AMD64
17648 #undef TOML_ARCH_ARM
17649 #undef TOML_ARCH_ARM32
17650 #undef TOML_ARCH_ARM64
17651 #undef TOML_ARCH_BITNESS
17652 #undef TOML_ARCH_ITANIUM
17653 #undef TOML_ARCH_X64
17654 #undef TOML_ARCH_X86
17655 #undef TOML_ASSERT
17656 #undef TOML_ASSERT_ASSUME
17657 #undef TOML_ASSUME
17658 #undef TOML_ASYMMETRICAL_EQUALITY_OPS
17659 #undef TOML_ATTR
17660 #undef TOML_CLANG
17661 #undef TOML_CLANG_VERSION
17662 #undef TOML_CLOSED_ENUM
17663 #undef TOML_CLOSED_FLAGS_ENUM
17664 #undef TOML_COMPILER_HAS_EXCEPTIONS
17665 #undef TOML_COMPILER_HAS_RTTI
17666 #undef TOML_CONST
17667 #undef TOML_CONST_GETTER
17668 #undef TOML_CONST_INLINE_GETTER
17669 #undef TOML_CONSTRAINED_TEMPLATE
17670 #undef TOML_CPP
17671 #undef TOML_DECLSPEC
17672 #undef TOML_DELETE_DEFAULTS
17673 #undef TOML_DISABLE_ARITHMETIC_WARNINGS
17674 #undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
17675 #undef TOML_DISABLE_SPAM_WARNINGS
17676 #undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
17677 #undef TOML_DISABLE_SPAM_WARNINGS_CLANG_11
17678 #undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
17679 #undef TOML_DISABLE_SWITCH_WARNINGS
17680 #undef TOML_DISABLE_WARNINGS
17681 #undef TOML_DOXYGEN
17682 #undef TOML_EMPTY_BASES
17683 #undef TOML_ENABLE_IF
17684 #undef TOML_ENABLE_WARNINGS
17685 #undef TOML_EVAL_BOOL_0
17686 #undef TOML_EVAL_BOOL_1
17687 #undef TOML_EXTERNAL_LINKAGE
17688 #undef TOML_FLAGS_ENUM
17689 #undef TOML_FLOAT_CHARCONV
17690 #undef TOML_FLOAT128
17691 #undef TOML_FLOAT16_DIG
17692 #undef TOML_FLOAT16_LIMITS_SET
17693 #undef TOML_FLOAT16_MANT_DIG
17694 #undef TOML_FLOAT16_MAX_10_EXP
17695 #undef TOML_FLOAT16_MAX_EXP
17696 #undef TOML_FLOAT16_MIN_10_EXP
17697 #undef TOML_FLOAT16_MIN_EXP
17698 #undef TOML_GCC
17699 #undef TOML_GCC_LIKE
17700 #undef TOML_HAS_ATTR
17701 #undef TOML_HAS_BUILTIN
17702 #undef TOML_HAS_CHAR8
17703 #undef TOML_HAS_CPP_ATTR
17704 #undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
17705 #undef TOML_HAS_FEATURE
17706 #undef TOML_HAS_INCLUDE
17707 #undef TOML_HAS_SSE2
17708 #undef TOML_HAS_SSE4_1
17709 #undef TOML_HIDDEN_CONSTRAINT
17710 #undef TOML_ICC
17711 #undef TOML_ICC_CL
17712 #undef TOML_IMPL_NAMESPACE_END
17713 #undef TOML_IMPL_NAMESPACE_START
17714 #undef TOML_IMPLEMENTATION
17715 #undef TOML_INCLUDE_WINDOWS_H
17716 #undef TOML_INLINE_GETTER
17717 #undef TOML_INT_CHARCONV
17718 #undef TOML_INT128
17719 #undef TOML_INTELLISENSE
17720 #undef TOML_INTERNAL_LINKAGE
17721 #undef TOML_LANG_AT_LEAST
17722 #undef TOML_LANG_EFFECTIVE_VERSION
17723 #undef TOML_LANG_HIGHER_THAN
17724 #undef TOML_LANG_UNRELEASED
17725 #undef TOML_LAUNDER
17726 #undef TOML_LIFETIME_HOOKS
17727 #undef TOML_LIKELY
17728 #undef TOML_LIKELY_CASE
17729 #undef TOML_LINUX
17730 #undef TOML_MAKE_FLAGS
17731 #undef TOML_MAKE_FLAGS_
17732 #undef TOML_MAKE_FLAGS_1
17733 #undef TOML_MAKE_FLAGS_2
17734 #undef TOML_MAKE_STRING
17735 #undef TOML_MAKE_STRING_1
17736 #undef TOML_MAKE_VERSION
17737 #undef TOML_MSVC
17738 #undef TOML_MSVC_LIKE
17739 #undef TOML_NAMESPACE
17740 #undef TOML_NEVER_INLINE
17741 #undef TOML_NODISCARD
17742 #undef TOML_NODISCARD_CTOR
17743 #undef TOML_NVCC
17744 #undef TOML_OPEN_ENUM
17745 #undef TOML_OPEN_FLAGS_ENUM
17746 #undef TOML_PARSER_TYPENAME
17747 #undef TOML_POP_WARNINGS
17748 #undef TOML_PRAGMA_CLANG
17749 #undef TOML_PRAGMA_CLANG_GE_10
17750 #undef TOML_PRAGMA_CLANG_GE_11
17751 #undef TOML_PRAGMA_CLANG_GE_8
17752 #undef TOML_PRAGMA_CLANG_GE_9
17753 #undef TOML_PRAGMA_GCC
17754 #undef TOML_PRAGMA_ICC
17755 #undef TOML_PRAGMA_MSVC
17756 #undef TOML_PURE
17757 #undef TOML_PURE_GETTER
17758 #undef TOML_PURE_INLINE_GETTER
17759 #undef TOML_PUSH_WARNINGS
17760 #undef TOML_REQUIRES
17761 #undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
17762 #undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
17763 #undef TOML_SA_LIST_BEG
17764 #undef TOML_SA_LIST_END
17765 #undef TOML_SA_LIST_NEW
17766 #undef TOML_SA_LIST_NXT
17767 #undef TOML_SA_LIST_SEP
17768 #undef TOML_SA_NATIVE_VALUE_TYPE_LIST
17769 #undef TOML_SA_NEWLINE
17770 #undef TOML_SA_NODE_TYPE_LIST
17771 #undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
17772 #undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
17773 #undef TOML_SA_VALUE_FUNC_MESSAGE
17774 #undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
17775 #undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
17776 #undef TOML_SA_VALUE_MESSAGE_WSTRING
17777 #undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
17778 #undef TOML_TRIVIAL_ABI
17779 #undef TOML_UINT128
17780 #undef TOML_UNIX
17781 #undef TOML_UNLIKELY
17782 #undef TOML_UNLIKELY_CASE
17783 #undef TOML_UNREACHABLE
17784 #undef TOML_UNUSED
17785 #undef TOML_WINDOWS
17786 #endif
17787 
17788 #endif // TOMLPLUSPLUS_HPP