File indexing completed on 2025-01-18 10:17:31
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #ifndef TOMLPLUSPLUS_HPP
0045 #define TOMLPLUSPLUS_HPP
0046
0047 #define INCLUDE_TOMLPLUSPLUS_H
0048 #define TOMLPLUSPLUS_H
0049
0050
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:
0094 #elif TOML_CPP < 17
0095 #error toml++ requires C++17 or higher. For a C++11 TOML library see https:
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
0127
0128
0129
0130
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
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
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
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
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
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
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
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
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
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
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
0381 #define TOML_CONCAT_1(x, y) x##y
0382 #define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)
0383
0384
0385 #define TOML_MAKE_STRING_1(s) #s
0386 #define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s)
0387
0388
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
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
0444 #ifndef TOML_NEVER_INLINE
0445 #ifdef _MSC_VER
0446 #define TOML_NEVER_INLINE TOML_DECLSPEC(noinline)
0447 #elif TOML_CUDA
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)) \
0758 __pragma(warning(disable : 26819)) \
0759 static_assert(true)
0760
0761 #define TOML_DISABLE_SPAM_WARNINGS \
0762 __pragma(warning(disable : 4127)) \
0763 __pragma(warning(disable : 4324)) \
0764 __pragma(warning(disable : 4348)) \
0765 __pragma(warning(disable : 4464)) \
0766 __pragma(warning(disable : 4505)) \
0767 __pragma(warning(disable : 4514)) \
0768 __pragma(warning(disable : 4582)) \
0769 __pragma(warning(disable : 4619)) \
0770 __pragma(warning(disable : 4623)) \
0771 __pragma(warning(disable : 4625)) \
0772 __pragma(warning(disable : 4626)) \
0773 __pragma(warning(disable : 4710)) \
0774 __pragma(warning(disable : 4711)) \
0775 __pragma(warning(disable : 4820)) \
0776 __pragma(warning(disable : 4946)) \
0777 __pragma(warning(disable : 5026)) \
0778 __pragma(warning(disable : 5027)) \
0779 __pragma(warning(disable : 5039)) \
0780 __pragma(warning(disable : 5045)) \
0781 __pragma(warning(disable : 5264)) \
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)) \
0791 __pragma(warning(disable : 4738)) \
0792 __pragma(warning(disable : 5219)) \
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)) \
0821 __pragma(warning(disable : 111)) \
0822 __pragma(warning(disable : 869)) \
0823 __pragma(warning(disable : 1011)) \
0824 __pragma(warning(disable : 2261)) \
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
0934 #ifndef TOML_SHARED_LIB
0935 #define TOML_SHARED_LIB 0
0936 #endif
0937
0938
0939 #if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE)
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
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
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
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
1006 #if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES)
1007
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
1019 #if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER)
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
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
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
1040 #if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT)
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
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
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
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
1091
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
1134
1135 #define TOML_FLOAT_CHARCONV 0
1136 #endif
1137 #if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__))
1138
1139
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
1177
1178
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
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
1250
1251
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
1303
1304 TOML_PUSH_WARNINGS;
1305 TOML_DISABLE_SPAM_WARNINGS;
1306 TOML_DISABLE_SWITCH_WARNINGS;
1307 TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
1308
1309
1310 #if TOML_MSVC
1311 #pragma warning(disable : 5031)
1312 #if TOML_SHARED_LIB
1313 #pragma warning(disable : 4251)
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
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
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
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
1383
1384
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
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
1455
1456
1457
1458 namespace toml
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;
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;
1523
1524
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
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
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
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
1785
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
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
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
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
1952 && digits10 <= 15;
1953
1954 static constexpr bool can_represent_native = digits >= 53
1955 && digits10 >= 15;
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
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
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
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
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;
2064 static constexpr bool can_represent_native = std::is_same_v<T, std::wstring>;
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
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
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
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
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
2317
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
2345
2346
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
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
2393
2394
2395
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
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
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{}
2890 {}
2891
2892 TOML_NODISCARD_CTOR
2893 explicit constexpr date_time(const toml::date& d) noexcept
2894 : date{ d },
2895 time{},
2896 offset{}
2897 {}
2898
2899 TOML_NODISCARD_CTOR
2900 explicit constexpr date_time(const toml::time& t) noexcept
2901 : date{},
2902 time{ t },
2903 offset{}
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;
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
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
3025
3026 TOML_DISABLE_WARNINGS;
3027 #include <vector>
3028 #include <iterator>
3029 TOML_ENABLE_WARNINGS;
3030
3031
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
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
3625
3626 TOML_DISABLE_WARNINGS;
3627 #include <utility>
3628 TOML_ENABLE_WARNINGS;
3629
3630
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
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
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
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
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
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
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
4264
4265 TOML_DISABLE_WARNINGS;
4266 #include <initializer_list>
4267 TOML_ENABLE_WARNINGS;
4268
4269
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
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
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
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
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
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
4947
4948 #endif
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)
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_;
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
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
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
5672
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
5682 else
5683 {
5684 switch (type())
5685 {
5686
5687 case node_type::integer:
5688 {
5689
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
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
5712 else if constexpr (is_natively_one_of<T, bool>)
5713 return static_cast<bool>(*ref_cast<int64_t>());
5714
5715
5716 else
5717 return {};
5718 }
5719
5720
5721 case node_type::floating_point:
5722 {
5723
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
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
5750 else
5751 return {};
5752 }
5753
5754
5755 case node_type::boolean:
5756 {
5757
5758 if constexpr (is_natively_one_of<T, bool>)
5759 return { *ref_cast<bool>() };
5760
5761
5762 else if constexpr (is_natively_one_of<T, int64_t>)
5763 return { static_cast<T>(*ref_cast<bool>()) };
5764
5765
5766 else
5767 return {};
5768 }
5769 }
5770
5771
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
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
5849
5850
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
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
5904 if constexpr (is_one_of<unwrapped_type, array, table>)
5905 {
5906 return new unwrapped_type(static_cast<T&&>(val));
5907 }
5908
5909
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
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
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
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
6140 {
6141 ++iter_;
6142 return *this;
6143 }
6144
6145 array_iterator operator++(int) noexcept
6146 {
6147 array_iterator out{ iter_ };
6148 ++iter_;
6149 return out;
6150 }
6151
6152 array_iterator& operator--() noexcept
6153 {
6154 --iter_;
6155 return *this;
6156 }
6157
6158 array_iterator operator--(int) noexcept
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[];
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
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
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
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
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
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
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
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
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
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
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
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 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
7482
7483 TOML_DISABLE_WARNINGS;
7484 #include <map>
7485 #include <iterator>
7486 TOML_ENABLE_WARNINGS;
7487
7488
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
7581 {
7582 ++iter_;
7583 proxy_instantiated_ = false;
7584 return *this;
7585 }
7586
7587 table_iterator operator++(int) noexcept
7588 {
7589 table_iterator out{ iter_ };
7590 ++iter_;
7591 proxy_instantiated_ = false;
7592 return out;
7593 }
7594
7595 table_iterator& operator--() noexcept
7596 {
7597 --iter_;
7598 proxy_instantiated_ = false;
7599 return *this;
7600 }
7601
7602 table_iterator operator--(int) noexcept
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
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
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
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
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
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
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
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
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
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
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
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
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
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
8438
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 });
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[];
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
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
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")
8699 #endif
8700
8701
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
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
8751 if TOML_UNLIKELY(c == U'+')
8752 return true;
8753 #endif
8754
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
8764
8765 TOML_CONST_GETTER
8766 constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept
8767 {
8768
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:
8779 {
8780
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
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
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
8932 ? 10u + (c | 0x20u) - 0x61u
8933 : c - 0x30u
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
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
9000
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
9082
9083 #if TOML_ENABLE_PARSER
9084
9085
9086
9087 TOML_DISABLE_WARNINGS;
9088 #if TOML_EXCEPTIONS
9089 #include <stdexcept>
9090 #endif
9091 TOML_ENABLE_WARNINGS;
9092
9093
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;
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
9208
9209
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 operator toml::table&() noexcept
9360 {
9361 return table();
9362 }
9363
9364 TOML_NODISCARD
9365 operator toml::table&&() noexcept
9366 {
9367 return std::move(table());
9368 }
9369
9370 TOML_NODISCARD
9371 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
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
9559
9560
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
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
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
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;
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
9662
9663 TOML_ABI_NAMESPACE_END;
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
9678
9679
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_;
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
9881
9882
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,
9926 format_flags::none,
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;
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
9986
9987
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,
10021 format_flags::allow_literal_strings | format_flags::allow_multi_line_strings,
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;
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
10076
10077
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,
10115 format_flags::allow_multi_line_strings,
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;
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
10171
10172 #if TOML_IMPLEMENTATION
10173
10174
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
10200 #endif
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
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
10280
10281
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;
10313
10314 template <>
10315 inline constexpr size_t charconv_buffer_length<int16_t> = 6;
10316
10317 template <>
10318 inline constexpr size_t charconv_buffer_length<int32_t> = 11;
10319
10320 template <>
10321 inline constexpr size_t charconv_buffer_length<int64_t> = 20;
10322
10323 template <>
10324 inline constexpr size_t charconv_buffer_length<uint8_t> = 3;
10325
10326 template <>
10327 inline constexpr size_t charconv_buffer_length<uint16_t> = 5;
10328
10329 template <>
10330 inline constexpr size_t charconv_buffer_length<uint32_t> = 10;
10331
10332 template <>
10333 inline constexpr size_t charconv_buffer_length<uint64_t> = 20;
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
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& ) noexcept
10798 {
10799
10800
10801
10802 }
10803
10804 TOML_EXTERNAL_LINKAGE
10805 node& node::operator=(const node& ) noexcept
10806 {
10807
10808
10809
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
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
10884 if (lhs == rhs)
10885 return true;
10886
10887
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
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
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;
10947
10948 while (pos < end)
10949 {
10950
10951 if (path[pos] == '[')
10952 {
10953
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
10972 size_t index_end = index_start + 1u;
10973 while (true)
10974 {
10975
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
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
11012 auto index_str = path.substr(index_start, index_end - index_start);
11013
11014
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
11045 else if (path[pos] == '.')
11046 {
11047
11048
11049
11050
11051
11052
11053
11054
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
11065 else if TOML_UNLIKELY(path[pos] == ']')
11066 return false;
11067
11068
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
11077
11078
11079
11080
11081
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
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
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, ¤t, 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
11173
11174
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
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
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
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
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
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)
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)
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
11590
11591
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
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 {};
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
11679 return {};
11680 }
11681
11682 if (!current)
11683 return {};
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
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--;
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);
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
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)
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
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
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
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
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
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)
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
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
12784
12785
12786 if TOML_UNLIKELY(!raw_bytes_read)
12787 {
12788 if (stream_.eof())
12789 {
12790
12791
12792
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
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
12829 const auto ascii_fast_path = !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
12830
12831
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
12848 else
12849 {
12850
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
12898
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;
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
13028 if (!negative_offset_)
13029 return head_;
13030
13031
13032 else
13033 return history_.buffer
13034 + ((history_.first + history_.count - negative_offset_) % history_buffer_size);
13035 }
13036 else
13037 {
13038
13039 if TOML_UNLIKELY(!history_.count && !head_)
13040 head_ = reader_.read_next();
13041
13042
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;
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;
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;
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
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
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
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
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
13273 else if constexpr (std::is_floating_point_v<arg_type>)
13274 concatenate(write_pos, buf_end, static_cast<double>(arg));
13275
13276
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 });
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
13446
13447
13448
13449
13450
13451
13452
13453
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
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;
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({});
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({});
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({});
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
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
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
13835 advance_and_return_if_error_or_eof({});
13836
13837
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
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
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
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
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
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
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
13983 case 1:
13984 str += '"';
13985 skipping_whitespace = false;
13986 continue;
13987
13988
13989 case 2:
13990 str.append("\"\""sv);
13991 skipping_whitespace = false;
13992 continue;
13993
13994
13995 case 3: return str;
13996
13997
13998 case 4: str += '"'; return str;
13999
14000
14001 case 5:
14002 str.append("\"\""sv);
14003 advance_and_return_if_error({});
14004 return str;
14005
14006 default: TOML_UNREACHABLE;
14007 }
14008 }
14009 else
14010 {
14011 advance_and_return_if_error({});
14012 return str;
14013 }
14014 }
14015
14016
14017 else if (*cp == U'\\')
14018 {
14019 advance_and_return_if_error_or_eof({});
14020 skipping_whitespace = false;
14021 escaped = true;
14022 continue;
14023 }
14024
14025
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
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
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
14077 advance_and_return_if_error_or_eof({});
14078
14079
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
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
14114 case 1: str += '\''; continue;
14115
14116
14117 case 2: str.append("''"sv); continue;
14118
14119
14120 case 3: return str;
14121
14122
14123 case 4: str += '\''; return str;
14124
14125
14126 case 5:
14127 str.append("''"sv);
14128 advance_and_return_if_error({});
14129 return str;
14130
14131 default: TOML_UNREACHABLE;
14132 }
14133 }
14134 else
14135 {
14136 advance_and_return_if_error({});
14137 return str;
14138 }
14139 }
14140
14141
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
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
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
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
14187
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
14197
14198 else if (first == second && first == third)
14199 {
14200 return { first == U'\'' ? parse_literal_string(true) : parse_basic_string(true), true };
14201 }
14202
14203
14204 else
14205 {
14206
14207
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
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
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
14332
14333
14334 if (!first_integer_part)
14335 set_error_and_return_default("expected decimal digit, saw '.'"sv);
14336
14337
14338 else if (seen_exponent)
14339 set_error_and_return_default("expected exponent decimal digit or sign, saw '.'"sv);
14340
14341
14342
14343
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
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;
14359 seen_exponent = true;
14360 }
14361 else if (is_match(*cp, U'+', U'-'))
14362 {
14363
14364 if (!seen_exponent)
14365 set_error_and_return_default("expected decimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14366
14367
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
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
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{}:
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
14458
14459
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
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
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
14475
14476
14477 struct fragment
14478 {
14479 char chars[24];
14480 size_t length;
14481 double value;
14482 };
14483 fragment fragments[] = {
14484 {},
14485 {},
14486 {}
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
14507 if (current_fragment == fragments + 2)
14508 set_error_and_return_default("expected exponent digit or sign, saw '.'"sv);
14509
14510
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
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
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
14533 if (current_fragment != fragments + 2)
14534 set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
14535
14536
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
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
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
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
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
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
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
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
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
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
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
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
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
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
14726 else
14727 {
14728 if TOML_UNLIKELY(digits[0] == '0')
14729 set_error_and_return_default("leading zeroes are prohibited"sv);
14730 }
14731
14732
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
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
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
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
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
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
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;
14840
14841 uint32_t digits[max_digits];
14842
14843
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
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)
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
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
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
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++)
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
14928 auto date = parse_date(true);
14929 set_error_and_return_if_eof({});
14930
14931
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
14937 auto time = parse_time(true);
14938 return_if_error({});
14939
14940
14941 if (is_eof() || is_value_terminator(*cp))
14942 return { date, time };
14943
14944
14945 time_offset offset{};
14946 if (is_match(*cp, U'Z', U'z'))
14947 advance_and_return_if_error({});
14948
14949
14950 else if (is_match(*cp, U'+', U'-'))
14951 {
14952 push_parse_scope("date-time offset"sv);
14953
14954
14955 int sign = *cp == U'-' ? -1 : 1;
14956 advance_and_return_if_error_or_eof({});
14957
14958
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
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
15004 case U'[': return parse_array();
15005
15006
15007 case U'{': return parse_inline_table();
15008
15009
15010 case U'.': return node_ptr{ new value{ parse_float() } };
15011
15012
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
15021 if (cp_upper == 70u || cp_upper == 84u)
15022 return node_ptr{ new value{ parse_boolean() } };
15023
15024
15025 else if (cp_upper == 73u || cp_upper == 78u)
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
15050
15051
15052 if TOML_UNLIKELY(is_control_character(*cp))
15053 set_error_and_return_default("unexpected control character"sv);
15054
15055
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
15068
15069
15070
15071 val = parse_value_known_prefixes();
15072 return_if_error({});
15073 if (val)
15074 break;
15075
15076
15077
15078 enum TOML_CLOSED_FLAGS_ENUM value_traits : int
15079 {
15080 has_nothing = 0,
15081 has_digits = 1,
15082 has_b = 1 << 1,
15083 has_e = 1 << 2,
15084 has_o = 1 << 3,
15085 has_p = 1 << 4,
15086 has_t = 1 << 5,
15087 has_x = 1 << 6,
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
15106
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
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
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
15238 go_back(advance_count);
15239
15240
15241
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();
15248 break;
15249 }
15250
15251
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
15258 return_if_error({});
15259 TOML_ASSERT_ASSUME(char_count >= 2u);
15260
15261
15262
15263
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
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
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();
15299 advance();
15300 break;
15301 }
15302
15303
15304 if (is_decimal_digit(chars[1]) && chars[2] == U'.')
15305 val.reset(new value{ parse_float() });
15306
15307
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
15317
15318
15319
15320 switch (unwrap_enum(traits))
15321 {
15322
15323
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
15330
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
15337
15338
15339
15340
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
15347
15348
15349
15350
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
15363
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
15370
15371
15372
15373
15374
15375
15376
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
15385
15386
15387
15388
15389
15390
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
15399
15400
15401
15402
15403
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
15409
15410
15411
15412
15413
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
15422
15423
15424
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
15429
15430
15431
15432
15433
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
15438
15439
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
15444
15445
15446
15447
15448
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
15456
15457
15458
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
15465
15466 case bzero_msk | has_minus: [[fallthrough]];
15467 case bdigit_msk | has_minus: val.reset(new value{ parse_date() }); break;
15468
15469
15470
15471
15472
15473
15474
15475
15476
15477
15478
15479
15480
15481
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
15487
15488
15489
15490
15491
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
15497
15498
15499
15500
15501
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
15539 if (is_bare_key_character(*cp))
15540 key_segment = parse_bare_key_segment();
15541
15542
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
15573 consume_leading_whitespace();
15574
15575
15576 key_buffer.push_back(key_segment, key_begin, key_end);
15577
15578
15579 if (is_eof() || *cp != U'.')
15580 break;
15581
15582
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
15617 {
15618
15619 advance_and_return_if_error_or_eof({});
15620
15621
15622 const bool had_leading_whitespace = consume_leading_whitespace();
15623 set_error_and_return_if_eof({});
15624
15625
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
15636 consume_leading_whitespace();
15637 set_error_and_return_if_eof({});
15638 }
15639
15640
15641 if (*cp == U']')
15642 set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
15643
15644
15645 start_recording();
15646 parse_key();
15647 stop_recording(1u);
15648 return_if_error({});
15649
15650
15651 consume_leading_whitespace();
15652 return_if_error({});
15653 set_error_and_return_if_eof({});
15654
15655
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
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
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
15682 if (pit != parent->end() && pit->first == segment)
15683 {
15684 node& p = pit->second;
15685
15686 if (auto tbl = p.as_table())
15687 {
15688
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
15699
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
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
15736
15737
15738
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
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
15800 else
15801 {
15802 auto last_key = make_key(key_buffer.size() - 1u);
15803
15804
15805
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
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
15838 start_recording();
15839 parse_key();
15840 stop_recording(1u);
15841 return_if_error({});
15842 TOML_ASSERT(key_buffer.size() >= 1u);
15843
15844
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
15854 consume_leading_whitespace();
15855 return_if_error({});
15856 set_error_and_return_if_eof({});
15857
15858
15859 if (is_value_terminator(*cp))
15860 set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
15861
15862
15863
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
15872 if (pit != tbl->end() && pit->first == segment)
15873 {
15874 table* p = pit->second.as_table();
15875
15876
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
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
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
15918
15919 auto last_key = make_key(key_buffer.size() - 1u);
15920
15921
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
15942 if (consume_leading_whitespace() || consume_line_break() || consume_comment())
15943 continue;
15944 return_if_error();
15945
15946
15947
15948 if (*cp == U'[')
15949 current_table = parse_table_header();
15950
15951
15952
15953
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
15961
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())
15989
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
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
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
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
16098 else if (*cp == U']')
16099 {
16100 advance_and_return_if_error({});
16101 break;
16102 }
16103
16104
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
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)
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
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
16178 else if (*cp == U'}')
16179 {
16180 if constexpr (!TOML_LANG_UNRELEASED)
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
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;
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
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
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
16281 constexpr auto large_file_threshold = 1024 * 1024 * 2;
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
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
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
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
16389
16390 TOML_ABI_NAMESPACE_END;
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
16406
16407
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,
16428 tabs = 1u << 1,
16429 control_chars = 1u << 2,
16430 single_quotes = 1u << 3,
16431 non_bare = 1u << 4,
16432 non_ascii = 1u << 5,
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
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
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
16561 else
16562 {
16563 traits |= formatted_string_traits::non_ascii;
16564 utf8_decoder decoder;
16565
16566
16567
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
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
16617
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
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
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
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
16651 print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
16652
16653
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
16668 if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
16669 print_to_stream(*stream_, control_char_escapes[c]);
16670
16671
16672 else
16673 print_to_stream(*stream_, c);
16674 }
16675 }
16676 }
16677 }
16678
16679
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
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
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
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
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
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
16930
16931
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
16988
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;
17012 size_t weight = 2u;
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
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
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
17217
17218 size_t child_value_count{};
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
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();
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
17337
17338
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
17462
17463
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();
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
17631
17632 #endif
17633
17634 TOML_POP_WARNINGS;
17635
17636
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