aboutsummaryrefslogtreecommitdiffstats
path: root/include/toml.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/toml.hpp')
-rw-r--r--include/toml.hpp12089
1 files changed, 12089 insertions, 0 deletions
diff --git a/include/toml.hpp b/include/toml.hpp
new file mode 100644
index 0000000..c351d3a
--- /dev/null
+++ b/include/toml.hpp
@@ -0,0 +1,12089 @@
+//----------------------------------------------------------------------------------------------------------------------
+//
+// toml++ v2.2.0
+// https://github.com/marzer/tomlplusplus
+// SPDX-License-Identifier: MIT
+//
+//----------------------------------------------------------------------------------------------------------------------
+//
+// - THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY -
+//
+// If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this
+// file was assembled from a number of smaller files by a python script, and code contributions should not be made
+// against it directly. You should instead make your changes in the relevant source file(s). The file names of the files
+// that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file.
+//
+//----------------------------------------------------------------------------------------------------------------------
+//
+// TOML Language Specifications:
+// latest: https://github.com/toml-lang/toml/blob/master/README.md
+// v1.0.0-rc.3: https://toml.io/en/v1.0.0-rc.3
+// v1.0.0-rc.2: https://toml.io/en/v1.0.0-rc.2
+// v1.0.0-rc.1: https://toml.io/en/v1.0.0-rc.1
+// v0.5.0: https://toml.io/en/v0.5.0
+// changelog: https://github.com/toml-lang/toml/blob/master/CHANGELOG.md
+//
+//----------------------------------------------------------------------------------------------------------------------
+//
+// MIT License
+//
+// Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//----------------------------------------------------------------------------------------------------------------------
+#ifndef INCLUDE_TOMLPLUSPLUS_H
+#define INCLUDE_TOMLPLUSPLUS_H
+
+#if 1 //------ ↓ toml_preprocessor.h --------------------------------------------------------------------------------
+
+#ifndef __cplusplus
+ #error toml++ is a C++ library.
+#endif
+
+#ifdef __INTELLISENSE__
+ #define TOML_INTELLISENSE 1
+#else
+ #define TOML_INTELLISENSE 0
+#endif
+#ifdef __clang__
+ #define TOML_CLANG __clang_major__
+#else
+ #define TOML_CLANG 0
+#endif
+#ifdef __INTEL_COMPILER
+ #define TOML_ICC __INTEL_COMPILER
+ #ifdef __ICL
+ #define TOML_ICC_CL TOML_ICC
+ #else
+ #define TOML_ICC_CL 0
+ #endif
+#else
+ #define TOML_ICC 0
+ #define TOML_ICC_CL 0
+#endif
+#if defined(_MSC_VER) && !TOML_CLANG && !TOML_ICC
+ #define TOML_MSVC _MSC_VER
+#else
+ #define TOML_MSVC 0
+#endif
+#if defined(__GNUC__) && !TOML_CLANG && !TOML_ICC
+ #define TOML_GCC __GNUC__
+#else
+ #define TOML_GCC 0
+#endif
+
+#if TOML_CLANG
+
+ #define TOML_PUSH_WARNINGS _Pragma("clang diagnostic push")
+ #define TOML_DISABLE_SWITCH_WARNINGS _Pragma("clang diagnostic ignored \"-Wswitch\"")
+ #define TOML_DISABLE_INIT_WARNINGS _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"")
+ #define TOML_DISABLE_ARITHMETIC_WARNINGS _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
+ _Pragma("clang diagnostic ignored \"-Wdouble-promotion\"") \
+ _Pragma("clang diagnostic ignored \"-Wchar-subscripts\"") \
+ _Pragma("clang diagnostic ignored \"-Wshift-sign-overflow\"")
+ #define TOML_DISABLE_SHADOW_WARNINGS _Pragma("clang diagnostic ignored \"-Wshadow\"")
+ #define TOML_DISABLE_SPAM_WARNINGS _Pragma("clang diagnostic ignored \"-Wweak-vtables\"") \
+ _Pragma("clang diagnostic ignored \"-Wweak-template-vtables\"") \
+ _Pragma("clang diagnostic ignored \"-Wpadded\"")
+ #define TOML_POP_WARNINGS _Pragma("clang diagnostic pop")
+ #define TOML_DISABLE_WARNINGS TOML_PUSH_WARNINGS \
+ _Pragma("clang diagnostic ignored \"-Weverything\"")
+ #define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
+ #define TOML_ASSUME(cond) __builtin_assume(cond)
+ #define TOML_UNREACHABLE __builtin_unreachable()
+ #define TOML_ATTR(...) __attribute__((__VA_ARGS__))
+ #if defined(_MSC_VER) // msvc compat mode
+ #ifdef __has_declspec_attribute
+ #if __has_declspec_attribute(novtable)
+ #define TOML_INTERFACE __declspec(novtable)
+ #endif
+ #if __has_declspec_attribute(empty_bases)
+ #define TOML_EMPTY_BASES __declspec(empty_bases)
+ #endif
+ #ifndef TOML_ALWAYS_INLINE
+ #define TOML_ALWAYS_INLINE __forceinline
+ #endif
+ #if __has_declspec_attribute(noinline)
+ #define TOML_NEVER_INLINE __declspec(noinline)
+ #endif
+ #endif
+ #endif
+ #ifdef __has_attribute
+ #if !defined(TOML_ALWAYS_INLINE) && __has_attribute(always_inline)
+ #define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
+ #endif
+ #if !defined(TOML_NEVER_INLINE) && __has_attribute(noinline)
+ #define TOML_NEVER_INLINE __attribute__((__noinline__))
+ #endif
+ #if !defined(TOML_TRIVIAL_ABI) && __has_attribute(trivial_abi)
+ #define TOML_TRIVIAL_ABI __attribute__((__trivial_abi__))
+ #endif
+ #endif
+ #define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
+ #define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
+
+ //floating-point from_chars and to_chars are not implemented in any version of clang as of 1/1/2020
+ #ifndef TOML_FLOAT_CHARCONV
+ #define TOML_FLOAT_CHARCONV 0
+ #endif
+
+ #define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1
+
+#endif // clang
+
+#if TOML_MSVC || TOML_ICC_CL
+
+ #define TOML_CPP_VERSION _MSVC_LANG
+ #define TOML_PUSH_WARNINGS __pragma(warning(push))
+ #if TOML_MSVC // !intel-cl
+ #define TOML_PUSH_WARNINGS __pragma(warning(push))
+ #define TOML_DISABLE_SWITCH_WARNINGS __pragma(warning(disable: 4063))
+ #define TOML_POP_WARNINGS __pragma(warning(pop))
+ #define TOML_DISABLE_WARNINGS __pragma(warning(push, 0))
+ #define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
+ #endif
+ #ifndef TOML_ALWAYS_INLINE
+ #define TOML_ALWAYS_INLINE __forceinline
+ #endif
+ #define TOML_NEVER_INLINE __declspec(noinline)
+ #define TOML_ASSUME(cond) __assume(cond)
+ #define TOML_UNREACHABLE __assume(0)
+ #define TOML_INTERFACE __declspec(novtable)
+ #define TOML_EMPTY_BASES __declspec(empty_bases)
+
+#endif // msvc
+
+#if TOML_ICC
+
+ #define TOML_PUSH_WARNINGS __pragma(warning(push))
+ #define TOML_DISABLE_SPAM_WARNINGS __pragma(warning(disable: 82)) /* storage class is not first */ \
+ __pragma(warning(disable: 111)) /* statement unreachable (false-positive) */ \
+ __pragma(warning(disable: 1011)) /* missing return (false-positive) */ \
+ __pragma(warning(disable: 2261)) /* assume expr side-effects discarded */
+ #define TOML_POP_WARNINGS __pragma(warning(pop))
+ #define TOML_DISABLE_WARNINGS __pragma(warning(push, 0))
+ #define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
+
+#endif // icc
+
+#if TOML_GCC
+
+ #define TOML_PUSH_WARNINGS _Pragma("GCC diagnostic push")
+ #define TOML_DISABLE_SWITCH_WARNINGS _Pragma("GCC diagnostic ignored \"-Wswitch\"") \
+ _Pragma("GCC diagnostic ignored \"-Wswitch-enum\"") \
+ _Pragma("GCC diagnostic ignored \"-Wswitch-default\"")
+ #define TOML_DISABLE_INIT_WARNINGS _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
+ _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \
+ _Pragma("GCC diagnostic ignored \"-Wuninitialized\"")
+ #define TOML_DISABLE_ARITHMETIC_WARNINGS _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"") \
+ _Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") \
+ _Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"")
+ #define TOML_DISABLE_SHADOW_WARNINGS _Pragma("GCC diagnostic ignored \"-Wshadow\"")
+ #define TOML_DISABLE_SPAM_WARNINGS _Pragma("GCC diagnostic ignored \"-Wpadded\"") \
+ _Pragma("GCC diagnostic ignored \"-Wcast-align\"") \
+ _Pragma("GCC diagnostic ignored \"-Wcomment\"") \
+ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
+ _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") \
+ _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=pure\"")
+ #define TOML_POP_WARNINGS _Pragma("GCC diagnostic pop")
+ #define TOML_DISABLE_WARNINGS TOML_PUSH_WARNINGS \
+ _Pragma("GCC diagnostic ignored \"-Wall\"") \
+ _Pragma("GCC diagnostic ignored \"-Wextra\"") \
+ _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
+ TOML_DISABLE_SWITCH_WARNINGS \
+ TOML_DISABLE_INIT_WARNINGS \
+ TOML_DISABLE_ARITHMETIC_WARNINGS \
+ TOML_DISABLE_SHADOW_WARNINGS \
+ TOML_DISABLE_SPAM_WARNINGS
+ #define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
+
+ #define TOML_ATTR(...) __attribute__((__VA_ARGS__))
+ #ifndef TOML_ALWAYS_INLINE
+ #define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
+ #endif
+ #define TOML_NEVER_INLINE __attribute__((__noinline__))
+ #define TOML_UNREACHABLE __builtin_unreachable()
+ #define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
+ #define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
+
+ // floating-point from_chars and to_chars are not implemented in any version of gcc as of 1/1/2020
+ #ifndef TOML_FLOAT_CHARCONV
+ #define TOML_FLOAT_CHARCONV 0
+ #endif
+
+#endif
+
+#ifdef TOML_CONFIG_HEADER
+ #include TOML_CONFIG_HEADER
+#endif
+
+#ifdef DOXYGEN
+ #define TOML_HEADER_ONLY 0
+ #define TOML_WINDOWS_COMPAT 1
+#endif
+
+#if defined(TOML_ALL_INLINE) && !defined(TOML_HEADER_ONLY)
+ #define TOML_HEADER_ONLY TOML_ALL_INLINE
+#endif
+
+#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
+ #undef TOML_HEADER_ONLY
+ #define TOML_HEADER_ONLY 1
+#endif
+
+#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
+ #undef TOML_IMPLEMENTATION
+ #define TOML_IMPLEMENTATION 1
+#else
+ #define TOML_IMPLEMENTATION 0
+#endif
+
+#ifndef TOML_API
+ #define TOML_API
+#endif
+
+#ifndef TOML_UNRELEASED_FEATURES
+ #define TOML_UNRELEASED_FEATURES 0
+#endif
+
+#ifndef TOML_LARGE_FILES
+ #define TOML_LARGE_FILES 0
+#endif
+
+#ifndef TOML_UNDEF_MACROS
+ #define TOML_UNDEF_MACROS 1
+#endif
+
+#ifndef TOML_PARSER
+ #define TOML_PARSER 1
+#endif
+
+#ifndef DOXYGEN
+ #if defined(_WIN32) && !defined(TOML_WINDOWS_COMPAT)
+ #define TOML_WINDOWS_COMPAT 1
+ #endif
+ #if !defined(_WIN32) || !defined(TOML_WINDOWS_COMPAT)
+ #undef TOML_WINDOWS_COMPAT
+ #define TOML_WINDOWS_COMPAT 0
+ #endif
+#endif
+
+#ifdef TOML_OPTIONAL_TYPE
+ #define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
+#else
+ #define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
+#endif
+
+#ifdef TOML_CHAR_8_STRINGS
+ #if TOML_CHAR_8_STRINGS
+ #error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; \
+all value setters and getters can now work with char8_t strings implicitly so changing the underlying string type \
+is no longer necessary.
+ #endif
+#endif
+
+#ifndef TOML_CPP_VERSION
+ #define TOML_CPP_VERSION __cplusplus
+#endif
+#if TOML_CPP_VERSION < 201103L
+ #error toml++ requires C++17 or higher. For a TOML library supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml
+#elif TOML_CPP_VERSION < 201703L
+ #error toml++ requires C++17 or higher. For a TOML library supporting C++11 see https://github.com/ToruNiina/toml11
+#elif TOML_CPP_VERSION >= 202600L
+ #define TOML_CPP 26
+#elif TOML_CPP_VERSION >= 202300L
+ #define TOML_CPP 23
+#elif TOML_CPP_VERSION >= 202002L
+ #define TOML_CPP 20
+#elif TOML_CPP_VERSION >= 201703L
+ #define TOML_CPP 17
+#endif
+#undef TOML_CPP_VERSION
+
+#ifdef __has_include
+ #define TOML_HAS_INCLUDE(header) __has_include(header)
+#else
+ #define TOML_HAS_INCLUDE(header) 0
+#endif
+
+#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions)
+ #define TOML_COMPILER_EXCEPTIONS 1
+#else
+ #define TOML_COMPILER_EXCEPTIONS 0
+#endif
+#if TOML_COMPILER_EXCEPTIONS
+ #if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
+ #undef TOML_EXCEPTIONS
+ #define TOML_EXCEPTIONS 1
+ #endif
+#else
+ #if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS
+ #error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler.
+ #endif
+ #undef TOML_EXCEPTIONS
+ #define TOML_EXCEPTIONS 0
+#endif
+
+#if TOML_EXCEPTIONS
+ #define TOML_MAY_THROW
+#else
+ #define TOML_MAY_THROW noexcept
+#endif
+
+#ifndef TOML_INT_CHARCONV
+ #define TOML_INT_CHARCONV 1
+#endif
+#ifndef TOML_FLOAT_CHARCONV
+ #define TOML_FLOAT_CHARCONV 1
+#endif
+#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE(<charconv>)
+ #undef TOML_INT_CHARCONV
+ #undef TOML_FLOAT_CHARCONV
+ #define TOML_INT_CHARCONV 0
+ #define TOML_FLOAT_CHARCONV 0
+#endif
+
+#ifndef TOML_PUSH_WARNINGS
+ #define TOML_PUSH_WARNINGS
+#endif
+#ifndef TOML_DISABLE_SWITCH_WARNINGS
+ #define TOML_DISABLE_SWITCH_WARNINGS
+#endif
+#ifndef TOML_DISABLE_INIT_WARNINGS
+ #define TOML_DISABLE_INIT_WARNINGS
+#endif
+#ifndef TOML_DISABLE_SPAM_WARNINGS
+ #define TOML_DISABLE_SPAM_WARNINGS
+#endif
+#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
+ #define TOML_DISABLE_ARITHMETIC_WARNINGS
+#endif
+#ifndef TOML_DISABLE_SHADOW_WARNINGS
+ #define TOML_DISABLE_SHADOW_WARNINGS
+#endif
+#ifndef TOML_POP_WARNINGS
+ #define TOML_POP_WARNINGS
+#endif
+#ifndef TOML_DISABLE_WARNINGS
+ #define TOML_DISABLE_WARNINGS
+#endif
+#ifndef TOML_ENABLE_WARNINGS
+ #define TOML_ENABLE_WARNINGS
+#endif
+
+#ifndef TOML_ATTR
+ #define TOML_ATTR(...)
+#endif
+
+#ifndef TOML_INTERFACE
+ #define TOML_INTERFACE
+#endif
+
+#ifndef TOML_EMPTY_BASES
+ #define TOML_EMPTY_BASES
+#endif
+
+#ifndef TOML_NEVER_INLINE
+ #define TOML_NEVER_INLINE
+#endif
+
+#ifndef TOML_ASSUME
+ #define TOML_ASSUME(cond) (void)0
+#endif
+
+#ifndef TOML_UNREACHABLE
+ #define TOML_UNREACHABLE TOML_ASSERT(false)
+#endif
+
+#define TOML_NO_DEFAULT_CASE default: TOML_UNREACHABLE
+
+#ifdef __cpp_consteval
+ #define TOML_CONSTEVAL consteval
+#else
+ #define TOML_CONSTEVAL constexpr
+#endif
+
+#ifdef __has_cpp_attribute
+ #define TOML_HAS_ATTR(...) __has_cpp_attribute(__VA_ARGS__)
+#else
+ #define TOML_HAS_ATTR(...) 0
+#endif
+
+#if !defined(DOXYGEN) && !TOML_INTELLISENSE
+ #if !defined(TOML_LIKELY) && TOML_HAS_ATTR(likely)
+ #define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
+ #endif
+ #if !defined(TOML_UNLIKELY) && TOML_HAS_ATTR(unlikely)
+ #define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
+ #endif
+ #if TOML_HAS_ATTR(nodiscard) >= 201907L
+ #define TOML_NODISCARD_CTOR [[nodiscard]]
+ #endif
+#endif
+
+#ifndef TOML_LIKELY
+ #define TOML_LIKELY(...) (__VA_ARGS__)
+#endif
+#ifndef TOML_UNLIKELY
+ #define TOML_UNLIKELY(...) (__VA_ARGS__)
+#endif
+#ifndef TOML_NODISCARD_CTOR
+ #define TOML_NODISCARD_CTOR
+#endif
+
+#ifndef TOML_TRIVIAL_ABI
+ #define TOML_TRIVIAL_ABI
+#endif
+
+#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
+ __VA_ARGS__ [[nodiscard]] friend bool operator == (RHS rhs, LHS lhs) noexcept { return lhs == rhs; } \
+ __VA_ARGS__ [[nodiscard]] friend bool operator != (LHS lhs, RHS rhs) noexcept { return !(lhs == rhs); } \
+ __VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }
+
+#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
+ #define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0
+#endif
+
+#define TOML_CONCAT_1(x, y) x##y
+#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)
+
+#define TOML_EVAL_BOOL_1(T, F) T
+#define TOML_EVAL_BOOL_0(T, F) F
+
+#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \
+ || defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE)
+ #define TOML_ARM 1
+#else
+ #define TOML_ARM 0
+#endif
+
+#define TOML_MAKE_BITOPS(type) \
+ [[nodiscard]] \
+ TOML_ALWAYS_INLINE \
+ TOML_ATTR(const) \
+ TOML_ATTR(flatten) \
+ constexpr type operator & (type lhs, type rhs) noexcept \
+ { \
+ return static_cast<type>(::toml::impl::unwrap_enum(lhs) & ::toml::impl::unwrap_enum(rhs)); \
+ } \
+ [[nodiscard]] \
+ TOML_ALWAYS_INLINE \
+ TOML_ATTR(const) \
+ TOML_ATTR(flatten) \
+ constexpr type operator | (type lhs, type rhs) noexcept \
+ { \
+ return static_cast<type>(::toml::impl::unwrap_enum(lhs) | ::toml::impl::unwrap_enum(rhs)); \
+ }
+
+#ifndef TOML_LIFETIME_HOOKS
+ #define TOML_LIFETIME_HOOKS 0
+#endif
+
+#ifdef __FLT16_MANT_DIG__
+ #if __FLT_RADIX__ == 2 \
+ && __FLT16_MANT_DIG__ == 11 \
+ && __FLT16_DIG__ == 3 \
+ && __FLT16_MIN_EXP__ == -13 \
+ && __FLT16_MIN_10_EXP__ == -4 \
+ && __FLT16_MAX_EXP__ == 16 \
+ && __FLT16_MAX_10_EXP__ == 4
+ #if TOML_ARM && (TOML_GCC || TOML_CLANG)
+ #define TOML_FP16 __fp16
+ #endif
+ #if TOML_ARM && TOML_CLANG // not present in g++
+ #define TOML_FLOAT16 _Float16
+ #endif
+ #endif
+#endif
+
+#if defined(__SIZEOF_FLOAT128__) \
+ && defined(__FLT128_MANT_DIG__) \
+ && defined(__LDBL_MANT_DIG__) \
+ && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__
+ #define TOML_FLOAT128 __float128
+#endif
+
+#ifdef __SIZEOF_INT128__
+ #define TOML_INT128 __int128_t
+ #define TOML_UINT128 __uint128_t
+#endif
+
+#define TOML_LIB_MAJOR 2
+#define TOML_LIB_MINOR 2
+#define TOML_LIB_PATCH 0
+
+#define TOML_LANG_MAJOR 1
+#define TOML_LANG_MINOR 0
+#define TOML_LANG_PATCH 0
+
+#define TOML_LIB_SINGLE_HEADER 1
+
+#define TOML_MAKE_VERSION(maj, min, rev) \
+ ((maj) * 1000 + (min) * 25 + (rev))
+
+#if TOML_UNRELEASED_FEATURES
+ #define TOML_LANG_EFFECTIVE_VERSION \
+ TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
+#else
+ #define TOML_LANG_EFFECTIVE_VERSION \
+ TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
+#endif
+
+#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
+ (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(maj, min, rev))
+
+#define TOML_LANG_AT_LEAST(maj, min, rev) \
+ (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(maj, min, rev))
+
+#define TOML_LANG_UNRELEASED \
+ TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
+
+#ifndef TOML_ABI_NAMESPACES
+ #ifdef DOXYGEN
+ #define TOML_ABI_NAMESPACES 0
+ #else
+ #define TOML_ABI_NAMESPACES 1
+ #endif
+#endif
+#if TOML_ABI_NAMESPACES
+ #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR)
+ #define TOML_NAMESPACE_END }
+ #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR)
+ #define TOML_ABI_NAMESPACE_START(name) inline namespace name {
+ #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F))
+ #define TOML_ABI_NAMESPACE_END }
+#else
+ #define TOML_NAMESPACE_START namespace toml
+ #define TOML_NAMESPACE_END
+ #define TOML_NAMESPACE toml
+ #define TOML_ABI_NAMESPACE_START(...)
+ #define TOML_ABI_NAMESPACE_BOOL(...)
+ #define TOML_ABI_NAMESPACE_END
+#endif
+#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl
+#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END
+#if TOML_HEADER_ONLY
+ #define TOML_ANON_NAMESPACE_START TOML_IMPL_NAMESPACE_START
+ #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END
+ #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl
+ #define TOML_USING_ANON_NAMESPACE using namespace TOML_ANON_NAMESPACE
+ #define TOML_EXTERNAL_LINKAGE inline
+ #define TOML_INTERNAL_LINKAGE inline
+#else
+ #define TOML_ANON_NAMESPACE_START namespace
+ #define TOML_ANON_NAMESPACE_END
+ #define TOML_ANON_NAMESPACE
+ #define TOML_USING_ANON_NAMESPACE (void)0
+ #define TOML_EXTERNAL_LINKAGE
+ #define TOML_INTERNAL_LINKAGE static
+#endif
+
+TOML_DISABLE_WARNINGS
+#ifndef TOML_ASSERT
+ #if defined(NDEBUG) || !defined(_DEBUG)
+ #define TOML_ASSERT(expr) (void)0
+ #else
+ #ifndef assert
+ #include <cassert>
+ #endif
+ #define TOML_ASSERT(expr) assert(expr)
+ #endif
+#endif
+TOML_ENABLE_WARNINGS
+
+#endif //------ ↑ toml_preprocessor.h --------------------------------------------------------------------------------
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SPAM_WARNINGS
+
+#if 1 //---------------------------------- ↓ toml_common.h ----------------------------------------------------------
+
+TOML_DISABLE_WARNINGS
+#include <cstdint>
+#include <cstddef>
+#include <cstring>
+#include <cfloat>
+#include <climits>
+#include <limits>
+#include <memory>
+#include <string_view>
+#include <string>
+#include <vector>
+#include <map>
+#include <iosfwd>
+#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
+ #include <optional>
+#endif
+#if TOML_HAS_INCLUDE(<version>)
+ #include <version>
+#endif
+TOML_ENABLE_WARNINGS
+
+#ifdef __cpp_lib_launder
+ #define TOML_LAUNDER(x) std::launder(x)
+#else
+ #define TOML_LAUNDER(x) x
+#endif
+
+#ifndef DOXYGEN
+#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS
+#define TOML_ENV_MESSAGE \
+ "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \
+ "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \
+ "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \
+ "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \
+ "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. Thanks!"
+
+static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE);
+static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE);
+static_assert('A' == 65, TOML_ENV_MESSAGE);
+static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE);
+static_assert(std::numeric_limits<double>::is_iec559, TOML_ENV_MESSAGE);
+static_assert(std::numeric_limits<double>::digits == 53, TOML_ENV_MESSAGE);
+static_assert(std::numeric_limits<double>::digits10 == 15, TOML_ENV_MESSAGE);
+
+#undef TOML_ENV_MESSAGE
+#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS
+#endif // !DOXYGEN
+
+#ifndef DOXYGEN // undocumented forward declarations are hidden from doxygen because they fuck it up =/
+
+namespace toml // non-abi namespace; this is not an error
+{
+ using namespace std::string_literals;
+ using namespace std::string_view_literals;
+ using ::std::size_t;
+ using ::std::intptr_t;
+ using ::std::uintptr_t;
+ using ::std::ptrdiff_t;
+ using ::std::nullptr_t;
+ using ::std::int8_t;
+ using ::std::int16_t;
+ using ::std::int32_t;
+ using ::std::int64_t;
+ using ::std::uint8_t;
+ using ::std::uint16_t;
+ using ::std::uint32_t;
+ using ::std::uint64_t;
+ using ::std::uint_least32_t;
+ using ::std::uint_least64_t;
+
+ // legacy typedefs
+ using string_char = char;
+ using string = std::string;
+ using string_view = std::string_view;
+}
+
+TOML_NAMESPACE_START // abi namespace
+{
+ struct date;
+ struct time;
+ struct time_offset;
+
+ TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt)
+ struct date_time;
+ TOML_ABI_NAMESPACE_END
+
+ class node;
+ class array;
+ class table;
+
+ template <typename> class node_view;
+ template <typename> class value;
+ template <typename> class default_formatter;
+ template <typename> class json_formatter;
+
+ [[nodiscard]] TOML_API bool operator == (const array& lhs, const array& rhs) noexcept;
+ [[nodiscard]] TOML_API bool operator != (const array& lhs, const array& rhs) noexcept;
+ [[nodiscard]] TOML_API bool operator == (const table& lhs, const table& rhs) noexcept;
+ [[nodiscard]] TOML_API bool operator != (const table& lhs, const table& rhs) noexcept;
+
+ template <typename Char>
+ std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
+ template <typename Char, typename T>
+ std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const value<T>&);
+ template <typename Char>
+ std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
+ template <typename T, typename U>
+ std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&);
+ template <typename T, typename U>
+ std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&);
+ template <typename T, typename U>
+ std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&);
+ template <typename T, typename U>
+ std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&);
+ template <typename Char, typename T>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const node_view<T>&);
+
+ namespace impl
+ {
+ template <typename T>
+ using string_map = std::map<std::string, T, std::less<>>; // heterogeneous lookup
+
+ template <typename T>
+ using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
+
+ template <typename T, typename... U>
+ inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, U>);
+
+ template <typename T>
+ inline constexpr bool is_cvref = std::is_reference_v<T> || std::is_const_v<T> || std::is_volatile_v<T>;
+
+ template <typename T>
+ inline constexpr bool is_wide_string = is_one_of<
+ std::decay_t<T>,
+ const wchar_t*,
+ wchar_t*,
+ std::wstring_view,
+ std::wstring
+ >;
+
+ template <typename T>
+ inline constexpr bool dependent_false = false;
+
+ #if TOML_WINDOWS_COMPAT
+ [[nodiscard]] TOML_API std::string narrow(std::wstring_view) noexcept;
+ [[nodiscard]] TOML_API std::wstring widen(std::string_view) noexcept;
+ #ifdef __cpp_lib_char8_t
+ [[nodiscard]] TOML_API std::wstring widen(std::u8string_view) noexcept;
+ #endif
+ #endif // TOML_WINDOWS_COMPAT
+
+ #if TOML_ABI_NAMESPACES
+ #if TOML_EXCEPTIONS
+ TOML_ABI_NAMESPACE_START(ex)
+ #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::ex::parser
+ #else
+ TOML_ABI_NAMESPACE_START(noex)
+ #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::noex::parser
+ #endif
+ #else
+ #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser
+ #endif
+ class parser;
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+ }
+}
+TOML_NAMESPACE_END
+
+#endif // !DOXYGEN
+
+namespace toml { }
+
+TOML_NAMESPACE_START // abi namespace
+{
+ inline namespace literals {}
+
+ #if TOML_HAS_CUSTOM_OPTIONAL_TYPE
+ template <typename T>
+ using optional = TOML_OPTIONAL_TYPE<T>;
+ #else
+ template <typename T>
+ using optional = std::optional<T>;
+ #endif
+
+ enum class node_type : uint8_t
+ {
+ none,
+ table,
+ array,
+ string,
+ integer,
+ floating_point,
+ boolean,
+ date,
+ time,
+ date_time
+ };
+
+ using source_path_ptr = std::shared_ptr<const std::string>;
+
+ template <typename T>
+ struct TOML_TRIVIAL_ABI inserter
+ {
+ T&& value;
+ };
+ template <typename T> inserter(T&&) -> inserter<T>;
+}
+TOML_NAMESPACE_END
+
+TOML_IMPL_NAMESPACE_START
+{
+ // general value traits
+ // (as they relate to their equivalent native TOML type)
+ template <typename T>
+ struct value_traits
+ {
+ using native_type = void;
+ static constexpr bool is_native = false;
+ static constexpr bool is_losslessly_convertible_to_native = false;
+ static constexpr bool can_represent_native = false;
+ static constexpr bool can_partially_represent_native = false;
+ static constexpr auto type = node_type::none;
+ };
+ template <typename T> struct value_traits<T&> : value_traits<T> {};
+ template <typename T> struct value_traits<T&&> : value_traits<T> {};
+ template <typename T> struct value_traits<T* const> : value_traits<T*> {};
+ template <typename T> struct value_traits<T* volatile> : value_traits<T*> {};
+ template <typename T> struct value_traits<T* const volatile> : value_traits<T*> {};
+
+ // integer value traits
+ template <typename T>
+ struct integer_value_limits
+ {
+ static constexpr auto min = (std::numeric_limits<T>::min)();
+ static constexpr auto max = (std::numeric_limits<T>::max)();
+ };
+ template <typename T>
+ struct integer_value_traits_base : integer_value_limits<T>
+ {
+ using native_type = int64_t;
+ static constexpr bool is_native = std::is_same_v<T, native_type>;
+ static constexpr bool is_signed = static_cast<T>(-1) < T{}; // for impls not specializing std::is_signed<T>
+ static constexpr auto type = node_type::integer;
+ static constexpr bool can_partially_represent_native = true;
+ };
+ template <typename T>
+ struct unsigned_integer_value_traits : integer_value_traits_base<T>
+ {
+ static constexpr bool is_losslessly_convertible_to_native
+ = integer_value_limits<T>::max <= 9223372036854775807ULL;
+ static constexpr bool can_represent_native = false;
+
+ };
+ template <typename T>
+ struct signed_integer_value_traits : integer_value_traits_base<T>
+ {
+ using native_type = int64_t;
+ static constexpr bool is_losslessly_convertible_to_native
+ = integer_value_limits<T>::min >= (-9223372036854775807LL - 1LL)
+ && integer_value_limits<T>::max <= 9223372036854775807LL;
+ static constexpr bool can_represent_native
+ = integer_value_limits<T>::min <= (-9223372036854775807LL - 1LL)
+ && integer_value_limits<T>::max >= 9223372036854775807LL;
+ };
+ template <typename T, bool S = integer_value_traits_base<T>::is_signed>
+ struct integer_value_traits : signed_integer_value_traits<T> {};
+ template <typename T>
+ struct integer_value_traits<T, false> : unsigned_integer_value_traits<T> {};
+ template <> struct value_traits<signed char> : integer_value_traits<signed char> {};
+ template <> struct value_traits<unsigned char> : integer_value_traits<unsigned char> {};
+ template <> struct value_traits<signed short> : integer_value_traits<signed short> {};
+ template <> struct value_traits<unsigned short> : integer_value_traits<unsigned short> {};
+ template <> struct value_traits<signed int> : integer_value_traits<signed int> {};
+ template <> struct value_traits<unsigned int> : integer_value_traits<unsigned int> {};
+ template <> struct value_traits<signed long> : integer_value_traits<signed long> {};
+ template <> struct value_traits<unsigned long> : integer_value_traits<unsigned long> {};
+ template <> struct value_traits<signed long long> : integer_value_traits<signed long long> {};
+ template <> struct value_traits<unsigned long long> : integer_value_traits<unsigned long long> {};
+ #ifdef TOML_INT128
+ template <>
+ struct integer_value_limits<TOML_INT128>
+ {
+ static constexpr TOML_INT128 max = static_cast<TOML_INT128>(
+ (TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1
+ );
+ static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 };
+ };
+ template <>
+ struct integer_value_limits<TOML_UINT128>
+ {
+ static constexpr TOML_UINT128 min = TOML_UINT128{};
+ static constexpr TOML_UINT128 max = (2u * static_cast<TOML_UINT128>(integer_value_limits<TOML_INT128>::max)) + 1u;
+ };
+ template <> struct value_traits<TOML_INT128> : integer_value_traits<TOML_INT128> {};
+ template <> struct value_traits<TOML_UINT128> : integer_value_traits<TOML_UINT128> {};
+ #endif
+ #ifdef TOML_SMALL_INT_TYPE
+ template <> struct value_traits<TOML_SMALL_INT_TYPE> : signed_integer_value_traits<TOML_SMALL_INT_TYPE> {};
+ #endif
+ static_assert(value_traits<int64_t>::is_native);
+ static_assert(value_traits<int64_t>::is_signed);
+ static_assert(value_traits<int64_t>::is_losslessly_convertible_to_native);
+ static_assert(value_traits<int64_t>::can_represent_native);
+ static_assert(value_traits<int64_t>::can_partially_represent_native);
+
+ // float value traits
+ template <typename T>
+ struct float_value_limits
+ {
+ static constexpr bool is_iec559 = std::numeric_limits<T>::is_iec559;
+ static constexpr int digits = std::numeric_limits<T>::digits;
+ static constexpr int digits10 = std::numeric_limits<T>::digits10;
+ };
+ template <typename T>
+ struct float_value_traits : float_value_limits<T>
+ {
+ using native_type = double;
+ static constexpr bool is_native = std::is_same_v<T, native_type>;
+ static constexpr bool is_signed = true;
+ static constexpr bool is_losslessly_convertible_to_native
+ = float_value_limits<T>::is_iec559
+ && float_value_limits<T>::digits <= 53
+ && float_value_limits<T>::digits10 <= 15;
+ static constexpr bool can_represent_native
+ = float_value_limits<T>::is_iec559
+ && float_value_limits<T>::digits >= 53 // DBL_MANT_DIG
+ && float_value_limits<T>::digits10 >= 15; // DBL_DIG
+ static constexpr bool can_partially_represent_native //32-bit float values
+ = float_value_limits<T>::is_iec559
+ && float_value_limits<T>::digits >= 24
+ && float_value_limits<T>::digits10 >= 6;
+ static constexpr auto type = node_type::floating_point;
+ };
+ template <> struct value_traits<float> : float_value_traits<float> {};
+ template <> struct value_traits<double> : float_value_traits<double> {};
+ template <> struct value_traits<long double> : float_value_traits<long double> {};
+ template <int mant_dig, int dig>
+ struct extended_float_value_limits
+ {
+ static constexpr bool is_iec559 = true;
+ static constexpr int digits = mant_dig;
+ static constexpr int digits10 = dig;
+ };
+ #ifdef TOML_FP16
+ template <> struct float_value_limits<TOML_FP16> : extended_float_value_limits<__FLT16_MANT_DIG__, __FLT16_DIG__> {};
+ template <> struct value_traits<TOML_FP16> : float_value_traits<TOML_FP16> {};
+ #endif
+ #ifdef TOML_FLOAT16
+ template <> struct float_value_limits<TOML_FLOAT16> : extended_float_value_limits<__FLT16_MANT_DIG__, __FLT16_DIG__> {};
+ template <> struct value_traits<TOML_FLOAT16> : float_value_traits<TOML_FLOAT16> {};
+ #endif
+ #ifdef TOML_FLOAT128
+ template <> struct float_value_limits<TOML_FLOAT128> : extended_float_value_limits<__FLT128_MANT_DIG__, __FLT128_DIG__> {};
+ template <> struct value_traits<TOML_FLOAT128> : float_value_traits<TOML_FLOAT128> {};
+ #endif
+ #ifdef TOML_SMALL_FLOAT_TYPE
+ template <> struct value_traits<TOML_SMALL_FLOAT_TYPE> : float_value_traits<TOML_SMALL_FLOAT_TYPE> {};
+ #endif
+ static_assert(value_traits<double>::is_native);
+ static_assert(value_traits<double>::is_losslessly_convertible_to_native);
+ static_assert(value_traits<double>::can_represent_native);
+ static_assert(value_traits<double>::can_partially_represent_native);
+
+ // string value traits
+ template <typename T>
+ struct string_value_traits
+ {
+ using native_type = std::string;
+ static constexpr bool is_native = std::is_same_v<T, native_type>;
+ static constexpr bool is_losslessly_convertible_to_native = true;
+ static constexpr bool can_represent_native
+ = !std::is_array_v<T>
+ && (!std::is_pointer_v<T> || std::is_const_v<std::remove_pointer_t<T>>);
+ static constexpr bool can_partially_represent_native = can_represent_native;
+ static constexpr auto type = node_type::string;
+ };
+ template <> struct value_traits<std::string> : string_value_traits<std::string> {};
+ template <> struct value_traits<std::string_view> : string_value_traits<std::string_view> {};
+ template <> struct value_traits<const char*> : string_value_traits<const char *> {};
+ template <size_t N> struct value_traits<const char[N]> : string_value_traits<const char[N]> {};
+ template <> struct value_traits<char*> : string_value_traits<char*> {};
+ template <size_t N> struct value_traits<char[N]> : string_value_traits<char[N]> {};
+ #ifdef __cpp_lib_char8_t
+ template <> struct value_traits<std::u8string> : string_value_traits<std::u8string> {};
+ template <> struct value_traits<std::u8string_view> : string_value_traits<std::u8string_view> {};
+ template <> struct value_traits<const char8_t*> : string_value_traits<const char8_t*> {};
+ template <size_t N> struct value_traits<const char8_t[N]> : string_value_traits<const char8_t[N]> {};
+ template <> struct value_traits<char8_t*> : string_value_traits<char8_t*> {};
+ template <size_t N> struct value_traits<char8_t[N]> : string_value_traits<char8_t[N]> {};
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ template <typename T>
+ struct wstring_value_traits
+ {
+ using native_type = std::string;
+ static constexpr bool is_native = false;
+ static constexpr bool is_losslessly_convertible_to_native = true; //narrow
+ static constexpr bool can_represent_native = std::is_same_v<T, std::wstring>; //widen
+ static constexpr bool can_partially_represent_native = can_represent_native;
+ static constexpr auto type = node_type::string;
+ };
+ template <> struct value_traits<std::wstring> : wstring_value_traits<std::wstring> {};
+ template <> struct value_traits<std::wstring_view> : wstring_value_traits<std::wstring_view> {};
+ template <> struct value_traits<const wchar_t*> : wstring_value_traits<const wchar_t*> {};
+ template <size_t N> struct value_traits<const wchar_t[N]> : wstring_value_traits<const wchar_t[N]> {};
+ template <> struct value_traits<wchar_t*> : wstring_value_traits<wchar_t*> {};
+ template <size_t N> struct value_traits<wchar_t[N]> : wstring_value_traits<wchar_t[N]> {};
+ #endif
+
+ // other native value traits
+ template <typename T, node_type NodeType>
+ struct native_value_traits
+ {
+ using native_type = T;
+ static constexpr bool is_native = true;
+ static constexpr bool is_losslessly_convertible_to_native = true;
+ static constexpr bool can_represent_native = true;
+ static constexpr bool can_partially_represent_native = true;
+ static constexpr auto type = NodeType;
+ };
+ template <> struct value_traits<bool> : native_value_traits<bool, node_type::boolean> {};
+ template <> struct value_traits<date> : native_value_traits<date, node_type::date> {};
+ template <> struct value_traits<time> : native_value_traits<time, node_type::time> {};
+ template <> struct value_traits<date_time> : native_value_traits<date_time, node_type::date_time> {};
+
+ // native value category queries
+ template <typename T>
+ using native_type_of = typename value_traits<T>::native_type;
+ template <typename T>
+ inline constexpr bool is_native = value_traits<T>::is_native;
+ template <typename T>
+ inline constexpr bool can_represent_native = value_traits<T>::can_represent_native;
+ template <typename T>
+ inline constexpr bool can_partially_represent_native = value_traits<T>::can_partially_represent_native;
+ template <typename T>
+ inline constexpr bool is_losslessly_convertible_to_native = value_traits<T>::is_losslessly_convertible_to_native;
+ template <typename T, typename... U>
+ inline constexpr bool is_natively_one_of = is_one_of<native_type_of<T>, U...>;
+
+ // native <=> node conversions
+ template <typename T> struct node_wrapper { using type = T; };
+ template <> struct node_wrapper<std::string> { using type = value<std::string>; };
+ template <> struct node_wrapper<int64_t> { using type = value<int64_t>; };
+ template <> struct node_wrapper<double> { using type = value<double>; };
+ template <> struct node_wrapper<bool> { using type = value<bool>; };
+ template <> struct node_wrapper<date> { using type = value<date>; };
+ template <> struct node_wrapper<time> { using type = value<time>; };
+ template <> struct node_wrapper<date_time> { using type = value<date_time>; };
+ template <typename T> using wrap_node = typename node_wrapper<T>::type;
+
+ template <typename T> struct node_unwrapper { using type = T; };
+ template <typename T> struct node_unwrapper<value<T>> { using type = T; };
+ template <typename T> using unwrap_node = typename node_unwrapper<T>::type;
+
+ template <typename T> struct node_type_getter { static constexpr auto value = value_traits<T>::type; };
+ template <> struct node_type_getter<table> { static constexpr auto value = node_type::table; };
+ template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; };
+ template <> struct node_type_getter<void> { static constexpr auto value = node_type::none; };
+ template <typename T>
+ inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value;
+
+ template <typename T>
+ inline constexpr bool is_node_view = is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>;
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ template <typename T>
+ inline constexpr bool is_table = std::is_same_v<impl::remove_cvref_t<T>, table>;
+
+ template <typename T>
+ inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>;
+
+ template <typename T>
+ inline constexpr bool is_string = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<std::string>>;
+
+ template <typename T>
+ inline constexpr bool is_integer = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<int64_t>>;
+
+ template <typename T>
+ inline constexpr bool is_floating_point = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<double>>;
+
+ template <typename T>
+ inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
+
+ template <typename T>
+ inline constexpr bool is_boolean = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<bool>>;
+
+ template <typename T>
+ inline constexpr bool is_date = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date>>;
+
+ template <typename T>
+ inline constexpr bool is_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<time>>;
+
+ template <typename T>
+ inline constexpr bool is_date_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date_time>>;
+}
+TOML_NAMESPACE_END
+
+TOML_IMPL_NAMESPACE_START
+{
+ template <typename T>
+ [[nodiscard]]
+ TOML_ATTR(const)
+ TOML_ALWAYS_INLINE
+ constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept
+ {
+ return static_cast<std::underlying_type_t<T>>(val);
+ }
+
+ // Q: "why not use the built-in fpclassify?"
+ // A: Because it gets broken by -ffast-math and friends
+ enum class fp_class : unsigned { ok, neg_inf, pos_inf, nan };
+ [[nodiscard]]
+ TOML_ATTR(pure)
+ inline fp_class fpclassify(const double& val) noexcept
+ {
+ constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
+ constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
+ constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;
+
+ uint64_t val_bits;
+ memcpy(&val_bits, &val, sizeof(val));
+ if ((val_bits & exponent) != exponent)
+ return fp_class::ok;
+ if ((val_bits & mantissa))
+ return fp_class::nan;
+ return (val_bits & sign) ? fp_class::neg_inf : fp_class::pos_inf;
+ }
+
+ // Q: "why not use std::find??"
+ // A: Because <algorithm> is _huge_ and std::find would be the only thing I used from it.
+ // I don't want to impose such a heavy compile-time burden on users.
+ template <typename T>
+ [[nodiscard]]
+ inline const T* find(const std::vector<T>& haystack, const T& needle) noexcept
+ {
+ for (size_t i = 0, e = haystack.size(); i < e; i++)
+ if (haystack[i] == needle)
+ return haystack.data() + i;
+ return nullptr;
+ }
+
+ inline constexpr std::string_view low_character_escape_table[] =
+ {
+ "\\u0000"sv,
+ "\\u0001"sv,
+ "\\u0002"sv,
+ "\\u0003"sv,
+ "\\u0004"sv,
+ "\\u0005"sv,
+ "\\u0006"sv,
+ "\\u0007"sv,
+ "\\b"sv,
+ "\\t"sv,
+ "\\n"sv,
+ "\\u000B"sv,
+ "\\f"sv,
+ "\\r"sv,
+ "\\u000E"sv,
+ "\\u000F"sv,
+ "\\u0010"sv,
+ "\\u0011"sv,
+ "\\u0012"sv,
+ "\\u0013"sv,
+ "\\u0014"sv,
+ "\\u0015"sv,
+ "\\u0016"sv,
+ "\\u0017"sv,
+ "\\u0018"sv,
+ "\\u0019"sv,
+ "\\u001A"sv,
+ "\\u001B"sv,
+ "\\u001C"sv,
+ "\\u001D"sv,
+ "\\u001E"sv,
+ "\\u001F"sv,
+ };
+
+ inline constexpr std::string_view node_type_friendly_names[] =
+ {
+ "none"sv,
+ "table"sv,
+ "array"sv,
+ "string"sv,
+ "integer"sv,
+ "floating-point"sv,
+ "boolean"sv,
+ "date"sv,
+ "time"sv,
+ "date-time"sv
+ };
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ [[nodiscard]]
+ TOML_ATTR(const)
+ TOML_ALWAYS_INLINE
+ TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept
+ {
+ return static_cast<size_t>(n);
+ }
+
+ TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, lf, sf)
+
+ #if TOML_LARGE_FILES
+ using source_index = uint32_t;
+ #else
+ using source_index = uint16_t;
+ #endif
+
+ struct TOML_TRIVIAL_ABI source_position
+ {
+ source_index line;
+ source_index column;
+
+ [[nodiscard]]
+ explicit constexpr operator bool () const noexcept
+ {
+ return line > source_index{} && column > source_index{};
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator == (const source_position& lhs, const source_position& rhs) noexcept
+ {
+ return lhs.line == rhs.line
+ && lhs.column == rhs.column;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator != (const source_position& lhs, const source_position& rhs) noexcept
+ {
+ return lhs.line != rhs.line
+ || lhs.column != rhs.column;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator < (const source_position& lhs, const source_position& rhs) noexcept
+ {
+ return lhs.line < rhs.line
+ || (lhs.line == rhs.line && lhs.column < rhs.column);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator <= (const source_position& lhs, const source_position& rhs) noexcept
+ {
+ return lhs.line < rhs.line
+ || (lhs.line == rhs.line && lhs.column <= rhs.column);
+ }
+ };
+
+ struct source_region
+ {
+ source_position begin;
+ source_position end;
+ source_path_ptr path;
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ optional<std::wstring> wide_path() const noexcept
+ {
+ if (!path || path->empty())
+ return {};
+ return { impl::widen(*path) };
+ }
+
+ #endif
+ };
+
+ TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
+
+ enum class value_flags : uint8_t
+ {
+ none,
+
+ format_as_binary = 1,
+
+ format_as_octal = 2,
+
+ format_as_hexadecimal = 3,
+ };
+ TOML_MAKE_BITOPS(value_flags)
+
+ enum class format_flags : uint8_t
+ {
+ none,
+
+ quote_dates_and_times = 1,
+
+ allow_literal_strings = 2,
+
+ allow_multi_line_strings = 4,
+
+ allow_value_format_flags = 8,
+ };
+ TOML_MAKE_BITOPS(format_flags)
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, node_type rhs)
+ {
+ using underlying_t = std::underlying_type_t<node_type>;
+ const auto str = impl::node_type_friendly_names[static_cast<underlying_t>(rhs)];
+ if constexpr (std::is_same_v<Char, char>)
+ return lhs << str;
+ else
+ {
+ if constexpr (sizeof(Char) == 1)
+ return lhs << std::basic_string_view<Char>{ reinterpret_cast<const Char*>(str.data()), str.length() };
+ else
+ return lhs << str.data();
+ }
+ }
+
+ #ifndef DOXYGEN
+
+ namespace impl
+ {
+ #define TOML_P2S_DECL(Type) \
+ template <typename Char> \
+ inline void print_to_stream(Type, std::basic_ostream<Char>&, value_flags = {})
+ TOML_P2S_DECL(int8_t);
+ TOML_P2S_DECL(int16_t);
+ TOML_P2S_DECL(int32_t);
+ TOML_P2S_DECL(int64_t);
+ TOML_P2S_DECL(uint8_t);
+ TOML_P2S_DECL(uint16_t);
+ TOML_P2S_DECL(uint32_t);
+ TOML_P2S_DECL(uint64_t);
+ #undef TOML_P2S_DECL
+
+ #define TOML_P2S_DECL(Type) \
+ template <typename Char> \
+ inline void print_to_stream(Type, std::basic_ostream<Char>&)
+ TOML_P2S_DECL(double);
+ TOML_P2S_DECL(const date&);
+ TOML_P2S_DECL(const time&);
+ TOML_P2S_DECL(time_offset);
+ TOML_P2S_DECL(const date_time&);
+ #undef TOML_P2S_DECL
+ }
+
+ #if !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, node_type);
+ #endif // !TOML_HEADER_ONLY
+
+ #endif // !DOXYGEN
+}
+TOML_NAMESPACE_END
+
+#endif //---------------------------------- ↑ toml_common.h ----------------------------------------------------------
+
+#if 1 //--------------------------------------------------------- ↓ toml_date_time.h --------------------------------
+
+TOML_NAMESPACE_START
+{
+ struct TOML_TRIVIAL_ABI date
+ {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+
+ [[nodiscard]]
+ friend constexpr bool operator == (date lhs, date rhs) noexcept
+ {
+ return lhs.year == rhs.year
+ && lhs.month == rhs.month
+ && lhs.day == rhs.day;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator != (date lhs, date rhs) noexcept
+ {
+ return lhs.year != rhs.year
+ || lhs.month != rhs.month
+ || lhs.day != rhs.day;
+ }
+
+ private:
+
+ [[nodiscard]] TOML_ALWAYS_INLINE
+ static constexpr uint32_t pack(date d) noexcept
+ {
+ return static_cast<uint32_t>(d.year) << 16
+ | static_cast<uint32_t>(d.month) << 8
+ | static_cast<uint32_t>(d.day);
+ }
+
+ public:
+
+ [[nodiscard]]
+ friend constexpr bool operator < (date lhs, date rhs) noexcept
+ {
+ return pack(lhs) < pack(rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator <= (date lhs, date rhs) noexcept
+ {
+ return pack(lhs) <= pack(rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator > (date lhs, date rhs) noexcept
+ {
+ return pack(lhs) > pack(rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator >= (date lhs, date rhs) noexcept
+ {
+ return pack(lhs) >= pack(rhs);
+ }
+ };
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const date& rhs)
+ {
+ impl::print_to_stream(rhs, lhs);
+ return lhs;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, const date&);
+ #endif
+
+ struct TOML_TRIVIAL_ABI time
+ {
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint32_t nanosecond;
+
+ [[nodiscard]]
+ friend constexpr bool operator == (const time& lhs, const time& rhs) noexcept
+ {
+ return lhs.hour == rhs.hour
+ && lhs.minute == rhs.minute
+ && lhs.second == rhs.second
+ && lhs.nanosecond == rhs.nanosecond;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator != (const time& lhs, const time& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ private:
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ static constexpr uint64_t pack(time t) noexcept
+ {
+ return static_cast<uint64_t>(t.hour) << 48
+ | static_cast<uint64_t>(t.minute) << 40
+ | static_cast<uint64_t>(t.second) << 32
+ | static_cast<uint64_t>(t.nanosecond);
+ }
+
+ public:
+
+ [[nodiscard]]
+ friend constexpr bool operator < (time lhs, time rhs) noexcept
+ {
+ return pack(lhs) < pack(rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator <= (time lhs, time rhs) noexcept
+ {
+ return pack(lhs) <= pack(rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator > (time lhs, time rhs) noexcept
+ {
+ return pack(lhs) > pack(rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator >= (time lhs, time rhs) noexcept
+ {
+ return pack(lhs) >= pack(rhs);
+ }
+ };
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const time& rhs)
+ {
+ impl::print_to_stream(rhs, lhs);
+ return lhs;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, const time&);
+ #endif
+
+ struct TOML_TRIVIAL_ABI time_offset
+ {
+ int16_t minutes;
+
+ TOML_NODISCARD_CTOR
+ constexpr time_offset() noexcept
+ : minutes{}
+ {}
+
+ TOML_NODISCARD_CTOR
+ constexpr time_offset(int8_t h, int8_t m) noexcept
+ : minutes{ static_cast<int16_t>(h * 60 + m) }
+ {}
+
+ [[nodiscard]]
+ friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept
+ {
+ return lhs.minutes == rhs.minutes;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator != (time_offset lhs, time_offset rhs) noexcept
+ {
+ return lhs.minutes != rhs.minutes;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator < (time_offset lhs, time_offset rhs) noexcept
+ {
+ return lhs.minutes < rhs.minutes;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator <= (time_offset lhs, time_offset rhs) noexcept
+ {
+ return lhs.minutes <= rhs.minutes;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator > (time_offset lhs, time_offset rhs) noexcept
+ {
+ return lhs.minutes > rhs.minutes;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator >= (time_offset lhs, time_offset rhs) noexcept
+ {
+ return lhs.minutes >= rhs.minutes;
+ }
+ };
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const time_offset& rhs)
+ {
+ impl::print_to_stream(rhs, lhs);
+ return lhs;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
+ #endif
+
+ TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt)
+
+ struct date_time
+ {
+ toml::date date;
+ toml::time time;
+ optional<toml::time_offset> offset;
+
+ TOML_NODISCARD_CTOR
+ constexpr date_time() noexcept
+ : date{},
+ time{}
+ {}
+
+ TOML_NODISCARD_CTOR
+ constexpr date_time(toml::date d, toml::time t) noexcept
+ : date{ d },
+ time{ t }
+ {}
+
+ TOML_NODISCARD_CTOR
+ constexpr date_time(toml::date d, toml::time t, toml::time_offset off) noexcept
+ : date{ d },
+ time{ t },
+ offset{ off }
+ {}
+
+ [[nodiscard]]
+ constexpr bool is_local() const noexcept
+ {
+ return !offset.has_value();
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator == (const date_time& lhs, const date_time& rhs) noexcept
+ {
+ return lhs.date == rhs.date
+ && lhs.time == rhs.time
+ && lhs.offset == rhs.offset;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator != (const date_time& lhs, const date_time& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator < (const date_time& lhs, const date_time& rhs) noexcept
+ {
+ if (lhs.date != rhs.date)
+ return lhs.date < rhs.date;
+ if (lhs.time != rhs.time)
+ return lhs.time < rhs.time;
+ return lhs.offset < rhs.offset;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator <= (const date_time& lhs, const date_time& rhs) noexcept
+ {
+ if (lhs.date != rhs.date)
+ return lhs.date < rhs.date;
+ if (lhs.time != rhs.time)
+ return lhs.time < rhs.time;
+ return lhs.offset <= rhs.offset;
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator > (const date_time& lhs, const date_time& rhs) noexcept
+ {
+ return !(lhs <= rhs);
+ }
+
+ [[nodiscard]]
+ friend constexpr bool operator >= (const date_time& lhs, const date_time& rhs) noexcept
+ {
+ return !(lhs < rhs);
+ }
+ };
+
+ TOML_ABI_NAMESPACE_END // TOML_HAS_CUSTOM_OPTIONAL_TYPE
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const date_time& rhs)
+ {
+ impl::print_to_stream(rhs, lhs);
+ return lhs;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, const date_time&);
+ #endif
+}
+TOML_NAMESPACE_END
+
+#endif //--------------------------------------------------------- ↑ toml_date_time.h --------------------------------
+
+#if 1 //------------------------------------------------------------------------------- ↓ toml_print_to_stream.h ----
+
+TOML_DISABLE_WARNINGS
+#include <cmath>
+#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
+ #include <charconv>
+#endif
+#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
+ #include <sstream>
+#endif
+#if !TOML_INT_CHARCONV
+ #include <iomanip>
+#endif
+TOML_ENABLE_WARNINGS
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+
+TOML_IMPL_NAMESPACE_START
+{
+ // Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
+ // A: - I'm supporting C++20's char8_t as well; wrapping streams allows switching string modes transparently.
+ // - I'm using <charconv> to format numerics. Faster and locale-independent.
+ // - I can avoid forcing users to drag in <sstream> and <iomanip>.
+
+ // Q: "there's a bit of reinterpret_casting here, is any of it UB?"
+ // A: - If the source string data is char and the output string is char8_t, then technically yes,
+ // but not in the other direction. I test in both modes on Clang, GCC and MSVC and have yet to
+ // see it actually causing an issue, but in the event it does present a problem it's not going to
+ // be a show-stopper since all it means is I need to do duplicate some code.
+ // - Strings in C++. Honestly.
+
+ template <typename Char1, typename Char2>
+ inline void print_to_stream(std::basic_string_view<Char1> str, std::basic_ostream<Char2>& stream)
+ {
+ static_assert(sizeof(Char1) == 1);
+ static_assert(sizeof(Char2) == 1);
+ stream.write(reinterpret_cast<const Char2*>(str.data()), static_cast<std::streamsize>(str.length()));
+ }
+
+ template <typename Char1, typename Char2>
+ inline void print_to_stream(const std::basic_string<Char1>& str, std::basic_ostream<Char2>& stream)
+ {
+ static_assert(sizeof(Char1) == 1);
+ static_assert(sizeof(Char2) == 1);
+ stream.write(reinterpret_cast<const Char2*>(str.data()), static_cast<std::streamsize>(str.length()));
+ }
+
+ template <typename Char>
+ inline void print_to_stream(char character, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ stream.put(static_cast<Char>(character));
+ }
+
+ template <typename Char>
+ TOML_ATTR(nonnull)
+ inline void print_to_stream(const char* str, size_t len, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
+ }
+
+ #ifdef __cpp_lib_char8_t
+
+ template <typename Char>
+ inline void print_to_stream(char8_t character, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ stream.put(static_cast<Char>(character));
+ }
+
+ template <typename Char>
+ TOML_ATTR(nonnull)
+ inline void print_to_stream(const char8_t* str, size_t len, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
+ }
+
+ #endif
+
+ template <typename T> inline constexpr size_t charconv_buffer_length = 0;
+ template <> inline constexpr size_t charconv_buffer_length<double> = 60;
+ template <> inline constexpr size_t charconv_buffer_length<float> = 40;
+ template <> inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
+ template <> inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
+ template <> inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
+ template <> inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
+ template <> inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
+ template <> inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
+ template <> inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
+ template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
+
+ template <typename T, typename Char>
+ inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream, value_flags format = {})
+ {
+ static_assert(
+ sizeof(Char) == 1,
+ "The stream's underlying character type must be 1 byte in size."
+ );
+
+ if (!val)
+ {
+ print_to_stream('0', stream);
+ return;
+ }
+
+ int base = 10;
+ if (format != value_flags::none && val >= T{})
+ {
+ switch (format)
+ {
+ case value_flags::format_as_binary: base = 2; break;
+ case value_flags::format_as_octal: base = 8; break;
+ case value_flags::format_as_hexadecimal: base = 16; break;
+ default: break;
+ }
+ }
+
+ #if TOML_INT_CHARCONV
+ {
+ char buf[(sizeof(T) * CHAR_BIT)];
+ const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
+ const auto len = static_cast<size_t>(res.ptr - buf);
+ if (base == 16)
+ {
+ for (size_t i = 0; i < len; i++)
+ if (buf[i] >= 'a')
+ buf[i] -= 32;
+ }
+ print_to_stream(buf, len, stream);
+ }
+ #else
+ {
+ using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
+ using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
+
+ if TOML_UNLIKELY(format == value_flags::format_as_binary)
+ {
+ bool found_one = false;
+ const auto v = static_cast<unsigned_type>(val);
+ unsigned_type mask = unsigned_type{ 1 } << (sizeof(unsigned_type) * CHAR_BIT - 1u);
+ for (unsigned i = 0; i < sizeof(unsigned_type) * CHAR_BIT; i++)
+ {
+ if ((v & mask))
+ {
+ print_to_stream('1', stream);
+ found_one = true;
+ }
+ else if (found_one)
+ print_to_stream('0', stream);
+ mask >>= 1;
+ }
+ }
+ else
+ {
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ ss << std::uppercase << std::setbase(base);
+ ss << static_cast<cast_type>(val);
+ const auto str = std::move(ss).str();
+ print_to_stream(str, stream);
+ }
+ }
+ #endif
+ }
+
+ #define TOML_P2S_OVERLOAD(Type) \
+ template <typename Char> \
+ inline void print_to_stream(Type val, std::basic_ostream<Char>& stream, value_flags format) \
+ { \
+ static_assert(sizeof(Char) == 1); \
+ print_integer_to_stream(val, stream, format); \
+ }
+
+ TOML_P2S_OVERLOAD(int8_t)
+ TOML_P2S_OVERLOAD(int16_t)
+ TOML_P2S_OVERLOAD(int32_t)
+ TOML_P2S_OVERLOAD(int64_t)
+ TOML_P2S_OVERLOAD(uint8_t)
+ TOML_P2S_OVERLOAD(uint16_t)
+ TOML_P2S_OVERLOAD(uint32_t)
+ TOML_P2S_OVERLOAD(uint64_t)
+
+ #undef TOML_P2S_OVERLOAD
+
+ template <typename T, typename Char>
+ inline void print_floating_point_to_stream(T val, std::basic_ostream<Char>& stream, bool hexfloat = false)
+ {
+ static_assert(
+ sizeof(Char) == 1,
+ "The stream's underlying character type must be 1 byte in size."
+ );
+
+ switch (impl::fpclassify(val))
+ {
+ case fp_class::neg_inf:
+ print_to_stream("-inf"sv, stream);
+ break;
+
+ case fp_class::pos_inf:
+ print_to_stream("inf"sv, stream);
+ break;
+
+ case fp_class::nan:
+ print_to_stream("nan"sv, stream);
+ break;
+
+ case fp_class::ok:
+ {
+ static constexpr auto needs_decimal_point = [](auto&& s) noexcept
+ {
+ for (auto c : s)
+ if (c == '.' || c == 'E' || c == 'e')
+ return false;
+ return true;
+ };
+
+ #if TOML_FLOAT_CHARCONV
+ {
+ char buf[charconv_buffer_length<T>];
+ const auto res = hexfloat
+ ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
+ : std::to_chars(buf, buf + sizeof(buf), val);
+ const auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
+ print_to_stream(str, stream);
+ if (!hexfloat && needs_decimal_point(str))
+ print_to_stream(".0"sv, stream);
+ }
+ #else
+ {
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ ss.precision(std::numeric_limits<T>::digits10 + 1);
+ if (hexfloat)
+ ss << std::hexfloat;
+ ss << val;
+ const auto str = std::move(ss).str();
+ print_to_stream(str, stream);
+ if (!hexfloat && needs_decimal_point(str))
+ print_to_stream(".0"sv, stream);
+ }
+ #endif
+
+ break;
+ }
+
+ TOML_NO_DEFAULT_CASE;
+ }
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
+ #endif
+
+ #define TOML_P2S_OVERLOAD(Type) \
+ template <typename Char> \
+ inline void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
+ { \
+ static_assert(sizeof(Char) == 1); \
+ print_floating_point_to_stream(val, stream); \
+ }
+
+ TOML_P2S_OVERLOAD(double)
+
+ #undef TOML_P2S_OVERLOAD
+
+ template <typename Char>
+ inline void print_to_stream(bool val, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ print_to_stream(val ? "true"sv : "false"sv, stream);
+ }
+
+ template <typename T, typename Char>
+ inline void print_to_stream(T val, std::basic_ostream<Char>& stream, size_t zero_pad_to_digits)
+ {
+ static_assert(sizeof(Char) == 1);
+ #if TOML_INT_CHARCONV
+
+ char buf[charconv_buffer_length<T>];
+ const auto res = std::to_chars(buf, buf + sizeof(buf), val);
+ const auto len = static_cast<size_t>(res.ptr - buf);
+ for (size_t i = len; i < zero_pad_to_digits; i++)
+ print_to_stream('0', stream);
+ print_to_stream(buf, static_cast<size_t>(res.ptr - buf), stream);
+
+ #else
+
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
+ ss << std::setfill('0') << std::setw(static_cast<int>(zero_pad_to_digits)) << static_cast<cast_type>(val);
+ const auto str = std::move(ss).str();
+ print_to_stream(str, stream);
+
+ #endif
+ }
+
+ template <typename Char>
+ inline void print_to_stream(const toml::date& val, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ print_to_stream(val.year, stream, 4_sz);
+ print_to_stream('-', stream);
+ print_to_stream(val.month, stream, 2_sz);
+ print_to_stream('-', stream);
+ print_to_stream(val.day, stream, 2_sz);
+ }
+
+ template <typename Char>
+ inline void print_to_stream(const toml::time& val, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ print_to_stream(val.hour, stream, 2_sz);
+ print_to_stream(':', stream);
+ print_to_stream(val.minute, stream, 2_sz);
+ print_to_stream(':', stream);
+ print_to_stream(val.second, stream, 2_sz);
+ if (val.nanosecond && val.nanosecond <= 999999999u)
+ {
+ print_to_stream('.', stream);
+ auto ns = val.nanosecond;
+ size_t digits = 9_sz;
+ while (ns % 10u == 0u)
+ {
+ ns /= 10u;
+ digits--;
+ }
+ print_to_stream(ns, stream, digits);
+ }
+ }
+
+ template <typename Char>
+ inline void print_to_stream(toml::time_offset val, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ if (!val.minutes)
+ print_to_stream('Z', stream);
+ else
+ {
+ auto mins = static_cast<int>(val.minutes);
+ if (mins < 0)
+ {
+ print_to_stream('-', stream);
+ mins = -mins;
+ }
+ else
+ print_to_stream('+', stream);
+ const auto hours = mins / 60;
+ if (hours)
+ {
+ print_to_stream(static_cast<unsigned int>(hours), stream, 2_sz);
+ mins -= hours * 60;
+ }
+ else
+ print_to_stream("00"sv, stream);
+ print_to_stream(':', stream);
+ print_to_stream(static_cast<unsigned int>(mins), stream, 2_sz);
+ }
+ }
+
+ template <typename Char>
+ inline void print_to_stream(const toml::date_time& val, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ print_to_stream(val.date, stream);
+ print_to_stream('T', stream);
+ print_to_stream(val.time, stream);
+ if (val.offset)
+ print_to_stream(*val.offset, stream);
+ }
+
+ TOML_PUSH_WARNINGS
+ TOML_DISABLE_ARITHMETIC_WARNINGS
+
+ template <typename T, typename Char>
+ void print_to_stream_with_escapes(T && str, std::basic_ostream<Char>& stream)
+ {
+ static_assert(sizeof(Char) == 1);
+ for (auto c : str)
+ {
+ if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
+ print_to_stream(low_character_escape_table[c], stream);
+ else if TOML_UNLIKELY(c == '\x7F')
+ print_to_stream("\\u007F"sv, stream);
+ else if TOML_UNLIKELY(c == '"')
+ print_to_stream("\\\""sv, stream);
+ else if TOML_UNLIKELY(c == '\\')
+ print_to_stream("\\\\"sv, stream);
+ else
+ print_to_stream(c, stream);
+ }
+ }
+
+ TOML_POP_WARNINGS // TOML_DISABLE_ARITHMETIC_WARNINGS
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const source_position& rhs)
+ {
+ static_assert(
+ sizeof(Char) == 1,
+ "The stream's underlying character type must be 1 byte in size."
+ );
+ impl::print_to_stream("line "sv, lhs);
+ impl::print_to_stream(rhs.line, lhs);
+ impl::print_to_stream(", column "sv, lhs);
+ impl::print_to_stream(rhs.column, lhs);
+ return lhs;
+ }
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const source_region& rhs)
+ {
+ static_assert(
+ sizeof(Char) == 1,
+ "The stream's underlying character type must be 1 byte in size."
+ );
+ lhs << rhs.begin;
+ if (rhs.path)
+ {
+ impl::print_to_stream(" of '"sv, lhs);
+ impl::print_to_stream(*rhs.path, lhs);
+ impl::print_to_stream('\'', lhs);
+ }
+ return lhs;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, const source_position&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const source_region&);
+ #endif
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
+
+#endif //------------------------------------------------------------------------------- ↑ toml_print_to_stream.h ----
+
+#if 1 //---------- ↓ toml_node.h ------------------------------------------------------------------------------------
+
+#if defined(DOXYGEN) || TOML_SIMPLE_STATIC_ASSERT_MESSAGES
+
+#define TOML_SA_NEWLINE " "
+#define TOML_SA_LIST_SEP ", "
+#define TOML_SA_LIST_BEG " ("
+#define TOML_SA_LIST_END ")"
+#define TOML_SA_LIST_NEW " "
+#define TOML_SA_LIST_NXT ", "
+
+#else
+
+#define TOML_SA_NEWLINE "\n| "
+#define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - "
+#define TOML_SA_LIST_BEG TOML_SA_LIST_SEP
+#define TOML_SA_LIST_END
+#define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE
+#define TOML_SA_LIST_NXT TOML_SA_LIST_NEW
+
+#endif
+
+#define TOML_SA_NATIVE_VALUE_TYPE_LIST \
+ TOML_SA_LIST_BEG "std::string" \
+ TOML_SA_LIST_SEP "int64_t" \
+ TOML_SA_LIST_SEP "double" \
+ TOML_SA_LIST_SEP "bool" \
+ TOML_SA_LIST_SEP "toml::date" \
+ TOML_SA_LIST_SEP "toml::time" \
+ TOML_SA_LIST_SEP "toml::date_time" \
+ TOML_SA_LIST_END
+
+#define TOML_SA_NODE_TYPE_LIST \
+ TOML_SA_LIST_BEG "toml::table" \
+ TOML_SA_LIST_SEP "toml::array" \
+ TOML_SA_LIST_SEP "toml::value<std::string>" \
+ TOML_SA_LIST_SEP "toml::value<int64_t>" \
+ TOML_SA_LIST_SEP "toml::value<double>" \
+ TOML_SA_LIST_SEP "toml::value<bool>" \
+ TOML_SA_LIST_SEP "toml::value<toml::date>" \
+ TOML_SA_LIST_SEP "toml::value<toml::time>" \
+ TOML_SA_LIST_SEP "toml::value<toml::date_time>" \
+ TOML_SA_LIST_END
+
+#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \
+ TOML_SA_LIST_NEW "A native TOML value type" \
+ TOML_SA_NATIVE_VALUE_TYPE_LIST \
+ \
+ TOML_SA_LIST_NXT "A TOML node type" \
+ TOML_SA_NODE_TYPE_LIST
+
+TOML_NAMESPACE_START
+{
+ class TOML_INTERFACE TOML_API node
+ {
+ private:
+ friend class TOML_PARSER_TYPENAME;
+ source_region source_{};
+
+ protected:
+
+ node() noexcept = default;
+ node(const node&) noexcept;
+ node(node&&) noexcept;
+ node& operator= (const node&) noexcept;
+ node& operator= (node&&) noexcept;
+
+ template <typename T>
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ impl::wrap_node<T>& ref_cast() & noexcept
+ {
+ return *reinterpret_cast<impl::wrap_node<T>*>(this);
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ impl::wrap_node<T>&& ref_cast() && noexcept
+ {
+ return std::move(*reinterpret_cast<impl::wrap_node<T>*>(this));
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ const impl::wrap_node<T>& ref_cast() const & noexcept
+ {
+ return *reinterpret_cast<const impl::wrap_node<T>*>(this);
+ }
+
+ template <typename N, typename T>
+ using ref_cast_type = decltype(std::declval<N>().template ref_cast<T>());
+
+ public:
+
+ virtual ~node() noexcept = default;
+
+ [[nodiscard]] virtual node_type type() const noexcept = 0;
+ [[nodiscard]] virtual bool is_table() const noexcept = 0;
+ [[nodiscard]] virtual bool is_array() const noexcept = 0;
+ [[nodiscard]] virtual bool is_value() const noexcept = 0;
+ [[nodiscard]] virtual bool is_string() const noexcept;
+ [[nodiscard]] virtual bool is_integer() const noexcept;
+ [[nodiscard]] virtual bool is_floating_point() const noexcept;
+ [[nodiscard]] virtual bool is_number() const noexcept;
+ [[nodiscard]] virtual bool is_boolean() const noexcept;
+ [[nodiscard]] virtual bool is_date() const noexcept;
+ [[nodiscard]] virtual bool is_time() const noexcept;
+ [[nodiscard]] virtual bool is_date_time() const noexcept;
+ [[nodiscard]] virtual bool is_array_of_tables() const noexcept;
+
+ template <typename T>
+ [[nodiscard]]
+ bool is() const noexcept
+ {
+ using type = impl::unwrap_node<T>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "The template type argument of node::is() must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ if constexpr (std::is_same_v<type, table>) return is_table();
+ else if constexpr (std::is_same_v<type, array>) return is_array();
+ else if constexpr (std::is_same_v<type, std::string>) return is_string();
+ else if constexpr (std::is_same_v<type, int64_t>) return is_integer();
+ else if constexpr (std::is_same_v<type, double>) return is_floating_point();
+ else if constexpr (std::is_same_v<type, bool>) return is_boolean();
+ else if constexpr (std::is_same_v<type, date>) return is_date();
+ else if constexpr (std::is_same_v<type, time>) return is_time();
+ else if constexpr (std::is_same_v<type, date_time>) return is_date_time();
+ }
+
+ [[nodiscard]] virtual table* as_table() noexcept;
+ [[nodiscard]] virtual array* as_array() noexcept;
+ [[nodiscard]] virtual toml::value<std::string>* as_string() noexcept;
+ [[nodiscard]] virtual toml::value<int64_t>* as_integer() noexcept;
+ [[nodiscard]] virtual toml::value<double>* as_floating_point() noexcept;
+ [[nodiscard]] virtual toml::value<bool>* as_boolean() noexcept;
+ [[nodiscard]] virtual toml::value<date>* as_date() noexcept;
+ [[nodiscard]] virtual toml::value<time>* as_time() noexcept;
+ [[nodiscard]] virtual toml::value<date_time>* as_date_time() noexcept;
+ [[nodiscard]] virtual const table* as_table() const noexcept;
+ [[nodiscard]] virtual const array* as_array() const noexcept;
+ [[nodiscard]] virtual const toml::value<std::string>* as_string() const noexcept;
+ [[nodiscard]] virtual const toml::value<int64_t>* as_integer() const noexcept;
+ [[nodiscard]] virtual const toml::value<double>* as_floating_point() const noexcept;
+ [[nodiscard]] virtual const toml::value<bool>* as_boolean() const noexcept;
+ [[nodiscard]] virtual const toml::value<date>* as_date() const noexcept;
+ [[nodiscard]] virtual const toml::value<time>* as_time() const noexcept;
+ [[nodiscard]] virtual const toml::value<date_time>* as_date_time() const noexcept;
+ [[nodiscard]] virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
+ [[nodiscard]] virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
+ [[nodiscard]] virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
+
+ template <typename ElemType = void>
+ [[nodiscard]]
+ bool is_homogeneous() const noexcept
+ {
+ using type = impl::unwrap_node<ElemType>;
+ static_assert(
+ std::is_void_v<type>
+ || ((impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>),
+ "The template type argument of node::is_homogeneous() must be void or one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+ return is_homogeneous(impl::node_type_of<type>);
+ }
+
+ private:
+
+ #ifndef DOXYGEN
+
+ template <typename T>
+ [[nodiscard]]
+ decltype(auto) get_value_exact() const noexcept;
+
+ #endif // !DOXYGEN
+
+ public:
+
+ template <typename T>
+ [[nodiscard]]
+ optional<T> value_exact() const noexcept;
+
+ template <typename T>
+ [[nodiscard]]
+ optional<T> value() const noexcept;
+
+ template <typename T>
+ [[nodiscard]]
+ auto value_or(T&& default_value) const noexcept;
+
+ //template <typename T>
+ //[[nodiscard]]
+ //std::vector<T> select_exact() const noexcept;
+
+ //template <typename T>
+ //[[nodiscard]]
+ //std::vector<T> select() const noexcept;
+
+ template <typename T>
+ [[nodiscard]]
+ impl::wrap_node<T>* as() noexcept
+ {
+ using type = impl::unwrap_node<T>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "The template type argument of node::as() must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ if constexpr (std::is_same_v<type, table>) return as_table();
+ else if constexpr (std::is_same_v<type, array>) return as_array();
+ else if constexpr (std::is_same_v<type, std::string>) return as_string();
+ else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
+ else if constexpr (std::is_same_v<type, double>) return as_floating_point();
+ else if constexpr (std::is_same_v<type, bool>) return as_boolean();
+ else if constexpr (std::is_same_v<type, date>) return as_date();
+ else if constexpr (std::is_same_v<type, time>) return as_time();
+ else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ const impl::wrap_node<T>* as() const noexcept
+ {
+ using type = impl::unwrap_node<T>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "The template type argument of node::as() must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ if constexpr (std::is_same_v<type, table>) return as_table();
+ else if constexpr (std::is_same_v<type, array>) return as_array();
+ else if constexpr (std::is_same_v<type, std::string>) return as_string();
+ else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
+ else if constexpr (std::is_same_v<type, double>) return as_floating_point();
+ else if constexpr (std::is_same_v<type, bool>) return as_boolean();
+ else if constexpr (std::is_same_v<type, date>) return as_date();
+ else if constexpr (std::is_same_v<type, time>) return as_time();
+ else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
+ }
+
+ [[nodiscard]] const source_region& source() const noexcept;
+
+ private:
+
+ template <typename Func, typename N, typename T>
+ static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<N, T>>;
+
+ template <typename Func, typename N>
+ static constexpr bool can_visit_any =
+ can_visit<Func, N, table>
+ || can_visit<Func, N, array>
+ || can_visit<Func, N, std::string>
+ || can_visit<Func, N, int64_t>
+ || can_visit<Func, N, double>
+ || can_visit<Func, N, bool>
+ || can_visit<Func, N, date>
+ || can_visit<Func, N, time>
+ || can_visit<Func, N, date_time>;
+
+ template <typename Func, typename N>
+ static constexpr bool can_visit_all =
+ can_visit<Func, N, table>
+ && can_visit<Func, N, array>
+ && can_visit<Func, N, std::string>
+ && can_visit<Func, N, int64_t>
+ && can_visit<Func, N, double>
+ && can_visit<Func, N, bool>
+ && can_visit<Func, N, date>
+ && can_visit<Func, N, time>
+ && can_visit<Func, N, date_time>;
+
+ template <typename Func, typename N, typename T>
+ static constexpr bool visit_is_nothrow_one =
+ !can_visit<Func, N, T>
+ || std::is_nothrow_invocable_v<Func, ref_cast_type<N, T>>;
+
+ template <typename Func, typename N>
+ static constexpr bool visit_is_nothrow =
+ visit_is_nothrow_one<Func, N, table>
+ && visit_is_nothrow_one<Func, N, array>
+ && visit_is_nothrow_one<Func, N, std::string>
+ && visit_is_nothrow_one<Func, N, int64_t>
+ && visit_is_nothrow_one<Func, N, double>
+ && visit_is_nothrow_one<Func, N, bool>
+ && visit_is_nothrow_one<Func, N, date>
+ && visit_is_nothrow_one<Func, N, time>
+ && visit_is_nothrow_one<Func, N, date_time>;
+
+ template <typename Func, typename N, typename T, bool = can_visit<Func, N, T>>
+ struct visit_return_type final
+ {
+ using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<N, T>>()));
+ };
+ template <typename Func, typename N, typename T>
+ struct visit_return_type<Func, N, T, false> final
+ {
+ using type = void;
+ };
+
+ template <typename A, typename B>
+ using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
+
+ template <typename N, typename Func>
+ static decltype(auto) do_visit(N&& n, Func&& visitor)
+ noexcept(visit_is_nothrow<Func&&, N&&>)
+ {
+ static_assert(
+ can_visit_any<Func&&, N&&>,
+ "TOML node visitors must be invocable for at least one of the toml::node specializations:"
+ TOML_SA_NODE_TYPE_LIST
+ );
+
+ switch (n.type())
+ {
+ case node_type::table:
+ if constexpr (can_visit<Func&&, N&&, table>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<table>());
+ break;
+
+ case node_type::array:
+ if constexpr (can_visit<Func&&, N&&, array>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<array>());
+ break;
+
+ case node_type::string:
+ if constexpr (can_visit<Func&&, N&&, std::string>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<std::string>());
+ break;
+
+ case node_type::integer:
+ if constexpr (can_visit<Func&&, N&&, int64_t>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<int64_t>());
+ break;
+
+ case node_type::floating_point:
+ if constexpr (can_visit<Func&&, N&&, double>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<double>());
+ break;
+
+ case node_type::boolean:
+ if constexpr (can_visit<Func&&, N&&, bool>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<bool>());
+ break;
+
+ case node_type::date:
+ if constexpr (can_visit<Func&&, N&&, date>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date>());
+ break;
+
+ case node_type::time:
+ if constexpr (can_visit<Func&&, N&&, time>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<time>());
+ break;
+
+ case node_type::date_time:
+ if constexpr (can_visit<Func&&, N&&, date_time>)
+ return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date_time>());
+ break;
+
+ case node_type::none: TOML_UNREACHABLE;
+ TOML_NO_DEFAULT_CASE;
+ }
+
+ if constexpr (can_visit_all<Func&&, N&&>)
+ TOML_UNREACHABLE;
+ else
+ {
+ using return_type =
+ nonvoid<typename visit_return_type<Func&&, N&&, table>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, array>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, std::string>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, int64_t>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, double>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, bool>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, date>::type,
+ nonvoid<typename visit_return_type<Func&&, N&&, time>::type,
+ typename visit_return_type<Func&&, N&&, date_time>::type
+ >>>>>>>>;
+
+ if constexpr (!std::is_void_v<return_type>)
+ {
+ static_assert(
+ std::is_default_constructible_v<return_type>,
+ "Non-exhaustive visitors must return a default-constructible type, or void"
+ );
+ return return_type{};
+ }
+ }
+ }
+
+ template <typename T, typename N>
+ [[nodiscard]]
+ static decltype(auto) do_ref(N&& n) noexcept
+ {
+ using type = impl::unwrap_node<T>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "The template type argument of node::ref() must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+ TOML_ASSERT(
+ n.template is<T>()
+ && "template type argument T provided to toml::node::ref() didn't match the node's actual type"
+ );
+ if constexpr (impl::is_native<type>)
+ return std::forward<N>(n).template ref_cast<type>().get();
+ else
+ return std::forward<N>(n).template ref_cast<type>();
+ }
+
+ public:
+
+ template <typename Func>
+ decltype(auto) visit(Func&& visitor) &
+ noexcept(visit_is_nothrow<Func&&, node&>)
+ {
+ return do_visit(*this, std::forward<Func>(visitor));
+ }
+
+ template <typename Func>
+ decltype(auto) visit(Func&& visitor) &&
+ noexcept(visit_is_nothrow<Func&&, node&&>)
+ {
+ return do_visit(std::move(*this), std::forward<Func>(visitor));
+ }
+
+ template <typename Func>
+ decltype(auto) visit(Func&& visitor) const&
+ noexcept(visit_is_nothrow<Func&&, const node&>)
+ {
+ return do_visit(*this, std::forward<Func>(visitor));
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ impl::unwrap_node<T>& ref() & noexcept
+ {
+ return do_ref<T>(*this);
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ impl::unwrap_node<T>&& ref() && noexcept
+ {
+ return do_ref<T>(std::move(*this));
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ const impl::unwrap_node<T>& ref() const& noexcept
+ {
+ return do_ref<T>(*this);
+ }
+
+ [[nodiscard]] explicit operator node_view<node>() noexcept;
+ [[nodiscard]] explicit operator node_view<const node>() const noexcept;
+ };
+}
+TOML_NAMESPACE_END
+
+#endif //---------- ↑ toml_node.h ------------------------------------------------------------------------------------
+
+#if 1 //---------------------------------- ↓ toml_value.h -----------------------------------------------------------
+
+#ifndef DOXYGEN
+ #if TOML_WINDOWS_COMPAT
+ #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
+ #else
+ #define TOML_SA_VALUE_MESSAGE_WSTRING
+ #endif
+
+ #ifdef __cpp_lib_char8_t
+ #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
+ #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
+ #else
+ #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
+ #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
+ #endif
+
+ #define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
+ "The " type_arg " must be one of:" \
+ TOML_SA_LIST_NEW "A native TOML value type" \
+ TOML_SA_NATIVE_VALUE_TYPE_LIST \
+ \
+ TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
+ TOML_SA_LIST_BEG "std::string" \
+ TOML_SA_VALUE_MESSAGE_WSTRING \
+ TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
+ TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
+ TOML_SA_LIST_END \
+ \
+ TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
+ TOML_SA_LIST_BEG "std::string_view" \
+ TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
+ TOML_SA_LIST_SEP "const char*" \
+ TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
+ TOML_SA_LIST_END
+
+ #define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
+ "The " type_arg " must be one of:" \
+ TOML_SA_LIST_NEW "A native TOML value type" \
+ TOML_SA_NATIVE_VALUE_TYPE_LIST \
+ \
+ TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
+ TOML_SA_LIST_BEG "std::string" \
+ TOML_SA_VALUE_MESSAGE_WSTRING \
+ TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
+ TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
+ TOML_SA_LIST_END \
+ \
+ TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
+ TOML_SA_LIST_BEG "any other integer type" \
+ TOML_SA_LIST_SEP "any floating-point type >= 32 bits" \
+ TOML_SA_LIST_END \
+ \
+ TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
+ TOML_SA_LIST_BEG "std::string_view" \
+ TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
+ TOML_SA_LIST_SEP "const char*" \
+ TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
+ TOML_SA_LIST_END
+#endif // !DOXYGEN
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_ARITHMETIC_WARNINGS
+
+TOML_IMPL_NAMESPACE_START
+{
+ template <typename T, typename...>
+ struct native_value_maker
+ {
+ template <typename... Args>
+ [[nodiscard]]
+ static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
+ {
+ return T(std::forward<Args>(args)...);
+ }
+ };
+
+ template <typename T>
+ struct native_value_maker<T, T>
+ {
+ template <typename U>
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ static U&& make(U&& val) noexcept
+ {
+ return std::forward<U>(val);
+ }
+ };
+
+ #if defined(__cpp_lib_char8_t) || TOML_WINDOWS_COMPAT
+
+ struct string_maker
+ {
+ template <typename T>
+ [[nodiscard]]
+ static std::string make(T&& arg) noexcept
+ {
+ #ifdef __cpp_lib_char8_t
+ if constexpr (is_one_of<std::decay_t<T>, char8_t*, const char8_t*>)
+ return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
+ else if constexpr (is_one_of<remove_cvref_t<T>, std::u8string, std::u8string_view>)
+ return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())), arg.length());
+ #endif // __cpp_lib_char8_t
+
+ #if TOML_WINDOWS_COMPAT
+ if constexpr (is_wide_string<T>)
+ return narrow(std::forward<T>(arg));
+ #endif // TOML_WINDOWS_COMPAT
+ }
+ };
+ #ifdef __cpp_lib_char8_t
+ template <> struct native_value_maker<std::string, char8_t*> : string_maker {};
+ template <> struct native_value_maker<std::string, const char8_t*> : string_maker {};
+ template <> struct native_value_maker<std::string, std::u8string> : string_maker {};
+ template <> struct native_value_maker<std::string, std::u8string_view> : string_maker {};
+ #endif // __cpp_lib_char8_t
+ #if TOML_WINDOWS_COMPAT
+ template <> struct native_value_maker<std::string, wchar_t*> : string_maker {};
+ template <> struct native_value_maker<std::string, const wchar_t*> : string_maker {};
+ template <> struct native_value_maker<std::string, std::wstring> : string_maker {};
+ template <> struct native_value_maker<std::string, std::wstring_view> : string_maker {};
+ #endif // TOML_WINDOWS_COMPAT
+
+ #endif // defined(__cpp_lib_char8_t) || TOML_WINDOWS_COMPAT
+
+ template <typename T>
+ [[nodiscard]]
+ TOML_ATTR(const)
+ inline optional<T> node_integer_cast(int64_t val) noexcept
+ {
+ static_assert(node_type_of<T> == node_type::integer);
+ static_assert(!is_cvref<T>);
+
+ using traits = value_traits<T>;
+ if constexpr (!traits::is_signed)
+ {
+ if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
+ {
+ using common_t = decltype(int64_t{} + T{});
+ if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
+ return {};
+ }
+ else
+ {
+ if (val < int64_t{})
+ return {};
+ }
+ }
+ else
+ {
+ if (val < traits::min || val > traits::max)
+ return {};
+ }
+ return { static_cast<T>(val) };
+ }
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ template <typename ValueType>
+ class TOML_API value final : public node
+ {
+ static_assert(
+ impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
+ "A toml::value<> must model one of the native TOML value types:"
+ TOML_SA_NATIVE_VALUE_TYPE_LIST
+ );
+
+ private:
+ friend class TOML_PARSER_TYPENAME;
+
+ template <typename T, typename U>
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ TOML_ATTR(const)
+ static auto as_value([[maybe_unused]] U* ptr) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, T>)
+ return ptr;
+ else
+ return nullptr;
+ }
+
+ ValueType val_;
+ value_flags flags_ = value_flags::none;
+
+ #if TOML_LIFETIME_HOOKS
+ void lh_ctor() noexcept
+ {
+ TOML_VALUE_CREATED;
+ }
+
+ void lh_dtor() noexcept
+ {
+ TOML_VALUE_DESTROYED;
+ }
+ #endif
+
+ public:
+
+ using value_type = ValueType;
+ using value_arg = std::conditional_t<
+ std::is_same_v<value_type, std::string>,
+ std::string_view,
+ std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>
+ >;
+
+ template <typename... Args>
+ TOML_NODISCARD_CTOR
+ explicit value(Args&&... args)
+ noexcept(noexcept(value_type(
+ impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...)
+ )))
+ : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...))
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_NODISCARD_CTOR
+ value(const value& other) noexcept
+ : node{ other },
+ val_{ other.val_ },
+ flags_{ other.flags_ }
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_NODISCARD_CTOR
+ value(value&& other) noexcept
+ : node{ std::move(other) },
+ val_{ std::move(other.val_) },
+ flags_{ other.flags_ }
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ value& operator= (const value& rhs) noexcept
+ {
+ node::operator=(rhs);
+ val_ = rhs.val_;
+ flags_ = rhs.flags_;
+ return *this;
+ }
+
+ value& operator= (value&& rhs) noexcept
+ {
+ if (&rhs != this)
+ {
+ node::operator=(std::move(rhs));
+ val_ = std::move(rhs.val_);
+ flags_ = rhs.flags_;
+ }
+ return *this;
+ }
+
+ #if TOML_LIFETIME_HOOKS
+ ~value() noexcept override
+ {
+ lh_dtor();
+ }
+ #endif
+
+ [[nodiscard]] node_type type() const noexcept override { return impl::node_type_of<value_type>; }
+ [[nodiscard]] bool is_table() const noexcept override { return false; }
+ [[nodiscard]] bool is_array() const noexcept override { return false; }
+ [[nodiscard]] bool is_value() const noexcept override { return true; }
+ [[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<value_type, std::string>; }
+ [[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v<value_type, int64_t>; }
+ [[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v<value_type, double>; }
+ [[nodiscard]] bool is_number() const noexcept override { return impl::is_one_of<value_type, int64_t, double>; }
+ [[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v<value_type, bool>; }
+ [[nodiscard]] bool is_date() const noexcept override { return std::is_same_v<value_type, date>; }
+ [[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<value_type, time>; }
+ [[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v<value_type, date_time>; }
+ [[nodiscard]] value<std::string>* as_string() noexcept override { return as_value<std::string>(this); }
+ [[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(this); }
+ [[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(this); }
+ [[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(this); }
+ [[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(this); }
+ [[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(this); }
+ [[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(this); }
+ [[nodiscard]] const value<std::string>* as_string() const noexcept override { return as_value<std::string>(this); }
+ [[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(this); }
+ [[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(this); }
+ [[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(this); }
+ [[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(this); }
+ [[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(this); }
+ [[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
+ [[nodiscard]]
+ bool is_homogeneous(node_type ntype) const noexcept override
+ {
+ return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
+ }
+ [[nodiscard]]
+ bool is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept override
+ {
+ if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
+ {
+ first_nonmatch = this;
+ return false;
+ }
+ return true;
+ }
+ [[nodiscard]]
+ bool is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept override
+ {
+ if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
+ {
+ first_nonmatch = this;
+ return false;
+ }
+ return true;
+ }
+ template <typename ElemType = void>
+ [[nodiscard]]
+ bool is_homogeneous() const noexcept
+ {
+ using type = impl::unwrap_node<ElemType>;
+ static_assert(
+ std::is_void_v<type>
+ || ((impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>),
+ "The template type argument of value::is_homogeneous() must be void or one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ using type = impl::unwrap_node<ElemType>;
+ if constexpr (std::is_void_v<type>)
+ return true;
+ else
+ return impl::node_type_of<type> == impl::node_type_of<value_type>;
+ }
+
+ [[nodiscard]] value_type& get() & noexcept { return val_; }
+ [[nodiscard]] value_type&& get() && noexcept { return std::move(val_); }
+ [[nodiscard]] const value_type& get() const & noexcept { return val_; }
+
+ [[nodiscard]] value_type& operator* () & noexcept { return val_; }
+ [[nodiscard]] value_type&& operator* () && noexcept { return std::move(val_); }
+ [[nodiscard]] const value_type& operator* () const& noexcept { return val_; }
+
+ [[nodiscard]] explicit operator value_type& () & noexcept { return val_; }
+ [[nodiscard]] explicit operator value_type && () && noexcept { return std::move(val_); }
+ [[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
+
+ [[nodiscard]] value_flags flags() const noexcept
+ {
+ return flags_;
+ }
+
+ value& flags(value_flags new_flags) noexcept
+ {
+ flags_ = new_flags;
+ return *this;
+ }
+
+ template <typename Char, typename T>
+ friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs);
+ // implemented in toml_default_formatter.h
+
+ value& operator= (value_arg rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, std::string>)
+ val_.assign(rhs);
+ else
+ val_ = rhs;
+ return *this;
+ }
+
+ template <typename T = value_type, typename = std::enable_if_t<std::is_same_v<T, std::string>>>
+ value& operator= (std::string&& rhs) noexcept
+ {
+ val_ = std::move(rhs);
+ return *this;
+ }
+
+ [[nodiscard]]
+ friend bool operator == (const value& lhs, value_arg rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, double>)
+ {
+ const auto lhs_class = impl::fpclassify(lhs.val_);
+ const auto rhs_class = impl::fpclassify(rhs);
+ if (lhs_class == impl::fp_class::nan && rhs_class == impl::fp_class::nan)
+ return true;
+ if ((lhs_class == impl::fp_class::nan) != (rhs_class == impl::fp_class::nan))
+ return false;
+ }
+ return lhs.val_ == rhs;
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, )
+ [[nodiscard]] friend bool operator < (const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; }
+ [[nodiscard]] friend bool operator < (value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; }
+ [[nodiscard]] friend bool operator <= (const value& lhs, value_arg rhs) noexcept { return lhs.val_ <= rhs; }
+ [[nodiscard]] friend bool operator <= (value_arg lhs, const value& rhs) noexcept { return lhs <= rhs.val_; }
+ [[nodiscard]] friend bool operator > (const value& lhs, value_arg rhs) noexcept { return lhs.val_ > rhs; }
+ [[nodiscard]] friend bool operator > (value_arg lhs, const value& rhs) noexcept { return lhs > rhs.val_; }
+ [[nodiscard]] friend bool operator >= (const value& lhs, value_arg rhs) noexcept { return lhs.val_ >= rhs; }
+ [[nodiscard]] friend bool operator >= (value_arg lhs, const value& rhs) noexcept { return lhs >= rhs.val_; }
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator == (const value& lhs, const value<T>& rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, T>)
+ return lhs == rhs.val_; //calls asymmetrical value-equality operator defined above
+ else
+ return false;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator != (const value& lhs, const value<T>& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator < (const value& lhs, const value<T>& rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, T>)
+ return lhs.val_ < rhs.val_;
+ else
+ return impl::node_type_of<value_type> < impl::node_type_of<T>;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator <= (const value& lhs, const value<T>& rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, T>)
+ return lhs.val_ <= rhs.val_;
+ else
+ return impl::node_type_of<value_type> <= impl::node_type_of<T>;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator > (const value& lhs, const value<T>& rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, T>)
+ return lhs.val_ > rhs.val_;
+ else
+ return impl::node_type_of<value_type> > impl::node_type_of<T>;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator >= (const value& lhs, const value<T>& rhs) noexcept
+ {
+ if constexpr (std::is_same_v<value_type, T>)
+ return lhs.val_ >= rhs.val_;
+ else
+ return impl::node_type_of<value_type> >= impl::node_type_of<T>;
+ }
+ };
+ template <typename T>
+ value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
+
+ #ifndef DOXYGEN
+ TOML_PUSH_WARNINGS
+ TOML_DISABLE_INIT_WARNINGS
+ TOML_DISABLE_SWITCH_WARNINGS
+
+ #if !TOML_HEADER_ONLY
+ extern template class TOML_API value<std::string>;
+ extern template class TOML_API value<int64_t>;
+ extern template class TOML_API value<double>;
+ extern template class TOML_API value<bool>;
+ extern template class TOML_API value<date>;
+ extern template class TOML_API value<time>;
+ extern template class TOML_API value<date_time>;
+ #endif
+
+ template <typename T>
+ [[nodiscard]]
+ inline decltype(auto) node::get_value_exact() const noexcept
+ {
+ using namespace impl;
+
+ static_assert(node_type_of<T> != node_type::none);
+ static_assert(node_type_of<T> != node_type::table);
+ static_assert(node_type_of<T> != node_type::array);
+ static_assert(is_native<T> || can_represent_native<T>);
+ static_assert(!is_cvref<T>);
+ TOML_ASSERT(this->type() == node_type_of<T>);
+
+ if constexpr (node_type_of<T> == node_type::string)
+ {
+ const auto& str = *ref_cast<std::string>();
+ if constexpr (std::is_same_v<T, std::string>)
+ return str;
+ else if constexpr (std::is_same_v<T, std::string_view>)
+ return T{ str };
+ else if constexpr (std::is_same_v<T, const char*>)
+ return str.c_str();
+
+ else if constexpr (std::is_same_v<T, std::wstring>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return widen(str);
+ #else
+ static_assert(dependent_false<T>, "Evaluated unreachable branch!");
+ #endif
+ }
+
+ #ifdef __cpp_lib_char8_t
+
+ // char -> char8_t (potentially unsafe - the feature is 'experimental'!)
+ else if constexpr (is_one_of<T, std::u8string, std::u8string_view>)
+ return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length());
+ else if constexpr (std::is_same_v<T, const char8_t*>)
+ return reinterpret_cast<const char8_t*>(str.c_str());
+ else
+ static_assert(dependent_false<T>, "Evaluated unreachable branch!");
+
+ #endif
+ }
+ else
+ return static_cast<T>(*ref_cast<native_type_of<T>>());
+ }
+
+ template <typename T>
+ inline optional<T> node::value_exact() const noexcept
+ {
+ using namespace impl;
+
+ static_assert(
+ !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ "Retrieving values as wide-character strings with node::value_exact() is only "
+ "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ static_assert(
+ (is_native<T> || can_represent_native<T>) && !is_cvref<T>,
+ TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")
+ );
+
+ // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
+ if constexpr ((is_native<T> || can_represent_native<T>) && !is_cvref<T>)
+ {
+ if (type() == node_type_of<T>)
+ return { this->get_value_exact<T>() };
+ else
+ return {};
+ }
+ }
+
+ template <typename T>
+ inline optional<T> node::value() const noexcept
+ {
+ using namespace impl;
+
+ static_assert(
+ !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ "Retrieving values as wide-character strings with node::value() is only "
+ "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+ static_assert(
+ (is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
+ TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")
+ );
+
+ // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
+ // semantics to be mindful of so the exact retrieval is enough.
+ if constexpr (is_natively_one_of<T, std::string, time, date, date_time>)
+ {
+ if (type() == node_type_of<T>)
+ return { this->get_value_exact<T>() };
+ else
+ return {};
+ }
+
+ // everything else requires a bit of logicking.
+ else
+ {
+ switch (type())
+ {
+ // int -> *
+ case node_type::integer:
+ {
+ // int -> int
+ if constexpr (is_natively_one_of<T, int64_t>)
+ {
+ if constexpr (is_native<T> || can_represent_native<T>)
+ return static_cast<T>(*ref_cast<int64_t>());
+ else
+ return node_integer_cast<T>(*ref_cast<int64_t>());
+ }
+
+ // int -> float
+ else if constexpr (is_natively_one_of<T, double>)
+ {
+ const int64_t val = *ref_cast<int64_t>();
+ if constexpr (std::numeric_limits<T>::digits < 64)
+ {
+ constexpr auto largest_whole_float = (int64_t{ 1 } << std::numeric_limits<T>::digits);
+ if (val < -largest_whole_float || val > largest_whole_float)
+ return {};
+ }
+ return static_cast<T>(val);
+ }
+
+ // int -> bool
+ else if constexpr (is_natively_one_of<T, bool>)
+ return static_cast<bool>(*ref_cast<int64_t>());
+
+ // int -> anything else
+ else
+ return {};
+ }
+
+ // float -> *
+ case node_type::floating_point:
+ {
+ // float -> float
+ if constexpr (is_natively_one_of<T, double>)
+ {
+ if constexpr (is_native<T> || can_represent_native<T>)
+ return { static_cast<T>(*ref_cast<double>()) };
+ else
+ {
+ const double val = *ref_cast<double>();
+ if (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)())
+ return {};
+ return { static_cast<T>(val) };
+ }
+ }
+
+ // float -> int
+ else if constexpr (is_natively_one_of<T, int64_t>)
+ {
+ const double val = *ref_cast<double>();
+ if (static_cast<double>(static_cast<int64_t>(val)) == val)
+ return node_integer_cast<T>(static_cast<int64_t>(val));
+ else
+ return {};
+ }
+
+ // float -> anything else
+ else
+ return {};
+ }
+
+ // bool -> *
+ case node_type::boolean:
+ {
+ // bool -> bool
+ if constexpr (is_natively_one_of<T, bool>)
+ return { *ref_cast<bool>() };
+
+ // bool -> int
+ else if constexpr (is_natively_one_of<T, int64_t>)
+ return { static_cast<T>(*ref_cast<bool>()) };
+
+ // bool -> anything else
+ else
+ return {};
+ }
+ }
+
+ // non-values, or 'exact' types covered above
+ return {};
+ }
+ }
+
+ template <typename T>
+ inline auto node::value_or(T&& default_value) const noexcept
+ {
+ using namespace impl;
+
+ static_assert(
+ !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ "Retrieving values as wide-character strings with node::value_or() is only "
+ "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (is_wide_string<T>)
+ {
+ #if TOML_WINDOWS_COMPAT
+
+ if (type() == node_type::string)
+ return widen(*ref_cast<std::string>());
+ return std::wstring{ std::forward<T>(default_value) };
+
+ #else
+
+ static_assert(dependent_false<T>, "Evaluated unreachable branch!");
+
+ #endif
+ }
+ else
+ {
+ using value_type = std::conditional_t<
+ std::is_pointer_v<std::decay_t<T>>,
+ std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
+ std::decay_t<T>
+ >;
+ using traits = value_traits<value_type>;
+
+ static_assert(
+ traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
+ "The default value type of node::value_or() must be one of:"
+ TOML_SA_LIST_NEW "A native TOML value type"
+ TOML_SA_NATIVE_VALUE_TYPE_LIST
+
+ TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
+ TOML_SA_LIST_BEG "std::string"
+ #if TOML_WINDOWS_COMPAT
+ TOML_SA_LIST_SEP "std::wstring"
+ #endif
+ TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
+ TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
+ TOML_SA_LIST_END
+
+ TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
+ TOML_SA_LIST_BEG "any other integer type"
+ TOML_SA_LIST_SEP "any floating-point type >= 32 bits"
+ TOML_SA_LIST_END
+
+ TOML_SA_LIST_NXT "A compatible view type"
+ TOML_SA_LIST_BEG "std::string_view"
+ #ifdef __cpp_lib_char8_t
+ TOML_SA_LIST_SEP "std::u8string_view"
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ TOML_SA_LIST_SEP "std::wstring_view"
+ #endif
+ TOML_SA_LIST_SEP "const char*"
+ #ifdef __cpp_lib_char8_t
+ TOML_SA_LIST_SEP "const char8_t*"
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ TOML_SA_LIST_SEP "const wchar_t*"
+ #endif
+ TOML_SA_LIST_END
+ );
+
+ // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
+ if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
+ {
+ if constexpr (traits::is_native)
+ {
+ if (type() == node_type_of<value_type>)
+ return *ref_cast<typename traits::native_type>();
+ }
+ if (auto val = this->value<value_type>())
+ return *val;
+ if constexpr (std::is_pointer_v<value_type>)
+ return value_type{ default_value };
+ else
+ return std::forward<T>(default_value);
+ }
+ }
+ }
+
+ #if !TOML_HEADER_ONLY
+
+ #define TOML_EXTERN(name, T) \
+ extern template TOML_API optional<T> node::name<T>() const noexcept
+ TOML_EXTERN(value_exact, std::string_view);
+ TOML_EXTERN(value_exact, std::string);
+ TOML_EXTERN(value_exact, const char*);
+ TOML_EXTERN(value_exact, int64_t);
+ TOML_EXTERN(value_exact, double);
+ TOML_EXTERN(value_exact, date);
+ TOML_EXTERN(value_exact, time);
+ TOML_EXTERN(value_exact, date_time);
+ TOML_EXTERN(value_exact, bool);
+ TOML_EXTERN(value, std::string_view);
+ TOML_EXTERN(value, std::string);
+ TOML_EXTERN(value, const char*);
+ TOML_EXTERN(value, signed char);
+ TOML_EXTERN(value, signed short);
+ TOML_EXTERN(value, signed int);
+ TOML_EXTERN(value, signed long);
+ TOML_EXTERN(value, signed long long);
+ TOML_EXTERN(value, unsigned char);
+ TOML_EXTERN(value, unsigned short);
+ TOML_EXTERN(value, unsigned int);
+ TOML_EXTERN(value, unsigned long);
+ TOML_EXTERN(value, unsigned long long);
+ TOML_EXTERN(value, double);
+ TOML_EXTERN(value, float);
+ TOML_EXTERN(value, date);
+ TOML_EXTERN(value, time);
+ TOML_EXTERN(value, date_time);
+ TOML_EXTERN(value, bool);
+ #ifdef __cpp_lib_char8_t
+ TOML_EXTERN(value_exact, std::u8string_view);
+ TOML_EXTERN(value_exact, std::u8string);
+ TOML_EXTERN(value_exact, const char8_t*);
+ TOML_EXTERN(value, std::u8string_view);
+ TOML_EXTERN(value, std::u8string);
+ TOML_EXTERN(value, const char8_t*);
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ TOML_EXTERN(value_exact, std::wstring);
+ TOML_EXTERN(value, std::wstring);
+ #endif
+ #undef TOML_EXTERN
+
+ #endif // !TOML_HEADER_ONLY
+
+ TOML_POP_WARNINGS // TOML_DISABLE_INIT_WARNINGS, TOML_DISABLE_SWITCH_WARNINGS
+ #endif // !DOXYGEN
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_ARITHMETIC_WARNINGS
+
+#endif //---------------------------------- ↑ toml_value.h -----------------------------------------------------------
+
+#if 1 //----------------------------------------------------------- ↓ toml_array.h ----------------------------------
+
+TOML_IMPL_NAMESPACE_START
+{
+ template <bool IsConst>
+ class TOML_TRIVIAL_ABI array_iterator final
+ {
+ private:
+ template <bool C>
+ friend class array_iterator;
+ friend class TOML_NAMESPACE::array;
+
+ using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator;
+ using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator;
+ using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
+
+ mutable raw_iterator raw_;
+
+ array_iterator(raw_mutable_iterator raw) noexcept
+ : raw_{ raw }
+ {}
+
+ template <bool C = IsConst, typename = std::enable_if_t<C>>
+ TOML_NODISCARD_CTOR
+ array_iterator(raw_const_iterator raw) noexcept
+ : raw_{ raw }
+ {}
+
+ public:
+
+ using value_type = std::conditional_t<IsConst, const node, node>;
+ using reference = value_type&;
+ using pointer = value_type*;
+ using difference_type = ptrdiff_t;
+
+ array_iterator() noexcept = default;
+ array_iterator(const array_iterator&) noexcept = default;
+ array_iterator& operator = (const array_iterator&) noexcept = default;
+
+ array_iterator& operator++() noexcept // ++pre
+ {
+ ++raw_;
+ return *this;
+ }
+
+ array_iterator operator++(int) noexcept // post++
+ {
+ array_iterator out{ raw_ };
+ ++raw_;
+ return out;
+ }
+
+ array_iterator& operator--() noexcept // --pre
+ {
+ --raw_;
+ return *this;
+ }
+
+ array_iterator operator--(int) noexcept // post--
+ {
+ array_iterator out{ raw_ };
+ --raw_;
+ return out;
+ }
+
+ [[nodiscard]]
+ reference operator * () const noexcept
+ {
+ return *raw_->get();
+ }
+
+ [[nodiscard]]
+ pointer operator -> () const noexcept
+ {
+ return raw_->get();
+ }
+
+ array_iterator& operator += (ptrdiff_t rhs) noexcept
+ {
+ raw_ += rhs;
+ return *this;
+ }
+
+ array_iterator& operator -= (ptrdiff_t rhs) noexcept
+ {
+ raw_ -= rhs;
+ return *this;
+ }
+
+ [[nodiscard]]
+ friend array_iterator operator + (const array_iterator& lhs, ptrdiff_t rhs) noexcept
+ {
+ return { lhs.raw_ + rhs };
+ }
+
+ [[nodiscard]]
+ friend array_iterator operator + (ptrdiff_t lhs, const array_iterator& rhs) noexcept
+ {
+ return { rhs.raw_ + lhs };
+ }
+
+ [[nodiscard]]
+ friend array_iterator operator - (const array_iterator& lhs, ptrdiff_t rhs) noexcept
+ {
+ return { lhs.raw_ - rhs };
+ }
+
+ [[nodiscard]]
+ friend ptrdiff_t operator - (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ - rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator == (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ == rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator != (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ != rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator < (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ < rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator <= (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ <= rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator > (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ > rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator >= (const array_iterator& lhs, const array_iterator& rhs) noexcept
+ {
+ return lhs.raw_ >= rhs.raw_;
+ }
+
+ [[nodiscard]]
+ reference operator[] (ptrdiff_t idx) const noexcept
+ {
+ return *(raw_ + idx)->get();
+ }
+
+ TOML_DISABLE_WARNINGS
+
+ template <bool C = IsConst, typename = std::enable_if_t<!C>>
+ operator array_iterator<true>() const noexcept
+ {
+ return array_iterator<true>{ raw_ };
+ }
+
+ TOML_ENABLE_WARNINGS
+ };
+
+ template <typename T>
+ [[nodiscard]]
+ TOML_ATTR(returns_nonnull)
+ auto* make_node_specialized(T&& val) noexcept
+ {
+ using type = unwrap_node<remove_cvref_t<T>>;
+ static_assert(!std::is_same_v<type, node>);
+ static_assert(!is_node_view<type>);
+
+ if constexpr (is_one_of<type, array, table>)
+ {
+ return new type{ std::forward<T>(val) };
+ }
+ else
+ {
+ static_assert(
+ !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ "Instantiating values from wide-character strings is only "
+ "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+ static_assert(
+ is_native<type> || is_losslessly_convertible_to_native<type>,
+ "Value initializers must be (or be promotable to) one of the TOML value types"
+ );
+ if constexpr (is_wide_string<T>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return new value{ narrow(std::forward<T>(val)) };
+ #else
+ static_assert(dependent_false<T>, "Evaluated unreachable branch!");
+ #endif
+ }
+ else
+ return new value{ std::forward<T>(val) };
+ }
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ auto* make_node(T&& val) noexcept
+ {
+ using type = unwrap_node<remove_cvref_t<T>>;
+ if constexpr (std::is_same_v<type, node> || is_node_view<type>)
+ {
+ if constexpr (is_node_view<type>)
+ {
+ if (!val)
+ return static_cast<toml::node*>(nullptr);
+ }
+
+ return std::forward<T>(val).visit([](auto&& concrete) noexcept
+ {
+ return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete)));
+ });
+ }
+ else
+ return make_node_specialized(std::forward<T>(val));
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ auto* make_node(inserter<T>&& val) noexcept
+ {
+ return make_node(std::move(val.value));
+ }
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ using array_iterator = impl::array_iterator<false>;
+ using const_array_iterator = impl::array_iterator<true>;
+
+ class TOML_API array final
+ : public node
+ {
+ private:
+ friend class TOML_PARSER_TYPENAME;
+ std::vector<std::unique_ptr<node>> elements;
+
+ void preinsertion_resize(size_t idx, size_t count) noexcept;
+
+ template <typename T>
+ void emplace_back_if_not_empty_view(T&& val) noexcept
+ {
+ if constexpr (impl::is_node_view<T>)
+ {
+ if (!val)
+ return;
+ }
+ elements.emplace_back(impl::make_node(std::forward<T>(val)));
+ }
+
+ #if TOML_LIFETIME_HOOKS
+ void lh_ctor() noexcept;
+ void lh_dtor() noexcept;
+ #endif
+
+ public:
+
+ using value_type = node;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using reference = node&;
+ using const_reference = const node&;
+ using iterator = array_iterator;
+ using const_iterator = const_array_iterator;
+
+ TOML_NODISCARD_CTOR
+ array() noexcept;
+
+ TOML_NODISCARD_CTOR
+ array(const array&) noexcept;
+
+ TOML_NODISCARD_CTOR
+ array(array&& other) noexcept;
+ array& operator= (const array&) noexcept;
+ array& operator= (array&& rhs) noexcept;
+
+ ~array() noexcept override;
+
+ template <typename ElemType, typename... ElemTypes, typename = std::enable_if_t<
+ (sizeof...(ElemTypes) > 0_sz)
+ || !std::is_same_v<impl::remove_cvref_t<ElemType>, array>
+ >>
+ TOML_NODISCARD_CTOR
+ explicit array(ElemType&& val, ElemTypes&&... vals)
+ {
+ elements.reserve(sizeof...(ElemTypes) + 1_sz);
+ emplace_back_if_not_empty_view(std::forward<ElemType>(val));
+ if constexpr (sizeof...(ElemTypes) > 0)
+ {
+ (
+ emplace_back_if_not_empty_view(std::forward<ElemTypes>(vals)),
+ ...
+ );
+ }
+
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ [[nodiscard]] node_type type() const noexcept override;
+ [[nodiscard]] bool is_table() const noexcept override;
+ [[nodiscard]] bool is_array() const noexcept override;
+ [[nodiscard]] bool is_value() const noexcept override;
+ [[nodiscard]] array* as_array() noexcept override;
+ [[nodiscard]] const array* as_array() const noexcept override;
+ [[nodiscard]] bool is_array_of_tables() const noexcept override;
+ [[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
+ [[nodiscard]] bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override;
+ [[nodiscard]] bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override;
+ template <typename ElemType = void>
+ [[nodiscard]]
+ bool is_homogeneous() const noexcept
+ {
+ using type = impl::unwrap_node<ElemType>;
+ static_assert(
+ std::is_void_v<type>
+ || ((impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>),
+ "The template type argument of array::is_homogeneous() must be void or one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+ return is_homogeneous(impl::node_type_of<type>);
+ }
+
+ [[nodiscard]] node& operator[] (size_t index) noexcept;
+ [[nodiscard]] const node& operator[] (size_t index) const noexcept;
+ [[nodiscard]] node& front() noexcept;
+ [[nodiscard]] const node& front() const noexcept;
+ [[nodiscard]] node& back() noexcept;
+ [[nodiscard]] const node& back() const noexcept;
+ [[nodiscard]] iterator begin() noexcept;
+ [[nodiscard]] const_iterator begin() const noexcept;
+ [[nodiscard]] const_iterator cbegin() const noexcept;
+ [[nodiscard]] iterator end() noexcept;
+ [[nodiscard]] const_iterator end() const noexcept;
+ [[nodiscard]] const_iterator cend() const noexcept;
+ [[nodiscard]] bool empty() const noexcept;
+ [[nodiscard]] size_t size() const noexcept;
+ void reserve(size_t new_capacity);
+ void clear() noexcept;
+
+ [[nodiscard]] size_t max_size() const noexcept;
+ [[nodiscard]] size_t capacity() const noexcept;
+ void shrink_to_fit();
+
+ template <typename ElemType>
+ iterator insert(const_iterator pos, ElemType&& val) noexcept
+ {
+ if constexpr (impl::is_node_view<ElemType>)
+ {
+ if (!val)
+ return end();
+ }
+ return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) };
+ }
+
+ template <typename ElemType>
+ iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept
+ {
+ if constexpr (impl::is_node_view<ElemType>)
+ {
+ if (!val)
+ return end();
+ }
+ switch (count)
+ {
+ case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
+ case 1: return insert(pos, std::forward<ElemType>(val));
+ default:
+ {
+ const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
+ preinsertion_resize(start_idx, count);
+ size_t i = start_idx;
+ for (size_t e = start_idx + count - 1_sz; i < e; i++)
+ elements[i].reset(impl::make_node(val));
+
+ elements[i].reset(impl::make_node(std::forward<ElemType>(val)));
+ return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
+ }
+ }
+ }
+
+ template <typename Iter>
+ iterator insert(const_iterator pos, Iter first, Iter last) noexcept
+ {
+ const auto distance = std::distance(first, last);
+ if (distance <= 0)
+ return { elements.begin() + (pos.raw_ - elements.cbegin()) };
+ else
+ {
+ auto count = distance;
+ using deref_type = decltype(*first);
+ if constexpr (impl::is_node_view<deref_type>)
+ {
+ for (auto it = first; it != last; it++)
+ if (!(*it))
+ count--;
+ if (!count)
+ return { elements.begin() + (pos.raw_ - elements.cbegin()) };
+ }
+ const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
+ preinsertion_resize(start_idx, static_cast<size_t>(count));
+ size_t i = start_idx;
+ for (auto it = first; it != last; it++)
+ {
+ if constexpr (impl::is_node_view<deref_type>)
+ {
+ if (!(*it))
+ continue;
+ }
+ if constexpr (std::is_rvalue_reference_v<deref_type>)
+ elements[i++].reset(impl::make_node(std::move(*it)));
+ else
+ elements[i++].reset(impl::make_node(*it));
+ }
+ return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
+ }
+ }
+
+ template <typename ElemType>
+ iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept
+ {
+ return insert(pos, ilist.begin(), ilist.end());
+ }
+
+ template <typename ElemType, typename... Args>
+ iterator emplace(const_iterator pos, Args&&... args) noexcept
+ {
+ using type = impl::unwrap_node<ElemType>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "Emplacement type parameter must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<Args>(args)...} ) };
+ }
+
+ iterator erase(const_iterator pos) noexcept;
+ iterator erase(const_iterator first, const_iterator last) noexcept;
+
+ template <typename ElemType>
+ void resize(size_t new_size, ElemType&& default_init_val) noexcept
+ {
+ static_assert(
+ !impl::is_node_view<ElemType>,
+ "The default element type argument to toml::array::resize may not be toml::node_view."
+ );
+
+ if (!new_size)
+ elements.clear();
+ else if (new_size < elements.size())
+ elements.resize(new_size);
+ else if (new_size > elements.size())
+ insert(cend(), new_size - elements.size(), std::forward<ElemType>(default_init_val));
+ }
+
+ void truncate(size_t new_size);
+
+ template <typename ElemType>
+ void push_back(ElemType&& val) noexcept
+ {
+ emplace_back_if_not_empty_view(std::forward<ElemType>(val));
+ }
+
+ template <typename ElemType, typename... Args>
+ decltype(auto) emplace_back(Args&&... args) noexcept
+ {
+ using type = impl::unwrap_node<ElemType>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "Emplacement type parameter must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ auto nde = new impl::wrap_node<type>{ std::forward<Args>(args)... };
+ elements.emplace_back(nde);
+ return *nde;
+ }
+
+ void pop_back() noexcept;
+ [[nodiscard]] node* get(size_t index) noexcept;
+ [[nodiscard]] const node* get(size_t index) const noexcept;
+
+ template <typename ElemType>
+ [[nodiscard]]
+ impl::wrap_node<ElemType>* get_as(size_t index) noexcept
+ {
+ if (auto val = get(index))
+ return val->as<ElemType>();
+ return nullptr;
+ }
+
+ template <typename ElemType>
+ [[nodiscard]]
+ const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
+ {
+ if (auto val = get(index))
+ return val->as<ElemType>();
+ return nullptr;
+ }
+
+ friend bool operator == (const array& lhs, const array& rhs) noexcept;
+ friend bool operator != (const array& lhs, const array& rhs) noexcept;
+
+ private:
+
+ template <typename T>
+ [[nodiscard]]
+ static bool container_equality(const array& lhs, const T& rhs) noexcept
+ {
+ using element_type = std::remove_const_t<typename T::value_type>;
+ static_assert(
+ impl::is_native<element_type> || impl::is_losslessly_convertible_to_native<element_type>,
+ "Container element type must be (or be promotable to) one of the TOML value types"
+ );
+
+ if (lhs.size() != rhs.size())
+ return false;
+ if (rhs.size() == 0_sz)
+ return true;
+
+ size_t i{};
+ for (auto& list_elem : rhs)
+ {
+ const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
+ if (!elem || *elem != list_elem)
+ return false;
+ }
+
+ return true;
+ }
+
+ [[nodiscard]] size_t total_leaf_count() const noexcept;
+ void flatten_child(array&& child, size_t& dest_index) noexcept;
+
+ public:
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator == (const array& lhs, const std::initializer_list<T>& rhs) noexcept
+ {
+ return container_equality(lhs, rhs);
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>)
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator == (const array& lhs, const std::vector<T>& rhs) noexcept
+ {
+ return container_equality(lhs, rhs);
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>)
+ array& flatten() &;
+ array&& flatten() &&
+ {
+ return static_cast<toml::array&&>(static_cast<toml::array&>(*this).flatten());
+ }
+
+ template <typename Char>
+ friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
+ // implemented in toml_default_formatter.h
+ };
+}
+TOML_NAMESPACE_END
+
+#endif //----------------------------------------------------------- ↑ toml_array.h ----------------------------------
+
+#if 1 //------------------------------------------------------------------------------------ ↓ toml_table.h ---------
+
+TOML_IMPL_NAMESPACE_START
+{
+ template <bool IsConst>
+ struct table_proxy_pair final
+ {
+ using value_type = std::conditional_t<IsConst, const node, node>;
+
+ const std::string& first;
+ value_type& second;
+ };
+
+ template <bool IsConst>
+ class table_iterator final
+ {
+ private:
+ template <bool C>
+ friend class table_iterator;
+ friend class TOML_NAMESPACE::table;
+
+ using proxy_type = table_proxy_pair<IsConst>;
+ using raw_mutable_iterator = string_map<std::unique_ptr<node>>::iterator;
+ using raw_const_iterator = string_map<std::unique_ptr<node>>::const_iterator;
+ using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
+
+ mutable raw_iterator raw_;
+ mutable std::aligned_storage_t<sizeof(proxy_type), alignof(proxy_type)> proxy;
+ mutable bool proxy_instantiated = false;
+
+ [[nodiscard]]
+ proxy_type* get_proxy() const noexcept
+ {
+ if (!proxy_instantiated)
+ {
+ auto p = new (&proxy) proxy_type{ raw_->first, *raw_->second.get() };
+ proxy_instantiated = true;
+ return p;
+ }
+ else
+ return TOML_LAUNDER(reinterpret_cast<proxy_type*>(&proxy));
+ }
+
+ table_iterator(raw_mutable_iterator raw) noexcept
+ : raw_{ raw }
+ {}
+
+ template <bool C = IsConst, typename = std::enable_if_t<C>>
+ TOML_NODISCARD_CTOR
+ table_iterator(raw_const_iterator raw) noexcept
+ : raw_{ raw }
+ {}
+
+ public:
+
+ table_iterator() noexcept = default;
+
+ table_iterator(const table_iterator& other) noexcept
+ : raw_{ other.raw_ }
+ {}
+
+ table_iterator& operator = (const table_iterator& rhs) noexcept
+ {
+ raw_ = rhs.raw_;
+ proxy_instantiated = false;
+ return *this;
+ }
+
+ using value_type = table_proxy_pair<IsConst>;
+ using reference = value_type&;
+ using pointer = value_type*;
+
+ table_iterator& operator++() noexcept // ++pre
+ {
+ ++raw_;
+ proxy_instantiated = false;
+ return *this;
+ }
+
+ table_iterator operator++(int) noexcept // post++
+ {
+ table_iterator out{ raw_ };
+ ++raw_;
+ proxy_instantiated = false;
+ return out;
+ }
+
+ table_iterator& operator--() noexcept // --pre
+ {
+ --raw_;
+ proxy_instantiated = false;
+ return *this;
+ }
+
+ table_iterator operator--(int) noexcept // post--
+ {
+ table_iterator out{ raw_ };
+ --raw_;
+ proxy_instantiated = false;
+ return out;
+ }
+
+ [[nodiscard]]
+ reference operator* () const noexcept
+ {
+ return *get_proxy();
+ }
+
+ [[nodiscard]]
+ pointer operator -> () const noexcept
+ {
+ return get_proxy();
+ }
+
+ [[nodiscard]]
+ friend bool operator == (const table_iterator& lhs, const table_iterator& rhs) noexcept
+ {
+ return lhs.raw_ == rhs.raw_;
+ }
+
+ [[nodiscard]]
+ friend bool operator != (const table_iterator& lhs, const table_iterator& rhs) noexcept
+ {
+ return lhs.raw_ != rhs.raw_;
+ }
+
+ TOML_DISABLE_WARNINGS
+
+ template <bool C = IsConst, typename = std::enable_if_t<!C>>
+ operator table_iterator<true>() const noexcept
+ {
+ return table_iterator<true>{ raw_ };
+ }
+
+ TOML_ENABLE_WARNINGS
+ };
+
+ struct table_init_pair final
+ {
+ std::string key;
+ std::unique_ptr<node> value;
+
+ template <typename V>
+ table_init_pair(std::string&& k, V&& v) noexcept
+ : key{ std::move(k) },
+ value{ make_node(std::forward<V>(v)) }
+ {}
+
+ template <typename V>
+ table_init_pair(std::string_view k, V&& v) noexcept
+ : key{ k },
+ value{ make_node(std::forward<V>(v)) }
+ {}
+
+ template <typename V>
+ table_init_pair(const char* k, V&& v) noexcept
+ : key{ k },
+ value{ make_node(std::forward<V>(v)) }
+ {}
+
+ #if TOML_WINDOWS_COMPAT
+
+ template <typename V>
+ table_init_pair(std::wstring&& k, V&& v) noexcept
+ : key{ narrow(k) },
+ value{ make_node(std::forward<V>(v)) }
+ {}
+
+ template <typename V>
+ table_init_pair(std::wstring_view k, V&& v) noexcept
+ : key{ narrow(k) },
+ value{ make_node(std::forward<V>(v)) }
+ {}
+
+ template <typename V>
+ table_init_pair(const wchar_t* k, V&& v) noexcept
+ : key{ narrow(std::wstring_view{ k }) },
+ value{ make_node(std::forward<V>(v)) }
+ {}
+
+ #endif
+ };
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ using table_iterator = impl::table_iterator<false>;
+ using const_table_iterator = impl::table_iterator<true>;
+
+ class TOML_API table final
+ : public node
+ {
+ private:
+ friend class TOML_PARSER_TYPENAME;
+
+ impl::string_map<std::unique_ptr<node>> map;
+ bool inline_ = false;
+
+ #if TOML_LIFETIME_HOOKS
+ void lh_ctor() noexcept;
+ void lh_dtor() noexcept;
+ #endif
+
+ table(impl::table_init_pair*, size_t) noexcept;
+
+ public:
+
+ using iterator = table_iterator;
+ using const_iterator = const_table_iterator;
+
+ TOML_NODISCARD_CTOR
+ table() noexcept;
+
+ TOML_NODISCARD_CTOR
+ table(const table&) noexcept;
+
+ TOML_NODISCARD_CTOR
+ table(table&& other) noexcept;
+ table& operator= (const table&) noexcept;
+ table& operator= (table&& rhs) noexcept;
+
+ ~table() noexcept override;
+
+ template <size_t N>
+ TOML_NODISCARD_CTOR
+ explicit table(impl::table_init_pair(&& arr)[N]) noexcept
+ : table{ arr, N }
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ [[nodiscard]] node_type type() const noexcept override;
+ [[nodiscard]] bool is_table() const noexcept override;
+ [[nodiscard]] bool is_array() const noexcept override;
+ [[nodiscard]] bool is_value() const noexcept override;
+ [[nodiscard]] table* as_table() noexcept override;
+ [[nodiscard]] const table* as_table() const noexcept override;
+ [[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
+ [[nodiscard]] bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override;
+ [[nodiscard]] bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override;
+ template <typename ElemType = void>
+ [[nodiscard]]
+ bool is_homogeneous() const noexcept
+ {
+ using type = impl::unwrap_node<ElemType>;
+ static_assert(
+ std::is_void_v<type>
+ || ((impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>),
+ "The template type argument of table::is_homogeneous() must be void or one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+ return is_homogeneous(impl::node_type_of<type>);
+ }
+
+ [[nodiscard]] bool is_inline() const noexcept;
+ void is_inline(bool val) noexcept;
+ [[nodiscard]] node_view<node> operator[] (std::string_view key) noexcept;
+ [[nodiscard]] node_view<const node> operator[] (std::string_view key) const noexcept;
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]] node_view<node> operator[] (std::wstring_view key) noexcept;
+ [[nodiscard]] node_view<const node> operator[] (std::wstring_view key) const noexcept;
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ [[nodiscard]] iterator begin() noexcept;
+ [[nodiscard]] const_iterator begin() const noexcept;
+ [[nodiscard]] const_iterator cbegin() const noexcept;
+ [[nodiscard]] iterator end() noexcept;
+ [[nodiscard]] const_iterator end() const noexcept;
+ [[nodiscard]] const_iterator cend() const noexcept;
+ [[nodiscard]] bool empty() const noexcept;
+ [[nodiscard]] size_t size() const noexcept;
+ void clear() noexcept;
+
+ template <typename KeyType, typename ValueType, typename = std::enable_if_t<
+ std::is_convertible_v<KeyType&&, std::string_view>
+ || impl::is_wide_string<KeyType>
+ >>
+ std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val) noexcept
+ {
+ static_assert(
+ !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
+ "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (impl::is_node_view<ValueType>)
+ {
+ if (!val)
+ return { end(), false };
+ }
+
+ if constexpr (impl::is_wide_string<KeyType>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val));
+ #else
+ static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
+ #endif
+ }
+ else
+ {
+ auto ipos = map.lower_bound(key);
+ if (ipos == map.end() || ipos->first != key)
+ {
+ ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
+ return { iterator{ ipos }, true };
+ }
+ return { iterator{ ipos }, false };
+ }
+ }
+
+ template <typename Iter, typename = std::enable_if_t<
+ !std::is_convertible_v<Iter, std::string_view>
+ && !impl::is_wide_string<Iter>
+ >>
+ void insert(Iter first, Iter last) noexcept
+ {
+ if (first == last)
+ return;
+ for (auto it = first; it != last; it++)
+ {
+ if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
+ insert(std::move((*it).first), std::move((*it).second));
+ else
+ insert((*it).first, (*it).second);
+ }
+ }
+
+ template <typename KeyType, typename ValueType>
+ std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) noexcept
+ {
+ static_assert(
+ !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
+ "Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (impl::is_node_view<ValueType>)
+ {
+ if (!val)
+ return { end(), false };
+ }
+
+ if constexpr (impl::is_wide_string<KeyType>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val));
+ #else
+ static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
+ #endif
+ }
+ else
+ {
+ auto ipos = map.lower_bound(key);
+ if (ipos == map.end() || ipos->first != key)
+ {
+ ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
+ return { iterator{ ipos }, true };
+ }
+ else
+ {
+ (*ipos).second.reset(impl::make_node(std::forward<ValueType>(val)));
+ return { iterator{ ipos }, false };
+ }
+ }
+ }
+
+ template <typename ValueType, typename KeyType, typename... ValueArgs>
+ std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args) noexcept
+ {
+ static_assert(
+ !impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
+ "Emplacement using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (impl::is_wide_string<KeyType>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return emplace<ValueType>(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueArgs>(args)...);
+ #else
+ static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
+ #endif
+ }
+ else
+ {
+ using type = impl::unwrap_node<ValueType>;
+ static_assert(
+ (impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
+ "The emplacement type argument of table::emplace() must be one of:"
+ TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ );
+
+ auto ipos = map.lower_bound(key);
+ if (ipos == map.end() || ipos->first != key)
+ {
+ ipos = map.emplace_hint(
+ ipos,
+ std::forward<KeyType>(key),
+ new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... }
+ );
+ return { iterator{ ipos }, true };
+ }
+ return { iterator{ ipos }, false };
+ }
+ }
+
+ iterator erase(iterator pos) noexcept;
+ iterator erase(const_iterator pos) noexcept;
+ iterator erase(const_iterator first, const_iterator last) noexcept;
+ bool erase(std::string_view key) noexcept;
+
+ #if TOML_WINDOWS_COMPAT
+
+ bool erase(std::wstring_view key) noexcept;
+
+ #endif
+
+ private:
+
+ template <typename Map, typename Key>
+ [[nodiscard]]
+ static auto do_get(Map& vals, const Key& key) noexcept
+ -> std::conditional_t<std::is_const_v<Map>, const node*, node*>
+ {
+ static_assert(
+ !impl::is_wide_string<Key> || TOML_WINDOWS_COMPAT,
+ "Retrieval using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (impl::is_wide_string<Key>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return do_get(vals, impl::narrow(key));
+ #else
+ static_assert(impl::dependent_false<Key>, "Evaluated unreachable branch!");
+ #endif
+ }
+ else
+ {
+ if (auto it = vals.find(key); it != vals.end())
+ return { it->second.get() };
+ return {};
+ }
+ }
+
+ template <typename T, typename Map, typename Key>
+ [[nodiscard]]
+ static auto do_get_as(Map& vals, const Key& key) noexcept
+ {
+ const auto node = do_get(vals, key);
+ return node ? node->template as<T>() : nullptr;
+ }
+
+ template <typename Map, typename Key>
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ static bool do_contains(Map& vals, const Key& key) noexcept
+ {
+ return do_get(vals, key) != nullptr;
+ }
+
+ public:
+
+ [[nodiscard]] node* get(std::string_view key) noexcept;
+ [[nodiscard]] const node* get(std::string_view key) const noexcept;
+ [[nodiscard]] iterator find(std::string_view key) noexcept;
+ [[nodiscard]] const_iterator find(std::string_view key) const noexcept;
+ [[nodiscard]] bool contains(std::string_view key) const noexcept;
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]] node* get(std::wstring_view key) noexcept;
+ [[nodiscard]] const node* get(std::wstring_view key) const noexcept;
+ [[nodiscard]] iterator find(std::wstring_view key) noexcept;
+ [[nodiscard]] const_iterator find(std::wstring_view key) const noexcept;
+ [[nodiscard]] bool contains(std::wstring_view key) const noexcept;
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ template <typename ValueType>
+ [[nodiscard]]
+ impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
+ {
+ return do_get_as<ValueType>(map, key);
+ }
+
+ template <typename ValueType>
+ [[nodiscard]]
+ const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
+ {
+ return do_get_as<ValueType>(map, key);
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ template <typename ValueType>
+ [[nodiscard]]
+ impl::wrap_node<ValueType>* get_as(std::wstring_view key) noexcept
+ {
+ return get_as<ValueType>(impl::narrow(key));
+ }
+
+ template <typename ValueType>
+ [[nodiscard]]
+ const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const noexcept
+ {
+ return get_as<ValueType>(impl::narrow(key));
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ friend bool operator == (const table& lhs, const table& rhs) noexcept;
+ friend bool operator != (const table& lhs, const table& rhs) noexcept;
+
+ template <typename Char>
+ friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
+ // implemented in toml_default_formatter.h
+ };
+
+ #ifndef DOXYGEN
+
+ //template <typename T>
+ //inline std::vector<T> node::select_exact() const noexcept
+ //{
+ // using namespace impl;
+
+ // static_assert(
+ // !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ // "Retrieving values as wide-character strings with node::select_exact() is only "
+ // "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ // );
+
+ // static_assert(
+ // (is_native<T> || can_represent_native<T>) && !is_cvref<T>,
+ // TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::select_exact()")
+ // );
+ //}
+
+ //template <typename T>
+ //inline std::vector<T> node::select() const noexcept
+ //{
+ // using namespace impl;
+
+ // static_assert(
+ // !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ // "Retrieving values as wide-character strings with node::select() is only "
+ // "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ // );
+ // static_assert(
+ // (is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
+ // TOML_SA_VALUE_FUNC_MESSAGE("return type of node::select()")
+ // );
+ //}
+
+ #endif // !DOXYGEN
+}
+TOML_NAMESPACE_END
+
+#endif //------------------------------------------------------------------------------------ ↑ toml_table.h ---------
+
+#if 1 //------- ↓ toml_node_view.h ----------------------------------------------------------------------------------
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_ARITHMETIC_WARNINGS
+
+TOML_NAMESPACE_START
+{
+ template <typename ViewedType>
+ class TOML_API TOML_TRIVIAL_ABI node_view
+ {
+ static_assert(
+ impl::is_one_of<ViewedType, toml::node, const toml::node>,
+ "A toml::node_view<> must wrap toml::node or const toml::node."
+ );
+
+ public:
+ using viewed_type = ViewedType;
+
+ private:
+ template <typename T> friend class TOML_NAMESPACE::node_view;
+
+ mutable viewed_type* node_ = nullptr;
+
+ template <typename Func>
+ static constexpr bool visit_is_nothrow
+ = noexcept(std::declval<viewed_type*>()->visit(std::declval<Func&&>()));
+
+ public:
+
+ TOML_NODISCARD_CTOR
+ node_view() noexcept = default;
+
+ TOML_NODISCARD_CTOR
+ explicit node_view(viewed_type* node) noexcept
+ : node_{ node }
+ {}
+
+ TOML_NODISCARD_CTOR
+ explicit node_view(viewed_type& node) noexcept
+ : node_{ &node }
+ {}
+
+ TOML_NODISCARD_CTOR
+ node_view(const node_view&) noexcept = default;
+
+ node_view& operator= (const node_view&) & noexcept = default;
+
+ TOML_NODISCARD_CTOR
+ node_view(node_view&&) noexcept = default;
+
+ node_view& operator= (node_view&&) & noexcept = default;
+ [[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
+ [[nodiscard]] viewed_type* node() const noexcept { return node_; }
+
+ [[nodiscard, deprecated("use node_view::node() instead")]]
+ viewed_type* get() const noexcept { return node_; }
+
+ [[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
+ [[nodiscard]] bool is_table() const noexcept { return node_ && node_->is_table(); }
+ [[nodiscard]] bool is_array() const noexcept { return node_ && node_->is_array(); }
+ [[nodiscard]] bool is_value() const noexcept { return node_ && node_->is_value(); }
+ [[nodiscard]] bool is_string() const noexcept { return node_ && node_->is_string(); }
+ [[nodiscard]] bool is_integer() const noexcept { return node_ && node_->is_integer(); }
+ [[nodiscard]] bool is_floating_point() const noexcept { return node_ && node_->is_floating_point(); }
+ [[nodiscard]] bool is_number() const noexcept { return node_ && node_->is_number(); }
+ [[nodiscard]] bool is_boolean() const noexcept { return node_ && node_->is_boolean(); }
+ [[nodiscard]] bool is_date() const noexcept { return node_ && node_->is_date(); }
+ [[nodiscard]] bool is_time() const noexcept { return node_ && node_->is_time(); }
+ [[nodiscard]] bool is_date_time() const noexcept { return node_ && node_->is_date_time(); }
+ [[nodiscard]] bool is_array_of_tables() const noexcept { return node_ && node_->is_array_of_tables(); }
+
+ template <typename T>
+ [[nodiscard]]
+ bool is() const noexcept
+ {
+ return node_ ? node_->template is<T>() : false;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ auto as() const noexcept
+ {
+ return node_ ? node_->template as<T>() : nullptr;
+ }
+
+ [[nodiscard]] auto as_table() const noexcept { return as<table>(); }
+ [[nodiscard]] auto as_array() const noexcept { return as<array>(); }
+ [[nodiscard]] auto as_string() const noexcept { return as<std::string>(); }
+ [[nodiscard]] auto as_integer() const noexcept { return as<int64_t>(); }
+ [[nodiscard]] auto as_floating_point() const noexcept { return as<double>(); }
+ [[nodiscard]] auto as_boolean() const noexcept { return as<bool>(); }
+ [[nodiscard]] auto as_date() const noexcept { return as<date>(); }
+ [[nodiscard]] auto as_time() const noexcept { return as<time>(); }
+ [[nodiscard]] auto as_date_time() const noexcept { return as<date_time>(); }
+ [[nodiscard]]
+ bool is_homogeneous(node_type ntype, viewed_type*& first_nonmatch) const noexcept
+ {
+ if (!node_)
+ {
+ first_nonmatch = {};
+ return false;
+ }
+ return node_->is_homogeneous(ntype, first_nonmatch);
+ }
+
+ [[nodiscard]]
+ bool is_homogeneous(node_type ntype) const noexcept
+ {
+ return node_ ? node_->is_homogeneous(ntype) : false;
+ }
+
+ template <typename ElemType = void>
+ [[nodiscard]]
+ bool is_homogeneous() const noexcept
+ {
+ return node_ ? node_->template is_homogeneous<impl::unwrap_node<ElemType>>() : false;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ optional<T> value_exact() const noexcept
+ {
+ if (node_)
+ return node_->template value_exact<T>();
+ return {};
+ }
+
+ TOML_PUSH_WARNINGS
+ TOML_DISABLE_INIT_WARNINGS
+
+ template <typename T>
+ [[nodiscard]]
+ optional<T> value() const noexcept
+ {
+ if (node_)
+ return node_->template value<T>();
+ return {};
+ }
+
+ TOML_POP_WARNINGS
+
+ template <typename T>
+ [[nodiscard]]
+ auto value_or(T&& default_value) const noexcept
+ {
+ using namespace ::toml::impl;
+
+ static_assert(
+ !is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ "Retrieving values as wide-character strings is only "
+ "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (is_wide_string<T>)
+ {
+ #if TOML_WINDOWS_COMPAT
+
+ if (node_)
+ return node_->value_or(std::forward<T>(default_value));
+ return std::wstring{ std::forward<T>(default_value) };
+
+ #else
+
+ static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
+
+ #endif
+ }
+ else
+ {
+ using value_type = std::conditional_t<
+ std::is_pointer_v<std::decay_t<T>>,
+ std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
+ std::decay_t<T>
+ >;
+
+ if (node_)
+ return node_->value_or(std::forward<T>(default_value));
+ if constexpr (std::is_pointer_v<value_type>)
+ return value_type{ default_value };
+ else
+ return std::forward<T>(default_value);
+ }
+ }
+
+ template <typename Func>
+ decltype(auto) visit(Func&& visitor) const
+ noexcept(visit_is_nothrow<Func&&>)
+ {
+ using return_type = decltype(node_->visit(std::forward<Func>(visitor)));
+ if (node_)
+ return node_->visit(std::forward<Func>(visitor));
+ if constexpr (!std::is_void_v<return_type>)
+ return return_type{};
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ decltype(auto) ref() const noexcept
+ {
+ TOML_ASSERT(
+ node_
+ && "toml::node_view::ref() called on a node_view that did not reference a node"
+ );
+ return node_->template ref<impl::unwrap_node<T>>();
+ }
+
+ [[nodiscard]]
+ friend bool operator == (const node_view& lhs, const table& rhs) noexcept
+ {
+ if (lhs.node_ == &rhs)
+ return true;
+ const auto tbl = lhs.as<table>();
+ return tbl && *tbl == rhs;
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const table&, )
+ [[nodiscard]]
+ friend bool operator == (const node_view& lhs, const array& rhs) noexcept
+ {
+ if (lhs.node_ == &rhs)
+ return true;
+ const auto arr = lhs.as<array>();
+ return arr && *arr == rhs;
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const array&, )
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator == (const node_view& lhs, const toml::value<T>& rhs) noexcept
+ {
+ if (lhs.node_ == &rhs)
+ return true;
+ const auto val = lhs.as<T>();
+ return val && *val == rhs;
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<T>&, template <typename T>)
+
+ template <typename T, typename = std::enable_if_t<
+ impl::is_native<T>
+ || impl::is_losslessly_convertible_to_native<T>
+ >>
+ [[nodiscard]]
+ friend bool operator == (const node_view& lhs, const T& rhs) noexcept
+ {
+ static_assert(
+ !impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
+ "Comparison with wide-character strings is only "
+ "supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+
+ if constexpr (impl::is_wide_string<T>)
+ {
+ #if TOML_WINDOWS_COMPAT
+ return lhs == impl::narrow(rhs);
+ #else
+ static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
+ #endif
+ }
+ else
+ {
+ const auto val = lhs.as<impl::native_type_of<T>>();
+ return val && *val == rhs;
+ }
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(
+ const node_view&,
+ const T&,
+ template <typename T, typename = std::enable_if_t<
+ impl::is_native<T>
+ || impl::is_losslessly_convertible_to_native<T>
+ >>
+ )
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator == (const node_view& lhs, const std::initializer_list<T>& rhs) noexcept
+ {
+ const auto arr = lhs.as<array>();
+ return arr && *arr == rhs;
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<T>&, template <typename T>)
+
+ template <typename T>
+ [[nodiscard]]
+ friend bool operator == (const node_view& lhs, const std::vector<T>& rhs) noexcept
+ {
+ const auto arr = lhs.as<array>();
+ return arr && *arr == rhs;
+ }
+ TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<T>&, template <typename T>)
+
+ [[nodiscard]]
+ node_view operator[] (std::string_view key) const noexcept
+ {
+ if (auto tbl = this->as_table())
+ return node_view{ tbl->get(key) };
+ return node_view{ nullptr };
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ node_view operator[] (std::wstring_view key) const noexcept
+ {
+ if (auto tbl = this->as_table())
+ return node_view{ tbl->get(key) };
+ return node_view{ nullptr };
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ node_view operator[] (size_t index) const noexcept
+ {
+ if (auto arr = this->as_array())
+ return node_view{ arr->get(index) };
+ return node_view{ nullptr };
+ }
+
+ template <typename Char, typename T>
+ friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const node_view<T>&);
+ };
+ template <typename T> node_view(const value<T>&) -> node_view<const node>;
+ node_view(const table&) -> node_view<const node>;
+ node_view(const array&) -> node_view<const node>;
+ template <typename T> node_view(value<T>&) -> node_view<node>;
+ node_view(table&) -> node_view<node>;
+ node_view(array&) -> node_view<node>;
+ template <typename T> node_view(const T*) -> node_view<const node>;
+ template <typename T> node_view(T*) -> node_view<node>;
+
+ template <typename Char, typename T>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& os, const node_view<T>& nv)
+ {
+ if (nv.node_)
+ {
+ nv.node_->visit([&os](const auto& n)
+ {
+ os << n;
+ });
+ }
+ return os;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+
+ extern template class TOML_API node_view<node>;
+ extern template class TOML_API node_view<const node>;
+
+ extern template TOML_API std::ostream& operator << (std::ostream&, const node_view<node>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const node_view<const node>&);
+
+ #define TOML_EXTERN(name, T) \
+ extern template TOML_API optional<T> node_view<node>::name<T>() const noexcept; \
+ extern template TOML_API optional<T> node_view<const node>::name<T>() const noexcept
+ TOML_EXTERN(value_exact, std::string_view);
+ TOML_EXTERN(value_exact, std::string);
+ TOML_EXTERN(value_exact, const char*);
+ TOML_EXTERN(value_exact, int64_t);
+ TOML_EXTERN(value_exact, double);
+ TOML_EXTERN(value_exact, date);
+ TOML_EXTERN(value_exact, time);
+ TOML_EXTERN(value_exact, date_time);
+ TOML_EXTERN(value_exact, bool);
+ TOML_EXTERN(value, std::string_view);
+ TOML_EXTERN(value, std::string);
+ TOML_EXTERN(value, const char*);
+ TOML_EXTERN(value, signed char);
+ TOML_EXTERN(value, signed short);
+ TOML_EXTERN(value, signed int);
+ TOML_EXTERN(value, signed long);
+ TOML_EXTERN(value, signed long long);
+ TOML_EXTERN(value, unsigned char);
+ TOML_EXTERN(value, unsigned short);
+ TOML_EXTERN(value, unsigned int);
+ TOML_EXTERN(value, unsigned long);
+ TOML_EXTERN(value, unsigned long long);
+ TOML_EXTERN(value, double);
+ TOML_EXTERN(value, float);
+ TOML_EXTERN(value, date);
+ TOML_EXTERN(value, time);
+ TOML_EXTERN(value, date_time);
+ TOML_EXTERN(value, bool);
+ #ifdef __cpp_lib_char8_t
+ TOML_EXTERN(value_exact, std::u8string_view);
+ TOML_EXTERN(value_exact, std::u8string);
+ TOML_EXTERN(value_exact, const char8_t*);
+ TOML_EXTERN(value, std::u8string_view);
+ TOML_EXTERN(value, std::u8string);
+ TOML_EXTERN(value, const char8_t*);
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ TOML_EXTERN(value_exact, std::wstring);
+ TOML_EXTERN(value, std::wstring);
+ #endif
+ #undef TOML_EXTERN
+
+ #endif // !TOML_HEADER_ONLY
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_ARITHMETIC_WARNINGS
+
+#endif //------- ↑ toml_node_view.h ----------------------------------------------------------------------------------
+
+#if 1 //----------------------------------- ↓ toml_utf8.h -----------------------------------------------------------
+
+#ifndef DOXYGEN
+
+TOML_IMPL_NAMESPACE_START
+{
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
+ {
+ return codepoint == U'\t' || codepoint == U' ';
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_non_ascii_whitespace(char32_t codepoint) noexcept
+ {
+ // see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
+ // (characters that don't say "is a line-break")
+
+ return codepoint == U'\u00A0' // no-break space
+ || codepoint == U'\u1680' // ogham space mark
+ || (codepoint >= U'\u2000' && codepoint <= U'\u200A') // em quad -> hair space
+ || codepoint == U'\u202F' // narrow no-break space
+ || codepoint == U'\u205F' // medium mathematical space
+ || codepoint == U'\u3000' // ideographic space
+ ;
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_whitespace(char32_t codepoint) noexcept
+ {
+ return is_ascii_whitespace(codepoint) || is_non_ascii_whitespace(codepoint);
+ }
+
+ template <bool IncludeCarriageReturn = true>
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
+ {
+ constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f';
+ return (codepoint >= U'\n' && codepoint <= low_range_end);
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_non_ascii_line_break(char32_t codepoint) noexcept
+ {
+ // see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
+ // (characters that say "is a line-break")
+
+ return codepoint == U'\u0085' // next line
+ || codepoint == U'\u2028' // line separator
+ || codepoint == U'\u2029' // paragraph separator
+ ;
+ }
+
+ template <bool IncludeCarriageReturn = true>
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_line_break(char32_t codepoint) noexcept
+ {
+ return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_non_ascii_line_break(codepoint);
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_string_delimiter(char32_t codepoint) noexcept
+ {
+ return codepoint == U'"' || codepoint == U'\'';
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_ascii_letter(char32_t codepoint) noexcept
+ {
+ return (codepoint >= U'a' && codepoint <= U'z')
+ || (codepoint >= U'A' && codepoint <= U'Z');
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_binary_digit(char32_t codepoint) noexcept
+ {
+ return codepoint == U'0' || codepoint == U'1';
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_octal_digit(char32_t codepoint) noexcept
+ {
+ return (codepoint >= U'0' && codepoint <= U'7');
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_decimal_digit(char32_t codepoint) noexcept
+ {
+ return (codepoint >= U'0' && codepoint <= U'9');
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_hexadecimal_digit(char32_t c) noexcept
+ {
+ return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr std::uint_least32_t hex_to_dec(const T codepoint) noexcept
+ {
+ if constexpr (std::is_same_v<remove_cvref_t<T>, std::uint_least32_t>)
+ return codepoint >= 0x41u // >= 'A'
+ ? 10u + (codepoint | 0x20u) - 0x61u // - 'a'
+ : codepoint - 0x30u // - '0'
+ ;
+ else
+ return hex_to_dec(static_cast<std::uint_least32_t>(codepoint));
+ }
+
+ #if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_non_ascii_letter(char32_t c) noexcept
+ {
+ if (U'\xAA' > c || c > U'\U0003134A')
+ return false;
+
+ const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xAAull) / 0xC4Bull;
+ if ((1ull << child_index_0) & 0x26180C0000ull)
+ return false;
+ if ((1ull << child_index_0) & 0x8A7FFC004001CFA0ull)
+ return true;
+ switch (child_index_0)
+ {
+ case 0x00: // [0] 00AA - 0CF4
+ {
+ if (c > U'\u0CF2')
+ return false;
+ TOML_ASSUME(U'\xAA' <= c);
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFDFFFFFC10801u, 0xFFFFFFFFFFFFDFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0x07C000FFF0FFFFFFu, 0x0000000000000014u, 0x0000000000000000u, 0xFEFFFFF5D02F37C0u,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFEFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFF00FFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFC09FFFFFFFFFBFu, 0x000000007FFFFFFFu,
+ 0xFFFFFFC000000000u, 0xFFC00000000001E1u, 0x00000001FFFFFFFFu, 0xFFFFFFFFFFFFFFB0u,
+ 0x18000BFFFFFFFFFFu, 0xFFFFFF4000270030u, 0xFFFFFFF80000003Fu, 0x0FFFFFFFFFFFFFFFu,
+ 0xFFFFFFFF00000080u, 0x44010FFFFFC10C01u, 0xFFC07FFFFFC00000u, 0xFFC0000000000001u,
+ 0x000000003FFFF7FFu, 0xFFFFFFFFFC000000u, 0x00FFC0400008FFFFu, 0x7FFFFE67F87FFF80u,
+ 0x00EC00100008F17Fu, 0x7FFFFE61F80400C0u, 0x001780000000DB7Fu, 0x7FFFFEEFF8000700u,
+ 0x00C000400008FB7Fu, 0x7FFFFE67F8008000u, 0x00EC00000008FB7Fu, 0xC6358F71FA000080u,
+ 0x000000400000FFF1u, 0x7FFFFF77F8000000u, 0x00C1C0000008FFFFu, 0x7FFFFF77F8400000u,
+ 0x00D000000008FBFFu, 0x0000000000000180u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xAAull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xAAull) % 0x40ull));
+ // 1922 code units from 124 ranges (spanning a search area of 3145)
+ }
+ case 0x01: // [1] 0CF5 - 193F
+ {
+ if (U'\u0D04' > c || c > U'\u191E')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x027FFFFFFFFFDDFFu, 0x0FC0000038070400u, 0xF2FFBFFFFFC7FFFEu, 0xE000000000000007u,
+ 0xF000DFFFFFFFFFFFu, 0x6000000000000007u, 0xF200DFFAFFFFFF7Du, 0x100000000F000005u,
+ 0xF000000000000000u, 0x000001FFFFFFFFEFu, 0x00000000000001F0u, 0xF000000000000000u,
+ 0x0800007FFFFFFFFFu, 0x3FFE1C0623C3F000u, 0xFFFFFFFFF0000400u, 0xFF7FFFFFFFFFF20Bu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFF3D7F3DFu, 0xD7F3DFFFFFFFF3DFu, 0xFFFFFFFFFFF7FFF3u,
+ 0xFFFFFFFFFFF3DFFFu, 0xF0000000007FFFFFu, 0xFFFFFFFFF0000FFFu, 0xE3F3FFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xEFFFF9FFFFFFFFFFu, 0xFFFFFFFFF07FFFFFu, 0xF01FE07FFFFFFFFFu,
+ 0xF0003FFFF0003DFFu, 0xF0001DFFF0003FFFu, 0x0000FFFFFFFFFFFFu, 0x0000000001080000u,
+ 0xFFFFFFFFF0000000u, 0xF01FFFFFFFFFFFFFu, 0xFFFFF05FFFFFFFF9u, 0xF003FFFFFFFFFFFFu,
+ 0x0000000007FFFFFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xD04ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xD04ull) % 0x40ull));
+ // 2239 code units from 83 ranges (spanning a search area of 3099)
+ }
+ case 0x02: // [2] 1940 - 258A
+ {
+ if (U'\u1950' > c || c > U'\u2184')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFF001F3FFFFFFFu, 0x03FFFFFF0FFFFFFFu, 0xFFFF000000000000u, 0xFFFFFFFFFFFF007Fu,
+ 0x000000000000001Fu, 0x0000000000800000u, 0xFFE0000000000000u, 0x0FE0000FFFFFFFFFu,
+ 0xFFF8000000000000u, 0xFFFFFC00C001FFFFu, 0xFFFF0000003FFFFFu, 0xE0000000000FFFFFu,
+ 0x01FF3FFFFFFFFC00u, 0x0000E7FFFFFFFFFFu, 0xFFFF046FDE000000u, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0x0000FFFFFFFFFFFFu, 0xFFFF000000000000u, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3F3FFFFFFFFF3F3Fu,
+ 0xFFFF3FFFFFFFAAFFu, 0x1FDC5FDFFFFFFFFFu, 0x00001FDC1FFF0FCFu, 0x0000000000000000u,
+ 0x0000800200000000u, 0x0000000000001FFFu, 0xFC84000000000000u, 0x43E0F3FFBD503E2Fu,
+ 0x0018000000000000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x1950ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x1950ull) % 0x40ull));
+ // 1184 code units from 59 ranges (spanning a search area of 2101)
+ }
+ case 0x03: // [3] 258B - 31D5
+ {
+ if (U'\u2C00' > c || c > U'\u31BF')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFF7FFFFFFFFFFFu, 0xFFFFFFFF7FFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000C781FFFFFFFFFu,
+ 0xFFFF20BFFFFFFFFFu, 0x000080FFFFFFFFFFu, 0x7F7F7F7F007FFFFFu, 0x000000007F7F7F7Fu,
+ 0x0000800000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x183E000000000060u, 0xFFFFFFFFFFFFFFFEu, 0xFFFFFFFEE07FFFFFu, 0xF7FFFFFFFFFFFFFFu,
+ 0xFFFEFFFFFFFFFFE0u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFF00007FFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x2C00ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 771 code units from 30 ranges (spanning a search area of 1472)
+ }
+ case 0x04: return (U'\u31F0' <= c && c <= U'\u31FF') || U'\u3400' <= c;
+ case 0x06: return c <= U'\u4DBF' || U'\u4E00' <= c;
+ case 0x0C: return c <= U'\u9FFC' || U'\uA000' <= c;
+ case 0x0D: // [13] A079 - ACC3
+ {
+ TOML_ASSUME(U'\uA079' <= c && c <= U'\uACC3');
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0x00000000000FFFFFu, 0xFFFFFFFFFF800000u, 0xFFFFFFFFFFFFFF9Fu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x0006007FFF8FFFFFu, 0x003FFFFFFFFFFF80u,
+ 0xFFFFFF9FFFFFFFC0u, 0x00001FFFFFFFFFFFu, 0xFFFFFE7FC0000000u, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFCFFFFu, 0xF00000000003FE7Fu, 0x000003FFFFFBDDFFu, 0x07FFFFFFFFFFFF80u,
+ 0x07FFFFFFFFFFFE00u, 0x7E00000000000000u, 0xFF801FFFFFFE0034u, 0xFFFFFF8000003FFFu,
+ 0x03FFFFFFFFFFF80Fu, 0x007FEF8000400000u, 0x0000FFFFFFFFFFBEu, 0x3FFFFF800007FB80u,
+ 0x317FFFFFFFFFFFE2u, 0x0E03FF9C0000029Fu, 0xFFBFBF803F3F3F00u, 0xFF81FFFBFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0x000003FFFFFFFFFFu, 0xFFFFFFFFFFFFFF80u, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0x00000000000007FFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xA079ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xA079ull) % 0x40ull));
+ // 2554 code units from 52 ranges (spanning a search area of 3147)
+ }
+ case 0x11: return c <= U'\uD7A3' || (U'\uD7B0' <= c && c <= U'\uD7C6') || (U'\uD7CB' <= c && c <= U'\uD7FB');
+ case 0x14: // [20] F686 - 102D0
+ {
+ if (U'\uF900' > c)
+ return false;
+ TOML_ASSUME(c <= U'\U000102D0');
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFF3FFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x0000000003FFFFFFu,
+ 0x5F7FFDFFA0F8007Fu, 0xFFFFFFFFFFFFFFDBu, 0x0003FFFFFFFFFFFFu, 0xFFFFFFFFFFF80000u,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0x3FFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFF0000u, 0xFFFFFFFFFFFCFFFFu, 0x0FFF0000000000FFu,
+ 0x0000000000000000u, 0xFFDF000000000000u, 0xFFFFFFFFFFFFFFFFu, 0x1FFFFFFFFFFFFFFFu,
+ 0x07FFFFFE00000000u, 0xFFFFFFC007FFFFFEu, 0x7FFFFFFFFFFFFFFFu, 0x000000001CFCFCFCu,
+ 0xB7FFFF7FFFFFEFFFu, 0x000000003FFF3FFFu, 0xFFFFFFFFFFFFFFFFu, 0x07FFFFFFFFFFFFFFu,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0xFFFFFFFF1FFFFFFFu, 0x000000000001FFFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xF900ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 1710 code units from 34 ranges (spanning a search area of 2513)
+ }
+ case 0x15: // [21] 102D1 - 10F1B
+ {
+ if (U'\U00010300' > c)
+ return false;
+ TOML_ASSUME(c <= U'\U00010F1B');
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFE000FFFFFFFFu, 0x003FFFFFFFFF03FDu, 0xFFFFFFFF3FFFFFFFu, 0x000000000000FF0Fu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFF00003FFFFFFFu, 0x0FFFFFFFFF0FFFFFu,
+ 0xFFFF00FFFFFFFFFFu, 0x0000000FFFFFFFFFu, 0x0000000000000000u, 0x0000000000000000u,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0x007FFFFFFFFFFFFFu, 0x000000FF003FFFFFu, 0x0000000000000000u, 0x0000000000000000u,
+ 0x91BFFFFFFFFFFD3Fu, 0x007FFFFF003FFFFFu, 0x000000007FFFFFFFu, 0x0037FFFF00000000u,
+ 0x03FFFFFF003FFFFFu, 0x0000000000000000u, 0xC0FFFFFFFFFFFFFFu, 0x0000000000000000u,
+ 0x003FFFFFFEEF0001u, 0x1FFFFFFF00000000u, 0x000000001FFFFFFFu, 0x0000001FFFFFFEFFu,
+ 0x003FFFFFFFFFFFFFu, 0x0007FFFF003FFFFFu, 0x000000000003FFFFu, 0x0000000000000000u,
+ 0xFFFFFFFFFFFFFFFFu, 0x00000000000001FFu, 0x0007FFFFFFFFFFFFu, 0x0007FFFFFFFFFFFFu,
+ 0x0000000FFFFFFFFFu, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x000303FFFFFFFFFFu, 0x0000000000000000u,
+ 0x000000000FFFFFFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x10300ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 1620 code units from 48 ranges (spanning a search area of 3100)
+ }
+ case 0x16: // [22] 10F1C - 11B66
+ {
+ if (c > U'\U00011AF8')
+ return false;
+ TOML_ASSUME(U'\U00010F1C' <= c);
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x000003FFFFF00801u, 0x0000000000000000u, 0x000001FFFFF00000u, 0xFFFFFF8007FFFFF0u,
+ 0x000000000FFFFFFFu, 0xFFFFFF8000000000u, 0xFFF00000000FFFFFu, 0xFFFFFF8000001FFFu,
+ 0xFFF00900000007FFu, 0xFFFFFF80047FFFFFu, 0x400001E0007FFFFFu, 0xFFBFFFF000000001u,
+ 0x000000000000FFFFu, 0xFFFBD7F000000000u, 0xFFFFFFFFFFF01FFBu, 0xFF99FE0000000007u,
+ 0x001000023EDFDFFFu, 0x000000000000003Eu, 0x0000000000000000u, 0xFFFFFFF000000000u,
+ 0x0000780001FFFFFFu, 0xFFFFFFF000000038u, 0x00000B00000FFFFFu, 0x0000000000000000u,
+ 0x0000000000000000u, 0xFFFFFFF000000000u, 0xF00000000007FFFFu, 0xFFFFFFF000000000u,
+ 0x00000100000FFFFFu, 0xFFFFFFF000000000u, 0x0000000010007FFFu, 0x7FFFFFF000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0xFFFFFFF000000000u,
+ 0x000000000000FFFFu, 0x0000000000000000u, 0xFFFFFFFFFFFFFFF0u, 0xF6FF27F80000000Fu,
+ 0x00000028000FFFFFu, 0x0000000000000000u, 0x001FFFFFFFFFCFF0u, 0xFFFF8010000000A0u,
+ 0x00100000407FFFFFu, 0x00003FFFFFFFFFFFu, 0xFFFFFFF000000002u, 0x000000001FFFFFFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x10F1Cull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x10F1Cull) % 0x40ull));
+ // 1130 code units from 67 ranges (spanning a search area of 3037)
+ }
+ case 0x17: // [23] 11B67 - 127B1
+ {
+ if (U'\U00011C00' > c || c > U'\U00012543')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x00007FFFFFFFFDFFu, 0xFFFC000000000001u, 0x000000000000FFFFu, 0x0000000000000000u,
+ 0x0001FFFFFFFFFB7Fu, 0xFFFFFDBF00000040u, 0x00000000010003FFu, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0007FFFF00000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0001000000000000u, 0x0000000000000000u,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x0000000003FFFFFFu, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0x000000000000000Fu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x11C00ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 1304 code units from 16 ranges (spanning a search area of 2372)
+ }
+ case 0x18: return U'\U00013000' <= c;
+ case 0x19: return c <= U'\U0001342E';
+ case 0x1A: return U'\U00014400' <= c && c <= U'\U00014646';
+ case 0x1D: // [29] 16529 - 17173
+ {
+ if (U'\U00016800' > c)
+ return false;
+ TOML_ASSUME(c <= U'\U00017173');
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0x01FFFFFFFFFFFFFFu, 0x000000007FFFFFFFu, 0x0000000000000000u, 0x00003FFFFFFF0000u,
+ 0x0000FFFFFFFFFFFFu, 0xE0FFFFF80000000Fu, 0x000000000000FFFFu, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0xFFFFFFFFFFFFFFFFu, 0x0000000000000000u, 0x0000000000000000u,
+ 0xFFFFFFFFFFFFFFFFu, 0x00000000000107FFu, 0x00000000FFF80000u, 0x0000000B00000000u,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0x000FFFFFFFFFFFFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x16800ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 1250 code units from 14 ranges (spanning a search area of 2420)
+ }
+ case 0x1F: return c <= U'\U000187F7' || U'\U00018800' <= c;
+ case 0x20: return c <= U'\U00018CD5' || (U'\U00018D00' <= c && c <= U'\U00018D08');
+ case 0x23: // [35] 1AEEB - 1BB35
+ {
+ if (U'\U0001B000' > c || c > U'\U0001B2FB')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0x000000007FFFFFFFu, 0xFFFF00F000070000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x0FFFFFFFFFFFFFFFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x1B000ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 690 code units from 4 ranges (spanning a search area of 764)
+ }
+ case 0x24: // [36] 1BB36 - 1C780
+ {
+ if (U'\U0001BC00' > c || c > U'\U0001BC99')
+ return false;
+
+ switch ((static_cast<uint_least64_t>(c) - 0x1BC00ull) / 0x40ull)
+ {
+ case 0x01: return c <= U'\U0001BC7C' && (1ull << (static_cast<uint_least64_t>(c) - 0x1BC40u)) & 0x1FFF07FFFFFFFFFFull;
+ case 0x02: return (1u << (static_cast<uint_least32_t>(c) - 0x1BC80u)) & 0x3FF01FFu;
+ default: return true;
+ }
+ // 139 code units from 4 ranges (spanning a search area of 154)
+ TOML_UNREACHABLE;
+ }
+ case 0x26: // [38] 1D3CC - 1E016
+ {
+ if (U'\U0001D400' > c || c > U'\U0001D7CB')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFDFFFFFu, 0xEBFFDE64DFFFFFFFu, 0xFFFFFFFFFFFFFFEFu,
+ 0x7BFFFFFFDFDFE7BFu, 0xFFFFFFFFFFFDFC5Fu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFF3FFFFFFFFFu, 0xF7FFFFFFF7FFFFFDu,
+ 0xFFDFFFFFFFDFFFFFu, 0xFFFF7FFFFFFF7FFFu, 0xFFFFFDFFFFFFFDFFu, 0x0000000000000FF7u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x1D400ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 936 code units from 30 ranges (spanning a search area of 972)
+ }
+ case 0x27: // [39] 1E017 - 1EC61
+ {
+ if (U'\U0001E100' > c || c > U'\U0001E94B')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x3F801FFFFFFFFFFFu, 0x0000000000004000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x00000FFFFFFFFFFFu,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000000000000001Fu,
+ 0xFFFFFFFFFFFFFFFFu, 0x000000000000080Fu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x1E100ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 363 code units from 7 ranges (spanning a search area of 2124)
+ }
+ case 0x28: // [40] 1EC62 - 1F8AC
+ {
+ if (U'\U0001EE00' > c || c > U'\U0001EEBB')
+ return false;
+
+ switch ((static_cast<uint_least64_t>(c) - 0x1EE00ull) / 0x40ull)
+ {
+ case 0x00: return c <= U'\U0001EE3B' && (1ull << (static_cast<uint_least64_t>(c) - 0x1EE00u)) & 0xAF7FE96FFFFFFEFull;
+ case 0x01: return U'\U0001EE42' <= c && c <= U'\U0001EE7E'
+ && (1ull << (static_cast<uint_least64_t>(c) - 0x1EE42u)) & 0x17BDFDE5AAA5BAA1ull;
+ case 0x02: return (1ull << (static_cast<uint_least64_t>(c) - 0x1EE80u)) & 0xFFFFBEE0FFFFBFFull;
+ TOML_NO_DEFAULT_CASE;
+ }
+ // 141 code units from 33 ranges (spanning a search area of 188)
+ TOML_UNREACHABLE;
+ }
+ case 0x29: return U'\U00020000' <= c;
+ case 0x37: return c <= U'\U0002A6DD' || U'\U0002A700' <= c;
+ case 0x38: return c <= U'\U0002B734' || (U'\U0002B740' <= c && c <= U'\U0002B81D') || U'\U0002B820' <= c;
+ case 0x3A: return c <= U'\U0002CEA1' || U'\U0002CEB0' <= c;
+ case 0x3C: return c <= U'\U0002EBE0';
+ case 0x3D: return U'\U0002F800' <= c && c <= U'\U0002FA1D';
+ case 0x3E: return U'\U00030000' <= c;
+ TOML_NO_DEFAULT_CASE;
+ }
+ // 131189 code units from 620 ranges (spanning a search area of 201377)
+ TOML_UNREACHABLE;
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_non_ascii_number(char32_t c) noexcept
+ {
+ if (U'\u0660' > c || c > U'\U0001FBF9')
+ return false;
+
+ const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0x660ull) / 0x7D7ull;
+ if ((1ull << child_index_0) & 0x47FFDFE07FCFFFD0ull)
+ return false;
+ switch (child_index_0)
+ {
+ case 0x00: // [0] 0660 - 0E36
+ {
+ if (c > U'\u0DEF')
+ return false;
+ TOML_ASSUME(U'\u0660' <= c);
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x00000000000003FFu, 0x0000000000000000u, 0x0000000003FF0000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x000003FF00000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x000000000000FFC0u, 0x0000000000000000u, 0x000000000000FFC0u, 0x0000000000000000u,
+ 0x000000000000FFC0u, 0x0000000000000000u, 0x000000000000FFC0u, 0x0000000000000000u,
+ 0x000000000000FFC0u, 0x0000000000000000u, 0x000000000000FFC0u, 0x0000000000000000u,
+ 0x000000000000FFC0u, 0x0000000000000000u, 0x000000000000FFC0u, 0x0000000000000000u,
+ 0x000000000000FFC0u, 0x0000000000000000u, 0x000000000000FFC0u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x660ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x660ull) % 0x40ull));
+ // 130 code units from 13 ranges (spanning a search area of 1936)
+ }
+ case 0x01: // [1] 0E37 - 160D
+ {
+ if (U'\u0E50' > c || c > U'\u1099')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x00000000000003FFu, 0x0000000000000000u, 0x00000000000003FFu, 0x0000000003FF0000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x03FF000000000000u,
+ 0x0000000000000000u, 0x00000000000003FFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xE50ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xE50ull) % 0x40ull));
+ // 50 code units from 5 ranges (spanning a search area of 586)
+ }
+ case 0x02: // [2] 160E - 1DE4
+ {
+ if (U'\u16EE' > c || c > U'\u1C59')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x0000000000000007u, 0x0000000000000000u, 0x0000000000000000u, 0x0FFC000000000000u,
+ 0x00000FFC00000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x00000003FF000000u, 0x0000000000000000u, 0x00000FFC00000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x00000FFC0FFC0000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x00000FFC00000000u, 0x0000000000000000u, 0x0000000000000FFCu,
+ 0x0000000000000000u, 0x00000FFC0FFC0000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x16EEull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x16EEull) % 0x40ull));
+ // 103 code units from 11 ranges (spanning a search area of 1388)
+ }
+ case 0x03: return U'\u2160' <= c && c <= U'\u2188' && (1ull << (static_cast<uint_least64_t>(c) - 0x2160u)) & 0x1E7FFFFFFFFull;
+ case 0x05: return U'\u3007' <= c && c <= U'\u303A' && (1ull << (static_cast<uint_least64_t>(c) - 0x3007u)) & 0xE0007FC000001ull;
+ case 0x14: // [20] A32C - AB02
+ {
+ if (U'\uA620' > c || c > U'\uAA59')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x00000000000003FFu, 0x0000000000000000u, 0x0000000000000000u, 0x000000000000FFC0u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x03FF000000000000u, 0x000003FF00000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x03FF000000000000u, 0x0000000003FF0000u,
+ 0x03FF000000000000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xA620ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xA620ull) % 0x40ull));
+ // 70 code units from 7 ranges (spanning a search area of 1082)
+ }
+ case 0x15: return U'\uABF0' <= c && c <= U'\uABF9';
+ case 0x1F: return U'\uFF10' <= c && c <= U'\uFF19';
+ case 0x20: // [32] 10140 - 10916
+ {
+ if (c > U'\U000104A9')
+ return false;
+ TOML_ASSUME(U'\U00010140' <= c);
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x001FFFFFFFFFFFFFu, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000402u, 0x0000000000000000u, 0x00000000003E0000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x000003FF00000000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x10140ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 70 code units from 5 ranges (spanning a search area of 874)
+ }
+ case 0x21: return (U'\U00010D30' <= c && c <= U'\U00010D39') || (U'\U00011066' <= c && c <= U'\U0001106F');
+ case 0x22: // [34] 110EE - 118C4
+ {
+ if (U'\U000110F0' > c || c > U'\U00011739')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x00000000000003FFu, 0x000000000000FFC0u, 0x0000000000000000u, 0x000003FF00000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x00000000000003FFu, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x000003FF00000000u, 0x0000000000000000u, 0x000003FF00000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x000003FF00000000u, 0x0000000000000000u, 0x0000000003FF0000u,
+ 0x0000000000000000u, 0x00000000000003FFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x110F0ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x110F0ull) % 0x40ull));
+ // 90 code units from 9 ranges (spanning a search area of 1610)
+ }
+ case 0x23: // [35] 118C5 - 1209B
+ {
+ if (U'\U000118E0' > c || c > U'\U00011DA9')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x00000000000003FFu, 0x03FF000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x03FF000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x03FF000000000000u, 0x0000000000000000u, 0x00000000000003FFu,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x118E0ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x118E0ull) % 0x40ull));
+ // 50 code units from 5 ranges (spanning a search area of 1226)
+ }
+ case 0x24: return U'\U00012400' <= c && c <= U'\U0001246E';
+ case 0x2D: return (U'\U00016A60' <= c && c <= U'\U00016A69') || (U'\U00016B50' <= c && c <= U'\U00016B59');
+ case 0x3B: return U'\U0001D7CE' <= c && c <= U'\U0001D7FF';
+ case 0x3C: return (U'\U0001E140' <= c && c <= U'\U0001E149') || (U'\U0001E2F0' <= c && c <= U'\U0001E2F9');
+ case 0x3D: return U'\U0001E950' <= c && c <= U'\U0001E959';
+ case 0x3F: return U'\U0001FBF0' <= c;
+ TOML_NO_DEFAULT_CASE;
+ }
+ // 876 code units from 72 ranges (spanning a search area of 128410)
+ TOML_UNREACHABLE;
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_combining_mark(char32_t c) noexcept
+ {
+ if (U'\u0300' > c || c > U'\U000E01EF')
+ return false;
+
+ const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0x300ull) / 0x37FCull;
+ if ((1ull << child_index_0) & 0x7FFFFFFFFFFFFE02ull)
+ return false;
+ switch (child_index_0)
+ {
+ case 0x00: // [0] 0300 - 3AFB
+ {
+ if (c > U'\u309A')
+ return false;
+ TOML_ASSUME(U'\u0300' <= c);
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0xFFFFFFFFFFFFFFFFu, 0x0000FFFFFFFFFFFFu, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x00000000000000F8u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0xBFFFFFFFFFFE0000u, 0x00000000000000B6u,
+ 0x0000000007FF0000u, 0x00010000FFFFF800u, 0x0000000000000000u, 0x00003D9F9FC00000u,
+ 0xFFFF000000020000u, 0x00000000000007FFu, 0x0001FFC000000000u, 0x200FF80000000000u,
+ 0x00003EEFFBC00000u, 0x000000000E000000u, 0x0000000000000000u, 0xFFFFFFFBFFF80000u,
+ 0xDC0000000000000Fu, 0x0000000C00FEFFFFu, 0xD00000000000000Eu, 0x4000000C0080399Fu,
+ 0xD00000000000000Eu, 0x0023000000023987u, 0xD00000000000000Eu, 0xFC00000C00003BBFu,
+ 0xD00000000000000Eu, 0x0000000C00E0399Fu, 0xC000000000000004u, 0x0000000000803DC7u,
+ 0xC00000000000001Fu, 0x0000000C00603DDFu, 0xD00000000000000Eu, 0x0000000C00603DDFu,
+ 0xD80000000000000Fu, 0x0000000C00803DDFu, 0x000000000000000Eu, 0x000C0000FF5F8400u,
+ 0x07F2000000000000u, 0x0000000000007F80u, 0x1FF2000000000000u, 0x0000000000003F00u,
+ 0xC2A0000003000000u, 0xFFFE000000000000u, 0x1FFFFFFFFEFFE0DFu, 0x0000000000000040u,
+ 0x7FFFF80000000000u, 0x001E3F9DC3C00000u, 0x000000003C00BFFCu, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x00000000E0000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x001C0000001C0000u, 0x000C0000000C0000u, 0xFFF0000000000000u, 0x00000000200FFFFFu,
+ 0x0000000000003800u, 0x0000000000000000u, 0x0000020000000060u, 0x0000000000000000u,
+ 0x0FFF0FFF00000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x000000000F800000u, 0x9FFFFFFF7FE00000u, 0xBFFF000000000000u, 0x0000000000000001u,
+ 0xFFF000000000001Fu, 0x000FF8000000001Fu, 0x00003FFE00000007u, 0x000FFFC000000000u,
+ 0x00FFFFF000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x039021FFFFF70000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0xFBFFFFFFFFFFFFFFu,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0001FFE21FFF0000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0003800000000000u,
+ 0x0000000000000000u, 0x8000000000000000u, 0x0000000000000000u, 0xFFFFFFFF00000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000FC0000000000u, 0x0000000000000000u, 0x0000000006000000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x300ull) / 0x40ull]
+ & (0x1ull << (static_cast<uint_least64_t>(c) % 0x40ull));
+ // 1106 code units from 156 ranges (spanning a search area of 11675)
+ }
+ case 0x02: // [2] 72F8 - AAF3
+ {
+ if (U'\uA66F' > c || c > U'\uAAEF')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x0001800000007FE1u, 0x0000000000000000u, 0x0000000000000006u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x21F0000010880000u, 0x0000000000000000u,
+ 0x0000000000060000u, 0xFFFE0000007FFFE0u, 0x7F80000000010007u, 0x0000001FFF000000u,
+ 0x00000000001E0000u, 0x004000000003FFF0u, 0xFC00000000000000u, 0x00000000601000FFu,
+ 0x0000000000007000u, 0xF00000000005833Au, 0x0000000000000001u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xA66Full) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xA66Full) % 0x40ull));
+ // 137 code units from 28 ranges (spanning a search area of 1153)
+ }
+ case 0x03: return (U'\uAAF5' <= c && c <= U'\uAAF6') || (U'\uABE3' <= c && c <= U'\uABEA') || (U'\uABEC' <= c && c <= U'\uABED');
+ case 0x04: // [4] E2F0 - 11AEB
+ {
+ if (U'\uFB1E' > c || c > U'\U00011A99')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x0000000000000001u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0003FFFC00000000u,
+ 0x000000000003FFFCu, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000080000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000004u,
+ 0x0000000000000000u, 0x000000001F000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0003C1B800000000u,
+ 0x000000021C000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000180u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x00000000000003C0u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000006000u, 0x0000000000000000u,
+ 0x0007FF0000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000001C00000000u,
+ 0x000001FFFC000000u, 0x0000001E00000000u, 0x000000001FFC0000u, 0x0000001C00000000u,
+ 0x00000180007FFE00u, 0x0000001C00200000u, 0x00037807FFE00000u, 0x0000000000000000u,
+ 0x0000000103FFC000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000003C00001FFEu,
+ 0x0200E67F60000000u, 0x00000000007C7F30u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x000001FFFF800000u, 0x0000000000000001u, 0x0000003FFFFC0000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0xC0000007FCFE0000u, 0x0000000000000000u,
+ 0x00000007FFFC0000u, 0x0000000000000000u, 0x0000000003FFE000u, 0x8000000000000000u,
+ 0x0000000000003FFFu, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x000000001FFFC000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x00000035E6FC0000u, 0x0000000000000000u, 0xF3F8000000000000u, 0x00001FF800000047u,
+ 0x3FF80201EFE00000u, 0x0FFFF00000000000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xFB1Eull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xFB1Eull) % 0x40ull));
+ // 402 code units from 63 ranges (spanning a search area of 8060)
+ }
+ case 0x05: // [5] 11AEC - 152E7
+ {
+ if (U'\U00011C2F' > c || c > U'\U00011EF6')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x000000000001FEFFu, 0xFDFFFFF800000000u, 0x00000000000000FFu, 0x0000000000000000u,
+ 0x00000000017F68FCu, 0x000001F6F8000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x00000000000000F0u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x11C2Full) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x11C2Full) % 0x40ull));
+ // 85 code units from 13 ranges (spanning a search area of 712)
+ }
+ case 0x06: // [6] 152E8 - 18AE3
+ {
+ if (U'\U00016AF0' > c || c > U'\U00016FF1')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x000000000000001Fu, 0x000000000000007Fu, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0xFFFFFFFE80000000u, 0x0000000780FFFFFFu, 0x0010000000000000u,
+ 0x0000000000000003u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x16AF0ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x16AF0ull) % 0x40ull));
+ // 75 code units from 7 ranges (spanning a search area of 1282)
+ }
+ case 0x07: return U'\U0001BC9D' <= c && c <= U'\U0001BC9E';
+ case 0x08: // [8] 1C2E0 - 1FADB
+ {
+ if (U'\U0001D165' > c || c > U'\U0001E94A')
+ return false;
+
+ constexpr uint_least64_t bitmask_table_1[] =
+ {
+ 0x0000007F3FC03F1Fu, 0x00000000000001E0u, 0x0000000000000000u, 0x00000000E0000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0xFFFFFFFFF8000000u, 0xFFFFFFFFFFC3FFFFu,
+ 0xF7C00000800100FFu, 0x00000000000007FFu, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0xDFCFFFFBF8000000u, 0x000000000000003Eu,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x000000000003F800u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000780u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
+ 0x0000000000000000u, 0x0003F80000000000u, 0x0000000000000000u, 0x0000003F80000000u,
+ };
+ return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0x1D165ull) / 0x40ull]
+ & (0x1ull << ((static_cast<uint_least64_t>(c) - 0x1D165ull) % 0x40ull));
+ // 223 code units from 21 ranges (spanning a search area of 6118)
+ }
+ case 0x3F: return U'\U000E0100' <= c;
+ TOML_NO_DEFAULT_CASE;
+ }
+ // 2282 code units from 293 ranges (spanning a search area of 917232)
+ TOML_UNREACHABLE;
+ }
+
+ #endif // TOML_LANG_UNRELEASED
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_bare_key_character(char32_t codepoint) noexcept
+ {
+ return is_ascii_letter(codepoint)
+ || is_decimal_digit(codepoint)
+ || codepoint == U'-'
+ || codepoint == U'_'
+ #if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys) & toml/issues/687 (unicode bare keys)
+ || codepoint == U'+'
+ || is_non_ascii_letter(codepoint)
+ || is_non_ascii_number(codepoint)
+ || is_combining_mark(codepoint)
+ #endif
+ ;
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_value_terminator(char32_t codepoint) noexcept
+ {
+ return is_ascii_line_break(codepoint)
+ || is_ascii_whitespace(codepoint)
+ || codepoint == U']'
+ || codepoint == U'}'
+ || codepoint == U','
+ || codepoint == U'#'
+ || is_non_ascii_line_break(codepoint)
+ || is_non_ascii_whitespace(codepoint)
+ ;
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_control_character(char32_t codepoint) noexcept
+ {
+ return codepoint <= U'\u001F' || codepoint == U'\u007F';
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_nontab_control_character(char32_t codepoint) noexcept
+ {
+ return codepoint <= U'\u0008'
+ || (codepoint >= U'\u000A' && codepoint <= U'\u001F')
+ || codepoint == U'\u007F';
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept
+ {
+ return codepoint >= 0xD800u && codepoint <= 0xDFFF;
+ }
+
+ struct utf8_decoder final
+ {
+ // utf8_decoder based on this: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+ // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+
+ uint_least32_t state{};
+ char32_t codepoint{};
+
+ static constexpr uint8_t state_table[]
+ {
+ 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,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,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,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,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,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,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,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,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,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ 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,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,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,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
+ };
+
+ [[nodiscard]]
+ constexpr bool error() const noexcept
+ {
+ return state == uint_least32_t{ 12u };
+ }
+
+ [[nodiscard]]
+ constexpr bool has_code_point() const noexcept
+ {
+ return state == uint_least32_t{};
+ }
+
+ [[nodiscard]]
+ constexpr bool needs_more_input() const noexcept
+ {
+ return state > uint_least32_t{} && state != uint_least32_t{ 12u };
+ }
+
+ constexpr void operator () (uint8_t byte) noexcept
+ {
+ TOML_ASSERT(!error());
+
+ const auto type = state_table[byte];
+
+ codepoint = static_cast<char32_t>(
+ has_code_point()
+ ? (uint_least32_t{ 255u } >> type) & byte
+ : (byte & uint_least32_t{ 63u }) | (static_cast<uint_least32_t>(codepoint) << 6)
+ );
+
+ state = state_table[state + uint_least32_t{ 256u } + type];
+ }
+ };
+}
+TOML_IMPL_NAMESPACE_END
+
+#endif // !DOXYGEN
+
+#endif //----------------------------------- ↑ toml_utf8.h -----------------------------------------------------------
+
+#if 1 //--------------------------------------------------------- ↓ toml_formatter.h --------------------------------
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+
+TOML_IMPL_NAMESPACE_START
+{
+ template <typename Char = char>
+ class TOML_API formatter
+ {
+ private:
+ const toml::node* source_;
+ std::basic_ostream<Char>* stream_ = nullptr;
+ format_flags flags_;
+ int indent_;
+ bool naked_newline_;
+
+ protected:
+
+ [[nodiscard]] const toml::node& source() const noexcept { return *source_; }
+ [[nodiscard]] std::basic_ostream<Char>& stream() const noexcept { return *stream_; }
+
+ static constexpr size_t indent_columns = 4;
+ static constexpr std::string_view indent_string = " "sv;
+ [[nodiscard]] int indent() const noexcept { return indent_; }
+ void indent(int level) noexcept { indent_ = level; }
+ void increase_indent() noexcept { indent_++; }
+ void decrease_indent() noexcept { indent_--; }
+ [[nodiscard]]
+ bool quote_dates_and_times() const noexcept
+ {
+ return (flags_ & format_flags::quote_dates_and_times) != format_flags::none;
+ }
+
+ [[nodiscard]]
+ bool literal_strings_allowed() const noexcept
+ {
+ return (flags_ & format_flags::allow_literal_strings) != format_flags::none;
+ }
+
+ [[nodiscard]]
+ bool multi_line_strings_allowed() const noexcept
+ {
+ return (flags_ & format_flags::allow_multi_line_strings) != format_flags::none;
+ }
+
+ [[nodiscard]]
+ bool value_format_flags_allowed() const noexcept
+ {
+ return (flags_ & format_flags::allow_value_format_flags) != format_flags::none;
+ }
+
+ [[nodiscard]]
+ bool naked_newline() const noexcept
+ {
+ return naked_newline_;
+ }
+
+ void clear_naked_newline() noexcept
+ {
+ naked_newline_ = false;
+ }
+
+ void attach(std::basic_ostream<Char>& stream) noexcept
+ {
+ indent_ = {};
+ naked_newline_ = true;
+ stream_ = &stream;
+ }
+
+ void detach() noexcept
+ {
+ stream_ = nullptr;
+ }
+
+ void print_newline(bool force = false)
+ {
+ if (!naked_newline_ || force)
+ {
+ print_to_stream('\n', *stream_);
+ naked_newline_ = true;
+ }
+ }
+
+ void print_indent()
+ {
+ for (int i = 0; i < indent_; i++)
+ {
+ print_to_stream(indent_string, *stream_);
+ naked_newline_ = false;
+ }
+ }
+
+ void print_quoted_string(std::string_view str, bool allow_multi_line = true)
+ {
+ auto literals = literal_strings_allowed();
+ if (str.empty())
+ {
+ print_to_stream(literals ? "''"sv : "\"\""sv, *stream_);
+ clear_naked_newline();
+ return;
+ }
+
+ auto multi_line = allow_multi_line && multi_line_strings_allowed();
+ if (multi_line || literals)
+ {
+ utf8_decoder decoder;
+ bool has_line_breaks = false;
+ bool has_control_chars = false;
+ bool has_single_quotes = false;
+ for (size_t i = 0; i < str.length() && !(has_line_breaks && has_control_chars && has_single_quotes); i++)
+ {
+ decoder(static_cast<uint8_t>(str[i]));
+ if (decoder.error())
+ {
+ has_line_breaks = false;
+ has_control_chars = true; //force ""
+ has_single_quotes = true;
+ break;
+ }
+ else if (decoder.has_code_point())
+ {
+ if (is_line_break(decoder.codepoint))
+ has_line_breaks = true;
+ else if (is_nontab_control_character(decoder.codepoint))
+ has_control_chars = true;
+ else if (decoder.codepoint == U'\'')
+ has_single_quotes = true;
+ }
+ }
+ multi_line = multi_line && has_line_breaks;
+ literals = literals && !has_control_chars && !(!multi_line && has_single_quotes);
+ }
+
+ if (literals)
+ {
+ const auto quot = multi_line ? "'''"sv : "'"sv;
+ print_to_stream(quot, *stream_);
+ print_to_stream(str, *stream_);
+ print_to_stream(quot, *stream_);
+ }
+ else
+ {
+ const auto quot = multi_line ? R"(""")"sv : R"(")"sv;
+ print_to_stream(quot, *stream_);
+ print_to_stream_with_escapes(str, *stream_);
+ print_to_stream(quot, *stream_);
+ }
+ clear_naked_newline();
+ }
+
+ template <typename T>
+ void print(const value<T>& val)
+ {
+ if constexpr (std::is_same_v<T, std::string>)
+ {
+ print_quoted_string(val.get());
+ }
+ else
+ {
+ if constexpr (is_one_of<T, date, time, date_time>)
+ {
+ if (quote_dates_and_times())
+ {
+ const auto quot = literal_strings_allowed() ? '\'' : '"';
+ print_to_stream(quot, *stream_);
+ print_to_stream(*val, *stream_);
+ print_to_stream(quot, *stream_);
+ }
+ else
+ print_to_stream(*val, *stream_);
+ }
+ else if constexpr (is_one_of<T, int64_t/*, double*/>)
+ {
+ if (value_format_flags_allowed() && *val >= 0)
+ {
+ const auto fmt = val.flags() & value_flags::format_as_hexadecimal;
+ if (fmt != value_flags::none)
+ {
+ switch (fmt)
+ {
+ case value_flags::format_as_binary: print_to_stream("0b"sv, *stream_); break;
+ case value_flags::format_as_octal: print_to_stream("0o"sv, *stream_); break;
+ case value_flags::format_as_hexadecimal: print_to_stream("0x"sv, *stream_); break;
+ }
+ print_to_stream(*val, *stream_, fmt);
+ }
+ else
+ print_to_stream(*val, *stream_);
+ }
+ else
+ print_to_stream(*val, *stream_);
+ }
+ else
+ print_to_stream(*val, *stream_);
+
+ naked_newline_ = false;
+ }
+ }
+
+ void print_value(const node& val_node, node_type type)
+ {
+ TOML_ASSUME(type > node_type::array);
+ switch (type)
+ {
+ case node_type::string: print(*reinterpret_cast<const value<std::string>*>(&val_node)); break;
+ case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
+ case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
+ case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
+ case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
+ case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
+ case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
+ TOML_NO_DEFAULT_CASE;
+ }
+ }
+
+ formatter(const toml::node& source, format_flags flags) noexcept
+ : source_{ &source },
+ flags_{ flags }
+ {}
+ };
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template class TOML_API formatter<char>;
+ #endif
+
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
+
+#endif //--------------------------------------------------------- ↑ toml_formatter.h --------------------------------
+
+#if 1 //------------------------------------------------------------------------------ ↓ toml_default_formatter.h ---
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+
+TOML_IMPL_NAMESPACE_START
+{
+ [[nodiscard]] TOML_API std::string default_formatter_make_key_segment(const std::string&) noexcept;
+ [[nodiscard]] TOML_API size_t default_formatter_inline_columns(const node&) noexcept;
+ [[nodiscard]] TOML_API bool default_formatter_forces_multiline(const node&, size_t = 0) noexcept;
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ template <typename Char = char>
+ class TOML_API default_formatter final : impl::formatter<Char>
+ {
+ private:
+ using base = impl::formatter<Char>;
+ std::vector<std::string> key_path;
+
+ void print_key_segment(const std::string& str)
+ {
+ if (str.empty())
+ impl::print_to_stream("''"sv, base::stream());
+ else
+ {
+ bool requiresQuotes = false;
+ {
+ impl::utf8_decoder decoder;
+ for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
+ {
+ decoder(static_cast<uint8_t>(str[i]));
+ if (decoder.error())
+ requiresQuotes = true;
+ else if (decoder.has_code_point())
+ requiresQuotes = !impl::is_bare_key_character(decoder.codepoint);
+ }
+ }
+
+ if (requiresQuotes)
+ {
+ impl::print_to_stream('"', base::stream());
+ impl::print_to_stream_with_escapes(str, base::stream());
+ impl::print_to_stream('"', base::stream());
+ }
+ else
+ impl::print_to_stream(str, base::stream());
+ }
+ base::clear_naked_newline();
+ }
+
+ void print_key_path()
+ {
+ for (const auto& segment : key_path)
+ {
+ if (std::addressof(segment) > key_path.data())
+ impl::print_to_stream('.', base::stream());
+ impl::print_to_stream(segment, base::stream());
+ }
+ base::clear_naked_newline();
+ }
+
+ void print_inline(const table& /*tbl*/);
+ void print(const array& arr)
+ {
+ if (arr.empty())
+ impl::print_to_stream("[]"sv, base::stream());
+ else
+ {
+ const auto original_indent = base::indent();
+ const auto multiline = impl::default_formatter_forces_multiline(
+ arr,
+ base::indent_columns * static_cast<size_t>(original_indent < 0 ? 0 : original_indent)
+ );
+ impl::print_to_stream("["sv, base::stream());
+ if (multiline)
+ {
+ if (original_indent < 0)
+ base::indent(0);
+ base::increase_indent();
+ }
+ else
+ impl::print_to_stream(' ', base::stream());
+
+ for (size_t i = 0; i < arr.size(); i++)
+ {
+ if (i > 0_sz)
+ {
+ impl::print_to_stream(',', base::stream());
+ if (!multiline)
+ impl::print_to_stream(' ', base::stream());
+ }
+
+ if (multiline)
+ {
+ base::print_newline(true);
+ base::print_indent();
+ }
+
+ auto& v = arr[i];
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type)
+ {
+ case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
+ case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
+ default:
+ base::print_value(v, type);
+ }
+
+ }
+ if (multiline)
+ {
+ base::indent(original_indent);
+ base::print_newline(true);
+ base::print_indent();
+ }
+ else
+ impl::print_to_stream(' ', base::stream());
+ impl::print_to_stream("]"sv, base::stream());
+ }
+ base::clear_naked_newline();
+ }
+
+ void print(const table& tbl)
+ {
+ static constexpr auto is_non_inline_array_of_tables = [](auto&& nde) noexcept
+ {
+ auto arr = nde.as_array();
+ return arr
+ && arr->is_array_of_tables()
+ && !arr->template get_as<table>(0_sz)->is_inline();
+ };
+
+ // values, arrays, and inline tables/table arrays
+ for (auto&& [k, v] : tbl)
+ {
+ const auto type = v.type();
+ if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
+ || (type == node_type::array && is_non_inline_array_of_tables(v)))
+ continue;
+
+ base::print_newline();
+ base::print_indent();
+ print_key_segment(k);
+ impl::print_to_stream(" = "sv, base::stream());
+ TOML_ASSUME(type != node_type::none);
+ switch (type)
+ {
+ case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
+ case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
+ default:
+ base::print_value(v, type);
+ }
+ }
+
+ // non-inline tables
+ for (auto&& [k, v] : tbl)
+ {
+ const auto type = v.type();
+ if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
+ continue;
+ auto& child_tbl = *reinterpret_cast<const table*>(&v);
+
+ // we can skip indenting and emitting the headers for tables that only contain other tables
+ // (so we don't over-nest)
+ size_t child_value_count{}; //includes inline tables and non-table arrays
+ size_t child_table_count{};
+ size_t child_table_array_count{};
+ for (auto&& [child_k, child_v] : child_tbl)
+ {
+ (void)child_k;
+ const auto child_type = child_v.type();
+ TOML_ASSUME(child_type != node_type::none);
+ switch (child_type)
+ {
+ case node_type::table:
+ if (reinterpret_cast<const table*>(&child_v)->is_inline())
+ child_value_count++;
+ else
+ child_table_count++;
+ break;
+
+ case node_type::array:
+ if (is_non_inline_array_of_tables(child_v))
+ child_table_array_count++;
+ else
+ child_value_count++;
+ break;
+
+ default:
+ child_value_count++;
+ }
+ }
+ bool skip_self = false;
+ if (child_value_count == 0_sz && (child_table_count > 0_sz || child_table_array_count > 0_sz))
+ skip_self = true;
+
+ key_path.push_back(impl::default_formatter_make_key_segment(k));
+
+ if (!skip_self)
+ {
+ if (!base::naked_newline())
+ {
+ base::print_newline();
+ base::print_newline(true);
+ }
+ base::increase_indent();
+ base::print_indent();
+ impl::print_to_stream("["sv, base::stream());
+ print_key_path();
+ impl::print_to_stream("]"sv, base::stream());
+ base::print_newline();
+ }
+
+ print(child_tbl);
+
+ key_path.pop_back();
+ if (!skip_self)
+ base::decrease_indent();
+ }
+
+ // table arrays
+ for (auto&& [k, v] : tbl)
+ {
+ if (!is_non_inline_array_of_tables(v))
+ continue;
+ auto& arr = *reinterpret_cast<const array*>(&v);
+
+ base::increase_indent();
+ key_path.push_back(impl::default_formatter_make_key_segment(k));
+
+ for (size_t i = 0; i < arr.size(); i++)
+ {
+ base::print_newline();
+ base::print_newline(true);
+ base::print_indent();
+ impl::print_to_stream("[["sv, base::stream());
+ print_key_path();
+ impl::print_to_stream("]]"sv, base::stream());
+ base::print_newline(true);
+ print(*reinterpret_cast<const table*>(&arr[i]));
+ }
+
+ key_path.pop_back();
+ base::decrease_indent();
+ }
+ }
+
+ void print()
+ {
+ switch (auto source_type = base::source().type())
+ {
+ case node_type::table:
+ {
+ auto& tbl = *reinterpret_cast<const table*>(&base::source());
+ if (tbl.is_inline())
+ print_inline(tbl);
+ else
+ {
+ base::decrease_indent(); // so root kvps and tables have the same indent
+ print(tbl);
+ }
+ break;
+ }
+
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&base::source()));
+ break;
+
+ default:
+ base::print_value(base::source(), source_type);
+ }
+ }
+
+ public:
+
+ static constexpr format_flags default_flags
+ = format_flags::allow_literal_strings
+ | format_flags::allow_multi_line_strings
+ | format_flags::allow_value_format_flags;
+
+ TOML_NODISCARD_CTOR
+ explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
+ : base{ source, flags }
+ {}
+
+ template <typename T, typename U>
+ friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&);
+ template <typename T, typename U>
+ friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&);
+ };
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template class TOML_API default_formatter<char>;
+ #endif
+
+ default_formatter(const table&) -> default_formatter<char>;
+ default_formatter(const array&) -> default_formatter<char>;
+ template <typename T> default_formatter(const value<T>&) -> default_formatter<char>;
+
+ template <typename T, typename U>
+ inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>& rhs)
+ {
+ rhs.attach(lhs);
+ rhs.key_path.clear();
+ rhs.print();
+ rhs.detach();
+ return lhs;
+ }
+
+ template <typename T, typename U>
+ inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>&& rhs)
+ {
+ return lhs << rhs; //as lvalue
+ }
+
+ #ifndef DOXYGEN
+
+ #if !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const table&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const array&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<std::string>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
+ #endif
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const table& rhs)
+ {
+ return lhs << default_formatter<Char>{ rhs };
+ }
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const array& rhs)
+ {
+ return lhs << default_formatter<Char>{ rhs };
+ }
+
+ template <typename Char, typename T>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs)
+ {
+ return lhs << default_formatter<Char>{ rhs };
+ }
+
+ #endif // !DOXYGEN
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
+
+#endif //------------------------------------------------------------------------------ ↑ toml_default_formatter.h ---
+
+#if 1 //----- ↓ toml_json_formatter.h -------------------------------------------------------------------------------
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+
+TOML_NAMESPACE_START
+{
+ template <typename Char = char>
+ class TOML_API json_formatter final : impl::formatter<Char>
+ {
+ private:
+ using base = impl::formatter<Char>;
+
+ void print(const toml::table& tbl);
+ void print(const array& arr)
+ {
+ if (arr.empty())
+ impl::print_to_stream("[]"sv, base::stream());
+ else
+ {
+ impl::print_to_stream('[', base::stream());
+ base::increase_indent();
+ for (size_t i = 0; i < arr.size(); i++)
+ {
+ if (i > 0_sz)
+ impl::print_to_stream(',', base::stream());
+ base::print_newline(true);
+ base::print_indent();
+
+ auto& v = arr[i];
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type)
+ {
+ case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
+ case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
+ default:
+ base::print_value(v, type);
+ }
+
+ }
+ base::decrease_indent();
+ base::print_newline(true);
+ base::print_indent();
+ impl::print_to_stream(']', base::stream());
+ }
+ base::clear_naked_newline();
+ }
+
+ void print()
+ {
+ switch (auto source_type = base::source().type())
+ {
+ case node_type::table:
+ print(*reinterpret_cast<const table*>(&base::source()));
+ base::print_newline();
+ break;
+
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&base::source()));
+ break;
+
+ default:
+ base::print_value(base::source(), source_type);
+ }
+ }
+
+ public:
+
+ static constexpr format_flags default_flags = format_flags::quote_dates_and_times;
+
+ TOML_NODISCARD_CTOR
+ explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
+ : base{ source, flags }
+ {}
+
+ template <typename T, typename U>
+ friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&);
+ template <typename T, typename U>
+ friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&);
+ };
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template class TOML_API json_formatter<char>;
+ #endif
+
+ json_formatter(const table&) -> json_formatter<char>;
+ json_formatter(const array&) -> json_formatter<char>;
+ template <typename T> json_formatter(const value<T>&) -> json_formatter<char>;
+
+ template <typename T, typename U>
+ inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>& rhs)
+ {
+ rhs.attach(lhs);
+ rhs.print();
+ rhs.detach();
+ return lhs;
+ }
+
+ template <typename T, typename U>
+ inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>&& rhs)
+ {
+ return lhs << rhs; //as lvalue
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&);
+ extern template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&&);
+ #endif
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
+
+#endif //----- ↑ toml_json_formatter.h -------------------------------------------------------------------------------
+
+#if TOML_PARSER
+
+#if 1 //------------------------------- ↓ toml_parse_error.h --------------------------------------------------------
+
+TOML_DISABLE_WARNINGS
+#if TOML_EXCEPTIONS
+ #include <stdexcept>
+#endif
+TOML_ENABLE_WARNINGS
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_INIT_WARNINGS
+
+TOML_NAMESPACE_START
+{
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ #if defined(DOXYGEN) || !TOML_EXCEPTIONS
+
+ class parse_error final
+ {
+ private:
+ std::string description_;
+ source_region source_;
+
+ public:
+
+ TOML_NODISCARD_CTOR
+ parse_error(std::string&& desc, source_region&& src) noexcept
+ : description_{ std::move(desc) },
+ source_{ std::move(src) }
+ {}
+
+ TOML_NODISCARD_CTOR
+ parse_error(std::string&& desc, const source_region& src) noexcept
+ : parse_error{ std::move(desc), source_region{ src } }
+ {}
+
+ TOML_NODISCARD_CTOR
+ parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
+ : parse_error{ std::move(desc), source_region{ position, position, path } }
+ {}
+
+ [[nodiscard]]
+ std::string_view description() const noexcept
+ {
+ return description_;
+ }
+
+ [[nodiscard]]
+ const source_region& source() const noexcept
+ {
+ return source_;
+ }
+ };
+
+ #else
+
+ class parse_error final
+ : public std::runtime_error
+ {
+ private:
+ source_region source_;
+
+ public:
+
+ TOML_NODISCARD_CTOR
+ TOML_ATTR(nonnull)
+ parse_error(const char* desc, source_region&& src) noexcept
+ : std::runtime_error{ desc },
+ source_{ std::move(src) }
+ {}
+
+ TOML_NODISCARD_CTOR
+ TOML_ATTR(nonnull)
+ parse_error(const char* desc, const source_region& src) noexcept
+ : parse_error{ desc, source_region{ src } }
+ {}
+
+ TOML_NODISCARD_CTOR
+ TOML_ATTR(nonnull)
+ parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept
+ : parse_error{ desc, source_region{ position, position, path } }
+ {}
+
+ [[nodiscard]]
+ std::string_view description() const noexcept
+ {
+ return std::string_view{ what() };
+ }
+
+ [[nodiscard]]
+ const source_region& source() const noexcept
+ {
+ return source_;
+ }
+ };
+
+ #endif
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+
+ template <typename Char>
+ inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const parse_error& rhs)
+ {
+ lhs << rhs.description();
+ lhs << "\n\t(error occurred at "sv;
+ lhs << rhs.source();
+ lhs << ")"sv;
+ return lhs;
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
+ #endif
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_INIT_WARNINGS
+
+#endif //------------------------------- ↑ toml_parse_error.h --------------------------------------------------------
+
+#if 1 //-------------------------------------------------------- ↓ toml_utf8_streams.h ------------------------------
+
+TOML_IMPL_NAMESPACE_START
+{
+ template <typename T>
+ class utf8_byte_stream;
+
+ inline constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
+
+ template <typename Char>
+ class TOML_API utf8_byte_stream<std::basic_string_view<Char>> final
+ {
+ static_assert(sizeof(Char) == 1_sz);
+
+ private:
+ std::basic_string_view<Char> source;
+ size_t position = {};
+
+ public:
+ explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept
+ : source{ sv }
+ {
+ // trim trailing nulls
+ const size_t initial_len = source.length();
+ size_t actual_len = initial_len;
+ for (size_t i = actual_len; i --> 0_sz;)
+ {
+ if (source[i] != Char{}) // not '\0'
+ {
+ actual_len = i + 1_sz;
+ break;
+ }
+ }
+ if (initial_len != actual_len)
+ source = source.substr(0_sz, actual_len);
+
+ // skip bom
+ if (actual_len >= 3_sz && memcmp(utf8_byte_order_mark.data(), source.data(), 3_sz) == 0)
+ position += 3_sz;
+ }
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ constexpr bool eof() const noexcept
+ {
+ return position >= source.length();
+ }
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ constexpr bool peek_eof() const noexcept
+ {
+ return eof();
+ }
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ constexpr bool error() const noexcept
+ {
+ return false;
+ }
+
+ [[nodiscard]]
+ constexpr unsigned int operator() () noexcept
+ {
+ if (position >= source.length())
+ return 0xFFFFFFFFu;
+ return static_cast<unsigned int>(static_cast<uint8_t>(source[position++]));
+ }
+ };
+
+ template <typename Char>
+ class TOML_API utf8_byte_stream<std::basic_istream<Char>> final
+ {
+ static_assert(sizeof(Char) == 1_sz);
+
+ private:
+ std::basic_istream<Char>* source;
+
+ public:
+ explicit utf8_byte_stream(std::basic_istream<Char>& stream)
+ : source{ &stream }
+ {
+ if (!source->good()) // eof, fail, bad
+ return;
+
+ const auto initial_pos = source->tellg();
+ Char bom[3];
+ source->read(bom, 3);
+ if (source->bad() || (source->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3_sz) == 0))
+ return;
+
+ source->clear();
+ source->seekg(initial_pos, std::basic_istream<Char>::beg);
+ }
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ bool eof() const noexcept
+ {
+ return source->eof();
+ }
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ bool peek_eof() const
+ {
+ using stream_traits = typename std::remove_pointer_t<decltype(source)>::traits_type;
+ return eof() || source->peek() == stream_traits::eof();
+ }
+
+ [[nodiscard]]
+ TOML_ALWAYS_INLINE
+ bool error() const noexcept
+ {
+ return !(*source);
+ }
+
+ [[nodiscard]]
+ unsigned int operator() ()
+ {
+ auto val = source->get();
+ if (val == std::basic_istream<Char>::traits_type::eof())
+ return 0xFFFFFFFFu;
+ return static_cast<unsigned int>(val);
+ }
+ };
+
+ TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, lf, sf)
+
+ struct utf8_codepoint final
+ {
+ char32_t value;
+ char bytes[4];
+ source_position position;
+
+ [[nodiscard]]
+ std::string_view as_view() const noexcept
+ {
+ return bytes[3]
+ ? std::string_view{ bytes, 4_sz }
+ : std::string_view{ bytes };
+ }
+
+ [[nodiscard]] TOML_ATTR(pure) constexpr operator char32_t& () noexcept { return value; }
+ [[nodiscard]] TOML_ATTR(pure) constexpr operator const char32_t& () const noexcept { return value; }
+ [[nodiscard]] TOML_ATTR(pure) constexpr const char32_t& operator* () const noexcept { return value; }
+ };
+ static_assert(std::is_trivial_v<utf8_codepoint>);
+ static_assert(std::is_standard_layout_v<utf8_codepoint>);
+
+ TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
+
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ #if TOML_EXCEPTIONS
+ #define TOML_ERROR_CHECK (void)0
+ #define TOML_ERROR throw parse_error
+ #else
+ #define TOML_ERROR_CHECK if (err) return nullptr
+ #define TOML_ERROR err.emplace
+ #endif
+
+ struct TOML_INTERFACE utf8_reader_interface
+ {
+ [[nodiscard]]
+ virtual const source_path_ptr& source_path() const noexcept = 0;
+
+ [[nodiscard]]
+ virtual const utf8_codepoint* read_next() = 0;
+ [[nodiscard]]
+ virtual bool peek_eof() const = 0;
+
+ #if !TOML_EXCEPTIONS
+
+ [[nodiscard]]
+ virtual optional<parse_error>&& error() noexcept = 0;
+
+ #endif
+
+ virtual ~utf8_reader_interface() noexcept = default;
+ };
+
+ template <typename T>
+ class TOML_EMPTY_BASES TOML_API utf8_reader final
+ : public utf8_reader_interface
+ {
+ private:
+ utf8_byte_stream<T> stream;
+ utf8_decoder decoder;
+ utf8_codepoint codepoints[2];
+ size_t cp_idx = 1;
+ uint8_t current_byte_count{};
+ source_path_ptr source_path_;
+ #if !TOML_EXCEPTIONS
+ optional<parse_error> err;
+ #endif
+
+ public:
+
+ template <typename U, typename String = std::string_view>
+ explicit utf8_reader(U && source, String&& source_path = {})
+ noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
+ : stream{ std::forward<U>(source) }
+ {
+ std::memset(codepoints, 0, sizeof(codepoints));
+ codepoints[0].position = { 1, 1 };
+ codepoints[1].position = { 1, 1 };
+
+ if (!source_path.empty())
+ source_path_ = std::make_shared<const std::string>(std::forward<String>(source_path));
+ }
+
+ [[nodiscard]]
+ const source_path_ptr& source_path() const noexcept override
+ {
+ return source_path_;
+ }
+
+ [[nodiscard]]
+ const utf8_codepoint* read_next() override
+ {
+ TOML_ERROR_CHECK;
+
+ auto& prev = codepoints[(cp_idx - 1_sz) % 2_sz];
+
+ if (stream.eof())
+ return nullptr;
+ else if (stream.error())
+ TOML_ERROR("An error occurred while reading from the underlying stream", prev.position, source_path_ );
+ else if (decoder.error())
+ TOML_ERROR( "Encountered invalid utf-8 sequence", prev.position, source_path_ );
+
+ TOML_ERROR_CHECK;
+
+ while (true)
+ {
+ uint8_t next_byte;
+ {
+ unsigned int next_byte_raw{ 0xFFFFFFFFu };
+ if constexpr (noexcept(stream()) || !TOML_EXCEPTIONS)
+ {
+ next_byte_raw = stream();
+ }
+ #if TOML_EXCEPTIONS
+ else
+ {
+ try
+ {
+ next_byte_raw = stream();
+ }
+ catch (const std::exception& exc)
+ {
+ throw parse_error{ exc.what(), prev.position, source_path_ };
+ }
+ catch (...)
+ {
+ throw parse_error{ "An unspecified error occurred", prev.position, source_path_ };
+ }
+ }
+ #endif
+
+ if (next_byte_raw >= 256u)
+ {
+ if (stream.eof())
+ {
+ if (decoder.needs_more_input())
+ TOML_ERROR("Encountered EOF during incomplete utf-8 code point sequence",
+ prev.position, source_path_);
+ return nullptr;
+ }
+ else
+ TOML_ERROR("An error occurred while reading from the underlying stream",
+ prev.position, source_path_);
+ }
+
+ TOML_ERROR_CHECK;
+ next_byte = static_cast<uint8_t>(next_byte_raw);
+ }
+
+ decoder(next_byte);
+ if (decoder.error())
+ TOML_ERROR( "Encountered invalid utf-8 sequence", prev.position, source_path_ );
+
+ TOML_ERROR_CHECK;
+
+ auto& current = codepoints[cp_idx % 2_sz];
+ current.bytes[current_byte_count++] = static_cast<char>(next_byte);
+ if (decoder.has_code_point())
+ {
+ //store codepoint
+ current.value = decoder.codepoint;
+
+ //reset prev (will be the next 'current')
+ std::memset(prev.bytes, 0, sizeof(prev.bytes));
+ current_byte_count = {};
+ if (is_line_break<false>(current.value))
+ prev.position = { static_cast<source_index>(current.position.line + 1), 1 };
+ else
+ prev.position = { current.position.line, static_cast<source_index>(current.position.column + 1) };
+ cp_idx++;
+ return &current;
+ }
+ }
+
+ TOML_UNREACHABLE;
+ }
+
+ [[nodiscard]]
+ bool peek_eof() const override
+ {
+ return stream.peek_eof();
+ }
+
+ #if !TOML_EXCEPTIONS
+
+ [[nodiscard]]
+ optional<parse_error>&& error() noexcept override
+ {
+ return std::move(err);
+ }
+
+ #endif
+ };
+
+ template <typename Char>
+ utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
+ template <typename Char>
+ utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
+ template <typename Char>
+ utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
+ template <typename Char>
+ utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
+
+ class TOML_EMPTY_BASES TOML_API utf8_buffered_reader final
+ : public utf8_reader_interface
+ {
+ public:
+ static constexpr size_t max_history_length = 72;
+
+ private:
+ static constexpr size_t history_buffer_size = max_history_length - 1; //'head' is stored in the reader
+ utf8_reader_interface& reader;
+ struct
+ {
+ utf8_codepoint buffer[history_buffer_size];
+ size_t count, first;
+ }
+ history = {};
+ const utf8_codepoint* head = {};
+ size_t negative_offset = {};
+
+ public:
+ explicit utf8_buffered_reader(utf8_reader_interface& reader_) noexcept;
+ const source_path_ptr& source_path() const noexcept override;
+ const utf8_codepoint* read_next() override;
+ const utf8_codepoint* step_back(size_t count) noexcept;
+ bool peek_eof() const override;
+ #if !TOML_EXCEPTIONS
+ optional<parse_error>&& error() noexcept override;
+ #endif
+ };
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+}
+TOML_IMPL_NAMESPACE_END
+
+#endif //-------------------------------------------------------- ↑ toml_utf8_streams.h ------------------------------
+
+#if 1 //------------------------------------------------------------------------------------ ↓ toml_parser.h --------
+
+TOML_NAMESPACE_START
+{
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ #if defined(DOXYGEN) || !TOML_EXCEPTIONS
+
+ class parse_result final
+ {
+ private:
+ std::aligned_storage_t<
+ (sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(toml::table)),
+ (alignof(toml::table) < alignof(parse_error) ? alignof(parse_error) : alignof(toml::table))
+ > storage;
+ bool is_err;
+ void destroy() noexcept
+ {
+ if (is_err)
+ TOML_LAUNDER(reinterpret_cast<parse_error*>(&storage))->~parse_error();
+ else
+ TOML_LAUNDER(reinterpret_cast<toml::table*>(&storage))->~table();
+ }
+
+ public:
+
+ using iterator = table_iterator;
+ using const_iterator = const_table_iterator;
+ [[nodiscard]] bool succeeded() const noexcept { return !is_err; }
+ [[nodiscard]] bool failed() const noexcept { return is_err; }
+ [[nodiscard]] explicit operator bool() const noexcept { return !is_err; }
+
+ [[nodiscard]]
+ toml::table& table() & noexcept
+ {
+ TOML_ASSERT(!is_err);
+ return *TOML_LAUNDER(reinterpret_cast<toml::table*>(&storage));
+ }
+ [[nodiscard]]
+ toml::table&& table() && noexcept
+ {
+ TOML_ASSERT(!is_err);
+ return std::move(*TOML_LAUNDER(reinterpret_cast<toml::table*>(&storage)));
+ }
+ [[nodiscard]]
+ const toml::table& table() const& noexcept
+ {
+ TOML_ASSERT(!is_err);
+ return *TOML_LAUNDER(reinterpret_cast<const toml::table*>(&storage));
+ }
+
+ [[nodiscard, deprecated("use parse_result::table() instead")]]
+ toml::table& get() & noexcept { return table(); }
+ [[nodiscard, deprecated("use parse_result::table() instead")]]
+ toml::table&& get() && noexcept { return std::move(table()); }
+ [[nodiscard, deprecated("use parse_result::table() instead")]]
+ const toml::table& get() const& noexcept { return table(); }
+ [[nodiscard]]
+ parse_error& error() & noexcept
+ {
+ TOML_ASSERT(is_err);
+ return *TOML_LAUNDER(reinterpret_cast<parse_error*>(&storage));
+ }
+ [[nodiscard]]
+ parse_error&& error() && noexcept
+ {
+ TOML_ASSERT(is_err);
+ return std::move(*TOML_LAUNDER(reinterpret_cast<parse_error*>(&storage)));
+ }
+ [[nodiscard]]
+ const parse_error& error() const& noexcept
+ {
+ TOML_ASSERT(is_err);
+ return *TOML_LAUNDER(reinterpret_cast<const parse_error*>(&storage));
+ }
+
+ [[nodiscard]] operator toml::table& () noexcept { return table(); }
+ [[nodiscard]] operator toml::table&& () noexcept { return std::move(table()); }
+ [[nodiscard]] operator const toml::table& () const noexcept { return table(); }
+ [[nodiscard]] explicit operator parse_error& () noexcept { return error(); }
+ [[nodiscard]] explicit operator parse_error && () noexcept { return std::move(error()); }
+ [[nodiscard]] explicit operator const parse_error& () const noexcept { return error(); }
+
+ TOML_NODISCARD_CTOR
+ explicit parse_result(toml::table&& tbl) noexcept
+ : is_err{ false }
+ {
+ ::new (&storage) toml::table{ std::move(tbl) };
+ }
+
+ TOML_NODISCARD_CTOR
+ explicit parse_result(parse_error&& err) noexcept
+ : is_err{ true }
+ {
+ ::new (&storage) parse_error{ std::move(err) };
+ }
+
+ TOML_NODISCARD_CTOR
+ parse_result(parse_result&& res) noexcept
+ : is_err{ res.is_err }
+ {
+ if (is_err)
+ ::new (&storage) parse_error{ std::move(res).error() };
+ else
+ ::new (&storage) toml::table{ std::move(res).table() };
+ }
+
+ parse_result& operator=(parse_result&& rhs) noexcept
+ {
+ if (is_err != rhs.is_err)
+ {
+ destroy();
+ is_err = rhs.is_err;
+ if (is_err)
+ ::new (&storage) parse_error{ std::move(rhs).error() };
+ else
+ ::new (&storage) toml::table{ std::move(rhs).table() };
+ }
+ else
+ {
+ if (is_err)
+ error() = std::move(rhs).error();
+ else
+ table() = std::move(rhs).table();
+ }
+ return *this;
+ }
+
+ ~parse_result() noexcept
+ {
+ destroy();
+ }
+
+ [[nodiscard]]
+ node_view<node> operator[] (string_view key) noexcept
+ {
+ return is_err ? node_view<node>{} : table()[key];
+ }
+
+ [[nodiscard]]
+ node_view<const node> operator[] (string_view key) const noexcept
+ {
+ return is_err ? node_view<const node>{} : table()[key];
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ node_view<node> operator[] (std::wstring_view key) noexcept
+ {
+ return is_err ? node_view<node>{} : table()[key];
+ }
+
+ [[nodiscard]]
+ node_view<const node> operator[] (std::wstring_view key) const noexcept
+ {
+ return is_err ? node_view<const node>{} : table()[key];
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ table_iterator begin() noexcept
+ {
+ return is_err ? table_iterator{} : table().begin();
+ }
+
+ [[nodiscard]]
+ const_table_iterator begin() const noexcept
+ {
+ return is_err ? const_table_iterator{} : table().begin();
+ }
+
+ [[nodiscard]]
+ const_table_iterator cbegin() const noexcept
+ {
+ return is_err ? const_table_iterator{} : table().cbegin();
+ }
+
+ [[nodiscard]]
+ table_iterator end() noexcept
+ {
+ return is_err ? table_iterator{} : table().end();
+ }
+
+ [[nodiscard]]
+ const_table_iterator end() const noexcept
+ {
+ return is_err ? const_table_iterator{} : table().end();
+ }
+
+ [[nodiscard]]
+ const_table_iterator cend() const noexcept
+ {
+ return is_err ? const_table_iterator{} : table().cend();
+ }
+
+ template <typename Char>
+ friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& os, const parse_result& result)
+ {
+ return result.is_err ? (os << result.error()) : (os << result.table());
+ }
+ };
+
+ #else
+
+ using parse_result = table;
+
+ #endif
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+}
+TOML_NAMESPACE_END
+
+TOML_IMPL_NAMESPACE_START
+{
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ [[nodiscard]] TOML_API parse_result do_parse(utf8_reader_interface&&) TOML_MAY_THROW;
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+}
+TOML_IMPL_NAMESPACE_END
+
+#if TOML_EXCEPTIONS
+ #define TOML_THROW_PARSE_ERROR(msg, path) \
+ throw parse_error{ \
+ msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
+ }
+#else
+ #define TOML_THROW_PARSE_ERROR(msg, path) \
+ return parse_result{ parse_error{ \
+ msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
+ }}
+#endif
+
+TOML_NAMESPACE_START
+{
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ [[nodiscard]]
+ TOML_API
+ parse_result parse(std::string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
+
+ [[nodiscard]]
+ TOML_API
+ parse_result parse(std::string_view doc, std::string&& source_path) TOML_MAY_THROW;
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ TOML_API
+ parse_result parse(std::string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ #ifdef __cpp_lib_char8_t
+
+ [[nodiscard]]
+ TOML_API
+ parse_result parse(std::u8string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
+
+ [[nodiscard]]
+ TOML_API
+ parse_result parse(std::u8string_view doc, std::string&& source_path) TOML_MAY_THROW;
+
+ #if TOML_WINDOWS_COMPAT
+
+ [[nodiscard]]
+ TOML_API
+ parse_result parse(std::u8string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ #endif // __cpp_lib_char8_t
+
+ template <typename Char>
+ [[nodiscard]]
+ inline parse_result parse(std::basic_istream<Char>& doc, std::string_view source_path = {}) TOML_MAY_THROW
+ {
+ static_assert(
+ sizeof(Char) == 1,
+ "The stream's underlying character type must be 1 byte in size."
+ );
+
+ return impl::do_parse(impl::utf8_reader{ doc, source_path });
+ }
+
+ template <typename Char>
+ [[nodiscard]]
+ inline parse_result parse(std::basic_istream<Char>& doc, std::string&& source_path) TOML_MAY_THROW
+ {
+ static_assert(
+ sizeof(Char) == 1,
+ "The stream's underlying character type must be 1 byte in size."
+ );
+
+ return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ template <typename Char>
+ [[nodiscard]]
+ inline parse_result parse(std::basic_istream<Char>& doc, std::wstring_view source_path) TOML_MAY_THROW
+ {
+ return parse(doc, impl::narrow(source_path));
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ // Q: "why are the parse_file functions templated??"
+ // A: I don't want to force users to drag in <fstream> if they're not going to do
+ // any parsing directly from files. Keeping them templated delays their instantiation
+ // until they're actually required, so only those users wanting to use parse_file()
+ // are burdened by the <fstream> overhead.
+
+ template <typename Char, typename StreamChar = char>
+ [[nodiscard]]
+ inline parse_result parse_file(std::basic_string_view<Char> file_path) TOML_MAY_THROW
+ {
+ static_assert(
+ !std::is_same_v<Char, wchar_t> || TOML_WINDOWS_COMPAT,
+ "Wide-character file paths are only supported on Windows with TOML_WINDOWS_COMPAT enabled."
+ );
+ #if TOML_WINDOWS_COMPAT
+ static_assert(
+ sizeof(Char) == 1 || std::is_same_v<Char, wchar_t>,
+ "The file path's underlying character type must be wchar_t or be 1 byte in size."
+ );
+ #else
+ static_assert(
+ sizeof(Char) == 1,
+ "The file path's underlying character type must be 1 byte in size."
+ );
+ #endif
+ static_assert(
+ std::is_same_v<StreamChar, char>,
+ "StreamChar must be 'char' (it is as an instantiation-delaying hack and is not user-configurable)."
+ );
+
+ std::string file_path_str;
+ #if TOML_WINDOWS_COMPAT
+ if constexpr (std::is_same_v<Char, wchar_t>)
+ file_path_str = impl::narrow(file_path);
+ else
+ #endif
+ file_path_str = std::string_view{ reinterpret_cast<const char*>(file_path.data()), file_path.length() };
+
+ // open file with a custom-sized stack buffer
+ using ifstream = std::basic_ifstream<StreamChar>;
+ ifstream file;
+ StreamChar file_buffer[sizeof(void*) * 4096_sz];
+ file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
+ file.open(file_path_str, ifstream::in | ifstream::binary | ifstream::ate);
+ if (!file.is_open())
+ TOML_THROW_PARSE_ERROR("File could not be opened for reading", file_path_str);
+
+ // get size
+ const auto file_size = file.tellg();
+ if (file_size == -1)
+ TOML_THROW_PARSE_ERROR("Could not determine file size", file_path_str);
+ file.seekg(0, ifstream::beg);
+
+ // read the whole file into memory first if the file isn't too large
+ constexpr auto large_file_threshold = 1024 * 1024 * static_cast<int>(sizeof(void*)) * 4; // 32 megabytes on 64-bit
+ if (file_size <= large_file_threshold)
+ {
+ std::vector<StreamChar> file_data;
+ file_data.resize(static_cast<size_t>(file_size));
+ file.read(file_data.data(), static_cast<std::streamsize>(file_size));
+ return parse(std::basic_string_view<StreamChar>{ file_data.data(), file_data.size() }, std::move(file_path_str));
+ }
+
+ // otherwise parse it using the streams
+ else
+ return parse(file, std::move(file_path_str));
+ }
+
+ #if !defined(DOXYGEN) && !TOML_HEADER_ONLY
+ extern template TOML_API parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
+ extern template TOML_API parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
+ extern template TOML_API parse_result parse_file(std::string_view) TOML_MAY_THROW;
+ #ifdef __cpp_lib_char8_t
+ extern template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ extern template TOML_API parse_result parse_file(std::wstring_view) TOML_MAY_THROW;
+ #endif
+ #endif
+
+ template <typename Char>
+ [[nodiscard]]
+ inline parse_result parse_file(const std::basic_string<Char>& file_path) TOML_MAY_THROW
+ {
+ return parse_file(std::basic_string_view<Char>{ file_path });
+ }
+
+ template <typename Char>
+ [[nodiscard]]
+ inline parse_result parse_file(const Char* file_path) TOML_MAY_THROW
+ {
+ return parse_file(std::basic_string_view<Char>{ file_path });
+ }
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+
+ inline namespace literals
+ {
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex)
+
+ [[nodiscard]]
+ TOML_API
+ parse_result operator"" _toml(const char* str, size_t len) TOML_MAY_THROW;
+
+ #ifdef __cpp_lib_char8_t
+
+ [[nodiscard]]
+ TOML_API
+ parse_result operator"" _toml(const char8_t* str, size_t len) TOML_MAY_THROW;
+
+ #endif // __cpp_lib_char8_t
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+ }
+}
+TOML_NAMESPACE_END
+
+#undef TOML_THROW_PARSE_ERROR
+
+#endif //------------------------------------------------------------------------------------ ↑ toml_parser.h --------
+
+#endif // TOML_PARSER
+
+#if TOML_IMPLEMENTATION
+
+#if 1 //--------- ↓ toml_node.hpp -----------------------------------------------------------------------------------
+
+TOML_NAMESPACE_START
+{
+ TOML_EXTERNAL_LINKAGE
+ node::node(const node& /*other*/) noexcept
+ {
+ // does not copy source information - this is not an error
+ //
+ // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node::node(node && other) noexcept
+ : source_{ std::move(other.source_) }
+ {
+ other.source_.begin = {};
+ other.source_.end = {};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node& node::operator= (const node& /*rhs*/) noexcept
+ {
+ // does not copy source information - this is not an error
+ //
+ // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
+
+ source_ = {};
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node& node::operator= (node && rhs) noexcept
+ {
+ source_ = std::move(rhs.source_);
+ rhs.source_.begin = {};
+ rhs.source_.end = {};
+ return *this;
+ }
+
+ #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
+
+ TOML_MEMBER_ATTR(const) bool node::is_string() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_integer() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_floating_point() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_number() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_boolean() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_date() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_time() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_date_time() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool node::is_array_of_tables() const noexcept { return false; }
+
+ TOML_MEMBER_ATTR(const) table* node::as_table() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) array* node::as_array() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<std::string>* node::as_string() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<int64_t>* node::as_integer() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<double>* node::as_floating_point() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<bool>* node::as_boolean() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<date>* node::as_date() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<time>* node::as_time() noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) value<date_time>* node::as_date_time() noexcept { return nullptr; }
+
+ TOML_MEMBER_ATTR(const) const table* node::as_table() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const array* node::as_array() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<std::string>* node::as_string() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<int64_t>* node::as_integer() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<double>* node::as_floating_point() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<bool>* node::as_boolean() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<date>* node::as_date() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<time>* node::as_time() const noexcept { return nullptr; }
+ TOML_MEMBER_ATTR(const) const value<date_time>* node::as_date_time() const noexcept { return nullptr; }
+
+ TOML_MEMBER_ATTR(const) const source_region& node::source() const noexcept { return source_; }
+
+ #undef TOML_MEMBER_ATTR
+
+ TOML_EXTERNAL_LINKAGE
+ node::operator node_view<node>() noexcept
+ {
+ return node_view<node>(this);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node::operator node_view<const node>() const noexcept
+ {
+ return node_view<const node>(this);
+ }
+}
+TOML_NAMESPACE_END
+
+#endif //--------- ↑ toml_node.hpp -----------------------------------------------------------------------------------
+
+#if 1 //--------------------------------- ↓ toml_array.hpp ----------------------------------------------------------
+
+TOML_NAMESPACE_START
+{
+ #if TOML_LIFETIME_HOOKS
+
+ TOML_EXTERNAL_LINKAGE
+ void array::lh_ctor() noexcept
+ {
+ TOML_ARRAY_CREATED;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::lh_dtor() noexcept
+ {
+ TOML_ARRAY_DESTROYED;
+ }
+
+ #endif
+
+ TOML_EXTERNAL_LINKAGE
+ array::array() noexcept
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::array(const array& other) noexcept
+ : node{ other }
+ {
+ elements.reserve(other.elements.size());
+ for (const auto& elem : other)
+ elements.emplace_back(impl::make_node(elem));
+
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::array(array&& other) noexcept
+ : node{ std::move(other) },
+ elements{ std::move(other.elements) }
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::operator= (const array& rhs) noexcept
+ {
+ if (&rhs != this)
+ {
+ node::operator=(rhs);
+ elements.clear();
+ elements.reserve(rhs.elements.size());
+ for (const auto& elem : rhs)
+ elements.emplace_back(impl::make_node(elem));
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::operator= (array&& rhs) noexcept
+ {
+ if (&rhs != this)
+ {
+ node::operator=(std::move(rhs));
+ elements = std::move(rhs.elements);
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::~array() noexcept
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_dtor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::preinsertion_resize(size_t idx, size_t count) noexcept
+ {
+ TOML_ASSERT(idx <= elements.size());
+ TOML_ASSERT(count >= 1_sz);
+ const auto old_size = elements.size();
+ const auto new_size = old_size + count;
+ const auto inserting_at_end = idx == old_size;
+ elements.resize(new_size);
+ if (!inserting_at_end)
+ {
+ for(size_t left = old_size, right = new_size - 1_sz; left --> idx; right--)
+ elements[right] = std::move(elements[left]);
+ }
+ }
+
+ #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
+
+ TOML_MEMBER_ATTR(const) node_type array::type() const noexcept { return node_type::array; }
+ TOML_MEMBER_ATTR(const) bool array::is_table() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool array::is_array() const noexcept { return true; }
+ TOML_MEMBER_ATTR(const) bool array::is_value() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) const array* array::as_array() const noexcept { return this; }
+ TOML_MEMBER_ATTR(const) array* array::as_array() noexcept { return this; }
+
+ TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *elements[index]; }
+ TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *elements[index]; }
+
+ TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *elements.front(); }
+ TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *elements.back(); }
+ TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *elements.front(); }
+ TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *elements.back(); }
+
+ TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { elements.begin() }; }
+ TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { elements.end() }; }
+ TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { elements.cbegin() }; }
+ TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { elements.cend() }; }
+ TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { elements.begin() }; }
+ TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { elements.end() }; }
+
+ TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return elements.size(); }
+ TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return elements.capacity(); }
+ TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return elements.empty(); }
+ TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return elements.max_size(); }
+
+ TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { elements.reserve(new_capacity); }
+ TOML_EXTERNAL_LINKAGE void array::clear() noexcept { elements.clear(); }
+ TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { elements.shrink_to_fit(); }
+
+ #undef TOML_MEMBER_ATTR
+
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_homogeneous(node_type ntype) const noexcept
+ {
+ if (elements.empty())
+ return false;
+
+ if (ntype == node_type::none)
+ ntype = elements[0]->type();
+
+ for (const auto& val : elements)
+ if (val->type() != ntype)
+ return false;
+ return true;
+ }
+
+ namespace impl
+ {
+ template <typename T, typename U>
+ TOML_INTERNAL_LINKAGE
+ bool array_is_homogeneous(T& elements, node_type ntype, U& first_nonmatch) noexcept
+ {
+ if (elements.empty())
+ {
+ first_nonmatch = {};
+ return false;
+ }
+ if (ntype == node_type::none)
+ ntype = elements[0]->type();
+ for (const auto& val : elements)
+ {
+ if (val->type() != ntype)
+ {
+ first_nonmatch = val.get();
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
+ {
+ return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
+ {
+ return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::truncate(size_t new_size)
+ {
+ if (new_size < elements.size())
+ elements.resize(new_size);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::iterator array::erase(const_iterator pos) noexcept
+ {
+ return { elements.erase(pos.raw_) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::iterator array::erase(const_iterator first, const_iterator last) noexcept
+ {
+ return { elements.erase(first.raw_, last.raw_) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::pop_back() noexcept
+ {
+ elements.pop_back();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ TOML_ATTR(pure)
+ node* array::get(size_t index) noexcept
+ {
+ return index < elements.size() ? elements[index].get() : nullptr;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ TOML_ATTR(pure)
+ const node* array::get(size_t index) const noexcept
+ {
+ return index < elements.size() ? elements[index].get() : nullptr;
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ bool operator == (const array& lhs, const array& rhs) noexcept
+ {
+ if (&lhs == &rhs)
+ return true;
+ if (lhs.elements.size() != rhs.elements.size())
+ return false;
+ for (size_t i = 0, e = lhs.elements.size(); i < e; i++)
+ {
+ const auto lhs_type = lhs.elements[i]->type();
+ const node& rhs_ = *rhs.elements[i];
+ const auto rhs_type = rhs_.type();
+ if (lhs_type != rhs_type)
+ return false;
+
+ const bool equal = lhs.elements[i]->visit([&](const auto& lhs_) noexcept
+ {
+ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
+ });
+ if (!equal)
+ return false;
+ }
+ return true;
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ bool operator != (const array& lhs, const array& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ size_t array::total_leaf_count() const noexcept
+ {
+ size_t leaves{};
+ for (size_t i = 0, e = elements.size(); i < e; i++)
+ {
+ auto arr = elements[i]->as_array();
+ leaves += arr ? arr->total_leaf_count() : 1_sz;
+ }
+ return leaves;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::flatten_child(array&& child, size_t& dest_index) noexcept
+ {
+ for (size_t i = 0, e = child.size(); i < e; i++)
+ {
+ auto type = child.elements[i]->type();
+ if (type == node_type::array)
+ {
+ array& arr = *reinterpret_cast<array*>(child.elements[i].get());
+ if (!arr.empty())
+ flatten_child(std::move(arr), dest_index);
+ }
+ else
+ elements[dest_index++] = std::move(child.elements[i]);
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::flatten() &
+ {
+ if (elements.empty())
+ return *this;
+
+ bool requires_flattening = false;
+ size_t size_after_flattening = elements.size();
+ for (size_t i = elements.size(); i --> 0_sz;)
+ {
+ auto arr = elements[i]->as_array();
+ if (!arr)
+ continue;
+ size_after_flattening--; //discount the array itself
+ const auto leaf_count = arr->total_leaf_count();
+ if (leaf_count > 0_sz)
+ {
+ requires_flattening = true;
+ size_after_flattening += leaf_count;
+ }
+ else
+ elements.erase(elements.cbegin() + static_cast<ptrdiff_t>(i));
+ }
+
+ if (!requires_flattening)
+ return *this;
+
+ elements.reserve(size_after_flattening);
+
+ size_t i = 0;
+ while (i < elements.size())
+ {
+ auto arr = elements[i]->as_array();
+ if (!arr)
+ {
+ i++;
+ continue;
+ }
+
+ std::unique_ptr<node> arr_storage = std::move(elements[i]);
+ const auto leaf_count = arr->total_leaf_count();
+ if (leaf_count > 1_sz)
+ preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
+ flatten_child(std::move(*arr), i); //increments i
+ }
+
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_array_of_tables() const noexcept
+ {
+ return is_homogeneous(node_type::table);
+ }
+}
+TOML_NAMESPACE_END
+
+#endif //--------------------------------- ↑ toml_array.hpp ----------------------------------------------------------
+
+#if 1 //---------------------------------------------------------- ↓ toml_table.hpp ---------------------------------
+
+TOML_NAMESPACE_START
+{
+ #if TOML_LIFETIME_HOOKS
+
+ TOML_EXTERNAL_LINKAGE
+ void table::lh_ctor() noexcept
+ {
+ TOML_TABLE_CREATED;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void table::lh_dtor() noexcept
+ {
+ TOML_TABLE_DESTROYED;
+ }
+
+ #endif
+
+ TOML_EXTERNAL_LINKAGE
+ table::table() noexcept
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::table(const table& other) noexcept
+ : node{ std::move(other) },
+ inline_{ other.inline_ }
+ {
+ for (auto&& [k, v] : other)
+ map.emplace_hint(map.end(), k, impl::make_node(v));
+
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::table(table&& other) noexcept
+ : node{ std::move(other) },
+ map{ std::move(other.map) },
+ inline_{ other.inline_ }
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_ctor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table& table::operator= (const table& rhs) noexcept
+ {
+ if (&rhs != this)
+ {
+ node::operator=(rhs);
+ map.clear();
+ for (auto&& [k, v] : rhs)
+ map.emplace_hint(map.end(), k, impl::make_node(v));
+ inline_ = rhs.inline_;
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table& table::operator= (table&& rhs) noexcept
+ {
+ if (&rhs != this)
+ {
+ node::operator=(std::move(rhs));
+ map = std::move(rhs.map);
+ inline_ = rhs.inline_;
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::~table() noexcept
+ {
+ #if TOML_LIFETIME_HOOKS
+ lh_dtor();
+ #endif
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::table(impl::table_init_pair* pairs, size_t count) noexcept
+ {
+ for (size_t i = 0; i < count; i++)
+ {
+ if (!pairs[i].value) // empty node_views
+ continue;
+ map.insert_or_assign(
+ std::move(pairs[i].key),
+ std::move(pairs[i].value)
+ );
+ }
+ }
+
+ #define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
+
+ TOML_MEMBER_ATTR(const) node_type table::type() const noexcept { return node_type::table; }
+ TOML_MEMBER_ATTR(const) bool table::is_table() const noexcept { return true; }
+ TOML_MEMBER_ATTR(const) bool table::is_array() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) bool table::is_value() const noexcept { return false; }
+ TOML_MEMBER_ATTR(const) const table* table::as_table() const noexcept { return this; }
+ TOML_MEMBER_ATTR(const) table* table::as_table() noexcept { return this; }
+
+ TOML_MEMBER_ATTR(pure) bool table::is_inline() const noexcept { return inline_; }
+ TOML_EXTERNAL_LINKAGE void table::is_inline(bool val) noexcept { inline_ = val; }
+
+ TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { map.begin() }; }
+ TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { map.end() }; }
+ TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { map.cbegin() }; }
+ TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { map.cend() }; }
+ TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { map.begin() }; }
+ TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { map.end() }; }
+
+ TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return map.empty(); }
+ TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return map.size(); }
+ TOML_EXTERNAL_LINKAGE void table::clear() noexcept { map.clear(); }
+
+ #undef TOML_MEMBER_ATTR
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::is_homogeneous(node_type ntype) const noexcept
+ {
+ if (map.empty())
+ return false;
+
+ if (ntype == node_type::none)
+ ntype = map.cbegin()->second->type();
+
+ for (const auto& [k, v] : map)
+ {
+ (void)k;
+ if (v->type() != ntype)
+ return false;
+ }
+
+ return true;
+ }
+
+ namespace impl
+ {
+ template <typename T, typename U>
+ TOML_INTERNAL_LINKAGE
+ bool table_is_homogeneous(T& map, node_type ntype, U& first_nonmatch) noexcept
+ {
+ if (map.empty())
+ {
+ first_nonmatch = {};
+ return false;
+ }
+ if (ntype == node_type::none)
+ ntype = map.cbegin()->second->type();
+ for (const auto& [k, v] : map)
+ {
+ (void)k;
+ if (v->type() != ntype)
+ {
+ first_nonmatch = v.get();
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
+ {
+ return impl::table_is_homogeneous(map, ntype, first_nonmatch);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
+ {
+ return impl::table_is_homogeneous(map, ntype, first_nonmatch);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> table::operator[] (std::string_view key) noexcept
+ {
+ return node_view<node>{ this->get(key) };
+ }
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> table::operator[] (std::string_view key) const noexcept
+ {
+ return node_view<const node>{ this->get(key) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::iterator table::erase(iterator pos) noexcept
+ {
+ return { map.erase(pos.raw_) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::iterator table::erase(const_iterator pos) noexcept
+ {
+ return { map.erase(pos.raw_) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::iterator table::erase(const_iterator first, const_iterator last) noexcept
+ {
+ return { map.erase(first.raw_, last.raw_) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::erase(std::string_view key) noexcept
+ {
+ if (auto it = map.find(key); it != map.end())
+ {
+ map.erase(it);
+ return true;
+ }
+ return false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node* table::get(std::string_view key) noexcept
+ {
+ return do_get(map, key);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ const node* table::get(std::string_view key) const noexcept
+ {
+ return do_get(map, key);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::iterator table::find(std::string_view key) noexcept
+ {
+ return { map.find(key) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::const_iterator table::find(std::string_view key) const noexcept
+ {
+ return { map.find(key) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::contains(std::string_view key) const noexcept
+ {
+ return do_contains(map, key);
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> table::operator[] (std::wstring_view key) noexcept
+ {
+ return node_view<node>{ this->get(key) };
+ }
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> table::operator[] (std::wstring_view key) const noexcept
+ {
+ return node_view<const node>{ this->get(key) };
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::erase(std::wstring_view key) noexcept
+ {
+ return erase(impl::narrow(key));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node* table::get(std::wstring_view key) noexcept
+ {
+ return get(impl::narrow(key));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ const node* table::get(std::wstring_view key) const noexcept
+ {
+ return get(impl::narrow(key));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::iterator table::find(std::wstring_view key) noexcept
+ {
+ return find(impl::narrow(key));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::const_iterator table::find(std::wstring_view key) const noexcept
+ {
+ return find(impl::narrow(key));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool table::contains(std::wstring_view key) const noexcept
+ {
+ return contains(impl::narrow(key));
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ bool operator == (const table& lhs, const table& rhs) noexcept
+ {
+ if (&lhs == &rhs)
+ return true;
+ if (lhs.map.size() != rhs.map.size())
+ return false;
+
+ for (auto l = lhs.map.begin(), r = rhs.map.begin(), e = lhs.map.end(); l != e; l++, r++)
+ {
+ if (l->first != r->first)
+ return false;
+
+ const auto lhs_type = l->second->type();
+ const node& rhs_ = *r->second;
+ const auto rhs_type = rhs_.type();
+ if (lhs_type != rhs_type)
+ return false;
+
+ const bool equal = l->second->visit([&](const auto& lhs_) noexcept
+ {
+ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
+ });
+ if (!equal)
+ return false;
+ }
+ return true;
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ bool operator != (const table& lhs, const table& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+}
+TOML_NAMESPACE_END
+
+#endif //---------------------------------------------------------- ↑ toml_table.hpp ---------------------------------
+
+#if 1 //----------------------------------------------------------------------------- ↓ toml_default_formatter.hpp --
+
+TOML_DISABLE_WARNINGS
+#include <cmath>
+TOML_ENABLE_WARNINGS
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+TOML_DISABLE_ARITHMETIC_WARNINGS
+
+TOML_IMPL_NAMESPACE_START
+{
+ inline constexpr size_t default_formatter_line_wrap = 120_sz;
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ std::string default_formatter_make_key_segment(const std::string& str) noexcept
+ {
+ if (str.empty())
+ return "''"s;
+ else
+ {
+ bool requiresQuotes = false;
+ {
+ utf8_decoder decoder;
+ for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
+ {
+ decoder(static_cast<uint8_t>(str[i]));
+ if (decoder.error())
+ requiresQuotes = true;
+ else if (decoder.has_code_point())
+ requiresQuotes = !is_bare_key_character(decoder.codepoint);
+ }
+ }
+
+ if (requiresQuotes)
+ {
+ std::string s;
+ s.reserve(str.length() + 2_sz);
+ s += '"';
+ for (auto c : str)
+ {
+ if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
+ {
+ const auto& sv = low_character_escape_table[c];
+ s.append(reinterpret_cast<const char*>(sv.data()), sv.length());
+ }
+ else if TOML_UNLIKELY(c == '\x7F')
+ s.append("\\u007F"sv);
+ else if TOML_UNLIKELY(c == '"')
+ s.append("\\\""sv);
+ else
+ s += c;
+ }
+ s += '"';
+ return s;
+ }
+ else
+ return str;
+ }
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ size_t default_formatter_inline_columns(const node& node) noexcept
+ {
+ switch (node.type())
+ {
+ case node_type::table:
+ {
+ auto& n = *reinterpret_cast<const table*>(&node);
+ if (n.empty())
+ return 2_sz; // "{}"
+ size_t weight = 3_sz; // "{ }"
+ for (auto&& [k, v] : n)
+ {
+ weight += k.length() + default_formatter_inline_columns(v) + 2_sz; // + ", "
+ if (weight >= default_formatter_line_wrap)
+ break;
+ }
+ return weight;
+ }
+
+ case node_type::array:
+ {
+ auto& n = *reinterpret_cast<const array*>(&node);
+ if (n.empty())
+ return 2_sz; // "[]"
+ size_t weight = 3_sz; // "[ ]"
+ for (auto& elem : n)
+ {
+ weight += default_formatter_inline_columns(elem) + 2_sz; // + ", "
+ if (weight >= default_formatter_line_wrap)
+ break;
+ }
+ return weight;
+ }
+
+ case node_type::string:
+ {
+ auto& n = *reinterpret_cast<const value<std::string>*>(&node);
+ return n.get().length() + 2_sz; // + ""
+ }
+
+ case node_type::integer:
+ {
+ auto& n = *reinterpret_cast<const value<int64_t>*>(&node);
+ auto v = n.get();
+ if (!v)
+ return 1_sz;
+ size_t weight = {};
+ if (v < 0)
+ {
+ weight += 1;
+ v *= -1;
+ }
+ return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1_sz;
+ }
+
+ case node_type::floating_point:
+ {
+ auto& n = *reinterpret_cast<const value<double>*>(&node);
+ auto v = n.get();
+ if (v == 0.0)
+ return 3_sz; // "0.0"
+ size_t weight = 2_sz; // ".0"
+ if (v < 0.0)
+ {
+ weight += 1;
+ v *= -1.0;
+ }
+ return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1_sz;
+ break;
+ }
+
+ case node_type::boolean: return 5_sz;
+ case node_type::date: [[fallthrough]];
+ case node_type::time: return 10_sz;
+ case node_type::date_time: return 30_sz;
+ case node_type::none: TOML_UNREACHABLE;
+ TOML_NO_DEFAULT_CASE;
+ }
+
+ TOML_UNREACHABLE;
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias) noexcept
+ {
+ return (default_formatter_inline_columns(node) + starting_column_bias) > default_formatter_line_wrap;
+ }
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ template <typename Char>
+ inline void default_formatter<Char>::print_inline(const toml::table& tbl)
+ {
+ if (tbl.empty())
+ impl::print_to_stream("{}"sv, base::stream());
+ else
+ {
+ impl::print_to_stream("{ "sv, base::stream());
+
+ bool first = false;
+ for (auto&& [k, v] : tbl)
+ {
+ if (first)
+ impl::print_to_stream(", "sv, base::stream());
+ first = true;
+
+ print_key_segment(k);
+ impl::print_to_stream(" = "sv, base::stream());
+
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type)
+ {
+ case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
+ case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
+ default:
+ base::print_value(v, type);
+ }
+ }
+
+ impl::print_to_stream(" }"sv, base::stream());
+ }
+ base::clear_naked_newline();
+ }
+}
+TOML_NAMESPACE_END
+
+// implementations of windows wide string nonsense
+#if TOML_WINDOWS_COMPAT
+
+TOML_DISABLE_WARNINGS
+#include <windows.h> // fuckkkk :(
+TOML_ENABLE_WARNINGS
+
+TOML_IMPL_NAMESPACE_START
+{
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ std::string narrow(std::wstring_view str) noexcept
+ {
+ if (str.empty())
+ return {};
+
+ std::string s;
+ const auto len = WideCharToMultiByte(
+ 65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr
+ );
+ if (len)
+ {
+ s.resize(static_cast<size_t>(len));
+ WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len, nullptr, nullptr);
+ }
+ return s;
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ std::wstring widen(std::string_view str) noexcept
+ {
+ if (str.empty())
+ return {};
+
+ std::wstring s;
+ const auto len = MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
+ if (len)
+ {
+ s.resize(static_cast<size_t>(len));
+ MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
+ }
+ return s;
+ }
+
+ #ifdef __cpp_lib_char8_t
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ std::wstring widen(std::u8string_view str) noexcept
+ {
+ if (str.empty())
+ return {};
+
+ return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
+ }
+
+ #endif // __cpp_lib_char8_t
+}
+TOML_IMPL_NAMESPACE_END
+
+#endif // TOML_WINDOWS_COMPAT
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_ARITHMETIC_WARNINGS
+
+#endif //----------------------------------------------------------------------------- ↑ toml_default_formatter.hpp --
+
+#if 1 //---- ↓ toml_json_formatter.hpp ------------------------------------------------------------------------------
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+
+TOML_NAMESPACE_START
+{
+ template <typename Char>
+ inline void json_formatter<Char>::print(const toml::table& tbl)
+ {
+ if (tbl.empty())
+ impl::print_to_stream("{}"sv, base::stream());
+ else
+ {
+ impl::print_to_stream('{', base::stream());
+ base::increase_indent();
+ bool first = false;
+ for (auto&& [k, v] : tbl)
+ {
+ if (first)
+ impl::print_to_stream(", "sv, base::stream());
+ first = true;
+ base::print_newline(true);
+ base::print_indent();
+
+ base::print_quoted_string(k, false);
+ impl::print_to_stream(" : "sv, base::stream());
+
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type)
+ {
+ case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
+ case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
+ default:
+ base::print_value(v, type);
+ }
+
+ }
+ base::decrease_indent();
+ base::print_newline(true);
+ base::print_indent();
+ impl::print_to_stream('}', base::stream());
+ }
+ base::clear_naked_newline();
+ }
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
+
+#endif //---- ↑ toml_json_formatter.hpp ------------------------------------------------------------------------------
+
+#if TOML_PARSER
+
+#if 1 //------------------------------ ↓ toml_utf8_streams.hpp ------------------------------------------------------
+
+#if !TOML_EXCEPTIONS
+ #undef TOML_ERROR_CHECK
+ #define TOML_ERROR_CHECK if (reader.error()) return nullptr
+#endif
+
+TOML_IMPL_NAMESPACE_START
+{
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ TOML_EXTERNAL_LINKAGE
+ utf8_buffered_reader::utf8_buffered_reader(utf8_reader_interface& reader_) noexcept
+ : reader{ reader_ }
+ {}
+
+ TOML_EXTERNAL_LINKAGE
+ const source_path_ptr& utf8_buffered_reader::source_path() const noexcept
+ {
+ return reader.source_path();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ const utf8_codepoint* utf8_buffered_reader::read_next()
+ {
+ TOML_ERROR_CHECK;
+
+ if (negative_offset)
+ {
+ negative_offset--;
+
+ // an entry negative offset of 1 just means "replay the current head"
+ if (!negative_offset)
+ return head;
+
+ // otherwise step back into the history buffer
+ else
+ return history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size);
+ }
+ else
+ {
+ // first character read from stream
+ if TOML_UNLIKELY(!history.count && !head)
+ head = reader.read_next();
+
+ // subsequent characters and not eof
+ else if (head)
+ {
+ if TOML_UNLIKELY(history.count < history_buffer_size)
+ history.buffer[history.count++] = *head;
+ else
+ history.buffer[(history.first++ + history_buffer_size) % history_buffer_size] = *head;
+
+ head = reader.read_next();
+ }
+
+ return head;
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ const utf8_codepoint* utf8_buffered_reader::step_back(size_t count) noexcept
+ {
+ TOML_ERROR_CHECK;
+ TOML_ASSERT(history.count);
+ TOML_ASSERT(negative_offset + count <= history.count);
+
+ negative_offset += count;
+
+ return negative_offset
+ ? history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size)
+ : head;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool utf8_buffered_reader::peek_eof() const
+ {
+ return reader.peek_eof();
+ }
+
+ #if !TOML_EXCEPTIONS
+ TOML_EXTERNAL_LINKAGE
+ optional<parse_error>&& utf8_buffered_reader::error() noexcept
+ {
+ return reader.error();
+ }
+ #endif
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+}
+TOML_IMPL_NAMESPACE_END
+
+#undef TOML_ERROR_CHECK
+#undef TOML_ERROR
+
+#endif //------------------------------ ↑ toml_utf8_streams.hpp ------------------------------------------------------
+
+#if 1 //---------------------------------------------------------- ↓ toml_parser.hpp --------------------------------
+
+TOML_DISABLE_WARNINGS
+#include <cmath>
+#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
+ #include <charconv>
+#endif
+#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
+ #include <sstream>
+#endif
+#if !TOML_HEADER_ONLY
+ using namespace std::string_view_literals;
+#endif
+TOML_ENABLE_WARNINGS
+
+TOML_PUSH_WARNINGS
+TOML_DISABLE_SWITCH_WARNINGS
+
+#if TOML_EXCEPTIONS && !defined(__INTELLISENSE__)
+ #define TOML_RETURNS_BY_THROWING [[noreturn]]
+#else
+ #define TOML_RETURNS_BY_THROWING
+#endif
+
+TOML_ANON_NAMESPACE_START
+{
+ template <typename... T>
+ [[nodiscard]]
+ TOML_ATTR(const)
+ constexpr bool is_match(char32_t codepoint, T... vals) noexcept
+ {
+ static_assert((std::is_same_v<char32_t, T> && ...));
+ return ((codepoint == vals) || ...);
+ }
+
+ template <uint64_t> struct parse_integer_traits;
+ template <> struct parse_integer_traits<2> final
+ {
+ static constexpr auto scope_qualifier = "binary integer"sv;
+ static constexpr auto is_digit = ::toml::impl::is_binary_digit;
+ static constexpr auto is_signed = false;
+ static constexpr auto buffer_length = 63;
+ static constexpr auto prefix_codepoint = U'b';
+ static constexpr auto prefix = "b"sv;
+ };
+ template <> struct parse_integer_traits<8> final
+ {
+ static constexpr auto scope_qualifier = "octal integer"sv;
+ static constexpr auto is_digit = ::toml::impl::is_octal_digit;
+ static constexpr auto is_signed = false;
+ static constexpr auto buffer_length = 21; // strlen("777777777777777777777")
+ static constexpr auto prefix_codepoint = U'o';
+ static constexpr auto prefix = "o"sv;
+ };
+ template <> struct parse_integer_traits<10> final
+ {
+ static constexpr auto scope_qualifier = "decimal integer"sv;
+ static constexpr auto is_digit = ::toml::impl::is_decimal_digit;
+ static constexpr auto is_signed = true;
+ static constexpr auto buffer_length = 19; //strlen("9223372036854775807")
+ };
+ template <> struct parse_integer_traits<16> final
+ {
+ static constexpr auto scope_qualifier = "hexadecimal integer"sv;
+ static constexpr auto is_digit = ::toml::impl::is_hexadecimal_digit;
+ static constexpr auto is_signed = false;
+ static constexpr auto buffer_length = 16; //strlen("7FFFFFFFFFFFFFFF")
+ static constexpr auto prefix_codepoint = U'x';
+ static constexpr auto prefix = "x"sv;
+ };
+
+ [[nodiscard]]
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(::toml::node_type val) noexcept
+ {
+ using namespace ::toml::impl;
+
+ return node_type_friendly_names[unwrap_enum(val)];
+ }
+
+ [[nodiscard]]
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(const std::string& str) noexcept
+ {
+ return std::string_view{ str };
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(const)
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(bool val) noexcept
+ {
+ using namespace std::string_view_literals;
+
+ return val ? "true"sv : "false"sv;
+ }
+
+ [[nodiscard]]
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(const ::toml::impl::utf8_codepoint& cp) noexcept
+ {
+ using namespace ::toml;
+ using namespace ::toml::impl;
+
+ if TOML_UNLIKELY(cp.value <= U'\x1F')
+ return low_character_escape_table[cp.value];
+ else if TOML_UNLIKELY(cp.value == U'\x7F')
+ return "\\u007F"sv;
+ else
+ return cp.as_view();
+ }
+
+ [[nodiscard]]
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(const ::toml::impl::utf8_codepoint* cp) noexcept
+ {
+ if (cp)
+ return to_sv(*cp);
+ return ""sv;
+ }
+
+ template <typename T>
+ TOML_ATTR(nonnull)
+ TOML_INTERNAL_LINKAGE
+ TOML_NEVER_INLINE
+ void concatenate(char*& write_pos, char *const buf_end, const T& arg) noexcept
+ {
+ using namespace ::toml;
+ using namespace ::toml::impl;
+
+ static_assert(
+ is_one_of<remove_cvref_t<T>, std::string_view, int64_t, uint64_t, double>,
+ "concatenate inputs are limited to std::string_view, int64_t, uint64_t and double to keep "
+ "instantiations to a minimum as an anti-bloat measure (hint: to_sv will probably help)"
+ );
+
+ if (write_pos >= buf_end)
+ return;
+
+ using arg_t = remove_cvref_t<T>;
+ if constexpr (std::is_same_v<arg_t, std::string_view>)
+ {
+ const auto max_chars = static_cast<size_t>(buf_end - write_pos);
+ const auto len = max_chars < arg.length() ? max_chars : arg.length();
+ std::memcpy(write_pos, arg.data(), len);
+ write_pos += len;
+ }
+ else if constexpr (std::is_floating_point_v<arg_t>)
+ {
+ #if TOML_FLOAT_CHARCONV
+ {
+ const auto result = std::to_chars(write_pos, buf_end, arg);
+ write_pos = result.ptr;
+ }
+ #else
+ {
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ ss.precision(std::numeric_limits<arg_t>::digits10 + 1);
+ ss << arg;
+ concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
+ }
+ #endif
+ }
+ else if constexpr (std::is_integral_v<arg_t>)
+ {
+ #if TOML_INT_CHARCONV
+ {
+ const auto result = std::to_chars(write_pos, buf_end, arg);
+ write_pos = result.ptr;
+ }
+ #else
+ {
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ using cast_type = std::conditional_t<std::is_signed_v<arg_t>, int64_t, uint64_t>;
+ ss << static_cast<cast_type>(arg);
+ concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
+ }
+ #endif
+ }
+ }
+
+ struct error_builder final
+ {
+ static constexpr std::size_t buf_size = 512;
+ char buf[buf_size];
+ char* write_pos = buf;
+ char* const max_write_pos = buf + (buf_size - std::size_t{ 1 }); //allow for null terminator
+
+ error_builder(std::string_view scope) noexcept
+ {
+ concatenate(write_pos, max_write_pos, "Error while parsing "sv);
+ concatenate(write_pos, max_write_pos, scope);
+ concatenate(write_pos, max_write_pos, ": "sv);
+ }
+
+ template <typename T>
+ void append(const T& arg) noexcept
+ {
+ concatenate(write_pos, max_write_pos, arg);
+ }
+
+ TOML_RETURNS_BY_THROWING
+ auto finish(const ::toml::source_position& pos, const ::toml::source_path_ptr& source_path) const TOML_MAY_THROW
+ {
+ using namespace ::toml;
+
+ *write_pos = '\0';
+
+ #if TOML_EXCEPTIONS
+ throw parse_error{ buf, pos, source_path };
+ #else
+ return parse_error{
+ std::string(buf, static_cast<size_t>(write_pos - buf)),
+ pos,
+ source_path
+ };
+ #endif
+ }
+ };
+
+ struct parse_scope final
+ {
+ std::string_view& storage_;
+ std::string_view parent_;
+
+ TOML_NODISCARD_CTOR
+ explicit parse_scope(std::string_view& current_scope, std::string_view new_scope) noexcept
+ : storage_{ current_scope },
+ parent_{ current_scope }
+ {
+ storage_ = new_scope;
+ }
+
+ ~parse_scope() noexcept
+ {
+ storage_ = parent_;
+ }
+ };
+ #define push_parse_scope_2(scope, line) parse_scope ps_##line{ current_scope, scope }
+ #define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
+ #define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
+
+ // Q: "why not std::unique_ptr??
+ // A: It caused a lot of bloat on some implementations so this exists an internal substitute.
+ class node_ptr
+ {
+ private:
+ toml::node* node_ = {};
+
+ public:
+ TOML_NODISCARD_CTOR
+ node_ptr() noexcept = default;
+
+ TOML_NODISCARD_CTOR
+ explicit node_ptr(toml::node* n) noexcept
+ : node_{ n }
+ {}
+
+ ~node_ptr() noexcept
+ {
+ delete node_;
+ }
+
+ node_ptr& operator=(toml::node* val) noexcept
+ {
+ if (val != node_)
+ {
+ delete node_;
+ node_ = val;
+ }
+ return *this;
+ }
+
+ node_ptr(const node_ptr&) = delete;
+ node_ptr& operator=(const node_ptr&) = delete;
+ node_ptr(node_ptr&&) = delete;
+ node_ptr& operator=(node_ptr&&) = delete;
+
+ [[nodiscard]]
+ TOML_ATTR(pure)
+ operator bool() const noexcept
+ {
+ return node_ != nullptr;
+ }
+
+ [[nodiscard]]
+ TOML_ATTR(pure)
+ toml::node* get() const noexcept
+ {
+ return node_;
+ }
+
+ [[nodiscard]]
+ toml::node* release() noexcept
+ {
+ auto n = node_;
+ node_ = nullptr;
+ return n;
+ }
+ };
+
+ struct parsed_key final
+ {
+ std::vector<std::string> segments;
+ };
+
+ struct parsed_key_value_pair final
+ {
+ parsed_key key;
+ node_ptr value;
+ };
+
+}
+TOML_ANON_NAMESPACE_END
+
+TOML_IMPL_NAMESPACE_START
+{
+ // Q: "what the fuck is this? MACROS????"
+ // A: The parser needs to work in exceptionless mode (returning error objects directly)
+ // and exception mode (reporting parse failures by throwing). Two totally different control flows.
+ // These macros encapsulate the differences between the two modes so I can write code code
+ // as though I was only targeting one mode and not want yeet myself into the sun.
+ // They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
+ // of toml++.
+
+ #if defined(NDEBUG) || !defined(_DEBUG)
+ #define assert_or_assume(cond) TOML_ASSUME(cond)
+ #else
+ #define assert_or_assume(cond) TOML_ASSERT(cond)
+ #endif
+
+ #define is_eof() !cp
+ #define assert_not_eof() assert_or_assume(cp != nullptr)
+ #define return_if_eof(...) do { if (is_eof()) return __VA_ARGS__; } while(false)
+ #if TOML_EXCEPTIONS
+ #define is_error() false
+ #define return_after_error(...) TOML_UNREACHABLE
+ #define assert_not_error() (void)0
+ #define return_if_error(...) (void)0
+ #define return_if_error_or_eof(...) return_if_eof(__VA_ARGS__)
+ #else
+ #define is_error() !!err
+ #define return_after_error(...) return __VA_ARGS__
+ #define assert_not_error() TOML_ASSERT(!is_error())
+ #define return_if_error(...) do { if (is_error()) return __VA_ARGS__; } while(false)
+ #define return_if_error_or_eof(...) do { if (is_eof() || is_error()) return __VA_ARGS__; } while(false)
+ #endif
+ #define set_error_and_return(ret, ...) \
+ do { if (!is_error()) set_error(__VA_ARGS__); return_after_error(ret); } while(false)
+ #define set_error_and_return_default(...) set_error_and_return({}, __VA_ARGS__)
+ #define set_error_and_return_if_eof(...) \
+ do { if (is_eof()) set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); } while(false)
+ #define advance_and_return_if_error(...) \
+ do { assert_not_eof(); advance(); return_if_error(__VA_ARGS__); } while (false)
+ #define advance_and_return_if_error_or_eof(...) \
+ do { \
+ assert_not_eof(); \
+ advance(); \
+ return_if_error(__VA_ARGS__); \
+ set_error_and_return_if_eof(__VA_ARGS__); \
+ } while (false)
+
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ class parser final
+ {
+ private:
+ utf8_buffered_reader reader;
+ table root;
+ source_position prev_pos = { 1, 1 };
+ const utf8_codepoint* cp = {};
+ std::vector<table*> implicit_tables;
+ std::vector<table*> dotted_key_tables;
+ std::vector<array*> table_arrays;
+ std::string recording_buffer; //for diagnostics
+ bool recording = false, recording_whitespace = true;
+ std::string_view current_scope;
+ #if !TOML_EXCEPTIONS
+ mutable optional<toml::parse_error> err;
+ #endif
+
+ [[nodiscard]]
+ source_position current_position(source_index fallback_offset = 0) const noexcept
+ {
+ if (!is_eof())
+ return cp->position;
+ return { prev_pos.line, static_cast<source_index>(prev_pos.column + fallback_offset) };
+ }
+
+ template <typename... T>
+ TOML_RETURNS_BY_THROWING
+ TOML_NEVER_INLINE
+ void set_error_at(source_position pos, const T&... reason) const TOML_MAY_THROW
+ {
+ static_assert(sizeof...(T) > 0_sz);
+ #if !TOML_EXCEPTIONS
+ if (err)
+ return;
+ #endif
+
+ error_builder builder{ current_scope };
+ (builder.append(reason), ...);
+
+ #if TOML_EXCEPTIONS
+ builder.finish(pos, reader.source_path());
+ #else
+ err.emplace(builder.finish(pos, reader.source_path()));
+ #endif
+ }
+
+ template <typename... T>
+ TOML_RETURNS_BY_THROWING
+ void set_error(const T&... reason) const TOML_MAY_THROW
+ {
+ set_error_at(current_position(1), reason...);
+ }
+
+ void go_back(size_t count = 1_sz) noexcept
+ {
+ return_if_error();
+ assert_or_assume(count);
+
+ cp = reader.step_back(count);
+ prev_pos = cp->position;
+ }
+
+ void advance() TOML_MAY_THROW
+ {
+ return_if_error();
+ assert_not_eof();
+
+ prev_pos = cp->position;
+ cp = reader.read_next();
+
+ #if !TOML_EXCEPTIONS
+ if (reader.error())
+ {
+ err = std::move(reader.error());
+ return;
+ }
+ #endif
+
+ if (recording && !is_eof())
+ {
+ if (recording_whitespace || !(is_whitespace(*cp) || is_line_break(*cp)))
+ recording_buffer.append(cp->as_view());
+ }
+ }
+
+ void start_recording(bool include_current = true) noexcept
+ {
+ return_if_error();
+
+ recording = true;
+ recording_whitespace = true;
+ recording_buffer.clear();
+ if (include_current && !is_eof())
+ recording_buffer.append(cp->as_view());
+ }
+
+ void stop_recording(size_t pop_bytes = 0_sz) noexcept
+ {
+ return_if_error();
+
+ recording = false;
+ if (pop_bytes)
+ {
+ if (pop_bytes >= recording_buffer.length())
+ recording_buffer.clear();
+ else if (pop_bytes == 1_sz)
+ recording_buffer.pop_back();
+ else
+ recording_buffer.erase(
+ recording_buffer.begin() + static_cast<ptrdiff_t>(recording_buffer.length() - pop_bytes),
+ recording_buffer.end()
+ );
+ }
+ }
+
+ bool consume_leading_whitespace() TOML_MAY_THROW
+ {
+ return_if_error_or_eof({});
+
+ bool consumed = false;
+ while (!is_eof() && is_whitespace(*cp))
+ {
+ consumed = true;
+ advance_and_return_if_error({});
+ }
+ return consumed;
+ }
+
+ bool consume_line_break() TOML_MAY_THROW
+ {
+ return_if_error_or_eof({});
+
+ if (!is_line_break(*cp))
+ return false;
+
+ if (*cp == U'\r')
+ {
+ advance_and_return_if_error({}); // skip \r
+
+ if (is_eof())
+ return true; //eof after \r is 'fine'
+ else if (*cp != U'\n')
+ set_error_and_return_default("expected \\n, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ advance_and_return_if_error({}); // skip \n (or other single-character line ending)
+ return true;
+ }
+
+ bool consume_rest_of_line() TOML_MAY_THROW
+ {
+ return_if_error_or_eof({});
+
+ do
+ {
+ if (is_line_break(*cp))
+ return consume_line_break();
+ else
+ advance();
+ return_if_error({});
+ }
+ while (!is_eof());
+
+ return true;
+ }
+
+ bool consume_comment() TOML_MAY_THROW
+ {
+ return_if_error_or_eof({});
+
+ if (*cp != U'#')
+ return false;
+
+ push_parse_scope("comment"sv);
+
+ advance_and_return_if_error({}); //skip the '#'
+
+ while (!is_eof())
+ {
+ if (consume_line_break())
+ return true;
+ return_if_error({});
+
+ if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
+ {
+ // toml/issues/567 (disallow non-TAB control characters in comments)
+ if (is_nontab_control_character(*cp))
+ set_error_and_return_default(
+ "control characters other than TAB (U+0009) are explicitly prohibited"sv
+ );
+
+ // toml/pull/720 (disallow surrogates in comments)
+ else if (is_unicode_surrogate(*cp))
+ set_error_and_return_default(
+ "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv
+ );
+ }
+ advance_and_return_if_error({});
+ }
+
+ return true;
+ }
+
+ [[nodiscard]]
+ bool consume_expected_sequence(std::u32string_view seq) TOML_MAY_THROW
+ {
+ return_if_error({});
+ TOML_ASSERT(!seq.empty());
+
+ for (auto c : seq)
+ {
+ set_error_and_return_if_eof({});
+ if (*cp != c)
+ return false;
+ advance_and_return_if_error({});
+ }
+ return true;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ bool consume_digit_sequence(T* digits, size_t len) TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_or_assume(digits);
+ assert_or_assume(len);
+
+ for (size_t i = 0; i < len; i++)
+ {
+ set_error_and_return_if_eof({});
+ if (!is_decimal_digit(*cp))
+ return false;
+
+ digits[i] = static_cast<T>(*cp - U'0');
+ advance_and_return_if_error({});
+ }
+ return true;
+ }
+
+ template <typename T>
+ [[nodiscard]]
+ size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len) TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_or_assume(buffer);
+ assert_or_assume(max_len);
+
+ size_t i = {};
+ for (; i < max_len; i++)
+ {
+ if (is_eof() || !is_decimal_digit(*cp))
+ break;
+
+ buffer[i] = static_cast<T>(*cp - U'0');
+ advance_and_return_if_error({});
+ }
+ return i;
+ }
+
+ //template <bool MultiLine>
+ [[nodiscard]]
+ std::string parse_basic_string(bool multi_line) TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(*cp == U'"');
+ push_parse_scope("string"sv);
+
+ // skip the '"'
+ advance_and_return_if_error_or_eof({});
+
+ // multiline strings ignore a single line ending right at the beginning
+ if (multi_line)
+ {
+ consume_line_break();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+ }
+
+ std::string str;
+ bool escaped = false;
+ [[maybe_unused]] bool skipping_whitespace = false;
+ do
+ {
+ if (escaped)
+ {
+ escaped = false;
+
+ // handle 'line ending slashes' in multi-line mode
+ if (multi_line)
+ {
+ if (is_line_break(*cp) || is_whitespace(*cp))
+ {
+ consume_leading_whitespace();
+ if (!consume_line_break())
+ set_error_and_return_default(
+ "line-ending backslashes must be the last non-whitespace character on the line"sv
+ );
+ skipping_whitespace = true;
+ return_if_error({});
+ continue;
+ }
+ }
+
+ bool skipped_escaped_codepoint = false;
+ assert_not_eof();
+ switch (const auto escaped_codepoint = *cp)
+ {
+ // 'regular' escape codes
+ case U'b': str += '\b'; break;
+ case U'f': str += '\f'; break;
+ case U'n': str += '\n'; break;
+ case U'r': str += '\r'; break;
+ case U't': str += '\t'; break;
+ case U'"': str += '"'; break;
+ case U'\\': str += '\\'; break;
+
+ // unicode scalar sequences
+ case U'x':
+ #if TOML_LANG_UNRELEASED // toml/pull/709 (\xHH unicode scalar sequences)
+ [[fallthrough]];
+ #else
+ set_error_and_return_default(
+ "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv
+ );
+ #endif
+ case U'u': [[fallthrough]];
+ case U'U':
+ {
+ push_parse_scope("unicode scalar escape sequence"sv);
+ advance_and_return_if_error_or_eof({});
+ skipped_escaped_codepoint = true;
+
+ uint32_t place_value = escaped_codepoint == U'U'
+ ? 0x10000000u
+ : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
+ uint32_t sequence_value{};
+ while (place_value)
+ {
+ set_error_and_return_if_eof({});
+ if (!is_hexadecimal_digit(*cp))
+ set_error_and_return_default("expected hex digit, saw '"sv, to_sv(*cp), "'"sv);
+ sequence_value += place_value * hex_to_dec(*cp);
+ place_value /= 16u;
+ advance_and_return_if_error({});
+ }
+
+ if (is_unicode_surrogate(sequence_value))
+ set_error_and_return_default(
+ "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv
+ );
+ else if (sequence_value > 0x10FFFFu)
+ set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
+ else if (sequence_value <= 0x7Fu) //ascii
+ str += static_cast<char>(sequence_value & 0x7Fu);
+ else if (sequence_value <= 0x7FFu)
+ {
+ str += static_cast<char>(0xC0u | ((sequence_value >> 6) & 0x1Fu));
+ str += static_cast<char>(0x80u | (sequence_value & 0x3Fu));
+ }
+ else if (sequence_value <= 0xFFFFu)
+ {
+ str += static_cast<char>(0xE0u | ((sequence_value >> 12) & 0x0Fu));
+ str += static_cast<char>(0x80u | ((sequence_value >> 6) & 0x1Fu));
+ str += static_cast<char>(0x80u | (sequence_value & 0x3Fu));
+ }
+ else
+ {
+ str += static_cast<char>(0xF0u | ((sequence_value >> 18) & 0x07u));
+ str += static_cast<char>(0x80u | ((sequence_value >> 12) & 0x3Fu));
+ str += static_cast<char>(0x80u | ((sequence_value >> 6) & 0x3Fu));
+ str += static_cast<char>(0x80u | (sequence_value & 0x3Fu));
+ }
+ break;
+ }
+
+ // ???
+ default:
+ set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
+ }
+
+ // skip the escaped character
+ if (!skipped_escaped_codepoint)
+ advance_and_return_if_error_or_eof({});
+ }
+ else
+ {
+ // handle closing delimiters
+ if (*cp == U'"')
+ {
+ if (multi_line)
+ {
+ size_t lookaheads = {};
+ size_t consecutive_delimiters = 1_sz;
+ do
+ {
+ advance_and_return_if_error({});
+ lookaheads++;
+ if (!is_eof() && *cp == U'"')
+ consecutive_delimiters++;
+ else
+ break;
+ }
+ while (lookaheads < 4_sz);
+
+ switch (consecutive_delimiters)
+ {
+ // """ " (one quote somewhere in a ML string)
+ case 1_sz:
+ str += '"';
+ skipping_whitespace = false;
+ continue;
+
+ // """ "" (two quotes somewhere in a ML string)
+ case 2_sz:
+ str.append("\"\""sv);
+ skipping_whitespace = false;
+ continue;
+
+ // """ """ (the end of the string)
+ case 3_sz:
+ return str;
+
+ // """ """" (one at the end of the string)
+ case 4_sz:
+ str += '"';
+ return str;
+
+ // """ """"" (two quotes at the end of the string)
+ case 5_sz:
+ str.append("\"\""sv);
+ advance_and_return_if_error({}); // skip the last '"'
+ return str;
+
+ TOML_NO_DEFAULT_CASE;
+ }
+ }
+ else
+ {
+ advance_and_return_if_error({}); // skip the closing delimiter
+ return str;
+ }
+ }
+
+ // handle escapes
+ else if (*cp == U'\\')
+ {
+ advance_and_return_if_error_or_eof({}); // skip the '\'
+ skipping_whitespace = false;
+ escaped = true;
+ continue;
+ }
+
+ // handle line endings in multi-line mode
+ if (multi_line && is_line_break(*cp))
+ {
+ consume_line_break();
+ return_if_error({});
+ if (!skipping_whitespace)
+ str += '\n';
+ continue;
+ }
+
+ // handle control characters
+ if (is_nontab_control_character(*cp))
+ set_error_and_return_default(
+ "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv
+ );
+
+ // handle surrogates in strings (1.0.0 and later)
+ if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
+ {
+ if (is_unicode_surrogate(*cp))
+ set_error_and_return_default(
+ "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv
+ );
+ }
+
+ if (multi_line)
+ {
+ if (!skipping_whitespace || !is_whitespace(*cp))
+ {
+ skipping_whitespace = false;
+ str.append(cp->as_view());
+ }
+ }
+ else
+ str.append(cp->as_view());
+
+ advance_and_return_if_error({});
+ }
+ }
+ while (!is_eof());
+
+ set_error_and_return_default("encountered end-of-file"sv);
+ }
+
+ [[nodiscard]]
+ std::string parse_literal_string(bool multi_line) TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(*cp == U'\'');
+ push_parse_scope("literal string"sv);
+
+ // skip the delimiter
+ advance_and_return_if_error_or_eof({});
+
+ // multiline strings ignore a single line ending right at the beginning
+ if (multi_line)
+ {
+ consume_line_break();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+ }
+
+ std::string str;
+ do
+ {
+ return_if_error({});
+
+ // handle closing delimiters
+ if (*cp == U'\'')
+ {
+ if (multi_line)
+ {
+ size_t lookaheads = {};
+ size_t consecutive_delimiters = 1_sz;
+ do
+ {
+ advance_and_return_if_error({});
+ lookaheads++;
+ if (!is_eof() && *cp == U'\'')
+ consecutive_delimiters++;
+ else
+ break;
+ }
+ while (lookaheads < 4_sz);
+
+ switch (consecutive_delimiters)
+ {
+ // ''' ' (one quote somewhere in a ML string)
+ case 1_sz:
+ str += '\'';
+ continue;
+
+ // ''' '' (two quotes somewhere in a ML string)
+ case 2_sz:
+ str.append("''"sv);
+ continue;
+
+ // ''' ''' (the end of the string)
+ case 3_sz:
+ return str;
+
+ // ''' '''' (one at the end of the string)
+ case 4_sz:
+ str += '\'';
+ return str;
+
+ // ''' ''''' (two quotes at the end of the string)
+ case 5_sz:
+ str.append("''"sv);
+ advance_and_return_if_error({}); // skip the last '
+ return str;
+
+ TOML_NO_DEFAULT_CASE;
+ }
+ }
+ else
+ {
+ advance_and_return_if_error({}); // skip the closing delimiter
+ return str;
+ }
+ }
+
+ // handle line endings in multi-line mode
+ if (multi_line && is_line_break(*cp))
+ {
+ consume_line_break();
+ return_if_error({});
+ str += '\n';
+ continue;
+ }
+
+ // handle control characters
+ if (is_nontab_control_character(*cp))
+ set_error_and_return_default(
+ "control characters other than TAB (U+0009) are explicitly prohibited"sv
+ );
+
+ // handle surrogates in strings (1.0.0 and later)
+ if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
+ {
+ if (is_unicode_surrogate(*cp))
+ set_error_and_return_default(
+ "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv
+ );
+ }
+
+ str.append(cp->as_view());
+ advance_and_return_if_error({});
+ }
+ while (!is_eof());
+
+ set_error_and_return_default("encountered end-of-file"sv);
+ }
+
+ struct parsed_string final
+ {
+ std::string value;
+ bool was_multi_line;
+ };
+
+ [[nodiscard]]
+ TOML_NEVER_INLINE
+ parsed_string parse_string() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_string_delimiter(*cp));
+ push_parse_scope("string"sv);
+
+ // get the first three characters to determine the string type
+ const auto first = cp->value;
+ advance_and_return_if_error_or_eof({});
+ const auto second = cp->value;
+ advance_and_return_if_error({});
+ const auto third = cp ? cp->value : U'\0';
+
+ // if we were eof at the third character then first and second need to be
+ // the same string character (otherwise it's an unterminated string)
+ if (is_eof())
+ {
+ if (second == first)
+ return {};
+
+ set_error_and_return_default("encountered end-of-file"sv);
+ }
+
+ // if the first three characters are all the same string delimiter then
+ // it's a multi-line string.
+ else if (first == second && first == third)
+ {
+ return
+ {
+ first == U'\''
+ ? parse_literal_string(true)
+ : parse_basic_string(true),
+ true
+ };
+ }
+
+ // otherwise it's just a regular string.
+ else
+ {
+ // step back two characters so that the current
+ // character is the string delimiter
+ go_back(2_sz);
+
+ return
+ {
+ first == U'\''
+ ? parse_literal_string(false)
+ : parse_basic_string(false),
+ false
+ };
+ }
+ }
+
+ [[nodiscard]]
+ std::string parse_bare_key_segment() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_bare_key_character(*cp));
+
+ std::string segment;
+
+ while (!is_eof())
+ {
+ if (!is_bare_key_character(*cp))
+ break;
+
+ segment.append(cp->as_view());
+ advance_and_return_if_error({});
+ }
+
+ return segment;
+ }
+
+ [[nodiscard]]
+ bool parse_boolean() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_match(*cp, U't', U'f', U'T', U'F'));
+ push_parse_scope("boolean"sv);
+
+ start_recording(true);
+ auto result = is_match(*cp, U't', U'T');
+ if (!consume_expected_sequence(result ? U"true"sv : U"false"sv))
+ set_error_and_return_default(
+ "expected '"sv, to_sv(result), "', saw '"sv, to_sv(recording_buffer), "'"sv
+ );
+ stop_recording();
+
+ if (cp && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return result;
+ }
+
+ [[nodiscard]]
+ double parse_inf_or_nan() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
+ push_parse_scope("floating-point"sv);
+
+ start_recording(true);
+ const bool negative = *cp == U'-';
+ if (negative || *cp == U'+')
+ advance_and_return_if_error_or_eof({});
+
+ const bool inf = is_match(*cp, U'i', U'I');
+ if (!consume_expected_sequence(inf ? U"inf"sv : U"nan"sv))
+ set_error_and_return_default(
+ "expected '"sv, inf ? "inf"sv : "nan"sv, "', saw '"sv, to_sv(recording_buffer), "'"sv
+ );
+ stop_recording();
+
+ if (cp && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return inf ? (negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity())
+ : std::numeric_limits<double>::quiet_NaN();
+ }
+
+ TOML_PUSH_WARNINGS
+ TOML_DISABLE_SWITCH_WARNINGS
+ TOML_DISABLE_INIT_WARNINGS
+
+ [[nodiscard]]
+ double parse_float() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
+ push_parse_scope("floating-point"sv);
+
+ // sign
+ const int sign = *cp == U'-' ? -1 : 1;
+ if (is_match(*cp, U'+', U'-'))
+ advance_and_return_if_error_or_eof({});
+
+ // consume value chars
+ char chars[64];
+ size_t length = {};
+ const utf8_codepoint* prev = {};
+ bool seen_decimal = false, seen_exponent = false;
+ char first_integer_part = '\0';
+ while (!is_eof() && !is_value_terminator(*cp))
+ {
+ if (*cp == U'_')
+ {
+ if (!prev || !is_decimal_digit(*prev))
+ set_error_and_return_default("underscores may only follow digits"sv);
+
+ prev = cp;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ }
+ else if (prev && *prev == U'_' && !is_decimal_digit(*cp))
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ else if (*cp == U'.')
+ {
+ // .1
+ // -.1
+ // +.1 (no integer part)
+ if (!first_integer_part)
+ set_error_and_return_default("expected decimal digit, saw '.'"sv);
+
+ // 1.0e+.10 (exponent cannot have '.')
+ else if (seen_exponent)
+ set_error_and_return_default("expected exponent decimal digit or sign, saw '.'"sv);
+
+ // 1.0.e+.10
+ // 1..0
+ // (multiple '.')
+ else if (seen_decimal)
+ set_error_and_return_default("expected decimal digit or exponent, saw '.'"sv);
+
+ seen_decimal = true;
+ }
+ else if (is_match(*cp, U'e', U'E'))
+ {
+ if (prev && !is_decimal_digit(*prev))
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ // 1.0ee+10 (multiple 'e')
+ else if (seen_exponent)
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ seen_decimal = true; // implied
+ seen_exponent = true;
+ }
+ else if (is_match(*cp, U'+', U'-'))
+ {
+ // 1.-0 (sign in mantissa)
+ if (!seen_exponent)
+ set_error_and_return_default("expected decimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
+
+ // 1.0e1-0 (misplaced exponent sign)
+ else if (!is_match(*prev, U'e', U'E'))
+ set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ else if (is_decimal_digit(*cp))
+ {
+ if (!seen_decimal)
+ {
+ if (!first_integer_part)
+ first_integer_part = static_cast<char>(cp->bytes[0]);
+ else if (first_integer_part == '0')
+ set_error_and_return_default("leading zeroes are prohibited"sv);
+ }
+ }
+ else
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ if (length == sizeof(chars))
+ set_error_and_return_default(
+ "exceeds maximum length of "sv, static_cast<uint64_t>(sizeof(chars)), " characters"sv
+ );
+
+ chars[length++] = static_cast<char>(cp->bytes[0]);
+ prev = cp;
+ advance_and_return_if_error({});
+ }
+
+ // sanity-check ending state
+ if (prev)
+ {
+ if (*prev == U'_')
+ {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ }
+ else if (is_match(*prev, U'e', U'E', U'+', U'-', U'.'))
+ {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ }
+
+ // convert to double
+ double result;
+ #if TOML_FLOAT_CHARCONV
+ {
+ auto fc_result = std::from_chars(chars, chars + length, result);
+ switch (fc_result.ec)
+ {
+ case std::errc{}: //ok
+ return result * sign;
+
+ case std::errc::invalid_argument:
+ set_error_and_return_default(
+ "'"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
+ );
+ break;
+
+ case std::errc::result_out_of_range:
+ set_error_and_return_default(
+ "'"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
+ );
+ break;
+
+ default: //??
+ set_error_and_return_default(
+ "an unspecified error occurred while trying to interpret '"sv,
+ std::string_view{ chars, length }, "' as a value"sv
+ );
+ }
+ }
+ #else
+ {
+ std::stringstream ss;
+ ss.imbue(std::locale::classic());
+ ss.write(chars, static_cast<std::streamsize>(length));
+ if ((ss >> result))
+ return result * sign;
+ else
+ set_error_and_return_default(
+ "'"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
+ );
+ }
+ #endif
+ }
+
+ [[nodiscard]]
+ double parse_hex_float() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_match(*cp, U'0', U'+', U'-'));
+ push_parse_scope("hexadecimal floating-point"sv);
+
+ #if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
+
+ // sign
+ const int sign = *cp == U'-' ? -1 : 1;
+ if (is_match(*cp, U'+', U'-'))
+ advance_and_return_if_error_or_eof({});
+
+ // '0'
+ if (*cp != U'0')
+ set_error_and_return_default(" expected '0', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // 'x' or 'X'
+ if (!is_match(*cp, U'x', U'X'))
+ set_error_and_return_default("expected 'x' or 'X', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // <HEX DIGITS> ([.]<HEX DIGITS>)? [pP] [+-]? <DEC DIGITS>
+
+ // consume value fragments
+ struct fragment
+ {
+ char chars[24];
+ size_t length;
+ double value;
+ };
+ fragment fragments[] =
+ {
+ {}, // mantissa, whole part
+ {}, // mantissa, fractional part
+ {} // exponent
+ };
+ fragment* current_fragment = fragments;
+ const utf8_codepoint* prev = {};
+ int exponent_sign = 1;
+ while (!is_eof() && !is_value_terminator(*cp))
+ {
+ if (*cp == U'_')
+ {
+ if (!prev || !is_hexadecimal_digit(*prev))
+ set_error_and_return_default("underscores may only follow digits"sv);
+
+ prev = cp;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ }
+ else if (prev && *prev == U'_' && !is_hexadecimal_digit(*cp))
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ else if (*cp == U'.')
+ {
+ // 0x10.0p-.0 (exponent cannot have '.')
+ if (current_fragment == fragments + 2)
+ set_error_and_return_default("expected exponent digit or sign, saw '.'"sv);
+
+ // 0x10.0.p-0 (multiple '.')
+ else if (current_fragment == fragments + 1)
+ set_error_and_return_default("expected hexadecimal digit or exponent, saw '.'"sv);
+
+ else
+ current_fragment++;
+ }
+ else if (is_match(*cp, U'p', U'P'))
+ {
+ // 0x10.0pp-0 (multiple 'p')
+ if (current_fragment == fragments + 2)
+ set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
+
+ // 0x.p-0 (mantissa is just '.')
+ else if (fragments[0].length == 0_sz && fragments[1].length == 0_sz)
+ set_error_and_return_default("expected hexadecimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ else
+ current_fragment = fragments + 2;
+ }
+ else if (is_match(*cp, U'+', U'-'))
+ {
+ // 0x-10.0p-0 (sign in mantissa)
+ if (current_fragment != fragments + 2)
+ set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
+
+ // 0x10.0p0- (misplaced exponent sign)
+ else if (!is_match(*prev, U'p', U'P'))
+ set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ else
+ exponent_sign = *cp == U'-' ? -1 : 1;
+ }
+ else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*cp))
+ set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
+ else if (current_fragment == fragments + 2 && !is_decimal_digit(*cp))
+ set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
+ else if (current_fragment->length == sizeof(fragment::chars))
+ set_error_and_return_default(
+ "fragment exceeeds maximum length of "sv,
+ static_cast<uint64_t>(sizeof(fragment::chars)), " characters"sv
+ );
+ else
+ current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
+
+ prev = cp;
+ advance_and_return_if_error({});
+ }
+
+ // sanity-check ending state
+ if (current_fragment != fragments + 2 || current_fragment->length == 0_sz)
+ {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("missing exponent"sv);
+ }
+ else if (prev && *prev == U'_')
+ {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ }
+
+ // calculate values for the three fragments
+ for (int fragment_idx = 0; fragment_idx < 3; fragment_idx++)
+ {
+ auto& f = fragments[fragment_idx];
+ const uint32_t base = fragment_idx == 2 ? 10 : 16;
+
+ // left-trim zeroes
+ const char* c = f.chars;
+ size_t sig = {};
+ while (f.length && *c == '0')
+ {
+ f.length--;
+ c++;
+ sig++;
+ }
+ if (!f.length)
+ continue;
+
+ // calculate value
+ auto place = 1u;
+ for (size_t i = 0; i < f.length - 1_sz; i++)
+ place *= base;
+ uint32_t val{};
+ while (place)
+ {
+ if (base == 16)
+ val += place * hex_to_dec(*c);
+ else
+ val += place * static_cast<uint32_t>(*c - '0');
+ if (fragment_idx == 1)
+ sig++;
+ c++;
+ place /= base;
+ }
+ f.value = static_cast<double>(val);
+
+ // shift the fractional part
+ if (fragment_idx == 1)
+ {
+ while (sig--)
+ f.value /= base;
+ }
+ }
+
+ return (fragments[0].value + fragments[1].value)
+ * pow(2.0, fragments[2].value * exponent_sign)
+ * sign;
+
+ #else // !TOML_LANG_UNRELEASED
+
+ set_error_and_return_default(
+ "hexadecimal floating-point values are not supported "
+ "in TOML 1.0.0 and earlier"sv
+ );
+
+ #endif // !TOML_LANG_UNRELEASED
+ }
+
+ template <uint64_t base>
+ [[nodiscard]]
+ int64_t parse_integer() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ using traits = parse_integer_traits<base>;
+ push_parse_scope(traits::scope_qualifier);
+
+ [[maybe_unused]] int64_t sign = 1;
+ if constexpr (traits::is_signed)
+ {
+ sign = *cp == U'-' ? -1 : 1;
+ if (is_match(*cp, U'+', U'-'))
+ advance_and_return_if_error_or_eof({});
+ }
+
+ if constexpr (base == 10)
+ {
+ if (!traits::is_digit(*cp))
+ set_error_and_return_default("expected expected digit or sign, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ else
+ {
+ // '0'
+ if (*cp != U'0')
+ set_error_and_return_default("expected '0', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // 'b', 'o', 'x'
+ if (*cp != traits::prefix_codepoint)
+ set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+ }
+
+ // consume value chars
+ char chars[traits::buffer_length];
+ size_t length = {};
+ const utf8_codepoint* prev = {};
+ while (!is_eof() && !is_value_terminator(*cp))
+ {
+ if (*cp == U'_')
+ {
+ if (!prev || !traits::is_digit(*prev))
+ set_error_and_return_default("underscores may only follow digits"sv);
+
+ prev = cp;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ }
+ else if (prev && *prev == U'_' && !traits::is_digit(*cp))
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ else if (!traits::is_digit(*cp))
+ set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
+ else if (length == sizeof(chars))
+ set_error_and_return_default(
+ "exceeds maximum length of "sv,
+ static_cast<uint64_t>(sizeof(chars)), " characters"sv
+ );
+ else
+ chars[length++] = static_cast<char>(cp->bytes[0]);
+
+ prev = cp;
+ advance_and_return_if_error({});
+ }
+
+ // sanity check ending state
+ if (prev && *prev == U'_')
+ {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ }
+
+ // check for leading zeroes
+ if constexpr (base == 10)
+ {
+ if (chars[0] == '0')
+ set_error_and_return_default("leading zeroes are prohibited"sv);
+ }
+
+ // single digits can be converted trivially
+ if (length == 1_sz)
+ {
+ if constexpr (base == 16)
+ return static_cast<int64_t>(hex_to_dec(chars[0]));
+ else if constexpr (base <= 10)
+ return static_cast<int64_t>(chars[0] - '0');
+ }
+
+ // otherwise do the thing
+ uint64_t result = {};
+ {
+ const char* msd = chars;
+ const char* end = msd + length;
+ while (msd < end && *msd == '0')
+ msd++;
+ if (msd == end)
+ return 0ll;
+ uint64_t power = 1;
+ while (--end >= msd)
+ {
+ if constexpr (base == 16)
+ result += power * hex_to_dec(*end);
+ else
+ result += power * static_cast<uint64_t>(*end - '0');
+ power *= base;
+ }
+ }
+
+ // range check
+ if (result > static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()) + (sign < 0 ? 1ull : 0ull))
+ set_error_and_return_default(
+ "'"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
+ );
+
+ if constexpr (traits::is_signed)
+ return static_cast<int64_t>(result) * sign;
+ else
+ return static_cast<int64_t>(result);
+ }
+
+ [[nodiscard]]
+ date parse_date(bool part_of_datetime = false) TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_decimal_digit(*cp));
+ push_parse_scope("date"sv);
+
+ // "YYYY"
+ uint32_t digits[4];
+ if (!consume_digit_sequence(digits, 4_sz))
+ set_error_and_return_default("expected 4-digit year, saw '"sv, to_sv(cp), "'"sv);
+ const auto year = digits[3]
+ + digits[2] * 10u
+ + digits[1] * 100u
+ + digits[0] * 1000u;
+ const auto is_leap_year = (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
+ set_error_and_return_if_eof({});
+
+ // '-'
+ if (*cp != U'-')
+ set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "MM"
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
+ const auto month = digits[1] + digits[0] * 10u;
+ if (month == 0u || month > 12u)
+ set_error_and_return_default(
+ "expected month between 1 and 12 (inclusive), saw "sv, static_cast<uint64_t>(month)
+ );
+ const auto max_days_in_month =
+ month == 2u
+ ? (is_leap_year ? 29u : 28u)
+ : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u)
+ ;
+ set_error_and_return_if_eof({});
+
+ // '-'
+ if (*cp != U'-')
+ set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "DD"
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit day, saw '"sv, to_sv(cp), "'"sv);
+ const auto day = digits[1] + digits[0] * 10u;
+ if (day == 0u || day > max_days_in_month)
+ set_error_and_return_default(
+ "expected day between 1 and "sv, static_cast<uint64_t>(max_days_in_month),
+ " (inclusive), saw "sv, static_cast<uint64_t>(day)
+ );
+
+ if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return
+ {
+ static_cast<uint16_t>(year),
+ static_cast<uint8_t>(month),
+ static_cast<uint8_t>(day)
+ };
+ }
+
+ [[nodiscard]]
+ time parse_time(bool part_of_datetime = false) TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_decimal_digit(*cp));
+ push_parse_scope("time"sv);
+
+ static constexpr auto max_digits = 9_sz;
+ uint32_t digits[max_digits];
+
+ // "HH"
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
+ const auto hour = digits[1] + digits[0] * 10u;
+ if (hour > 23u)
+ set_error_and_return_default(
+ "expected hour between 0 to 59 (inclusive), saw "sv, static_cast<uint64_t>(hour)
+ );
+ set_error_and_return_if_eof({});
+
+ // ':'
+ if (*cp != U':')
+ set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "MM"
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
+ const auto minute = digits[1] + digits[0] * 10u;
+ if (minute > 59u)
+ set_error_and_return_default(
+ "expected minute between 0 and 59 (inclusive), saw "sv, static_cast<uint64_t>(minute)
+ );
+ auto time = ::toml::time{
+ static_cast<uint8_t>(hour),
+ static_cast<uint8_t>(minute),
+ };
+
+ // ':'
+ if constexpr (TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
+ {
+ if (is_eof()
+ || is_value_terminator(*cp)
+ || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z')))
+ return time;
+ }
+ else
+ set_error_and_return_if_eof({});
+ if (*cp != U':')
+ set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "SS"
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
+ const auto second = digits[1] + digits[0] * 10u;
+ if (second > 59u)
+ set_error_and_return_default(
+ "expected second between 0 and 59 (inclusive), saw "sv, static_cast<uint64_t>(second)
+ );
+ time.second = static_cast<uint8_t>(second);
+
+ // '.' (early-exiting is allowed; fractional is optional)
+ if (is_eof()
+ || is_value_terminator(*cp)
+ || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z')))
+ return time;
+ if (*cp != U'.')
+ set_error_and_return_default("expected '.', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "FFFFFFFFF"
+ auto digit_count = consume_variable_length_digit_sequence(digits, max_digits);
+ if (!digit_count)
+ {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("expected fractional digits, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ else if (!is_eof())
+ {
+ if (digit_count == max_digits && is_decimal_digit(*cp))
+ set_error_and_return_default(
+ "fractional component exceeds maximum precision of "sv, static_cast<uint64_t>(max_digits)
+ );
+ else if (!part_of_datetime && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+ }
+
+ uint32_t value = 0u;
+ uint32_t place = 1u;
+ for (auto i = digit_count; i --> 0_sz;)
+ {
+ value += digits[i] * place;
+ place *= 10u;
+ }
+ for (auto i = digit_count; i < max_digits; i++) //implicit zeros
+ value *= 10u;
+ time.nanosecond = value;
+ return time;
+ }
+
+ [[nodiscard]]
+ date_time parse_date_time() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_decimal_digit(*cp));
+ push_parse_scope("date-time"sv);
+
+ // "YYYY-MM-DD"
+ auto date = parse_date(true);
+ set_error_and_return_if_eof({});
+
+ // ' ' or 'T'
+ if (!is_match(*cp, U' ', U'T'))
+ set_error_and_return_default("expected space or 'T', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "HH:MM:SS.FFFFFFFFF"
+ auto time = parse_time(true);
+ return_if_error({});
+
+ // no offset
+ if (is_eof() || is_value_terminator(*cp))
+ return { date, time };
+
+ // zero offset ("Z")
+ time_offset offset;
+ if (*cp == U'Z')
+ advance_and_return_if_error({});
+
+ // explicit offset ("+/-HH:MM")
+ else if (is_match(*cp, U'+', U'-'))
+ {
+ push_parse_scope("date-time offset"sv);
+
+ // sign
+ int sign = *cp == U'-' ? -1 : 1;
+ advance_and_return_if_error_or_eof({});
+
+ // "HH"
+ int digits[2];
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
+ const auto hour = digits[1] + digits[0] * 10;
+ if (hour > 23)
+ set_error_and_return_default(
+ "expected hour between 0 and 23 (inclusive), saw "sv, static_cast<int64_t>(hour)
+ );
+ set_error_and_return_if_eof({});
+
+ // ':'
+ if (*cp != U':')
+ set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "MM"
+ if (!consume_digit_sequence(digits, 2_sz))
+ set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
+ const auto minute = digits[1] + digits[0] * 10;
+ if (minute > 59)
+ set_error_and_return_default(
+ "expected minute between 0 and 59 (inclusive), saw "sv, static_cast<int64_t>(minute)
+ );
+ offset.minutes = static_cast<int16_t>((hour * 60 + minute) * sign);
+ }
+
+ if (!is_eof() && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return { date, time, offset };
+ }
+
+ TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_INIT_WARNINGS
+
+ [[nodiscard]] toml::array* parse_array() TOML_MAY_THROW;
+ [[nodiscard]] toml::table* parse_inline_table() TOML_MAY_THROW;
+ [[nodiscard]]
+ node* parse_value_known_prefixes() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(!is_control_character(*cp));
+ assert_or_assume(*cp != U'_');
+
+ switch (cp->value)
+ {
+ // arrays
+ case U'[':
+ return parse_array();
+
+ // inline tables
+ case U'{':
+ return parse_inline_table();
+
+ // floats beginning with '.'
+ case U'.':
+ return new value{ parse_float() };
+
+ // strings
+ case U'"': [[fallthrough]];
+ case U'\'':
+ return new value{ std::move(parse_string().value) };
+
+ // bools
+ case U't': [[fallthrough]];
+ case U'f': [[fallthrough]];
+ case U'T': [[fallthrough]];
+ case U'F':
+ return new value{ parse_boolean() };
+
+ // inf/nan
+ case U'i': [[fallthrough]];
+ case U'I': [[fallthrough]];
+ case U'n': [[fallthrough]];
+ case U'N':
+ return new value{ parse_inf_or_nan() };
+ }
+ return nullptr;
+ }
+
+ [[nodiscard]]
+ node* parse_value() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(!is_value_terminator(*cp));
+ push_parse_scope("value"sv);
+
+ // check if it begins with some control character
+ // (note that this will also fail for whitespace but we're assuming we've
+ // called consume_leading_whitespace() before calling parse_value())
+ if TOML_UNLIKELY(is_control_character(*cp))
+ set_error_and_return_default("unexpected control character"sv);
+
+ // underscores at the beginning
+ else if (*cp == U'_')
+ set_error_and_return_default("values may not begin with underscores"sv);
+
+ const auto begin_pos = cp->position;
+ node_ptr val;
+
+ do
+ {
+ assert_or_assume(!is_control_character(*cp));
+ assert_or_assume(*cp != U'_');
+
+ // detect the value type and parse accordingly,
+ // starting with value types that can be detected
+ // unambiguously from just one character.
+
+ val = parse_value_known_prefixes();
+ return_if_error({});
+ if (val)
+ break;
+
+ // value types from here down require more than one character to unambiguously identify
+ // so scan ahead and collect a set of value 'traits'.
+ enum value_traits : int
+ {
+ has_nothing = 0,
+ has_digits = 1,
+ has_b = 1 << 1, // as second char only (0b)
+ has_e = 1 << 2, // only float exponents
+ has_o = 1 << 3, // as second char only (0o)
+ has_p = 1 << 4, // only hexfloat exponents
+ has_t = 1 << 5,
+ has_x = 1 << 6, // as second or third char only (0x, -0x, +0x)
+ has_z = 1 << 7,
+ has_colon = 1 << 8,
+ has_plus = 1 << 9,
+ has_minus = 1 << 10,
+ has_dot = 1 << 11,
+ begins_sign = 1 << 12,
+ begins_digit = 1 << 13,
+ begins_zero = 1 << 14
+
+ // Q: "why not make these real values in the enum??"
+ // A: because the visual studio debugger stops treating them as a set of flags if you add
+ // non-pow2 values, making them much harder to debug.
+ #define signs_msk (has_plus | has_minus)
+ #define bzero_msk (begins_zero | has_digits)
+ #define bdigit_msk (begins_digit | has_digits)
+ };
+ value_traits traits = has_nothing;
+ const auto has_any = [&](auto t) noexcept { return (traits & t) != has_nothing; };
+ const auto has_none = [&](auto t) noexcept { return (traits & t) == has_nothing; };
+ const auto add_trait = [&](auto t) noexcept { traits = static_cast<value_traits>(traits | t); };
+
+ // examine the first character to get the 'begins with' traits
+ // (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
+ if (is_decimal_digit(*cp))
+ add_trait(*cp == U'0' ? begins_zero : begins_digit);
+ else if (is_match(*cp, U'+', U'-'))
+ add_trait(begins_sign);
+ else
+ break;
+
+ // scan the rest of the value to determine the remaining traits
+ char32_t chars[utf8_buffered_reader::max_history_length];
+ size_t char_count = {}, advance_count = {};
+ bool eof_while_scanning = false;
+ const auto scan = [&]() TOML_MAY_THROW
+ {
+ if (is_eof())
+ return;
+ assert_or_assume(!is_value_terminator(*cp));
+
+ do
+ {
+ if (const auto c = **cp; c != U'_')
+ {
+ chars[char_count++] = c;
+
+ if (is_decimal_digit(c))
+ add_trait(has_digits);
+ else if (is_ascii_letter(c))
+ {
+ assert_or_assume((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
+ switch (static_cast<char32_t>(c | 32u))
+ {
+ case U'b':
+ if (char_count == 2_sz && has_any(begins_zero))
+ add_trait(has_b);
+ break;
+
+ case U'e':
+ if (char_count > 1_sz
+ && has_none(has_b | has_o | has_p | has_t | has_x | has_z | has_colon)
+ && (has_none(has_plus | has_minus) || has_any(begins_sign)))
+ add_trait(has_e);
+ break;
+
+ case U'o':
+ if (char_count == 2_sz && has_any(begins_zero))
+ add_trait(has_o);
+ break;
+
+ case U'p':
+ if (has_any(has_x))
+ add_trait(has_p);
+ break;
+
+ case U'x':
+ if ((char_count == 2_sz && has_any(begins_zero))
+ || (char_count == 3_sz && has_any(begins_sign) && chars[1] == U'0'))
+ add_trait(has_x);
+ break;
+
+ case U't': add_trait(has_t); break;
+ case U'z': add_trait(has_z); break;
+ }
+ }
+ else if (c <= U':')
+ {
+ assert_or_assume(c < U'0' || c > U'9');
+ switch (c)
+ {
+ case U'+': add_trait(has_plus); break;
+ case U'-': add_trait(has_minus); break;
+ case U'.': add_trait(has_dot); break;
+ case U':': add_trait(has_colon); break;
+ }
+ }
+ }
+
+ advance_and_return_if_error();
+ advance_count++;
+ eof_while_scanning = is_eof();
+ }
+ while (advance_count < utf8_buffered_reader::max_history_length
+ && !is_eof()
+ && !is_value_terminator(*cp)
+ );
+ };
+ scan();
+ return_if_error({});
+
+ // force further scanning if this could have been a date-time with a space instead of a T
+ if (char_count == 10_sz
+ && traits == (bdigit_msk | has_minus)
+ && chars[4] == U'-'
+ && chars[7] == U'-'
+ && !is_eof()
+ && *cp == U' ')
+ {
+ const auto pre_advance_count = advance_count;
+ const auto pre_scan_traits = traits;
+ chars[char_count++] = *cp;
+ add_trait(has_t);
+
+ const auto backpedal = [&]() noexcept
+ {
+ go_back(advance_count - pre_advance_count);
+ advance_count = pre_advance_count;
+ traits = pre_scan_traits;
+ char_count = 10_sz;
+ };
+
+ advance_and_return_if_error({});
+ advance_count++;
+
+ if (is_eof() || !is_decimal_digit(*cp))
+ backpedal();
+ else
+ {
+ chars[char_count++] = *cp;
+
+ advance_and_return_if_error({});
+ advance_count++;
+
+ scan();
+ return_if_error({});
+
+ if (char_count == 12_sz)
+ backpedal();
+ }
+ }
+
+ // set the reader back to where we started
+ go_back(advance_count);
+ if (char_count < utf8_buffered_reader::max_history_length - 1_sz)
+ chars[char_count] = U'\0';
+
+ // if after scanning ahead we still only have one value character,
+ // the only valid value type is an integer.
+ if (char_count == 1_sz)
+ {
+ if (has_any(begins_zero | begins_digit))
+ {
+ val = new value{ static_cast<int64_t>(chars[0] - U'0') };
+ advance(); //skip the digit
+ break;
+ }
+
+ //anything else would be ambiguous.
+ else
+ set_error_and_return_default(
+ eof_while_scanning
+ ? "encountered end-of-file"sv
+ : "could not determine value type"sv
+ );
+ }
+
+ // now things that can be identified from two or more characters
+ return_if_error({});
+ assert_or_assume(char_count >= 2_sz);
+
+ // do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
+ // typed parse functions to take over and show better diagnostics if there's an issue
+ // (as opposed to the fallback "could not determine type" message)
+ if (has_any(has_p))
+ val = new value{ parse_hex_float() };
+ else if (has_any(has_x))
+ {
+ val = new value{ parse_integer<16>() };
+ reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_hexadecimal);
+ }
+ else if (has_any(has_o))
+ {
+ val = new value{ parse_integer<8>() };
+ reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_octal);
+ }
+ else if (has_any(has_b))
+ {
+ val = new value{ parse_integer<2>() };
+ reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_binary);
+ }
+ else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
+ val = new value{ parse_float() };
+ else if (has_any(begins_sign))
+ {
+ // single-digit signed integers
+ if (char_count == 2_sz && has_any(has_digits))
+ {
+ val = new value{
+ static_cast<int64_t>(chars[1] - U'0')
+ * (chars[0] == U'-' ? -1LL : 1LL)
+ };
+ advance(); //skip the sign
+ advance(); //skip the digit
+ break;
+ }
+
+ // simple signed floats (e.g. +1.0)
+ if (is_decimal_digit(chars[1]) && chars[2] == U'.')
+ val = new value{ parse_float() };
+
+ // signed infinity or nan
+ else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
+ val = new value{ parse_inf_or_nan() };
+ }
+
+ return_if_error({});
+ if (val)
+ break;
+
+ // match trait masks against what they can match exclusively.
+ // all correct value parses will come out of this list, so doing this as a switch is likely to
+ // be a better friend to the optimizer on the success path (failure path can be slow but that
+ // doesn't matter much).
+ switch (unwrap_enum(traits))
+ {
+ //=================== binary integers
+ // 0b10
+ case bzero_msk | has_b:
+ val = new value{ parse_integer<2>() };
+ reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_binary);
+ break;
+
+ //=================== octal integers
+ // 0o10
+ case bzero_msk | has_o:
+ val = new value{ parse_integer<8>() };
+ reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_octal);
+ break;
+
+ //=================== decimal integers
+ // 00
+ // 10
+ // +10
+ // -10
+ case bzero_msk: [[fallthrough]];
+ case bdigit_msk: [[fallthrough]];
+ case begins_sign | has_digits | has_minus: [[fallthrough]];
+ case begins_sign | has_digits | has_plus:
+ val = new value{ parse_integer<10>() };
+ break;
+
+ //=================== hexadecimal integers
+ // 0x10
+ case bzero_msk | has_x:
+ val = new value{ parse_integer<16>() };
+ reinterpret_cast<value<int64_t>*>(val.get())->flags(value_flags::format_as_hexadecimal);
+ break;
+
+ //=================== decimal floats
+ // 0e1
+ // 0e-1
+ // 0e+1
+ // 0.0
+ // 0.0e1
+ // 0.0e-1
+ // 0.0e+1
+ case bzero_msk | has_e: [[fallthrough]];
+ case bzero_msk | has_e | has_minus: [[fallthrough]];
+ case bzero_msk | has_e | has_plus: [[fallthrough]];
+ case bzero_msk | has_dot: [[fallthrough]];
+ case bzero_msk | has_dot | has_e: [[fallthrough]];
+ case bzero_msk | has_dot | has_e | has_minus: [[fallthrough]];
+ case bzero_msk | has_dot | has_e | has_plus: [[fallthrough]];
+ // 1e1
+ // 1e-1
+ // 1e+1
+ // 1.0
+ // 1.0e1
+ // 1.0e-1
+ // 1.0e+1
+ case bdigit_msk | has_e: [[fallthrough]];
+ case bdigit_msk | has_e | has_minus: [[fallthrough]];
+ case bdigit_msk | has_e | has_plus: [[fallthrough]];
+ case bdigit_msk | has_dot: [[fallthrough]];
+ case bdigit_msk | has_dot | has_e: [[fallthrough]];
+ case bdigit_msk | has_dot | has_e | has_minus: [[fallthrough]];
+ case bdigit_msk | has_dot | has_e | has_plus: [[fallthrough]];
+ // +1e1
+ // +1.0
+ // +1.0e1
+ // +1.0e+1
+ // +1.0e-1
+ // -1.0e+1
+ case begins_sign | has_digits | has_e | has_plus: [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_plus: [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_e | has_plus: [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_e | signs_msk: [[fallthrough]];
+ // -1e1
+ // -1e+1
+ // +1e-1
+ // -1.0
+ // -1.0e1
+ // -1.0e-1
+ case begins_sign | has_digits | has_e | has_minus: [[fallthrough]];
+ case begins_sign | has_digits | has_e | signs_msk: [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_minus: [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_e | has_minus:
+ val = new value{ parse_float() };
+ break;
+
+ //=================== hexadecimal floats
+ // 0x10p0
+ // 0x10p-0
+ // 0x10p+0
+ case bzero_msk | has_x | has_p: [[fallthrough]];
+ case bzero_msk | has_x | has_p | has_minus: [[fallthrough]];
+ case bzero_msk | has_x | has_p | has_plus: [[fallthrough]];
+ // -0x10p0
+ // -0x10p-0
+ // +0x10p0
+ // +0x10p+0
+ // -0x10p+0
+ // +0x10p-0
+ case begins_sign | has_digits | has_x | has_p | has_minus: [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_p | has_plus: [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_p | signs_msk: [[fallthrough]];
+ // 0x10.1p0
+ // 0x10.1p-0
+ // 0x10.1p+0
+ case bzero_msk | has_x | has_dot | has_p: [[fallthrough]];
+ case bzero_msk | has_x | has_dot | has_p | has_minus: [[fallthrough]];
+ case bzero_msk | has_x | has_dot | has_p | has_plus: [[fallthrough]];
+ // -0x10.1p0
+ // -0x10.1p-0
+ // +0x10.1p0
+ // +0x10.1p+0
+ // -0x10.1p+0
+ // +0x10.1p-0
+ case begins_sign | has_digits | has_x | has_dot | has_p | has_minus: [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_dot | has_p | has_plus: [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
+ val = new value{ parse_hex_float() };
+ break;
+
+ //=================== times
+ // HH:MM
+ // HH:MM:SS
+ // HH:MM:SS.FFFFFF
+ case bzero_msk | has_colon: [[fallthrough]];
+ case bzero_msk | has_colon | has_dot: [[fallthrough]];
+ case bdigit_msk | has_colon: [[fallthrough]];
+ case bdigit_msk | has_colon | has_dot:
+ val = new value{ parse_time() };
+ break;
+
+ //=================== local dates
+ // YYYY-MM-DD
+ case bzero_msk | has_minus: [[fallthrough]];
+ case bdigit_msk | has_minus:
+ val = new value{ parse_date() };
+ break;
+
+ //=================== date-times
+ // YYYY-MM-DDTHH:MM
+ // YYYY-MM-DDTHH:MM-HH:MM
+ // YYYY-MM-DDTHH:MM+HH:MM
+ // YYYY-MM-DD HH:MM
+ // YYYY-MM-DD HH:MM-HH:MM
+ // YYYY-MM-DD HH:MM+HH:MM
+ // YYYY-MM-DDTHH:MM:SS
+ // YYYY-MM-DDTHH:MM:SS-HH:MM
+ // YYYY-MM-DDTHH:MM:SS+HH:MM
+ // YYYY-MM-DD HH:MM:SS
+ // YYYY-MM-DD HH:MM:SS-HH:MM
+ // YYYY-MM-DD HH:MM:SS+HH:MM
+ case bzero_msk | has_minus | has_colon | has_t: [[fallthrough]];
+ case bzero_msk | signs_msk | has_colon | has_t: [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_t: [[fallthrough]];
+ case bdigit_msk | signs_msk | has_colon | has_t: [[fallthrough]];
+ // YYYY-MM-DDTHH:MM:SS.FFFFFF
+ // YYYY-MM-DDTHH:MM:SS.FFFFFF-HH:MM
+ // YYYY-MM-DDTHH:MM:SS.FFFFFF+HH:MM
+ // YYYY-MM-DD HH:MM:SS.FFFFFF
+ // YYYY-MM-DD HH:MM:SS.FFFFFF-HH:MM
+ // YYYY-MM-DD HH:MM:SS.FFFFFF+HH:MM
+ case bzero_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
+ case bzero_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
+ case bdigit_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
+ // YYYY-MM-DDTHH:MMZ
+ // YYYY-MM-DD HH:MMZ
+ // YYYY-MM-DDTHH:MM:SSZ
+ // YYYY-MM-DD HH:MM:SSZ
+ // YYYY-MM-DDTHH:MM:SS.FFFFFFZ
+ // YYYY-MM-DD HH:MM:SS.FFFFFFZ
+ case bzero_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
+ case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t: [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
+ val = new value{ parse_date_time() };
+ break;
+ }
+
+ #undef signs_msk
+ #undef bzero_msk
+ #undef bdigit_msk
+ }
+ while (false);
+
+ if (!val)
+ {
+ set_error_at(begin_pos, "could not determine value type"sv);
+ return_after_error({});
+ }
+
+ #if !TOML_LANG_AT_LEAST(1, 0, 0) // toml/issues/665 (heterogeneous arrays)
+ {
+ if (auto arr = val->as_array(); arr && !arr->is_homogeneous())
+ {
+ delete arr;
+ set_error_at(
+ begin_pos,
+ "arrays cannot contain values of different types before TOML 1.0.0"sv
+ );
+ return_after_error({});
+ }
+ }
+ #endif
+
+ val.get()->source_ = { begin_pos, current_position(1), reader.source_path() };
+ return val.release();
+ }
+
+ [[nodiscard]]
+ parsed_key parse_key() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_bare_key_character(*cp) || is_string_delimiter(*cp));
+ push_parse_scope("key"sv);
+
+ parsed_key key;
+ recording_whitespace = false;
+
+ while (!is_error())
+ {
+ #if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
+ if (is_combining_mark(*cp))
+ set_error_and_return_default("bare keys may not begin with unicode combining marks"sv);
+ else
+ #endif
+
+ // bare_key_segment
+ if (is_bare_key_character(*cp))
+ key.segments.emplace_back(parse_bare_key_segment());
+
+ // "quoted key segment"
+ else if (is_string_delimiter(*cp))
+ {
+ const auto begin_pos = cp->position;
+
+ recording_whitespace = true;
+ auto str = parse_string();
+ recording_whitespace = false;
+ return_if_error({});
+
+ if (str.was_multi_line)
+ {
+ set_error_at(
+ begin_pos,
+ "multi-line strings are prohibited in "sv,
+ key.segments.empty() ? ""sv : "dotted "sv,
+ "keys"sv
+ );
+ return_after_error({});
+ }
+ else
+ key.segments.emplace_back(std::move(str.value));
+ }
+
+ // ???
+ else
+ set_error_and_return_default(
+ "expected bare key starting character or string delimiter, saw '"sv, to_sv(*cp), "'"sv
+ );
+
+ // whitespace following the key segment
+ consume_leading_whitespace();
+
+ // eof or no more key to come
+ if (is_eof() || *cp != U'.')
+ break;
+
+ // was a dotted key, so go around again to consume the next segment
+ advance_and_return_if_error_or_eof({});
+ consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+ }
+ return_if_error({});
+ return key;
+ }
+
+ [[nodiscard]]
+ parsed_key_value_pair parse_key_value_pair() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(is_string_delimiter(*cp) || is_bare_key_character(*cp));
+ push_parse_scope("key-value pair"sv);
+
+ // get the key
+ start_recording();
+ auto key = parse_key();
+ stop_recording(1_sz);
+
+ // skip past any whitespace that followed the key
+ consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+
+ // '='
+ if (*cp != U'=')
+ set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // skip past any whitespace that followed the '='
+ consume_leading_whitespace();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+
+ // get the value
+ if (is_value_terminator(*cp))
+ set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
+ return { std::move(key), node_ptr{ parse_value() } };
+ }
+
+ [[nodiscard]]
+ toml::table* parse_table_header() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(*cp == U'[');
+ push_parse_scope("table header"sv);
+
+ const auto header_begin_pos = cp->position;
+ source_position header_end_pos;
+ parsed_key key;
+ bool is_arr = false;
+
+ //parse header
+ {
+ // skip first '['
+ advance_and_return_if_error_or_eof({});
+
+ // skip past any whitespace that followed the '['
+ const bool had_leading_whitespace = consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+
+ // skip second '[' (if present)
+ if (*cp == U'[')
+ {
+ if (had_leading_whitespace)
+ set_error_and_return_default(
+ "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv
+ );
+
+ is_arr = true;
+ advance_and_return_if_error_or_eof({});
+
+ // skip past any whitespace that followed the '['
+ consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+ }
+
+ // check for a premature closing ']'
+ if (*cp == U']')
+ set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
+
+ // get the actual key
+ start_recording();
+ key = parse_key();
+ stop_recording(1_sz);
+ return_if_error({});
+
+ // skip past any whitespace that followed the key
+ consume_leading_whitespace();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+
+ // consume the closing ']'
+ if (*cp != U']')
+ set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
+ if (is_arr)
+ {
+ advance_and_return_if_error_or_eof({});
+ if (*cp != U']')
+ set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
+ }
+ advance_and_return_if_error({});
+ header_end_pos = current_position(1);
+
+ // handle the rest of the line after the header
+ consume_leading_whitespace();
+ if (!is_eof() && !consume_comment() && !consume_line_break())
+ set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
+ }
+ TOML_ASSERT(!key.segments.empty());
+
+ // check if each parent is a table/table array, or can be created implicitly as a table.
+ auto parent = &root;
+ for (size_t i = 0; i < key.segments.size() - 1_sz; i++)
+ {
+ auto child = parent->get(key.segments[i]);
+ if (!child)
+ {
+ child = parent->map.emplace(
+ key.segments[i],
+ new toml::table{}
+ ).first->second.get();
+ implicit_tables.push_back(&child->ref_cast<table>());
+ child->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
+ parent = &child->ref_cast<table>();
+ }
+ else if (child->is_table())
+ {
+ parent = &child->ref_cast<table>();
+ }
+ else if (child->is_array() && find(table_arrays, &child->ref_cast<array>()))
+ {
+ // table arrays are a special case;
+ // the spec dictates we select the most recently declared element in the array.
+ TOML_ASSERT(!child->ref_cast<array>().elements.empty());
+ TOML_ASSERT(child->ref_cast<array>().elements.back()->is_table());
+ parent = &child->ref_cast<array>().elements.back()->ref_cast<table>();
+ }
+ else
+ {
+ if (!is_arr && child->type() == node_type::table)
+ set_error_and_return_default(
+ "cannot redefine existing table '"sv, to_sv(recording_buffer), "'"sv
+ );
+ else
+ set_error_and_return_default(
+ "cannot redefine existing "sv, to_sv(child->type()),
+ " '"sv, to_sv(recording_buffer),
+ "' as "sv, is_arr ? "array-of-tables"sv : "table"sv
+ );
+ }
+ }
+
+ // check the last parent table for a node matching the last key.
+ // if there was no matching node, then sweet;
+ // we can freely instantiate a new table/table array.
+ auto matching_node = parent->get(key.segments.back());
+ if (!matching_node)
+ {
+ // if it's an array we need to make the array and it's first table element,
+ // set the starting regions, and return the table element
+ if (is_arr)
+ {
+ auto tab_arr = &parent->map.emplace(
+ key.segments.back(),
+ new toml::array{}
+ ).first->second->ref_cast<array>();
+ table_arrays.push_back(tab_arr);
+ tab_arr->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
+
+ tab_arr->elements.emplace_back(new toml::table{});
+ tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
+ return &tab_arr->elements.back()->ref_cast<table>();
+ }
+
+ //otherwise we're just making a table
+ else
+ {
+ auto tab = &parent->map.emplace(
+ key.segments.back(),
+ new toml::table{})
+ .first->second->ref_cast<table>();
+ tab->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
+ return tab;
+ }
+ }
+
+ // if there was already a matching node some sanity checking is necessary;
+ // this is ok if we're making an array and the existing element is already an array (new element)
+ // or if we're making a table and the existing element is an implicitly-created table (promote it),
+ // otherwise this is a redefinition error.
+ else
+ {
+ if (is_arr && matching_node->is_array() && find(table_arrays, &matching_node->ref_cast<array>()))
+ {
+ auto tab_arr = &matching_node->ref_cast<array>();
+ tab_arr->elements.emplace_back(new toml::table{});
+ tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
+ return &tab_arr->elements.back()->ref_cast<table>();
+ }
+
+ else if (!is_arr
+ && matching_node->is_table()
+ && !implicit_tables.empty())
+ {
+ auto tbl = &matching_node->ref_cast<table>();
+ if (auto found = find(implicit_tables, tbl))
+ {
+ implicit_tables.erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
+ tbl->source_.begin = header_begin_pos;
+ tbl->source_.end = header_end_pos;
+ return tbl;
+ }
+ }
+
+ //if we get here it's a redefinition error.
+ if (!is_arr && matching_node->type() == node_type::table)
+ set_error_and_return_default("cannot redefine existing table '"sv, to_sv(recording_buffer), "'"sv);
+ else
+ set_error_and_return_default(
+ "cannot redefine existing "sv, to_sv(matching_node->type()),
+ " '"sv, to_sv(recording_buffer),
+ "' as "sv, is_arr ? "array-of-tables"sv : "table"sv
+ );
+ }
+ }
+
+ void parse_key_value_pair_and_insert(toml::table* tab) TOML_MAY_THROW
+ {
+ return_if_error();
+ assert_not_eof();
+ push_parse_scope("key-value pair"sv);
+
+ auto kvp = parse_key_value_pair();
+ return_if_error();
+
+ TOML_ASSERT(kvp.key.segments.size() >= 1_sz);
+ if (kvp.key.segments.size() > 1_sz)
+ {
+ for (size_t i = 0; i < kvp.key.segments.size() - 1_sz; i++)
+ {
+ auto child = tab->get(kvp.key.segments[i]);
+ if (!child)
+ {
+ child = tab->map.emplace(
+ std::move(kvp.key.segments[i]),
+ new toml::table{}
+ ).first->second.get();
+ dotted_key_tables.push_back(&child->ref_cast<table>());
+ dotted_key_tables.back()->inline_ = true;
+ child->source_ = kvp.value.get()->source_;
+ }
+ else if (!child->is_table() || !find(dotted_key_tables, &child->ref_cast<table>()))
+ set_error("cannot redefine existing "sv, to_sv(child->type()), " as dotted key-value pair"sv);
+ else
+ child->source_.end = kvp.value.get()->source_.end;
+ return_if_error();
+ tab = &child->ref_cast<table>();
+ }
+ }
+
+ if (auto conflicting_node = tab->get(kvp.key.segments.back()))
+ {
+ if (conflicting_node->type() == kvp.value.get()->type())
+ set_error(
+ "cannot redefine existing "sv, to_sv(conflicting_node->type()),
+ " '"sv, to_sv(recording_buffer), "'"sv
+ );
+ else
+ set_error(
+ "cannot redefine existing "sv, to_sv(conflicting_node->type()),
+ " '"sv, to_sv(recording_buffer),
+ "' as "sv, to_sv(kvp.value.get()->type())
+ );
+ }
+
+ return_if_error();
+ tab->map.emplace(
+ std::move(kvp.key.segments.back()),
+ std::unique_ptr<node>{ kvp.value.release() }
+ );
+ }
+
+ void parse_document() TOML_MAY_THROW
+ {
+ assert_not_error();
+ assert_not_eof();
+ push_parse_scope("root table"sv);
+ table* current_table = &root;
+
+ do
+ {
+ return_if_error();
+
+ // leading whitespace, line endings, comments
+ if (consume_leading_whitespace()
+ || consume_line_break()
+ || consume_comment())
+ continue;
+ return_if_error();
+
+ // [tables]
+ // [[table array]]
+ if (*cp == U'[')
+ current_table = parse_table_header();
+
+ // bare_keys
+ // dotted.keys
+ // "quoted keys"
+ else if (is_bare_key_character(*cp) || is_string_delimiter(*cp))
+ {
+ push_parse_scope("key-value pair"sv);
+
+ parse_key_value_pair_and_insert(current_table);
+
+ // handle the rest of the line after the kvp
+ // (this is not done in parse_key_value_pair() because that is also used for inline tables)
+ consume_leading_whitespace();
+ return_if_error();
+ if (!is_eof() && !consume_comment() && !consume_line_break())
+ set_error("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
+ }
+
+ else // ??
+ set_error("expected keys, tables, whitespace or comments, saw '"sv, to_sv(cp), "'"sv);
+
+ }
+ while (!is_eof());
+
+ auto eof_pos = current_position(1);
+ root.source_.end = eof_pos;
+ if (current_table
+ && current_table != &root
+ && current_table->source_.end <= current_table->source_.begin)
+ current_table->source_.end = eof_pos;
+ }
+
+ static void update_region_ends(node& nde) noexcept
+ {
+ const auto type = nde.type();
+ if (type > node_type::array)
+ return;
+
+ if (type == node_type::table)
+ {
+ auto& tbl = nde.ref_cast<table>();
+ if (tbl.inline_) //inline tables (and all their inline descendants) are already correctly terminated
+ return;
+
+ auto end = nde.source_.end;
+ for (auto& [k, v] : tbl.map)
+ {
+ (void)k;
+ update_region_ends(*v);
+ if (end < v->source_.end)
+ end = v->source_.end;
+ }
+ }
+ else //arrays
+ {
+ auto& arr = nde.ref_cast<array>();
+ auto end = nde.source_.end;
+ for (auto& v : arr.elements)
+ {
+ update_region_ends(*v);
+ if (end < v->source_.end)
+ end = v->source_.end;
+ }
+ nde.source_.end = end;
+ }
+ }
+
+ public:
+
+ parser(utf8_reader_interface&& reader_) TOML_MAY_THROW
+ : reader{ reader_ }
+ {
+ root.source_ = { prev_pos, prev_pos, reader.source_path() };
+
+ if (!reader.peek_eof())
+ {
+ cp = reader.read_next();
+
+ #if !TOML_EXCEPTIONS
+ if (reader.error())
+ {
+ err = std::move(reader.error());
+ return;
+ }
+ #endif
+
+ if (cp)
+ parse_document();
+ }
+
+ update_region_ends(root);
+ }
+
+ TOML_PUSH_WARNINGS
+ TOML_DISABLE_INIT_WARNINGS
+
+ [[nodiscard]]
+ operator parse_result() && noexcept
+ {
+ #if TOML_EXCEPTIONS
+
+ return { std::move(root) };
+
+ #else
+
+ if (err)
+ return parse_result{ *std::move(err) };
+ else
+ return parse_result{ std::move(root) };
+
+ #endif
+
+ }
+
+ TOML_POP_WARNINGS
+ };
+
+ TOML_EXTERNAL_LINKAGE
+ toml::array* parser::parse_array() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(*cp == U'[');
+ push_parse_scope("array"sv);
+
+ // skip opening '['
+ advance_and_return_if_error_or_eof({});
+
+ node_ptr arr{ new array{} };
+ auto& vals = reinterpret_cast<array*>(arr.get())->elements;
+ enum parse_elem : int
+ {
+ none,
+ comma,
+ val
+ };
+ parse_elem prev = none;
+
+ while (!is_error())
+ {
+ while (consume_leading_whitespace()
+ || consume_line_break()
+ || consume_comment())
+ continue;
+ set_error_and_return_if_eof({});
+
+ // commas - only legal after a value
+ if (*cp == U',')
+ {
+ if (prev == val)
+ {
+ prev = comma;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ }
+ set_error_and_return_default("expected value or closing ']', saw comma"sv);
+ }
+
+ // closing ']'
+ else if (*cp == U']')
+ {
+ advance_and_return_if_error({});
+ break;
+ }
+
+ // must be a value
+ else
+ {
+ if (prev == val)
+ {
+ set_error_and_return_default("expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
+ continue;
+ }
+ prev = val;
+ vals.emplace_back(parse_value());
+ }
+ }
+
+ return_if_error({});
+ return reinterpret_cast<array*>(arr.release());
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ toml::table* parser::parse_inline_table() TOML_MAY_THROW
+ {
+ return_if_error({});
+ assert_not_eof();
+ assert_or_assume(*cp == U'{');
+ push_parse_scope("inline table"sv);
+
+ // skip opening '{'
+ advance_and_return_if_error_or_eof({});
+
+ node_ptr tab{ new table{} };
+ reinterpret_cast<table*>(tab.get())->inline_ = true;
+ enum parse_elem : int
+ {
+ none,
+ comma,
+ kvp
+ };
+ parse_elem prev = none;
+
+ while (!is_error())
+ {
+ if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
+ {
+ while (consume_leading_whitespace()
+ || consume_line_break()
+ || consume_comment())
+ continue;
+ }
+ else
+ {
+ while (consume_leading_whitespace())
+ continue;
+ }
+ return_if_error({});
+ set_error_and_return_if_eof({});
+
+ // commas - only legal after a key-value pair
+ if (*cp == U',')
+ {
+ if (prev == kvp)
+ {
+ prev = comma;
+ advance_and_return_if_error_or_eof({});
+ }
+ else
+ set_error_and_return_default("expected key-value pair or closing '}', saw comma"sv);
+ }
+
+ // closing '}'
+ else if (*cp == U'}')
+ {
+ if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
+ {
+ if (prev == comma)
+ {
+ set_error_and_return_default("expected key-value pair, saw closing '}' (dangling comma)"sv);
+ continue;
+ }
+ }
+ advance_and_return_if_error({});
+ break;
+ }
+
+ // key-value pair
+ else if (is_string_delimiter(*cp) || is_bare_key_character(*cp))
+ {
+ if (prev == kvp)
+ set_error_and_return_default("expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
+ else
+ {
+ prev = kvp;
+ parse_key_value_pair_and_insert(reinterpret_cast<table*>(tab.get()));
+ }
+ }
+
+ else
+ set_error_and_return_default("expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
+ }
+
+ return_if_error({});
+ return reinterpret_cast<table*>(tab.release());
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result do_parse(utf8_reader_interface&& reader) TOML_MAY_THROW
+ {
+ return impl::parser{ std::move(reader) };
+ }
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+
+ #undef push_parse_scope_2
+ #undef push_parse_scope_1
+ #undef push_parse_scope
+ #undef TOML_RETURNS_BY_THROWING
+ #undef is_eof
+ #undef assert_not_eof
+ #undef return_if_eof
+ #undef is_error
+ #undef return_after_error
+ #undef assert_not_error
+ #undef return_if_error
+ #undef return_if_error_or_eof
+ #undef set_error_and_return
+ #undef set_error_and_return_default
+ #undef set_error_and_return_if_eof
+ #undef advance_and_return_if_error
+ #undef advance_and_return_if_error_or_eof
+ #undef assert_or_assume
+}
+TOML_IMPL_NAMESPACE_END
+
+TOML_NAMESPACE_START
+{
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result parse(std::string_view doc, std::string_view source_path) TOML_MAY_THROW
+ {
+ return impl::do_parse(impl::utf8_reader{ doc, source_path });
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result parse(std::string_view doc, std::string&& source_path) TOML_MAY_THROW
+ {
+ return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result parse(std::string_view doc, std::wstring_view source_path) TOML_MAY_THROW
+ {
+ return impl::do_parse(impl::utf8_reader{ doc, impl::narrow(source_path) });
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ #ifdef __cpp_lib_char8_t
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result parse(std::u8string_view doc, std::string_view source_path) TOML_MAY_THROW
+ {
+ return impl::do_parse(impl::utf8_reader{ doc, source_path });
+ }
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result parse(std::u8string_view doc, std::string&& source_path) TOML_MAY_THROW
+ {
+ return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
+ }
+
+ #if TOML_WINDOWS_COMPAT
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result parse(std::u8string_view doc, std::wstring_view source_path) TOML_MAY_THROW
+ {
+ return impl::do_parse(impl::utf8_reader{ doc, impl::narrow(source_path) });
+ }
+
+ #endif // TOML_WINDOWS_COMPAT
+
+ #endif // __cpp_lib_char8_t
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+
+ inline namespace literals
+ {
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex)
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result operator"" _toml(const char* str, size_t len) TOML_MAY_THROW
+ {
+ return parse(std::string_view{ str, len });
+ }
+
+ #ifdef __cpp_lib_char8_t
+
+ TOML_API
+ TOML_EXTERNAL_LINKAGE
+ parse_result operator"" _toml(const char8_t* str, size_t len) TOML_MAY_THROW
+ {
+ return parse(std::u8string_view{ str, len });
+ }
+
+ #endif // __cpp_lib_char8_t
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+ }
+}
+TOML_NAMESPACE_END
+
+TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
+
+#endif //---------------------------------------------------------- ↑ toml_parser.hpp --------------------------------
+
+#endif // TOML_PARSER
+
+#if !TOML_HEADER_ONLY
+
+#if 1 //------------------------------------------------------------------------------- ↓ toml_instantiations.hpp ---
+
+TOML_DISABLE_WARNINGS
+#include <ostream>
+#include <istream>
+#include <fstream>
+TOML_ENABLE_WARNINGS
+
+#if TOML_PARSER
+
+#endif
+
+// internal implementation namespace
+TOML_IMPL_NAMESPACE_START
+{
+ // formatters
+ template class TOML_API formatter<char>;
+
+ // print to stream machinery
+ template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
+}
+TOML_IMPL_NAMESPACE_END
+
+// public namespace
+TOML_NAMESPACE_START
+{
+ // value<>
+ template class TOML_API value<std::string>;
+ template class TOML_API value<int64_t>;
+ template class TOML_API value<double>;
+ template class TOML_API value<bool>;
+ template class TOML_API value<date>;
+ template class TOML_API value<time>;
+ template class TOML_API value<date_time>;
+
+ // node_view
+ template class TOML_API node_view<node>;
+ template class TOML_API node_view<const node>;
+
+ // formatters
+ template class TOML_API default_formatter<char>;
+ template class TOML_API json_formatter<char>;
+
+ // various ostream operators
+ template TOML_API std::ostream& operator << (std::ostream&, const source_position&);
+ template TOML_API std::ostream& operator << (std::ostream&, const source_region&);
+ template TOML_API std::ostream& operator << (std::ostream&, const date&);
+ template TOML_API std::ostream& operator << (std::ostream&, const time&);
+ template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
+ template TOML_API std::ostream& operator << (std::ostream&, const date_time&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<std::string>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
+ template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&);
+ template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&&);
+ template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&);
+ template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&&);
+ template TOML_API std::ostream& operator << (std::ostream&, const table&);
+ template TOML_API std::ostream& operator << (std::ostream&, const array&);
+ template TOML_API std::ostream& operator << (std::ostream&, const node_view<node>&);
+ template TOML_API std::ostream& operator << (std::ostream&, const node_view<const node>&);
+ template TOML_API std::ostream& operator << (std::ostream&, node_type);
+
+ // node::value, node_view:::value etc
+ #define TOML_INSTANTIATE(name, T) \
+ template TOML_API optional<T> node::name<T>() const noexcept; \
+ template TOML_API optional<T> node_view<node>::name<T>() const noexcept; \
+ template TOML_API optional<T> node_view<const node>::name<T>() const noexcept
+ TOML_INSTANTIATE(value_exact, std::string_view);
+ TOML_INSTANTIATE(value_exact, std::string);
+ TOML_INSTANTIATE(value_exact, const char*);
+ TOML_INSTANTIATE(value_exact, int64_t);
+ TOML_INSTANTIATE(value_exact, double);
+ TOML_INSTANTIATE(value_exact, date);
+ TOML_INSTANTIATE(value_exact, time);
+ TOML_INSTANTIATE(value_exact, date_time);
+ TOML_INSTANTIATE(value_exact, bool);
+ TOML_INSTANTIATE(value, std::string_view);
+ TOML_INSTANTIATE(value, std::string);
+ TOML_INSTANTIATE(value, const char*);
+ TOML_INSTANTIATE(value, signed char);
+ TOML_INSTANTIATE(value, signed short);
+ TOML_INSTANTIATE(value, signed int);
+ TOML_INSTANTIATE(value, signed long);
+ TOML_INSTANTIATE(value, signed long long);
+ TOML_INSTANTIATE(value, unsigned char);
+ TOML_INSTANTIATE(value, unsigned short);
+ TOML_INSTANTIATE(value, unsigned int);
+ TOML_INSTANTIATE(value, unsigned long);
+ TOML_INSTANTIATE(value, unsigned long long);
+ TOML_INSTANTIATE(value, double);
+ TOML_INSTANTIATE(value, float);
+ TOML_INSTANTIATE(value, date);
+ TOML_INSTANTIATE(value, time);
+ TOML_INSTANTIATE(value, date_time);
+ TOML_INSTANTIATE(value, bool);
+ #ifdef __cpp_lib_char8_t
+ TOML_INSTANTIATE(value_exact, std::u8string_view);
+ TOML_INSTANTIATE(value_exact, std::u8string);
+ TOML_INSTANTIATE(value_exact, const char8_t*);
+ TOML_INSTANTIATE(value, std::u8string_view);
+ TOML_INSTANTIATE(value, std::u8string);
+ TOML_INSTANTIATE(value, const char8_t*);
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ TOML_INSTANTIATE(value_exact, std::wstring);
+ TOML_INSTANTIATE(value, std::wstring);
+ #endif
+ #undef TOML_INSTANTIATE
+
+ // parser instantiations
+ #if TOML_PARSER
+
+ // parse error ostream
+ template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
+
+ // parse() and parse_file()
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex)
+
+ template TOML_API parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
+ template TOML_API parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
+ template TOML_API parse_result parse_file(std::string_view) TOML_MAY_THROW;
+ #ifdef __cpp_lib_char8_t
+ template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
+ #endif
+ #if TOML_WINDOWS_COMPAT
+ template TOML_API parse_result parse_file(std::wstring_view) TOML_MAY_THROW;
+ #endif
+
+ TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
+
+ #endif // TOML_PARSER
+}
+TOML_NAMESPACE_END
+
+#endif //------------------------------------------------------------------------------- ↑ toml_instantiations.hpp ---
+
+#endif // !TOML_HEADER_ONLY
+
+#endif // TOML_IMPLEMENTATION
+
+TOML_POP_WARNINGS // TOML_DISABLE_SPAM_WARNINGS
+
+// macro hygiene
+#if TOML_UNDEF_MACROS
+ #undef TOML_ABI_NAMESPACES
+ #undef TOML_ABI_NAMESPACE_BOOL
+ #undef TOML_ABI_NAMESPACE_END
+ #undef TOML_ABI_NAMESPACE_START
+ #undef TOML_ALWAYS_INLINE
+ #undef TOML_ANON_NAMESPACE
+ #undef TOML_ANON_NAMESPACE_END
+ #undef TOML_ANON_NAMESPACE_START
+ #undef TOML_ARM
+ #undef TOML_ASSERT
+ #undef TOML_ASSUME
+ #undef TOML_ASYMMETRICAL_EQUALITY_OPS
+ #undef TOML_ATTR
+ #undef TOML_CLANG
+ #undef TOML_COMPILER_EXCEPTIONS
+ #undef TOML_CONCAT
+ #undef TOML_CONCAT_1
+ #undef TOML_CONSTEVAL
+ #undef TOML_CPP
+ #undef TOML_DISABLE_ARITHMETIC_WARNINGS
+ #undef TOML_DISABLE_INIT_WARNINGS
+ #undef TOML_DISABLE_SPAM_WARNINGS
+ #undef TOML_DISABLE_SHADOW_WARNINGS
+ #undef TOML_DISABLE_SUGGEST_WARNINGS
+ #undef TOML_DISABLE_SWITCH_WARNINGS
+ #undef TOML_DISABLE_WARNINGS
+ #undef TOML_ENABLE_WARNINGS
+ #undef TOML_EMPTY_BASES
+ #undef TOML_EVAL_BOOL_0
+ #undef TOML_EVAL_BOOL_1
+ #undef TOML_EXTERNAL_LINKAGE
+ #undef TOML_FLOAT128
+ #undef TOML_FLOAT16
+ #undef TOML_FLOAT_CHARCONV
+ #undef TOML_FP16
+ #undef TOML_GCC
+ #undef TOML_HAS_ATTR
+ #undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
+ #undef TOML_HAS_INCLUDE
+ #undef TOML_ICC
+ #undef TOML_ICC_CL
+ #undef TOML_IMPLEMENTATION
+ #undef TOML_IMPL_NAMESPACE_END
+ #undef TOML_IMPL_NAMESPACE_START
+ #undef TOML_INT128
+ #undef TOML_INTELLISENSE
+ #undef TOML_INTERFACE
+ #undef TOML_INTERNAL_LINKAGE
+ #undef TOML_INT_CHARCONV
+ #undef TOML_LANG_AT_LEAST
+ #undef TOML_LANG_EFFECTIVE_VERSION
+ #undef TOML_LANG_HIGHER_THAN
+ #undef TOML_LANG_UNRELEASED
+ #undef TOML_LAUNDER
+ #undef TOML_LIFETIME_HOOKS
+ #undef TOML_LIKELY
+ #undef TOML_MAKE_BITOPS
+ #undef TOML_MAKE_VERSION
+ #undef TOML_MAY_THROW
+ #undef TOML_MSVC
+ #undef TOML_NAMESPACE
+ #undef TOML_NAMESPACE_END
+ #undef TOML_NAMESPACE_START
+ #undef TOML_NEVER_INLINE
+ #undef TOML_NODISCARD_CTOR
+ #undef TOML_NO_DEFAULT_CASE
+ #undef TOML_PARSER_TYPENAME
+ #undef TOML_POP_WARNINGS
+ #undef TOML_PUSH_WARNINGS
+ #undef TOML_SA_LIST_BEG
+ #undef TOML_SA_LIST_END
+ #undef TOML_SA_LIST_NEW
+ #undef TOML_SA_LIST_NXT
+ #undef TOML_SA_LIST_SEP
+ #undef TOML_SA_NATIVE_VALUE_TYPE_LIST
+ #undef TOML_SA_NEWLINE
+ #undef TOML_SA_NODE_TYPE_LIST
+ #undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
+ #undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
+ #undef TOML_SA_VALUE_FUNC_MESSAGE
+ #undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
+ #undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
+ #undef TOML_SA_VALUE_MESSAGE_WSTRING
+ #undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
+ #undef TOML_TRIVIAL_ABI
+ #undef TOML_UINT128
+ #undef TOML_UNLIKELY
+ #undef TOML_UNREACHABLE
+ #undef TOML_USING_ANON_NAMESPACE
+#endif
+
+#endif // INCLUDE_TOMLPLUSPLUS_H