//----------------------------------------------------------------------------------------------------------------------
//
// toml++ v3.4.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:      https://toml.io/en/v1.0.0
// 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) 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 TOMLPLUSPLUS_HPP
#define TOMLPLUSPLUS_HPP

#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3
#define TOMLPLUSPLUS_H         // guard name used in the legacy toml.h

//********  impl/preprocessor.hpp  *************************************************************************************

#ifndef __cplusplus
#error toml++ is a C++ library.
#endif

#ifndef TOML_CPP
#ifdef _MSVC_LANG
#if _MSVC_LANG > __cplusplus
#define TOML_CPP _MSVC_LANG
#endif
#endif
#ifndef TOML_CPP
#define TOML_CPP __cplusplus
#endif
#if TOML_CPP >= 202900L
#undef TOML_CPP
#define TOML_CPP 29
#elif TOML_CPP >= 202600L
#undef TOML_CPP
#define TOML_CPP 26
#elif TOML_CPP >= 202302L
#undef TOML_CPP
#define TOML_CPP 23
#elif TOML_CPP >= 202002L
#undef TOML_CPP
#define TOML_CPP 20
#elif TOML_CPP >= 201703L
#undef TOML_CPP
#define TOML_CPP 17
#elif TOML_CPP >= 201402L
#undef TOML_CPP
#define TOML_CPP 14
#elif TOML_CPP >= 201103L
#undef TOML_CPP
#define TOML_CPP 11
#else
#undef TOML_CPP
#define TOML_CPP 0
#endif
#endif

#if !TOML_CPP
#error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml
#elif TOML_CPP < 17
#error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11
#endif

#ifndef TOML_MAKE_VERSION
#define TOML_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + ((patch)))
#endif

#ifndef TOML_INTELLISENSE
#ifdef __INTELLISENSE__
#define TOML_INTELLISENSE 1
#else
#define TOML_INTELLISENSE 0
#endif
#endif

#ifndef TOML_DOXYGEN
#if defined(DOXYGEN)                                                                                                   \
    || defined(__DOXYGEN)                                                                                              \
    || defined(__DOXYGEN__)                                                                                            \
    || defined(__doxygen__)                                                                                            \
    || defined(__POXY__)                                                                                               \
    || defined(__poxy__)
#define TOML_DOXYGEN 1
#else
#define TOML_DOXYGEN 0
#endif
#endif

#ifndef TOML_CLANG
#ifdef __clang__
#define TOML_CLANG __clang_major__
#else
#define TOML_CLANG 0
#endif

// special handling for apple clang; see:
// - https://github.com/marzer/tomlplusplus/issues/189
// - https://en.wikipedia.org/wiki/Xcode
// -
// https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time
#if TOML_CLANG && defined(__apple_build_version__)
#undef TOML_CLANG
#define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
#if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0)
#define TOML_CLANG 16
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0)
#define TOML_CLANG 15
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0)
#define TOML_CLANG 14
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6)
#define TOML_CLANG 13
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0)
#define TOML_CLANG 12
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5)
#define TOML_CLANG 11
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0)
#define TOML_CLANG 10
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3)
#define TOML_CLANG 9
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0)
#define TOML_CLANG 8
#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1)
#define TOML_CLANG 7
#else
#define TOML_CLANG 6 // not strictly correct but doesn't matter below this
#endif
#undef TOML_CLANG_VERSION
#endif
#endif

#ifndef TOML_ICC
#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
#endif

#ifndef TOML_MSVC_LIKE
#ifdef _MSC_VER
#define TOML_MSVC_LIKE _MSC_VER
#else
#define TOML_MSVC_LIKE 0
#endif
#endif

#ifndef TOML_MSVC
#if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC
#define TOML_MSVC TOML_MSVC_LIKE
#else
#define TOML_MSVC 0
#endif
#endif

#ifndef TOML_GCC_LIKE
#ifdef __GNUC__
#define TOML_GCC_LIKE __GNUC__
#else
#define TOML_GCC_LIKE 0
#endif
#endif

#ifndef TOML_GCC
#if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC
#define TOML_GCC TOML_GCC_LIKE
#else
#define TOML_GCC 0
#endif
#endif

#ifndef TOML_CUDA
#if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__)
#define TOML_CUDA 1
#else
#define TOML_CUDA 0
#endif
#endif

#ifndef TOML_ARCH_ITANIUM
#if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64)
#define TOML_ARCH_ITANIUM 1
#define TOML_ARCH_BITNESS 64
#else
#define TOML_ARCH_ITANIUM 0
#endif
#endif

#ifndef TOML_ARCH_AMD64
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
#define TOML_ARCH_AMD64 1
#define TOML_ARCH_BITNESS 64
#else
#define TOML_ARCH_AMD64 0
#endif
#endif

#ifndef TOML_ARCH_X86
#if defined(__i386__) || defined(_M_IX86)
#define TOML_ARCH_X86 1
#define TOML_ARCH_BITNESS 32
#else
#define TOML_ARCH_X86 0
#endif
#endif

#ifndef TOML_ARCH_ARM
#if defined(__aarch64__)                                                                                               \
    || defined(__ARM_ARCH_ISA_A64)                                                                                     \
    || defined(_M_ARM64)                                                                                               \
    || defined(__ARM_64BIT_STATE)                                                                                      \
    || defined(_M_ARM64EC)
#define TOML_ARCH_ARM32 0
#define TOML_ARCH_ARM64 1
#define TOML_ARCH_ARM 1
#define TOML_ARCH_BITNESS 64
#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE)
#define TOML_ARCH_ARM32 1
#define TOML_ARCH_ARM64 0
#define TOML_ARCH_ARM 1
#define TOML_ARCH_BITNESS 32
#else
#define TOML_ARCH_ARM32 0
#define TOML_ARCH_ARM64 0
#define TOML_ARCH_ARM 0
#endif
#endif

#ifndef TOML_ARCH_BITNESS
#define TOML_ARCH_BITNESS 0
#endif

#ifndef TOML_ARCH_X64
#if TOML_ARCH_BITNESS == 64
#define TOML_ARCH_X64 1
#else
#define TOML_ARCH_X64 0
#endif
#endif

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__)
#define TOML_WINDOWS 1
#else
#define TOML_WINDOWS 0
#endif

#ifdef __unix__
#define TOML_UNIX 1
#else
#define TOML_UNIX 0
#endif

#ifdef __linux__
#define TOML_LINUX 1
#else
#define TOML_LINUX 0
#endif

// TOML_HAS_INCLUDE
#ifndef TOML_HAS_INCLUDE
#ifdef __has_include
#define TOML_HAS_INCLUDE(header)		__has_include(header)
#else
#define TOML_HAS_INCLUDE(header) 0
#endif
#endif

// TOML_HAS_BUILTIN
#ifndef TOML_HAS_BUILTIN
#ifdef __has_builtin
#define TOML_HAS_BUILTIN(name) __has_builtin(name)
#else
#define TOML_HAS_BUILTIN(name) 0
#endif
#endif

// TOML_HAS_FEATURE
#ifndef TOML_HAS_FEATURE
#ifdef __has_feature
#define TOML_HAS_FEATURE(name) __has_feature(name)
#else
#define TOML_HAS_FEATURE(name) 0
#endif
#endif

// TOML_HAS_ATTR
#ifndef TOML_HAS_ATTR
#ifdef __has_attribute
#define TOML_HAS_ATTR(attr) __has_attribute(attr)
#else
#define TOML_HAS_ATTR(attr) 0
#endif
#endif

// TOML_HAS_CPP_ATTR
#ifndef TOML_HAS_CPP_ATTR
#ifdef __has_cpp_attribute
#define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr)
#else
#define TOML_HAS_CPP_ATTR(attr) 0
#endif
#endif

// TOML_ATTR (gnu attributes)
#ifndef TOML_ATTR
#if TOML_CLANG || TOML_GCC_LIKE
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
#else
#define TOML_ATTR(...)
#endif
#endif

// TOML_DECLSPEC (msvc attributes)
#ifndef TOML_DECLSPEC
#if TOML_MSVC_LIKE
#define TOML_DECLSPEC(...) __declspec(__VA_ARGS__)
#else
#define TOML_DECLSPEC(...)
#endif
#endif

// TOML_COMPILER_HAS_EXCEPTIONS
#ifndef TOML_COMPILER_HAS_EXCEPTIONS
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions)
#define TOML_COMPILER_HAS_EXCEPTIONS 1
#else
#define TOML_COMPILER_HAS_EXCEPTIONS 0
#endif
#endif

// TOML_COMPILER_HAS_RTTI
#ifndef TOML_COMPILER_HAS_RTTI
#if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti)
#define TOML_COMPILER_HAS_RTTI 1
#else
#define TOML_COMPILER_HAS_RTTI 0
#endif
#endif

// TOML_CONCAT
#define TOML_CONCAT_1(x, y) x##y
#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)

// TOML_MAKE_STRING
#define TOML_MAKE_STRING_1(s) #s
#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s)

// TOML_PRAGMA_XXXX (compiler-specific pragmas)
#if TOML_CLANG
#define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl))
#else
#define TOML_PRAGMA_CLANG(decl)
#endif
#if TOML_CLANG >= 8
#define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl)
#else
#define TOML_PRAGMA_CLANG_GE_8(decl)
#endif
#if TOML_CLANG >= 9
#define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl)
#else
#define TOML_PRAGMA_CLANG_GE_9(decl)
#endif
#if TOML_CLANG >= 10
#define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl)
#else
#define TOML_PRAGMA_CLANG_GE_10(decl)
#endif
#if TOML_CLANG >= 11
#define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl)
#else
#define TOML_PRAGMA_CLANG_GE_11(decl)
#endif
#if TOML_GCC
#define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl))
#else
#define TOML_PRAGMA_GCC(decl)
#endif
#if TOML_MSVC
#define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__)
#else
#define TOML_PRAGMA_MSVC(...)
#endif
#if TOML_ICC
#define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__)
#else
#define TOML_PRAGMA_ICC(...)
#endif

// TOML_ALWAYS_INLINE
#ifdef _MSC_VER
#define TOML_ALWAYS_INLINE __forceinline
#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__)
#define TOML_ALWAYS_INLINE                                                                                             \
  TOML_ATTR(__always_inline__)                                                                                         \
  inline
#else
#define TOML_ALWAYS_INLINE inline
#endif

// TOML_NEVER_INLINE
#ifdef _MSC_VER
#define TOML_NEVER_INLINE TOML_DECLSPEC(noinline)
#elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555
#define TOML_NEVER_INLINE TOML_ATTR(noinline)
#else
#if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__)
#define TOML_NEVER_INLINE TOML_ATTR(__noinline__)
#endif
#endif
#ifndef TOML_NEVER_INLINE
#define TOML_NEVER_INLINE
#endif

// MSVC attributes
#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable)
#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases)

// TOML_TRIVIAL_ABI
#if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__)
#define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__)
#else
#define TOML_TRIVIAL_ABI
#endif

// TOML_NODISCARD
#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603
#define TOML_NODISCARD [[nodiscard]]
#elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__)
#define TOML_NODISCARD TOML_ATTR(__warn_unused_result__)
#else
#define TOML_NODISCARD
#endif

// TOML_NODISCARD_CTOR
#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907
#define TOML_NODISCARD_CTOR [[nodiscard]]
#else
#define TOML_NODISCARD_CTOR
#endif

// pure + const
#ifndef TOML_PURE
#ifdef NDEBUG
#define TOML_PURE                                                                                                      \
  TOML_DECLSPEC(noalias)                                                                                               \
  TOML_ATTR(pure)
#else
#define TOML_PURE
#endif
#endif
#ifndef TOML_CONST
#ifdef NDEBUG
#define TOML_CONST                                                                                                     \
  TOML_DECLSPEC(noalias)                                                                                               \
  TOML_ATTR(const)
#else
#define TOML_CONST
#endif
#endif
#ifndef TOML_INLINE_GETTER
#define TOML_INLINE_GETTER                                                                                             \
  TOML_NODISCARD                                                                                                       \
  TOML_ALWAYS_INLINE
#endif
#ifndef TOML_PURE_GETTER
#define TOML_PURE_GETTER                                                                                               \
  TOML_NODISCARD                                                                                                       \
  TOML_PURE
#endif
#ifndef TOML_PURE_INLINE_GETTER
#define TOML_PURE_INLINE_GETTER                                                                                        \
  TOML_NODISCARD                                                                                                       \
  TOML_ALWAYS_INLINE                                                                                                   \
  TOML_PURE
#endif
#ifndef TOML_CONST_GETTER
#define TOML_CONST_GETTER                                                                                              \
  TOML_NODISCARD                                                                                                       \
  TOML_CONST
#endif
#ifndef TOML_CONST_INLINE_GETTER
#define TOML_CONST_INLINE_GETTER                                                                                       \
  TOML_NODISCARD                                                                                                       \
  TOML_ALWAYS_INLINE                                                                                                   \
  TOML_CONST
#endif

// TOML_ASSUME
#ifdef _MSC_VER
#define TOML_ASSUME(expr) __assume(expr)
#elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume)
#define TOML_ASSUME(expr) __builtin_assume(expr)
#elif TOML_HAS_CPP_ATTR(assume) >= 202207
#define TOML_ASSUME(expr) [[assume(expr)]]
#elif TOML_HAS_ATTR(__assume__)
#define TOML_ASSUME(expr) __attribute__((__assume__(expr)))
#else
#define TOML_ASSUME(expr) static_cast<void>(0)
#endif

// TOML_UNREACHABLE
#ifdef _MSC_VER
#define TOML_UNREACHABLE __assume(0)
#elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable)
#define TOML_UNREACHABLE __builtin_unreachable()
#else
#define TOML_UNREACHABLE static_cast<void>(0)
#endif

// TOML_LIKELY
#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803
#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
#define TOML_LIKELY_CASE [[likely]]
#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1))
#else
#define TOML_LIKELY(...) (__VA_ARGS__)
#endif
#ifndef TOML_LIKELY_CASE
#define TOML_LIKELY_CASE
#endif

// TOML_UNLIKELY
#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803
#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
#define TOML_UNLIKELY_CASE [[unlikely]]
#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect)
#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0))
#else
#define TOML_UNLIKELY(...) (__VA_ARGS__)
#endif
#ifndef TOML_UNLIKELY_CASE
#define TOML_UNLIKELY_CASE
#endif

// TOML_FLAGS_ENUM
#if TOML_CLANG || TOML_HAS_ATTR(flag_enum)
#define TOML_FLAGS_ENUM __attribute__((flag_enum))
#else
#define TOML_FLAGS_ENUM
#endif

// TOML_OPEN_ENUM + TOML_CLOSED_ENUM
#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility)
#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open)))
#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed)))
#else
#define TOML_OPEN_ENUM
#define TOML_CLOSED_ENUM
#endif

// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM
#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM
#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM

// TOML_MAKE_FLAGS
#define TOML_MAKE_FLAGS_2(T, op, linkage)                                                                              \
  TOML_CONST_INLINE_GETTER                                                                                             \
  linkage constexpr T operator op(T lhs, T rhs) noexcept {                                                             \
    using under = std::underlying_type_t<T>;                                                                           \
    return static_cast<T>(static_cast<under>(lhs) op static_cast<under>(rhs));                                         \
  }                                                                                                                    \
                                                                                                                       \
  linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept { return lhs = (lhs op rhs); }             \
                                                                                                                       \
  static_assert(true)
#define TOML_MAKE_FLAGS_1(T, linkage)                                                                                  \
  static_assert(std::is_enum_v<T>);                                                                                    \
                                                                                                                       \
  TOML_MAKE_FLAGS_2(T, &, linkage);                                                                                    \
  TOML_MAKE_FLAGS_2(T, |, linkage);                                                                                    \
  TOML_MAKE_FLAGS_2(T, ^, linkage);                                                                                    \
                                                                                                                       \
  TOML_CONST_INLINE_GETTER                                                                                             \
  linkage constexpr T operator~(T val) noexcept {                                                                      \
    using under = std::underlying_type_t<T>;                                                                           \
    return static_cast<T>(~static_cast<under>(val));                                                                   \
  }                                                                                                                    \
                                                                                                                       \
  TOML_CONST_INLINE_GETTER                                                                                             \
  linkage constexpr bool operator!(T val) noexcept {                                                                   \
    using under = std::underlying_type_t<T>;                                                                           \
    return !static_cast<under>(val);                                                                                   \
  }                                                                                                                    \
                                                                                                                       \
  static_assert(true)
#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, )

#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)

#define TOML_DELETE_DEFAULTS(T)                                                                                        \
  T(const T&) = delete;                                                                                                \
  T(T&&) = delete;                                                                                                     \
  T& operator=(const T&) = delete;                                                                                     \
  T& operator=(T&&) = delete

#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...)                                                                  \
  __VA_ARGS__ TOML_NODISCARD friend bool operator==(RHS rhs, LHS lhs) noexcept { return lhs == rhs; }                  \
  __VA_ARGS__ TOML_NODISCARD friend bool operator!=(LHS lhs, RHS rhs) noexcept { return !(lhs == rhs); }               \
  __VA_ARGS__ TOML_NODISCARD friend bool operator!=(RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }               \
  static_assert(true)

#define TOML_EVAL_BOOL_1(T, F) T
#define TOML_EVAL_BOOL_0(T, F) F

#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL)
#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__
#endif

// COMPILER-SPECIFIC WARNING MANAGEMENT

#if TOML_CLANG

#define TOML_PUSH_WARNINGS                                                                                             \
  TOML_PRAGMA_CLANG(diagnostic push)                                                                                   \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option")                                                     \
  static_assert(true)

#define TOML_DISABLE_SWITCH_WARNINGS                                                                                   \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch")                                                                     \
  static_assert(true)

#define TOML_DISABLE_ARITHMETIC_WARNINGS                                                                               \
  TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wimplicit-int-float-conversion")                                        \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal")                                                                \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion")                                                           \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts")                                                            \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow")                                                        \
  static_assert(true)

#define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
  TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted")                                            \
  TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported")                                                \
  TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant")                                        \
  TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override")                                          \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables")                                                               \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables")                                                      \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion")                                                           \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts")                                                            \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers")                                                 \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded")                                                                     \
  static_assert(true)

#define TOML_POP_WARNINGS                                                                                              \
  TOML_PRAGMA_CLANG(diagnostic pop)                                                                                    \
  static_assert(true)

#define TOML_DISABLE_WARNINGS                                                                                          \
  TOML_PRAGMA_CLANG(diagnostic push)                                                                                   \
  TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything")                                                                 \
  static_assert(true, "")

#define TOML_ENABLE_WARNINGS                                                                                           \
  TOML_PRAGMA_CLANG(diagnostic pop)                                                                                    \
  static_assert(true)

#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1

#elif TOML_MSVC

#define TOML_PUSH_WARNINGS __pragma(warning(push)) static_assert(true)

#if TOML_HAS_INCLUDE(<CodeAnalysis / Warnings.h>)
#pragma warning(push, 0)
#include <CodeAnalysis/Warnings.h>
#pragma warning(pop)
#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) static_assert(true)
#else
#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
#endif

#define TOML_DISABLE_SWITCH_WARNINGS                                                                                   \
  __pragma(warning(disable : 4061)) __pragma(warning(disable : 4062)) __pragma(warning(disable : 4063))                \
      __pragma(warning(disable : 5262))  /* switch-case implicit fallthrough (false-positive) */                       \
      __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */                                             \
      static_assert(true)

#define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
  __pragma(warning(disable : 4127))     /* conditional expr is constant */                                             \
      __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */                          \
      __pragma(warning(disable : 4348)) __pragma(warning(disable : 4464)) /* relative include path contains '..' */    \
      __pragma(warning(disable : 4505))                                   /* unreferenced local function removed */    \
      __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */                            \
      __pragma(warning(disable : 4582)) /* constructor is not implicitly called */                                     \
      __pragma(warning(disable : 4619)) /*  there is no warning number 'XXXX' */                                       \
      __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */                    \
      __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */                       \
      __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */                    \
      __pragma(warning(disable : 4710)) /* function not inlined */                                                     \
      __pragma(warning(disable : 4711)) /* function selected for automatic expansion */                                \
      __pragma(warning(disable : 4820)) /* N bytes padding added */                                                    \
      __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */                            \
      __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted	*/                       \
      __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted	*/               \
      __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */            \
      __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */                                  \
      __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */                              \
      __pragma(warning(disable : 26451)) __pragma(warning(disable : 26490)) __pragma(warning(disable : 26495))         \
          __pragma(warning(disable : 26812)) __pragma(warning(disable : 26819)) static_assert(true)

#define TOML_DISABLE_ARITHMETIC_WARNINGS                                                                               \
  __pragma(warning(disable : 4365))     /* argument signed/unsigned mismatch */                                        \
      __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */                                    \
      __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */                               \
      static_assert(true)

#define TOML_POP_WARNINGS __pragma(warning(pop)) static_assert(true)

#define TOML_DISABLE_WARNINGS                                                                                          \
  __pragma(warning(push, 0)) __pragma(warning(disable : 4348)) __pragma(warning(disable : 4668))                       \
      __pragma(warning(disable : 5105)) __pragma(warning(disable : 5264)) TOML_DISABLE_CODE_ANALYSIS_WARNINGS;         \
  TOML_DISABLE_SWITCH_WARNINGS;                                                                                        \
  TOML_DISABLE_SPAM_WARNINGS;                                                                                          \
  TOML_DISABLE_ARITHMETIC_WARNINGS;                                                                                    \
  static_assert(true)

#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS

#elif TOML_ICC

#define TOML_PUSH_WARNINGS __pragma(warning(push)) static_assert(true)

#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 : 869))  /* unreferenced parameter */                                                   \
      __pragma(warning(disable : 1011)) /* missing return (false-positive) */                                          \
      __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */                                       \
      static_assert(true)

#define TOML_POP_WARNINGS __pragma(warning(pop)) static_assert(true)

#define TOML_DISABLE_WARNINGS __pragma(warning(push, 0)) TOML_DISABLE_SPAM_WARNINGS

#define TOML_ENABLE_WARNINGS __pragma(warning(pop)) static_assert(true)

#elif TOML_GCC

#define TOML_PUSH_WARNINGS                                                                                             \
  TOML_PRAGMA_GCC(diagnostic push)                                                                                     \
  static_assert(true)

#define TOML_DISABLE_SWITCH_WARNINGS                                                                                   \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch")                                                                       \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum")                                                                  \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default")                                                               \
  static_assert(true)

#define TOML_DISABLE_ARITHMETIC_WARNINGS                                                                               \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal")                                                                  \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion")                                                              \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts")                                                              \
  static_assert(true)

#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS                                                                             \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const")                                                      \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure")                                                       \
  static_assert(true)

#define TOML_DISABLE_SPAM_WARNINGS                                                                                     \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded")                                                                       \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align")                                                                   \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment")                                                                      \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits")                                                                  \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast")                                                                 \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts")                                                              \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage")                                                            \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers")                                                   \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized")                                                          \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept")                                                                     \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference")                                                             \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches")                                                          \
  static_assert(true)

#define TOML_POP_WARNINGS                                                                                              \
  TOML_PRAGMA_GCC(diagnostic pop)                                                                                      \
  static_assert(true)

#define TOML_DISABLE_WARNINGS                                                                                          \
  TOML_PRAGMA_GCC(diagnostic push)                                                                                     \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wall")                                                                          \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wextra")                                                                        \
  TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic")                                                                     \
  TOML_DISABLE_SWITCH_WARNINGS;                                                                                        \
  TOML_DISABLE_ARITHMETIC_WARNINGS;                                                                                    \
  TOML_DISABLE_SUGGEST_ATTR_WARNINGS;                                                                                  \
  TOML_DISABLE_SPAM_WARNINGS;                                                                                          \
  static_assert(true)

#define TOML_ENABLE_WARNINGS                                                                                           \
  TOML_PRAGMA_GCC(diagnostic pop)                                                                                      \
  static_assert(true)

#endif

#ifndef TOML_PUSH_WARNINGS
#define TOML_PUSH_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_SWITCH_WARNINGS
#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_SPAM_WARNINGS
#define TOML_DISABLE_SPAM_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true)
#endif
#ifndef TOML_POP_WARNINGS
#define TOML_POP_WARNINGS static_assert(true)
#endif
#ifndef TOML_DISABLE_WARNINGS
#define TOML_DISABLE_WARNINGS static_assert(true)
#endif
#ifndef TOML_ENABLE_WARNINGS
#define TOML_ENABLE_WARNINGS static_assert(true)
#endif
#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0
#endif

#ifdef TOML_CONFIG_HEADER
#include TOML_CONFIG_HEADER
#endif

// is the library being built as a shared lib/dll using meson and friends?
#ifndef TOML_SHARED_LIB
#define TOML_SHARED_LIB 0
#endif

// header-only mode
#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0
#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 TOML_DOXYGEN || TOML_SHARED_LIB
#undef TOML_HEADER_ONLY
#define TOML_HEADER_ONLY 0
#endif

// internal implementation switch
#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
#undef TOML_IMPLEMENTATION
#define TOML_IMPLEMENTATION 1
#else
#define TOML_IMPLEMENTATION 0
#endif

// dll/shared lib function exports (legacy - TOML_API was the old name for this setting)
#if !defined(TOML_EXPORTED_MEMBER_FUNCTION)                                                                            \
    && !defined(TOML_EXPORTED_STATIC_FUNCTION)                                                                         \
    && !defined(TOML_EXPORTED_FREE_FUNCTION)                                                                           \
    && !defined(TOML_EXPORTED_CLASS)                                                                                   \
    && defined(TOML_API)
#define TOML_EXPORTED_MEMBER_FUNCTION TOML_API
#define TOML_EXPORTED_STATIC_FUNCTION TOML_API
#define TOML_EXPORTED_FREE_FUNCTION TOML_API
#endif

// dll/shared lib exports
#if TOML_SHARED_LIB
#undef TOML_API
#undef TOML_EXPORTED_CLASS
#undef TOML_EXPORTED_MEMBER_FUNCTION
#undef TOML_EXPORTED_STATIC_FUNCTION
#undef TOML_EXPORTED_FREE_FUNCTION
#if TOML_WINDOWS
#if TOML_IMPLEMENTATION
#define TOML_EXPORTED_CLASS __declspec(dllexport)
#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport)
#else
#define TOML_EXPORTED_CLASS __declspec(dllimport)
#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport)
#endif
#ifndef TOML_CALLCONV
#define TOML_CALLCONV __cdecl
#endif
#elif defined(__GNUC__) && __GNUC__ >= 4
#define TOML_EXPORTED_CLASS __attribute__((visibility("default")))
#define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default")))
#define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default")))
#define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default")))
#endif
#endif
#ifndef TOML_EXPORTED_CLASS
#define TOML_EXPORTED_CLASS
#endif
#ifndef TOML_EXPORTED_MEMBER_FUNCTION
#define TOML_EXPORTED_MEMBER_FUNCTION
#endif
#ifndef TOML_EXPORTED_STATIC_FUNCTION
#define TOML_EXPORTED_STATIC_FUNCTION
#endif
#ifndef TOML_EXPORTED_FREE_FUNCTION
#define TOML_EXPORTED_FREE_FUNCTION
#endif

// experimental language features
#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES
                                                                                   // pre-3.0
#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES
#endif
#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE
#undef TOML_ENABLE_UNRELEASED_FEATURES
#define TOML_ENABLE_UNRELEASED_FEATURES 1
#endif
#ifndef TOML_ENABLE_UNRELEASED_FEATURES
#define TOML_ENABLE_UNRELEASED_FEATURES 0
#endif

// parser
#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0
#define TOML_ENABLE_PARSER TOML_PARSER
#endif
#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE
#undef TOML_ENABLE_PARSER
#define TOML_ENABLE_PARSER 1
#endif

// formatters
#if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE
#undef TOML_ENABLE_FORMATTERS
#define TOML_ENABLE_FORMATTERS 1
#endif

// SIMD
#if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE
#undef TOML_ENABLE_SIMD
#define TOML_ENABLE_SIMD 1
#endif

// windows compat
#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0
#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT
#endif
#if !defined(TOML_ENABLE_WINDOWS_COMPAT)                                                                               \
    || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT)                                             \
    || TOML_INTELLISENSE
#undef TOML_ENABLE_WINDOWS_COMPAT
#define TOML_ENABLE_WINDOWS_COMPAT 1
#endif

#if !TOML_WINDOWS
#undef TOML_ENABLE_WINDOWS_COMPAT
#define TOML_ENABLE_WINDOWS_COMPAT 0
#endif

#ifndef TOML_INCLUDE_WINDOWS_H
#define TOML_INCLUDE_WINDOWS_H 0
#endif

// custom optional
#ifdef TOML_OPTIONAL_TYPE
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
#else
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
#endif

// exceptions (library use)
#if TOML_COMPILER_HAS_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

// calling convention for static/free/friend functions
#ifndef TOML_CALLCONV
#define TOML_CALLCONV
#endif

#ifndef TOML_UNDEF_MACROS
#define TOML_UNDEF_MACROS 1
#endif

#ifndef TOML_MAX_NESTED_VALUES
#define TOML_MAX_NESTED_VALUES 256
// this refers to the depth of nested values, e.g. inline tables and arrays.
// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
#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 now work with char8_t strings implicitly.
#endif
#endif

#ifdef TOML_LARGE_FILES
#if !TOML_LARGE_FILES
#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0.
#endif
#endif

#ifndef TOML_LIFETIME_HOOKS
#define TOML_LIFETIME_HOOKS 0
#endif

#ifdef NDEBUG
#undef TOML_ASSERT
#define TOML_ASSERT(expr) static_assert(true)
#endif
#ifndef TOML_ASSERT
#ifndef assert
TOML_DISABLE_WARNINGS;
#include <cassert>
TOML_ENABLE_WARNINGS;
#endif
#define TOML_ASSERT(expr) assert(expr)
#endif
#ifdef NDEBUG
#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr)
#else
#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr)
#endif

#ifndef TOML_ENABLE_FLOAT16
#define TOML_ENABLE_FLOAT16 0
#endif

#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL))
// not supported by any version of GCC or Clang as of 26/11/2020
// not supported by any version of ICC on Linux as of 11/01/2021
#define TOML_FLOAT_CHARCONV 0
#endif
#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__))
// causes link errors on emscripten
// causes Mac OS SDK version errors on some versions of Apple Clang
#define TOML_INT_CHARCONV 0
#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

#if defined(__cpp_concepts) && __cpp_concepts >= 201907
#define TOML_REQUIRES(...) requires(__VA_ARGS__)
#else
#define TOML_REQUIRES(...)
#endif
#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0
#define TOML_CONSTRAINED_TEMPLATE(condition, ...)                                                                      \
  template <__VA_ARGS__ TOML_ENABLE_IF(condition)> TOML_REQUIRES(condition)
#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__)

#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

// clang-format off

//********  impl/version.hpp  ******************************************************************************************

#define TOML_LIB_MAJOR 3
#define TOML_LIB_MINOR 4
#define TOML_LIB_PATCH 0

#define TOML_LANG_MAJOR 1
#define TOML_LANG_MINOR 0
#define TOML_LANG_PATCH 0

//********  impl/preprocessor.hpp  *************************************************************************************

#define	TOML_LIB_SINGLE_HEADER 1

#if TOML_ENABLE_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(major, minor, patch)										\
		(TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch))

#define TOML_LANG_AT_LEAST(major, minor, patch)											\
		(TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch))

#define TOML_LANG_UNRELEASED															\
		TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)

#ifndef TOML_ABI_NAMESPACES
	#if TOML_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					} static_assert(true)
	#define TOML_NAMESPACE						::toml::TOML_CONCAT(v, TOML_LIB_MAJOR)
	#define TOML_ABI_NAMESPACE_START(name)		inline namespace name { static_assert(true)
	#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				} static_assert(true)
#else
	#define TOML_NAMESPACE_START				namespace toml
	#define TOML_NAMESPACE_END					static_assert(true)
	#define TOML_NAMESPACE						toml
	#define TOML_ABI_NAMESPACE_START(...)		static_assert(true)
	#define TOML_ABI_NAMESPACE_BOOL(...)		static_assert(true)
	#define TOML_ABI_NAMESPACE_END				static_assert(true)
#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			static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START
	#define TOML_ANON_NAMESPACE_END				TOML_IMPL_NAMESPACE_END
	#define TOML_ANON_NAMESPACE					TOML_NAMESPACE::impl
	#define TOML_EXTERNAL_LINKAGE				inline
	#define TOML_INTERNAL_LINKAGE				inline
#else
	#define TOML_ANON_NAMESPACE_START			static_assert(TOML_IMPLEMENTATION);	\
												using namespace toml;				\
												namespace
	#define TOML_ANON_NAMESPACE_END				static_assert(true)
	#define TOML_ANON_NAMESPACE
	#define TOML_EXTERNAL_LINKAGE
	#define TOML_INTERNAL_LINKAGE				static
#endif

// clang-format on

// clang-format off

#if 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

// clang-format on

TOML_PUSH_WARNINGS;
TOML_DISABLE_SPAM_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_DISABLE_SUGGEST_ATTR_WARNINGS;

// misc warning false-positives
#if TOML_MSVC
#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
#if TOML_SHARED_LIB
#pragma warning(disable : 4251) // dll exports for std lib types
#endif
#elif TOML_CLANG
TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene")
#if TOML_CLANG >= 12
TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions")
#endif
#if TOML_CLANG == 13
TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier")
#endif
#endif

//********  impl/std_new.hpp  ******************************************************************************************

TOML_DISABLE_WARNINGS;
#include <new>
TOML_ENABLE_WARNINGS;

#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914
#define TOML_LAUNDER(x) __builtin_launder(x)
#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
#define TOML_LAUNDER(x) std::launder(x)
#else
#define TOML_LAUNDER(x) x
#endif

//********  impl/std_string.hpp  ***************************************************************************************

TOML_DISABLE_WARNINGS;
#include <string>
#include <string_view>
TOML_ENABLE_WARNINGS;

#if TOML_DOXYGEN                                                                                                       \
    || (defined(__cpp_char8_t)                                                                                         \
        && __cpp_char8_t >= 201811                                                                                     \
        && defined(__cpp_lib_char8_t)                                                                                  \
        && __cpp_lib_char8_t >= 201907)
#define TOML_HAS_CHAR8 1
#else
#define TOML_HAS_CHAR8 0
#endif

namespace toml // non-abi namespace; this is not an error
{
  using namespace std::string_literals;
  using namespace std::string_view_literals;
} // namespace toml

#if TOML_ENABLE_WINDOWS_COMPAT

TOML_IMPL_NAMESPACE_START {
  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  std::string narrow(std::wstring_view);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  std::wstring widen(std::string_view);

#if TOML_HAS_CHAR8

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  std::wstring widen(std::u8string_view);

#endif
}
TOML_IMPL_NAMESPACE_END;

#endif // TOML_ENABLE_WINDOWS_COMPAT

//********  impl/std_optional.hpp  *************************************************************************************

TOML_DISABLE_WARNINGS;
#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
#include <optional>
#endif
TOML_ENABLE_WARNINGS;

TOML_NAMESPACE_START {
#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
}
TOML_NAMESPACE_END;

//********  impl/forward_declarations.hpp  *****************************************************************************

TOML_DISABLE_WARNINGS;
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iosfwd>
#include <limits>
#include <memory>
#include <type_traits>
TOML_ENABLE_WARNINGS;
TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

#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);
#ifdef FLT_RADIX
static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE);
#endif
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);
static_assert(std::numeric_limits<double>::radix == 2, TOML_ENV_MESSAGE);

#undef TOML_ENV_MESSAGE
#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS

// undocumented forward declarations are hidden from doxygen because they fuck it up =/

namespace toml // non-abi namespace; this is not an error
{
  using ::std::int16_t;
  using ::std::int32_t;
  using ::std::int64_t;
  using ::std::int8_t;
  using ::std::intptr_t;
  using ::std::nullptr_t;
  using ::std::ptrdiff_t;
  using ::std::size_t;
  using ::std::uint16_t;
  using ::std::uint32_t;
  using ::std::uint64_t;
  using ::std::uint8_t;
  using ::std::uint_least32_t;
  using ::std::uint_least64_t;
  using ::std::uintptr_t;
} // namespace toml

TOML_NAMESPACE_START {
  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;

  struct source_position;
  struct source_region;

  class node;
  template <typename> class node_view;

  class key;
  class array;
  class table;
  template <typename> class value;

  class path;

  class toml_formatter;
  class json_formatter;
  class yaml_formatter;

  TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
#if TOML_EXCEPTIONS
  using parse_result = table;
#else
  class parse_result;
#endif
  TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_NAMESPACE_END;

TOML_IMPL_NAMESPACE_START {
  using node_ptr = std::unique_ptr<node>;

  TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
  class parser;
  TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS

  // clang-format off

	inline constexpr std::string_view control_char_escapes[] =
	{
		"\\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
	};

  // clang-format on
}
TOML_IMPL_NAMESPACE_END;

#if TOML_ABI_NAMESPACES
#if TOML_EXCEPTIONS
#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser
#else
#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser
#endif
#else
#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser
#endif

namespace toml {}

TOML_NAMESPACE_START // abi namespace
{
  inline namespace literals {}

  enum class TOML_CLOSED_ENUM node_type : uint8_t {
    none,
    table,
    array,
    string,
    integer,
    floating_point,
    boolean,
    date,
    time,
    date_time
  };

  template <typename Char> inline std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& lhs, node_type rhs) {
    const auto str = impl::node_type_friendly_names[static_cast<std::underlying_type_t<node_type>>(rhs)];
    using str_char_t = decltype(str)::value_type;
    if constexpr (std::is_same_v<Char, str_char_t>)
      return lhs << str;
    else {
      if constexpr (sizeof(Char) == sizeof(str_char_t))
        return lhs << std::basic_string_view<Char>{reinterpret_cast<const Char*>(str.data()), str.length()};
      else
        return lhs << str.data();
    }
  }

  enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error
  {
    none,
    format_as_binary = 1,
    format_as_octal = 2,
    format_as_hexadecimal = 3,
  };
  TOML_MAKE_FLAGS(value_flags);

  inline constexpr value_flags preserve_source_value_flags =
      POXY_IMPLEMENTATION_DETAIL(value_flags{static_cast<std::underlying_type_t<value_flags>>(-1)});

  enum class TOML_CLOSED_FLAGS_ENUM format_flags : uint64_t {
    none,
    quote_dates_and_times = (1ull << 0),
    quote_infinities_and_nans = (1ull << 1),
    allow_literal_strings = (1ull << 2),
    allow_multi_line_strings = (1ull << 3),
    allow_real_tabs_in_strings = (1ull << 4),
    allow_unicode_strings = (1ull << 5),
    allow_binary_integers = (1ull << 6),
    allow_octal_integers = (1ull << 7),
    allow_hexadecimal_integers = (1ull << 8),
    indent_sub_tables = (1ull << 9),
    indent_array_elements = (1ull << 10),
    indentation = indent_sub_tables | indent_array_elements,
    relaxed_float_precision = (1ull << 11),
    terse_key_value_pairs = (1ull << 12),
  };
  TOML_MAKE_FLAGS(format_flags);

  template <typename T> struct TOML_TRIVIAL_ABI inserter {
    static_assert(std::is_reference_v<T>);

    T value;
  };
  template <typename T> inserter(T&&) -> inserter<T&&>;
  template <typename T> inserter(T&) -> inserter<T&>;

  using default_formatter = toml_formatter;
}
TOML_NAMESPACE_END;

TOML_IMPL_NAMESPACE_START {
  template <typename T> using remove_cvref = std::remove_cv_t<std::remove_reference_t<T>>;

  template <typename... T> using common_signed_type = std::common_type_t<std::make_signed_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 all_integral = (std::is_integral_v<T> && ...);

  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 value_retrieval_is_nothrow = !std::is_same_v<remove_cvref<T>, std::string>
#if TOML_HAS_CHAR8
      && !std::is_same_v<remove_cvref<T>, std::u8string>
#endif

      && !is_wide_string<T>;

  template <typename, typename> struct copy_ref_;
  template <typename Dest, typename Src> using copy_ref = typename copy_ref_<Dest, Src>::type;

  template <typename Dest, typename Src> struct copy_ref_ {
    using type = Dest;
  };

  template <typename Dest, typename Src> struct copy_ref_<Dest, Src&> {
    using type = std::add_lvalue_reference_t<Dest>;
  };

  template <typename Dest, typename Src> struct copy_ref_<Dest, Src&&> {
    using type = std::add_rvalue_reference_t<Dest>;
  };

  template <typename, typename> struct copy_cv_;
  template <typename Dest, typename Src> using copy_cv = typename copy_cv_<Dest, Src>::type;

  template <typename Dest, typename Src> struct copy_cv_ {
    using type = Dest;
  };

  template <typename Dest, typename Src> struct copy_cv_<Dest, const Src> {
    using type = std::add_const_t<Dest>;
  };

  template <typename Dest, typename Src> struct copy_cv_<Dest, volatile Src> {
    using type = std::add_volatile_t<Dest>;
  };

  template <typename Dest, typename Src> struct copy_cv_<Dest, const volatile Src> {
    using type = std::add_cv_t<Dest>;
  };

  template <typename Dest, typename Src>
  using copy_cvref =
      copy_ref<copy_ref<copy_cv<std::remove_reference_t<Dest>, std::remove_reference_t<Src>>, Dest>, Src>;

  template <typename...> inline constexpr bool always_false = false;

  template <typename T, typename... U> inline constexpr bool first_is_same = false;
  template <typename T, typename... U> inline constexpr bool first_is_same<T, T, U...> = true;

  template <typename T, bool = std::is_enum_v<T>> struct underlying_type_ {
    using type = std::underlying_type_t<T>;
  };
  template <typename T> struct underlying_type_<T, false> {
    using type = T;
  };
  template <typename T> using underlying_type = typename underlying_type_<T>::type;

  // general value traits
  // (as they relate to their equivalent native TOML type)
  struct default_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;

  template <typename T, bool = std::is_enum_v<T>> struct value_traits_base_selector {
    static_assert(!is_cvref<T>);

    using type = default_value_traits;
  };
  template <typename T> struct value_traits_base_selector<T, true> {
    static_assert(!is_cvref<T>);

    using type = value_traits<underlying_type<T>>;
  };

  template <typename T> struct value_traits : value_traits_base_selector<T>::type {};
  template <typename T> struct value_traits<const T> : value_traits<T> {};
  template <typename T> struct value_traits<volatile T> : value_traits<T> {};
  template <typename T> struct value_traits<const volatile T> : value_traits<T> {};
  template <typename T> struct value_traits<T&> : value_traits<T> {};
  template <typename T> struct value_traits<T&&> : value_traits<T> {};

  // integer value_traits specializations - standard types
  template <typename T> struct integer_limits {
    static constexpr T min = T{(std::numeric_limits<underlying_type<T>>::min)()};
    static constexpr T max = T{(std::numeric_limits<underlying_type<T>>::max)()};
  };
  template <typename T> struct integer_traits_base : integer_limits<T> {
    using native_type = int64_t;
    static constexpr bool is_native = std::is_same_v<underlying_type<T>, native_type>;
    static constexpr bool is_signed = static_cast<underlying_type<T>>(-1) < underlying_type<T>{};
    static constexpr auto type = node_type::integer;
    static constexpr bool can_partially_represent_native = true;
  };
  template <typename T> struct unsigned_integer_traits : integer_traits_base<T> {
    static constexpr bool is_losslessly_convertible_to_native =
        integer_limits<underlying_type<T>>::max <= 9223372036854775807ULL;
    static constexpr bool can_represent_native = false;
  };
  template <typename T> struct signed_integer_traits : integer_traits_base<T> {
    using native_type = int64_t;
    static constexpr bool is_losslessly_convertible_to_native =
        integer_limits<underlying_type<T>>::min >= (-9223372036854775807LL - 1LL)
        && integer_limits<underlying_type<T>>::max <= 9223372036854775807LL;
    static constexpr bool can_represent_native =
        integer_limits<underlying_type<T>>::min <= (-9223372036854775807LL - 1LL)
        && integer_limits<underlying_type<T>>::max >= 9223372036854775807LL;
  };
  template <typename T, bool S = integer_traits_base<T>::is_signed> struct integer_traits : signed_integer_traits<T> {};
  template <typename T> struct integer_traits<T, false> : unsigned_integer_traits<T> {};
  template <> struct value_traits<signed char> : integer_traits<signed char> {};
  template <> struct value_traits<unsigned char> : integer_traits<unsigned char> {};
  template <> struct value_traits<signed short> : integer_traits<signed short> {};
  template <> struct value_traits<unsigned short> : integer_traits<unsigned short> {};
  template <> struct value_traits<signed int> : integer_traits<signed int> {};
  template <> struct value_traits<unsigned int> : integer_traits<unsigned int> {};
  template <> struct value_traits<signed long> : integer_traits<signed long> {};
  template <> struct value_traits<unsigned long> : integer_traits<unsigned long> {};
  template <> struct value_traits<signed long long> : integer_traits<signed long long> {};
  template <> struct value_traits<unsigned long long> : integer_traits<unsigned long long> {};
  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);

  // integer value_traits specializations - non-standard types
#ifdef TOML_INT128
  template <> struct integer_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_limits<TOML_UINT128> {
    static constexpr TOML_UINT128 min = TOML_UINT128{};
    static constexpr TOML_UINT128 max = (2u * static_cast<TOML_UINT128>(integer_limits<TOML_INT128>::max)) + 1u;
  };
  template <> struct value_traits<TOML_INT128> : integer_traits<TOML_INT128> {};
  template <> struct value_traits<TOML_UINT128> : integer_traits<TOML_UINT128> {};
#endif
#ifdef TOML_SMALL_INT_TYPE
  template <> struct value_traits<TOML_SMALL_INT_TYPE> : signed_integer_traits<TOML_SMALL_INT_TYPE> {};
#endif

  // floating-point traits base
  template <typename T, int MantissaDigits, int DecimalDigits> struct float_traits_base {
    static constexpr auto type = node_type::floating_point;
    using native_type = double;
    static constexpr bool is_native = std::is_same_v<T, native_type>;
    static constexpr bool is_signed = true;

    static constexpr int bits = static_cast<int>(sizeof(T) * CHAR_BIT);
    static constexpr int digits = MantissaDigits;
    static constexpr int digits10 = DecimalDigits;

    static constexpr bool is_losslessly_convertible_to_native = bits <= 64 //
        && digits <= 53                                                    // DBL_MANT_DIG
        && digits10 <= 15;                                                 // DBL_DIG

    static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG
        && digits10 >= 15;                                    // DBL_DIG

    static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0;
  };
  template <typename T>
  struct float_traits : float_traits_base<T, std::numeric_limits<T>::digits, std::numeric_limits<T>::digits10> {};
#if TOML_ENABLE_FLOAT16
  template <> struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__> {};
#endif
#ifdef TOML_FLOAT128
  template <>
  struct float_traits<TOML_FLOAT128> : float_traits_base<TOML_FLOAT128, __FLT128_MANT_DIG__, __FLT128_DIG__> {};
#endif

  // floating-point traits
  template <> struct value_traits<float> : float_traits<float> {};
  template <> struct value_traits<double> : float_traits<double> {};
  template <> struct value_traits<long double> : float_traits<long double> {};
#if TOML_ENABLE_FLOAT16
  template <> struct value_traits<_Float16> : float_traits<_Float16> {};
#endif
#ifdef TOML_FLOAT128
  template <> struct value_traits<TOML_FLOAT128> : float_traits<TOML_FLOAT128> {};
#endif
#ifdef TOML_SMALL_FLOAT_TYPE
  template <> struct value_traits<TOML_SMALL_FLOAT_TYPE> : float_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 specializations - char-based strings
  template <typename T> struct string_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_traits<std::string> {};
  template <> struct value_traits<std::string_view> : string_traits<std::string_view> {};
  template <> struct value_traits<const char*> : string_traits<const char*> {};
  template <size_t N> struct value_traits<const char[N]> : string_traits<const char[N]> {};
  template <> struct value_traits<char*> : string_traits<char*> {};
  template <size_t N> struct value_traits<char[N]> : string_traits<char[N]> {};

  // string value_traits specializations - char8_t-based strings
#if TOML_HAS_CHAR8
  template <> struct value_traits<std::u8string> : string_traits<std::u8string> {};
  template <> struct value_traits<std::u8string_view> : string_traits<std::u8string_view> {};
  template <> struct value_traits<const char8_t*> : string_traits<const char8_t*> {};
  template <size_t N> struct value_traits<const char8_t[N]> : string_traits<const char8_t[N]> {};
  template <> struct value_traits<char8_t*> : string_traits<char8_t*> {};
  template <size_t N> struct value_traits<char8_t[N]> : string_traits<char8_t[N]> {};
#endif

  // string value_traits specializations - wchar_t-based strings on Windows
#if TOML_ENABLE_WINDOWS_COMPAT
  template <typename T> struct wstring_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_traits<std::wstring> {};
  template <> struct value_traits<std::wstring_view> : wstring_traits<std::wstring_view> {};
  template <> struct value_traits<const wchar_t*> : wstring_traits<const wchar_t*> {};
  template <size_t N> struct value_traits<const wchar_t[N]> : wstring_traits<const wchar_t[N]> {};
  template <> struct value_traits<wchar_t*> : wstring_traits<wchar_t*> {};
  template <size_t N> struct value_traits<wchar_t[N]> : wstring_traits<wchar_t[N]> {};
#endif

  // other 'native' value_traits specializations
  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 value types => nodes
  template <typename T> struct node_wrapper {
    using type = T;
  };
  template <typename T> struct node_wrapper<const T> {
    using type = std::add_const_t<typename node_wrapper<T>::type>;
  };
  template <typename T> struct node_wrapper<volatile T> {
    using type = std::add_volatile_t<typename node_wrapper<T>::type>;
  };
  template <typename T> struct node_wrapper<const volatile T> {
    using type = std::add_const_t<std::add_volatile_t<typename node_wrapper<T>::type>>;
  };
  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<std::remove_reference_t<T>>::type;

  // nodes => native value types
  template <typename T> struct node_unwrapper {
    using type = T;
  };
  template <typename T> struct node_unwrapper<value<T>> {
    using type = T;
  };
  template <typename T> struct node_unwrapper<const value<T>> {
    using type = std::add_const_t<T>;
  };
  template <typename T> struct node_unwrapper<volatile value<T>> {
    using type = std::add_volatile_t<T>;
  };
  template <typename T> struct node_unwrapper<const volatile value<T>> {
    using type = std::add_volatile_t<std::add_const_t<T>>;
  };
  template <typename T> using unwrap_node = typename node_unwrapper<std::remove_reference_t<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>>>::value;

  template <typename T, typename ConvertFrom>
  inline constexpr bool is_constructible_or_convertible = std::is_constructible_v<T, ConvertFrom> //
      || std::is_convertible_v<ConvertFrom, T>;
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  template <typename T> inline constexpr bool is_table = std::is_same_v<impl::remove_cvref<T>, table>;

  template <typename T> inline constexpr bool is_array = std::is_same_v<impl::remove_cvref<T>, array>;

  template <typename T> inline constexpr bool is_container = is_table<T> || is_array<T>;

  template <typename T>
	inline constexpr bool is_string = std::is_same_v<				//
		impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
		value<std::string>>;

  template <typename T>
	inline constexpr bool is_integer = std::is_same_v<				//
		impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
		value<int64_t>>;

  template <typename T>
	inline constexpr bool is_floating_point = std::is_same_v<		//
		impl::remove_cvref<impl::wrap_node<impl::remove_cvref<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::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
		value<bool>>;

  template <typename T>
	inline constexpr bool is_date = std::is_same_v<					//
		impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
		value<date>>;

  template <typename T>
	inline constexpr bool is_time = std::is_same_v<					//
		impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
		value<time>>;

  template <typename T>
	inline constexpr bool is_date_time = std::is_same_v<			//
		impl::remove_cvref<impl::wrap_node<impl::remove_cvref<T>>>, //
		value<date_time>>;

  template <typename T> inline constexpr bool is_chronological = is_date<T> || is_time<T> || is_date_time<T>;

  template <typename T>
  inline constexpr bool is_value = is_string<T> || is_number<T> || is_boolean<T> || is_chronological<T>;

  template <typename T>
  inline constexpr bool is_node = std::is_same_v<toml::node, impl::remove_cvref<T>> //
      || std::is_base_of_v<toml::node, impl::remove_cvref<T>>;

  template <typename T>
  inline constexpr bool is_node_view = impl::is_one_of<impl::remove_cvref<T>, node_view<node>, node_view<const node>>;
}
TOML_NAMESPACE_END;

TOML_IMPL_NAMESPACE_START {
  template <typename T> TOML_CONST_INLINE_GETTER constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept {
    return static_cast<std::underlying_type_t<T>>(val);
  }

  // Q: "why not use std::fpclassify?"
  // A: Because it gets broken by -ffast-math and friends
  enum class TOML_CLOSED_ENUM fp_class : unsigned { ok, neg_inf, pos_inf, nan };

  TOML_PURE_GETTER
  inline fp_class fpclassify(const double& val) noexcept {
    static_assert(sizeof(uint64_t) == sizeof(double));

    static constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull;
    static constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
    static constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull;

    uint64_t val_bits;
    std::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 and std::min?"
  // A: Because <algorithm> is _huge_ and these would be the only things I used from it.
  //    I don't want to impose such a heavy compile-time burden on users.

  template <typename Iterator, typename T>
  TOML_PURE_GETTER inline auto find(Iterator start, Iterator end, const T& needle) noexcept //
      -> decltype(&(*start)) {
    for (; start != end; start++)
      if (*start == needle)
        return &(*start);
    return nullptr;
  }

  template <typename T>
  TOML_PURE_INLINE_GETTER constexpr const T& min(const T& a, const T& b) noexcept //
  {
    return a < b ? a : b;
  }
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/print_to_stream.hpp  **********************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  // Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
  // A: - I'm using <charconv> to format numerics. Faster and locale-independent.
  //    - I can (potentially) avoid forcing users to drag in <sstream> and <iomanip>.
  //    - Strings in C++. Honestly.

  TOML_EXPORTED_FREE_FUNCTION
  TOML_ATTR(nonnull)
  void TOML_CALLCONV print_to_stream(std::ostream&, const char*, size_t);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, std::string_view);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const std::string&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, char);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, signed char, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, signed short, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, signed int, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, signed long, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, signed long long, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, unsigned char, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, unsigned short, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, unsigned int, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long long, value_flags = {}, size_t min_digits = 0);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, float, value_flags = {}, bool relaxed_precision = false);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, double, value_flags = {}, bool relaxed_precision = false);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, bool);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time_offset&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date_time&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const source_position&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const source_region&);

#if TOML_ENABLE_FORMATTERS

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const array&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const table&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<std::string>&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<int64_t>&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<double>&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<bool>&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<date>&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<time>&);

  TOML_EXPORTED_FREE_FUNCTION
  void TOML_CALLCONV print_to_stream(std::ostream&, const value<date_time>&);

#endif

  template <typename T, typename U>
  inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend) {
    print_to_stream(stream, bookend);
    print_to_stream(stream, val);
    print_to_stream(stream, bookend);
  }
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/source_region.hpp  ************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  using source_index = uint32_t;

  using source_path_ptr = std::shared_ptr<const std::string>;

  struct TOML_TRIVIAL_ABI source_position {
    source_index line;

    source_index column;

    TOML_PURE_GETTER
    explicit constexpr operator bool() const noexcept {
      return line > source_index{} //
      && column > source_index{};
    }

    TOML_PURE_GETTER
    friend constexpr bool operator==(const source_position& lhs, const source_position& rhs) noexcept {
      return lhs.line == rhs.line //
          && lhs.column == rhs.column;
    }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator!=(const source_position& lhs, const source_position& rhs) noexcept {
      return !(lhs == rhs);
    }

  private:
    TOML_PURE_GETTER
    static constexpr uint64_t pack(const source_position& pos) noexcept {
      return static_cast<uint64_t>(pos.line) << 32 | static_cast<uint64_t>(pos.column);
    }

  public:
    TOML_PURE_GETTER
    friend constexpr bool operator<(const source_position& lhs, const source_position& rhs) noexcept {
      return pack(lhs) < pack(rhs);
    }

    TOML_PURE_GETTER
    friend constexpr bool operator<=(const source_position& lhs, const source_position& rhs) noexcept {
      return pack(lhs) <= pack(rhs);
    }

    TOML_PURE_GETTER
    friend constexpr bool operator>(const source_position& lhs, const source_position& rhs) noexcept {
      return pack(lhs) > pack(rhs);
    }

    TOML_PURE_GETTER
    friend constexpr bool operator>=(const source_position& lhs, const source_position& rhs) noexcept {
      return pack(lhs) >= pack(rhs);
    }

    friend std::ostream& operator<<(std::ostream& lhs, const source_position& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }
  };

  struct source_region {
    source_position begin;

    source_position end;

    source_path_ptr path;

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    optional<std::wstring> wide_path() const {
      if (!path || path->empty())
        return {};
      return {impl::widen(*path)};
    }

#endif

    friend std::ostream& operator<<(std::ostream& lhs, const source_region& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }
  };
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/date_time.hpp  ****************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  struct TOML_TRIVIAL_ABI date {
    uint16_t year;

    uint8_t month;

    uint8_t day;

    TOML_NODISCARD_CTOR
    date() noexcept = default;

    TOML_CONSTRAINED_TEMPLATE((impl::all_integral<Y, M, D>), typename Y, typename M, typename D)
    TOML_NODISCARD_CTOR
    constexpr date(Y y, M m, D d) noexcept //
        : year{static_cast<uint16_t>(y)}, month{static_cast<uint8_t>(m)}, day{static_cast<uint8_t>(d)} {}

    TOML_PURE_GETTER
    friend constexpr bool operator==(const date& lhs, const date& rhs) noexcept {
      return lhs.year == rhs.year   //
          && lhs.month == rhs.month //
          && lhs.day == rhs.day;
    }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator!=(const date& lhs, const date& rhs) noexcept { return !(lhs == rhs); }

  private:
    TOML_PURE_GETTER
    static constexpr uint32_t pack(const 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:
    TOML_PURE_GETTER
    friend constexpr bool operator<(const date& lhs, const date& rhs) noexcept { return pack(lhs) < pack(rhs); }

    TOML_PURE_GETTER
    friend constexpr bool operator<=(const date& lhs, const date& rhs) noexcept { return pack(lhs) <= pack(rhs); }

    TOML_PURE_GETTER
    friend constexpr bool operator>(const date& lhs, const date& rhs) noexcept { return pack(lhs) > pack(rhs); }

    TOML_PURE_GETTER
    friend constexpr bool operator>=(const date& lhs, const date& rhs) noexcept { return pack(lhs) >= pack(rhs); }

    friend std::ostream& operator<<(std::ostream& lhs, const date& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }
  };

  struct TOML_TRIVIAL_ABI time {
    uint8_t hour;

    uint8_t minute;

    uint8_t second;

    uint32_t nanosecond;

    TOML_NODISCARD_CTOR
    time() noexcept = default;

    TOML_CONSTRAINED_TEMPLATE(
        (impl::all_integral<H, M, S, NS>), typename H, typename M, typename S = uint8_t, typename NS = uint32_t
    )
    TOML_NODISCARD_CTOR
    constexpr time(H h, M m, S s = S{}, NS ns = NS{}) noexcept //
        : hour{static_cast<uint8_t>(h)}, minute{static_cast<uint8_t>(m)}, second{static_cast<uint8_t>(s)},
          nanosecond{static_cast<uint32_t>(ns)} {}

    TOML_PURE_GETTER
    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;
    }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator!=(const time& lhs, const time& rhs) noexcept { return !(lhs == rhs); }

  private:
    TOML_PURE_GETTER
    static constexpr uint64_t pack(const 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:
    TOML_PURE_GETTER
    friend constexpr bool operator<(const time& lhs, const time& rhs) noexcept { return pack(lhs) < pack(rhs); }

    TOML_PURE_GETTER
    friend constexpr bool operator<=(const time& lhs, const time& rhs) noexcept { return pack(lhs) <= pack(rhs); }

    TOML_PURE_GETTER
    friend constexpr bool operator>(const time& lhs, const time& rhs) noexcept { return pack(lhs) > pack(rhs); }

    TOML_PURE_GETTER
    friend constexpr bool operator>=(const time& lhs, const time& rhs) noexcept { return pack(lhs) >= pack(rhs); }

    friend std::ostream& operator<<(std::ostream& lhs, const time& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }
  };

  struct TOML_TRIVIAL_ABI time_offset {
    int16_t minutes;

    TOML_NODISCARD_CTOR
    time_offset() noexcept = default;

    TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M>), typename H, typename M)
    TOML_NODISCARD_CTOR
    constexpr time_offset(H h, M m) noexcept //
        : minutes{static_cast<int16_t>(
              static_cast<impl::common_signed_type<H, M>>(h) * impl::common_signed_type<H, M>{60}
              + static_cast<impl::common_signed_type<H, M>>(m)
          )} {}

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept { return lhs.minutes == rhs.minutes; }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept { return lhs.minutes != rhs.minutes; }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept { return lhs.minutes < rhs.minutes; }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept { return lhs.minutes <= rhs.minutes; }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept { return lhs.minutes > rhs.minutes; }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept { return lhs.minutes >= rhs.minutes; }

    friend std::ostream& operator<<(std::ostream& lhs, const time_offset& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }
  };

  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
    date_time() noexcept = default;

    TOML_NODISCARD_CTOR
    constexpr date_time(const toml::date& d, const toml::time& t) noexcept //
        : date{d}, time{t}, offset{}                                       // TINAE - icc bugfix
    {}

    TOML_NODISCARD_CTOR
    explicit constexpr date_time(const toml::date& d) noexcept //
        : date{d}, time{}, offset{}                            // TINAE - icc bugfix
    {}

    TOML_NODISCARD_CTOR
    explicit constexpr date_time(const toml::time& t) noexcept //
        : date{}, time{t}, offset{}                            // TINAE - icc bugfix
    {}

    TOML_NODISCARD_CTOR
    constexpr date_time(const toml::date& d, const toml::time& t, const toml::time_offset& off) noexcept
        : date{d}, time{t}, offset{off} {}

    TOML_PURE_INLINE_GETTER
    constexpr bool is_local() const noexcept { return !offset.has_value(); }

    TOML_PURE_GETTER
    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;
    }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator!=(const date_time& lhs, const date_time& rhs) noexcept { return !(lhs == rhs); }

    TOML_PURE_GETTER
    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;
    }

    TOML_PURE_GETTER
    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;
    }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator>(const date_time& lhs, const date_time& rhs) noexcept { return !(lhs <= rhs); }

    TOML_PURE_INLINE_GETTER
    friend constexpr bool operator>=(const date_time& lhs, const date_time& rhs) noexcept { return !(lhs < rhs); }

    friend std::ostream& operator<<(std::ostream& lhs, const date_time& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }
  };

  TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/at_path.hpp  ******************************************************************************************

TOML_IMPL_NAMESPACE_START {
  template <typename T> using parse_path_callback = bool(TOML_CALLCONV*)(void*, T);

  TOML_NODISCARD
  bool TOML_CALLCONV parse_path(
      std::string_view, void*, parse_path_callback<std::string_view>, parse_path_callback<size_t>
  );
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept;

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept;

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path);

#endif
}
TOML_NAMESPACE_END;

//********  impl/std_vector.hpp  ***************************************************************************************

TOML_DISABLE_WARNINGS;
#include <iterator>
#include <vector>
TOML_ENABLE_WARNINGS;

//********  impl/path.hpp  *********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  enum class TOML_CLOSED_ENUM path_component_type : uint8_t { key = 0x1, array_index = 0x2 };

  class TOML_EXPORTED_CLASS path_component {
    struct storage_t {
      static constexpr size_t size = (sizeof(size_t) < sizeof(std::string) ? sizeof(std::string) : sizeof(size_t));
      static constexpr size_t align = (alignof(size_t) < alignof(std::string) ? alignof(std::string) : alignof(size_t));

      alignas(align) unsigned char bytes[size];
    };
    alignas(storage_t::align) mutable storage_t value_storage_;

    path_component_type type_;

    TOML_PURE_GETTER
    TOML_EXPORTED_STATIC_FUNCTION
    static bool TOML_CALLCONV equal(const path_component&, const path_component&) noexcept;

    template <typename Type> TOML_PURE_INLINE_GETTER static Type* get_as(storage_t& s) noexcept {
      return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
    }

    static void store_key(std::string_view key, storage_t& storage_) {
      ::new (static_cast<void*>(storage_.bytes)) std::string{key};
    }

    static void store_index(size_t index, storage_t& storage_) noexcept {
      ::new (static_cast<void*>(storage_.bytes)) std::size_t{index};
    }

    void destroy() noexcept {
      if (type_ == path_component_type::key)
        get_as<std::string>(value_storage_)->~basic_string();
    }

    TOML_NODISCARD
    size_t& index_ref() noexcept {
      TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
      return *get_as<size_t>(value_storage_);
    }

    TOML_NODISCARD
    std::string& key_ref() noexcept {
      TOML_ASSERT_ASSUME(type_ == path_component_type::key);
      return *get_as<std::string>(value_storage_);
    }

  public:
    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    path_component();

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    path_component(size_t index) noexcept;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    path_component(std::string_view key);

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    path_component(std::wstring_view key);

#endif

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    path_component(const path_component& pc);

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    path_component(path_component&& pc) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    path_component& operator=(const path_component& rhs);

    TOML_EXPORTED_MEMBER_FUNCTION
    path_component& operator=(path_component&& rhs) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    path_component& operator=(size_t new_index) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    path_component& operator=(std::string_view new_key);

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_EXPORTED_MEMBER_FUNCTION
    path_component& operator=(std::wstring_view new_key);

#endif

    ~path_component() noexcept { destroy(); }

    TOML_PURE_GETTER
    size_t index() const noexcept {
      TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
      return *get_as<const size_t>(value_storage_);
    }

    TOML_PURE_INLINE_GETTER
    explicit operator size_t() const noexcept { return index(); }

    TOML_PURE_GETTER
    const std::string& key() const noexcept {
      TOML_ASSERT_ASSUME(type_ == path_component_type::key);
      return *get_as<const std::string>(value_storage_);
    }

    TOML_PURE_INLINE_GETTER
    explicit operator const std::string&() const noexcept { return key(); }

    TOML_PURE_INLINE_GETTER
    path_component_type type() const noexcept { return type_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator==(const path_component& lhs, const path_component& rhs) noexcept { return equal(lhs, rhs); }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(const path_component& lhs, const path_component& rhs) noexcept { return !equal(lhs, rhs); }
  };

  class TOML_EXPORTED_CLASS path {
  private:
    std::vector<path_component> components_;

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_to(std::ostream&) const;

    TOML_PURE_GETTER
    TOML_EXPORTED_STATIC_FUNCTION
    static bool TOML_CALLCONV equal(const path&, const path&) noexcept;

  public:
    TOML_NODISCARD_CTOR
    path() noexcept = default;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    explicit path(std::string_view);

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    explicit path(std::wstring_view);

#endif

    ~path() noexcept = default;

    TOML_NODISCARD_CTOR
    path(const path&) = default;

    TOML_NODISCARD_CTOR
    path(path&&) noexcept = default;

    TOML_PURE_INLINE_GETTER
    size_t size() const noexcept { return components_.size(); }

    TOML_PURE_INLINE_GETTER
    explicit operator bool() const noexcept { return !components_.empty(); }

    TOML_PURE_INLINE_GETTER
    bool empty() const noexcept { return components_.empty(); }

    TOML_PURE_INLINE_GETTER
    path_component& operator[](size_t index) noexcept {
      TOML_ASSERT(index < size());
      return components_[index];
    }

    TOML_PURE_INLINE_GETTER
    const path_component& operator[](size_t index) const noexcept {
      TOML_ASSERT(index < size());
      return components_[index];
    }

    path& operator=(const path&) = default;

    path& operator=(path&&) noexcept = default;

    TOML_EXPORTED_MEMBER_FUNCTION
    path& operator=(std::string_view);

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_EXPORTED_MEMBER_FUNCTION
    path& operator=(std::wstring_view);

#endif

    TOML_ALWAYS_INLINE
    path& assign(const path& p) { return *this = p; }

    TOML_ALWAYS_INLINE
    path& assign(path&& p) noexcept { return *this = std::move(p); }

    TOML_ALWAYS_INLINE
    path& assign(std::string_view str) { return *this = str; }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_ALWAYS_INLINE
    path& assign(std::wstring_view str) { return *this = str; }

#endif

    TOML_EXPORTED_MEMBER_FUNCTION
    path& operator+=(const path&);

    TOML_EXPORTED_MEMBER_FUNCTION
    path& operator+=(path&&);

    TOML_EXPORTED_MEMBER_FUNCTION
    path& operator+=(std::string_view);

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_EXPORTED_MEMBER_FUNCTION
    path& operator+=(std::wstring_view);

#endif

    TOML_ALWAYS_INLINE
    path& append(const path& p) { return *this += p; }

    TOML_ALWAYS_INLINE
    path& append(path&& p) { return *this += std::move(p); }

    TOML_ALWAYS_INLINE
    path& append(std::string_view str) { return *this += str; }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_ALWAYS_INLINE
    path& append(std::wstring_view str) { return *this += str; }

#endif

    TOML_EXPORTED_MEMBER_FUNCTION
    path& prepend(const path&);

    TOML_EXPORTED_MEMBER_FUNCTION
    path& prepend(path&&);

    TOML_EXPORTED_MEMBER_FUNCTION
    path& prepend(std::string_view);

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_EXPORTED_MEMBER_FUNCTION
    path& prepend(std::wstring_view);

#endif

    TOML_NODISCARD
    friend path operator+(const path& lhs, const path& rhs) {
      path result = lhs;
      result += rhs;
      return result;
    }

    TOML_NODISCARD
    friend path operator+(const path& lhs, std::string_view rhs) {
      path result = lhs;
      result += rhs;
      return result;
    }

    TOML_NODISCARD
    friend path operator+(std::string_view lhs, const path& rhs) {
      path result = rhs;
      result.prepend(lhs);
      return result;
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    friend path operator+(const path& lhs, std::wstring_view rhs) {
      path result = lhs;
      result += rhs;
      return result;
    }

    TOML_NODISCARD
    friend path operator+(std::wstring_view lhs, const path& rhs) {
      path result = rhs;
      result.prepend(lhs);
      return result;
    }

#endif

    TOML_ALWAYS_INLINE
    friend std::ostream& operator<<(std::ostream& os, const path& rhs) {
      rhs.print_to(os);
      return os;
    }

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    std::string str() const;

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    explicit operator std::string() const { return str(); }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    std::wstring wide_str() const;

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    explicit operator std::wstring() const { return wide_str(); }

#endif

    TOML_PURE_INLINE_GETTER
    friend bool operator==(const path& lhs, const path& rhs) noexcept { return equal(lhs, rhs); }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(const path& lhs, const path& rhs) noexcept { return !equal(lhs, rhs); }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator==(const path& lhs, std::string_view rhs) { return lhs == path{rhs}; }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator==(std::string_view lhs, const path& rhs) { return rhs == lhs; }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator!=(const path& lhs, std::string_view rhs) { return lhs != path{rhs}; }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator!=(std::string_view lhs, const path& rhs) { return rhs != lhs; }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator==(const path& lhs, std::wstring_view rhs) { return lhs == path{rhs}; }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator==(std::wstring_view lhs, const path& rhs) { return rhs == lhs; }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator!=(const path& lhs, std::wstring_view rhs) { return lhs != path{rhs}; }

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    friend bool operator!=(std::wstring_view lhs, const path& rhs) { return rhs != lhs; }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    using iterator = std::vector<path_component>::iterator;

    using const_iterator = std::vector<path_component>::const_iterator;

    TOML_PURE_INLINE_GETTER
    iterator begin() noexcept { return components_.begin(); }

    TOML_PURE_INLINE_GETTER
    iterator end() noexcept { return components_.end(); }

    TOML_PURE_INLINE_GETTER
    const_iterator begin() const noexcept { return components_.begin(); }

    TOML_PURE_INLINE_GETTER
    const_iterator end() const noexcept { return components_.end(); }

    TOML_PURE_INLINE_GETTER
    const_iterator cbegin() const noexcept { return components_.begin(); }

    TOML_PURE_INLINE_GETTER
    const_iterator cend() const noexcept { return components_.end(); }

    TOML_EXPORTED_MEMBER_FUNCTION
    void clear() noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    path& truncate(size_t n);

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    path truncated(size_t n) const;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    path parent() const;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    path leaf(size_t n = 1) const;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    path subpath(const_iterator start, const_iterator end) const;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    path subpath(size_t start, size_t length) const;
  };

  inline namespace literals {
    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    path operator"" _tpath(const char* str, size_t len) { return path(std::string_view{str, len}); }
  } // namespace literals

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept;

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept;
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/std_utility.hpp  **************************************************************************************

TOML_DISABLE_WARNINGS;
#include <utility>
TOML_ENABLE_WARNINGS;

//********  impl/node.hpp  *********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  class TOML_ABSTRACT_INTERFACE TOML_EXPORTED_CLASS node {
  private:
    friend class TOML_PARSER_TYPENAME;
    source_region source_{};

    template <typename T>
    TOML_NODISCARD decltype(auto) get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);

    template <typename T, typename N>
		using ref_type_ = std::conditional_t<													//
			std::is_reference_v<T>,																//
			impl::copy_ref<impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>, T>, //
			impl::copy_cvref<impl::unwrap_node<T>, N>											//
			>;

    template <typename T, typename N>
		using ref_type = std::conditional_t<			 //
			std::is_reference_v<N>,						 //
			ref_type_<T, N>,							 //
			ref_type_<T, std::add_lvalue_reference_t<N>> //
			>;

    template <typename T, typename N> TOML_PURE_GETTER static ref_type<T, N&&> do_ref(N&& n) noexcept {
      using unwrapped_type = impl::unwrap_node<T>;
      static_assert(
          toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
          "The template type argument of node::ref() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
      );

      TOML_ASSERT_ASSUME(
          n.template is<unwrapped_type>()
          && "template type argument provided to toml::node::ref() didn't match the node's actual type"
      );

      using node_ref = std::remove_volatile_t<std::remove_reference_t<N>>&;
      using val_type = std::remove_volatile_t<unwrapped_type>;
      using out_ref = ref_type<T, N&&>;
      static_assert(std::is_reference_v<out_ref>);

      if constexpr (toml::is_value<unwrapped_type>)
        return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>().get());
      else
        return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>());
    }

  protected:
    TOML_EXPORTED_MEMBER_FUNCTION
    node() noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    node(const node&) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    node(node&&) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    node& operator=(const node&) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    node& operator=(node&&) noexcept;

    template <typename T, typename N>
		using ref_cast_type_ = std::conditional_t<											  //
			std::is_reference_v<T>,															  //
			impl::copy_ref<impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>, T>, //
			impl::copy_cvref<impl::wrap_node<T>, N>											  //
			>;

    template <typename T, typename N>
		using ref_cast_type = std::conditional_t<			  //
			std::is_reference_v<N>,							  //
			ref_cast_type_<T, N>,							  //
			ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
			>;

    template <typename T> TOML_PURE_INLINE_GETTER ref_cast_type<T, node&> ref_cast() & noexcept {
      using out_ref = ref_cast_type<T, node&>;
      using out_type = std::remove_reference_t<out_ref>;
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
    }

    template <typename T> TOML_PURE_INLINE_GETTER ref_cast_type<T, node&&> ref_cast() && noexcept {
      using out_ref = ref_cast_type<T, node&&>;
      using out_type = std::remove_reference_t<out_ref>;
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
    }

    template <typename T> TOML_PURE_INLINE_GETTER ref_cast_type<T, const node&> ref_cast() const& noexcept {
      using out_ref = ref_cast_type<T, const node&>;
      using out_type = std::remove_reference_t<out_ref>;
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
    }

    template <typename T> TOML_PURE_INLINE_GETTER ref_cast_type<T, const node&&> ref_cast() const&& noexcept {
      using out_ref = ref_cast_type<T, const node&&>;
      using out_type = std::remove_reference_t<out_ref>;
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
    }

  public:
    TOML_EXPORTED_MEMBER_FUNCTION
    virtual ~node() noexcept;

    TOML_PURE_GETTER
    virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_homogeneous(node_type ntype) const noexcept = 0;

    template <typename ElemType = void> TOML_PURE_GETTER bool is_homogeneous() const noexcept {
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
      static_assert(
          std::is_void_v<type> || toml::is_value<type> || toml::is_container<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>);
    }

    TOML_PURE_GETTER
    virtual node_type type() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_table() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_array() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_array_of_tables() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_value() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_string() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_integer() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_floating_point() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_number() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_boolean() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_date() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_time() const noexcept = 0;

    TOML_PURE_GETTER
    virtual bool is_date_time() const noexcept = 0;

    template <typename T> TOML_PURE_INLINE_GETTER bool is() const noexcept {
      using type = impl::remove_cvref<impl::unwrap_node<T>>;
      static_assert(
          toml::is_value<type> || toml::is_container<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();
    }

    TOML_PURE_GETTER
    virtual table* as_table() noexcept = 0;

    TOML_PURE_GETTER
    virtual array* as_array() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<std::string>* as_string() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<int64_t>* as_integer() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<double>* as_floating_point() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<bool>* as_boolean() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<date>* as_date() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<time>* as_time() noexcept = 0;

    TOML_PURE_GETTER
    virtual toml::value<date_time>* as_date_time() noexcept = 0;

    TOML_PURE_GETTER
    virtual const table* as_table() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const array* as_array() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<std::string>* as_string() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<int64_t>* as_integer() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<double>* as_floating_point() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<bool>* as_boolean() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<date>* as_date() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<time>* as_time() const noexcept = 0;

    TOML_PURE_GETTER
    virtual const toml::value<date_time>* as_date_time() const noexcept = 0;

    template <typename T> TOML_PURE_INLINE_GETTER impl::wrap_node<T>* as() noexcept {
      using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
      static_assert(
          toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
          "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
      );

      if constexpr (std::is_same_v<unwrapped_type, table>)
        return as_table();
      else if constexpr (std::is_same_v<unwrapped_type, array>)
        return as_array();
      else if constexpr (std::is_same_v<unwrapped_type, std::string>)
        return as_string();
      else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
        return as_integer();
      else if constexpr (std::is_same_v<unwrapped_type, double>)
        return as_floating_point();
      else if constexpr (std::is_same_v<unwrapped_type, bool>)
        return as_boolean();
      else if constexpr (std::is_same_v<unwrapped_type, date>)
        return as_date();
      else if constexpr (std::is_same_v<unwrapped_type, time>)
        return as_time();
      else if constexpr (std::is_same_v<unwrapped_type, date_time>)
        return as_date_time();
    }

    template <typename T> TOML_PURE_INLINE_GETTER const impl::wrap_node<T>* as() const noexcept {
      using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
      static_assert(
          toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
          "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
      );

      if constexpr (std::is_same_v<unwrapped_type, table>)
        return as_table();
      else if constexpr (std::is_same_v<unwrapped_type, array>)
        return as_array();
      else if constexpr (std::is_same_v<unwrapped_type, std::string>)
        return as_string();
      else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
        return as_integer();
      else if constexpr (std::is_same_v<unwrapped_type, double>)
        return as_floating_point();
      else if constexpr (std::is_same_v<unwrapped_type, bool>)
        return as_boolean();
      else if constexpr (std::is_same_v<unwrapped_type, date>)
        return as_date();
      else if constexpr (std::is_same_v<unwrapped_type, time>)
        return as_time();
      else if constexpr (std::is_same_v<unwrapped_type, date_time>)
        return as_date_time();
    }

    template <typename T> TOML_NODISCARD optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);

    template <typename T> TOML_NODISCARD optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>);

    template <typename T>
    TOML_NODISCARD auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>);

    template <typename T> TOML_PURE_GETTER decltype(auto) ref() & noexcept { return do_ref<T>(*this); }

    template <typename T> TOML_PURE_GETTER decltype(auto) ref() && noexcept { return do_ref<T>(std::move(*this)); }

    template <typename T> TOML_PURE_GETTER decltype(auto) ref() const& noexcept { return do_ref<T>(*this); }

    template <typename T> TOML_PURE_GETTER decltype(auto) ref() const&& noexcept { return do_ref<T>(std::move(*this)); }

    TOML_PURE_INLINE_GETTER
    const source_region& source() const noexcept { return source_; }

  private:
    template <typename Func, typename Node, typename T>
    static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, Node>>;

    template <typename Func, typename Node, typename T>
    static constexpr bool can_visit_nothrow = std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>;

    template <typename Func, typename Node>
    static constexpr bool can_visit_any = can_visit<Func, Node, table> //
        || can_visit<Func, Node, array>                                //
        || can_visit<Func, Node, std::string>                          //
        || can_visit<Func, Node, int64_t>                              //
        || can_visit<Func, Node, double>                               //
        || can_visit<Func, Node, bool>                                 //
        || can_visit<Func, Node, date>                                 //
        || can_visit<Func, Node, time>                                 //
        || can_visit<Func, Node, date_time>;

    // clang-format off

		template <typename Func, typename Node>
		static constexpr bool can_visit_all = can_visit<Func, Node, table>		 //
										   && can_visit<Func, Node, array>		 //
										   && can_visit<Func, Node, std::string> //
										   && can_visit<Func, Node, int64_t>	 //
										   && can_visit<Func, Node, double>		 //
										   && can_visit<Func, Node, bool>		 //
										   && can_visit<Func, Node, date>		 //
										   && can_visit<Func, Node, time>		 //
										   && can_visit<Func, Node, date_time>;

		template <typename Func, typename Node, typename T>
		static constexpr bool visit_is_nothrow_one = !can_visit<Func, Node, T> || can_visit_nothrow<Func, Node, T>;

		template <typename Func, typename Node>
		static constexpr bool visit_is_nothrow = visit_is_nothrow_one<Func, Node, table>	   //
											  && visit_is_nothrow_one<Func, Node, array>	   //
											  && visit_is_nothrow_one<Func, Node, std::string> //
											  && visit_is_nothrow_one<Func, Node, int64_t>	   //
											  && visit_is_nothrow_one<Func, Node, double>	   //
											  && visit_is_nothrow_one<Func, Node, bool>		   //
											  && visit_is_nothrow_one<Func, Node, date>		   //
											  && visit_is_nothrow_one<Func, Node, time>		   //
											  && visit_is_nothrow_one<Func, Node, date_time>;

    // clang-format on

    template <typename Func, typename Node, typename T, bool = can_visit<Func, Node, T>> struct visit_return_type_ {
      using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>()));
    };
    template <typename Func, typename Node, typename T> struct visit_return_type_<Func, Node, T, false> {
      using type = void;
    };

    template <typename Func, typename Node, typename T>
    using visit_return_type = typename visit_return_type_<Func, Node, T>::type;

    template <typename A, typename B> using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;

    template <typename Func, typename Node>
    static decltype(auto) do_visit(Func&& visitor, Node&& n) noexcept(visit_is_nothrow<Func&&, Node&&>) {
      static_assert(
          can_visit_any<Func&&, Node&&>,
          "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&&, Node&&, table>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<table>());
        break;

      case node_type::array:
        if constexpr (can_visit<Func&&, Node&&, array>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<array>());
        break;

      case node_type::string:
        if constexpr (can_visit<Func&&, Node&&, std::string>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<std::string>());
        break;

      case node_type::integer:
        if constexpr (can_visit<Func&&, Node&&, int64_t>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<int64_t>());
        break;

      case node_type::floating_point:
        if constexpr (can_visit<Func&&, Node&&, double>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<double>());
        break;

      case node_type::boolean:
        if constexpr (can_visit<Func&&, Node&&, bool>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<bool>());
        break;

      case node_type::date:
        if constexpr (can_visit<Func&&, Node&&, date>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date>());
        break;

      case node_type::time:
        if constexpr (can_visit<Func&&, Node&&, time>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<time>());
        break;

      case node_type::date_time:
        if constexpr (can_visit<Func&&, Node&&, date_time>)
          return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date_time>());
        break;

      case node_type::none:
        TOML_UNREACHABLE;
      default:
        TOML_UNREACHABLE;
      }

      if constexpr (!can_visit_all<Func&&, Node&&>) {
        // clang-format off

				using return_type =
					nonvoid<visit_return_type<Func&&, Node&&, table>,
					nonvoid<visit_return_type<Func&&, Node&&, array>,
					nonvoid<visit_return_type<Func&&, Node&&, std::string>,
					nonvoid<visit_return_type<Func&&, Node&&, int64_t>,
					nonvoid<visit_return_type<Func&&, Node&&, double>,
					nonvoid<visit_return_type<Func&&, Node&&, bool>,
					nonvoid<visit_return_type<Func&&, Node&&, date>,
					nonvoid<visit_return_type<Func&&, Node&&, time>,
							visit_return_type<Func&&, Node&&, date_time>
				>>>>>>>>;

        // clang-format on

        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{};
        }
      }
    }

  public:
    template <typename Func> decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>) {
      return do_visit(static_cast<Func&&>(visitor), *this);
    }

    template <typename Func> decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>) {
      return do_visit(static_cast<Func&&>(visitor), static_cast<node&&>(*this));
    }

    template <typename Func>
    decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>) {
      return do_visit(static_cast<Func&&>(visitor), *this);
    }

    template <typename Func>
    decltype(auto) visit(Func&& visitor) const&& noexcept(visit_is_nothrow<Func&&, const node&&>) {
      return do_visit(static_cast<Func&&>(visitor), static_cast<const node&&>(*this));
    }

    TOML_NODISCARD
    explicit operator node_view<node>() noexcept;

    TOML_NODISCARD
    explicit operator node_view<const node>() const noexcept;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<node> at_path(std::string_view path) noexcept;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<const node> at_path(std::string_view path) const noexcept;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<node> at_path(const toml::path& path) noexcept;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<const node> at_path(const toml::path& path) const noexcept;

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<node> at_path(std::wstring_view path);

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<const node> at_path(std::wstring_view path) const;

#endif // TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<node> operator[](const toml::path& path) noexcept;

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node_view<const node> operator[](const toml::path& path) const noexcept;
  };
}
TOML_NAMESPACE_END;

TOML_IMPL_NAMESPACE_START {
  TOML_PURE_GETTER
  TOML_EXPORTED_FREE_FUNCTION
  bool TOML_CALLCONV node_deep_equality(const node*, const node*) noexcept;
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/std_initializer_list.hpp  *****************************************************************************

TOML_DISABLE_WARNINGS;
#include <initializer_list>
TOML_ENABLE_WARNINGS;

//********  impl/node_view.hpp  ****************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_DISABLE_ARITHMETIC_WARNINGS;

TOML_NAMESPACE_START {
  template <typename ViewedType> class 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 node_view;

    mutable viewed_type* node_ = nullptr;

  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;

    TOML_NODISCARD_CTOR
    node_view(node_view&&) noexcept = default;

    node_view& operator=(const node_view&) & noexcept = default;

    node_view& operator=(node_view&&) & noexcept = default;

    TOML_PURE_INLINE_GETTER
    explicit operator bool() const noexcept { return node_ != nullptr; }

    TOML_PURE_INLINE_GETTER
    viewed_type* node() const noexcept { return node_; }

    TOML_PURE_GETTER
    node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }

    TOML_PURE_GETTER
    bool is_table() const noexcept { return node_ && node_->is_table(); }

    TOML_PURE_GETTER
    bool is_array() const noexcept { return node_ && node_->is_array(); }

    TOML_PURE_GETTER
    bool is_value() const noexcept { return node_ && node_->is_value(); }

    TOML_PURE_GETTER
    bool is_string() const noexcept { return node_ && node_->is_string(); }

    TOML_PURE_GETTER
    bool is_integer() const noexcept { return node_ && node_->is_integer(); }

    TOML_PURE_GETTER
    bool is_floating_point() const noexcept { return node_ && node_->is_floating_point(); }

    TOML_PURE_GETTER
    bool is_number() const noexcept { return node_ && node_->is_number(); }

    TOML_PURE_GETTER
    bool is_boolean() const noexcept { return node_ && node_->is_boolean(); }

    TOML_PURE_GETTER
    bool is_date() const noexcept { return node_ && node_->is_date(); }

    TOML_PURE_GETTER
    bool is_time() const noexcept { return node_ && node_->is_time(); }

    TOML_PURE_GETTER
    bool is_date_time() const noexcept { return node_ && node_->is_date_time(); }

    TOML_PURE_GETTER
    bool is_array_of_tables() const noexcept { return node_ && node_->is_array_of_tables(); }

    template <typename T> TOML_PURE_GETTER bool is() const noexcept {
      return node_ ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>() : false;
    }

    TOML_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);
    }

    TOML_NODISCARD
    bool is_homogeneous(node_type ntype) const noexcept { return node_ ? node_->is_homogeneous(ntype) : false; }

    template <typename ElemType = void> TOML_PURE_GETTER bool is_homogeneous() const noexcept {
      return node_ ? node_->template is_homogeneous<impl::unwrap_node<impl::remove_cvref<ElemType>>>() : false;
    }

    template <typename T> TOML_PURE_GETTER auto* as() const noexcept {
      return node_ ? node_->template as<T>() : nullptr;
    }

    TOML_PURE_GETTER
    auto* as_table() const noexcept { return as<table>(); }

    TOML_PURE_GETTER
    auto* as_array() const noexcept { return as<array>(); }

    TOML_PURE_GETTER
    auto* as_string() const noexcept { return as<std::string>(); }

    TOML_PURE_GETTER
    auto* as_integer() const noexcept { return as<int64_t>(); }

    TOML_PURE_GETTER
    auto* as_floating_point() const noexcept { return as<double>(); }

    TOML_PURE_GETTER
    auto* as_boolean() const noexcept { return as<bool>(); }

    TOML_PURE_GETTER
    auto* as_date() const noexcept { return as<date>(); }

    TOML_PURE_GETTER
    auto* as_time() const noexcept { return as<time>(); }

    TOML_PURE_GETTER
    auto* as_date_time() const noexcept { return as<date_time>(); }

    template <typename T> TOML_NODISCARD optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>) {
      if (node_)
        return node_->template value_exact<T>();
      return {};
    }

    template <typename T> TOML_NODISCARD optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>) {
      if (node_)
        return node_->template value<T>();
      return {};
    }

    template <typename T>
    TOML_NODISCARD auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>) {
      using namespace ::toml::impl;

      static_assert(
          !is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
          "Retrieving values as wide-character strings is only "
          "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."
      );

      if constexpr (is_wide_string<T>) {
#if TOML_ENABLE_WINDOWS_COMPAT

        if (node_)
          return node_->value_or(static_cast<T&&>(default_value));
        return std::wstring{static_cast<T&&>(default_value)};

#else

        static_assert(impl::always_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(static_cast<T&&>(default_value));
        if constexpr (std::is_pointer_v<value_type>)
          return value_type{default_value};
        else
          return static_cast<T&&>(default_value);
      }
    }

    template <typename T> TOML_PURE_INLINE_GETTER decltype(auto) ref() const noexcept {
      TOML_ASSERT_ASSUME(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
      return node_->template ref<T>();
    }

  private:
    template <typename Func>
    static constexpr bool visit_is_nothrow = noexcept(std::declval<viewed_type*>()->visit(std::declval<Func>()));

  public:
    template <typename Func> decltype(auto) visit(Func&& visitor) const noexcept(visit_is_nothrow<Func&&>) {
      using return_type = decltype(node_->visit(static_cast<Func&&>(visitor)));
      if (node_)
        return node_->visit(static_cast<Func&&>(visitor));
      if constexpr (!std::is_void_v<return_type>)
        return return_type{};
    }

  public:
    template <typename T>
    TOML_PURE_GETTER friend bool operator==(const node_view& lhs, const node_view<T>& rhs) noexcept {
      return impl::node_deep_equality(lhs.node_, rhs.node_);
    }

    template <typename T>
    TOML_PURE_GETTER friend bool operator!=(const node_view& lhs, const node_view<T>& rhs) noexcept {
      return !impl::node_deep_equality(lhs.node_, rhs.node_);
    }

    TOML_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&, );

    TOML_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>
    TOML_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>);

    TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
    TOML_NODISCARD
    friend bool operator==(const node_view& lhs, const T& rhs) noexcept(!impl::is_wide_string<T>) {
      static_assert(
          !impl::is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
          "Comparison with wide-character strings is only "
          "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."
      );

      if constexpr (impl::is_wide_string<T>) {
#if TOML_ENABLE_WINDOWS_COMPAT
        return lhs == impl::narrow(rhs);
#else
        static_assert(impl::always_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&, TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
    );

    template <typename T>
    TOML_NODISCARD friend bool
    operator==(const node_view& lhs, const std::initializer_list<T>& rhs) noexcept(!impl::is_wide_string<T>) {
      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>
    TOML_NODISCARD friend bool
    operator==(const node_view& lhs, const std::vector<T>& rhs) noexcept(!impl::is_wide_string<T>) {
      const auto arr = lhs.as<array>();
      return arr && *arr == rhs;
    }
    TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<T>&, template <typename T>);

    TOML_NODISCARD
    node_view operator[](std::string_view key) const noexcept {
      if (auto tbl = this->as_table())
        return node_view{tbl->get(key)};
      return {};
    }

    TOML_NODISCARD
    node_view operator[](const toml::path& path) const noexcept { return node_ ? node_->at_path(path) : node_view{}; }

    TOML_NODISCARD
    node_view at_path(std::string_view path) const noexcept { return node_ ? node_->at_path(path) : node_view{}; }

    TOML_NODISCARD
    node_view at_path(const toml::path& path) const noexcept { return node_ ? node_->at_path(path) : node_view{}; }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node_view operator[](std::wstring_view key) const {
      if (auto tbl = this->as_table())
        return node_view{tbl->get(key)};
      return {};
    }

    TOML_NODISCARD
    node_view at_path(std::wstring_view path) const { return node_ ? node_->at_path(path) : node_view{}; }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node_view operator[](size_t index) const noexcept {
      if (auto arr = this->as_array())
        return node_view{arr->get(index)};
      return {};
    }

#if TOML_ENABLE_FORMATTERS

    friend std::ostream& operator<<(std::ostream& os, const node_view& nv) {
      if (nv.node_)
        nv.node_->visit([&os](const auto& n) { os << n; });
      return os;
    }

#endif
  };

  template <typename T> node_view(const T&) -> node_view<const node>;

  template <typename T> node_view(const T*) -> node_view<const node>;

  template <typename T> node_view(T&) -> node_view<node>;

  template <typename T> node_view(T*) -> node_view<node>;
}
TOML_NAMESPACE_END;

TOML_NAMESPACE_START {
  inline node::operator node_view<node>() noexcept { return node_view<node>{this}; }

  inline node::operator node_view<const node>() const noexcept { return node_view<const node>{this}; }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/value.hpp  ********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_DISABLE_ARITHMETIC_WARNINGS;

// clang-format off

#if TOML_ENABLE_WINDOWS_COMPAT
	#define TOML_SA_VALUE_MESSAGE_WSTRING			TOML_SA_LIST_SEP "std::wstring"
#else
	#define TOML_SA_VALUE_MESSAGE_WSTRING
#endif
#if TOML_HAS_CHAR8
	#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 integral type"																\
	TOML_SA_LIST_SEP "any floating-point type"																\
	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

// clang-format on
TOML_IMPL_NAMESPACE_START {
  template <typename T, typename...> struct native_value_maker {
    template <typename... Args>
    TOML_NODISCARD static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>) {
      if constexpr (std::is_aggregate_v<T>)
        return T{static_cast<Args&&>(args)...};
      else
        return T(static_cast<Args&&>(args)...);
    }
  };

  template <typename T> struct native_value_maker<T, T> {
    template <typename U> TOML_NODISCARD TOML_ALWAYS_INLINE static U&& make(U&& val) noexcept {
      return static_cast<U&&>(val);
    }
  };

#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT

  struct string_maker {
    template <typename T> TOML_NODISCARD static std::string make(T&& arg) {
      using arg_type = std::decay_t<T>;
#if TOML_HAS_CHAR8
      if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>) {
        return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
      }
      if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>) {
        return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())), arg.length());
      }
#endif

#if TOML_ENABLE_WINDOWS_COMPAT
      if constexpr (is_wide_string<arg_type>) {
        return narrow(static_cast<T&&>(arg));
      }
#endif
    }
  };

#if TOML_HAS_CHAR8
  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 // TOML_HAS_CHAR8

#if TOML_ENABLE_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_ENABLE_WINDOWS_COMPAT

#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT

  template <typename T> TOML_CONST_GETTER 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)};
  }

  template <typename...> struct value_variadic_ctor_allowed : std::true_type {};

  template <typename T, typename... Args>
  struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type {};
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  template <typename ValueType> class value : 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> TOML_CONST_INLINE_GETTER 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;

  public:
    using value_type = ValueType;

    using value_arg = POXY_IMPLEMENTATION_DETAIL(
        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&>>
    );

    TOML_HIDDEN_CONSTRAINT(
        (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value), typename... Args
    )
    TOML_NODISCARD_CTOR
    explicit value(Args&&... args) noexcept(noexcept(
        value_type(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))
    ))
        : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...)) {
#if TOML_LIFETIME_HOOKS
      TOML_VALUE_CREATED;
#endif
    }

    TOML_NODISCARD_CTOR
    value(const value& other) noexcept //
        : node(other), val_{other.val_}, flags_{other.flags_} {
#if TOML_LIFETIME_HOOKS
      TOML_VALUE_CREATED;
#endif
    }

    TOML_NODISCARD_CTOR
    value(const value& other, value_flags flags) noexcept //
        : node(other), val_{other.val_}, flags_{flags == preserve_source_value_flags ? other.flags_ : flags} {
#if TOML_LIFETIME_HOOKS
      TOML_VALUE_CREATED;
#endif
    }

    TOML_NODISCARD_CTOR
    value(value&& other) noexcept //
        : node(std::move(other)), val_{std::move(other.val_)}, flags_{std::exchange(other.flags_, value_flags{})} {
#if TOML_LIFETIME_HOOKS
      TOML_VALUE_CREATED;
#endif
    }

    TOML_NODISCARD_CTOR
    value(value&& other, value_flags flags) noexcept //
        : node(std::move(other)), val_{std::move(other.val_)},
          flags_{flags == preserve_source_value_flags ? other.flags_ : flags} {
#if TOML_LIFETIME_HOOKS
      TOML_VALUE_CREATED;
#endif
      other.flags_ = {};
    }

    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_ = std::exchange(rhs.flags_, value_flags{});
      }
      return *this;
    }

#if TOML_LIFETIME_HOOKS
    ~value() noexcept { TOML_VALUE_DESTROYED; }
#endif

    TOML_CONST_INLINE_GETTER
    node_type type() const noexcept final { return impl::node_type_of<value_type>; }

    TOML_PURE_GETTER
    bool is_homogeneous(node_type ntype) const noexcept final {
      return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
    }

    TOML_PURE_GETTER
    bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final {
      if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) {
        first_nonmatch = this;
        return false;
      }
      return true;
    }

    TOML_PURE_GETTER
    bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final {
      if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) {
        first_nonmatch = this;
        return false;
      }
      return true;
    }

    template <typename ElemType = void> TOML_PURE_GETTER bool is_homogeneous() const noexcept {
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
      static_assert(
          std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
          "The template type argument of value::is_homogeneous() must be void or one "
          "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
      );

      if constexpr (std::is_void_v<type>)
        return true;
      else
        return impl::node_type_of<type> == impl::node_type_of<value_type>;
    }
    TOML_CONST_INLINE_GETTER
    bool is_table() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_array() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_array_of_tables() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_value() const noexcept final { return true; }

    TOML_CONST_INLINE_GETTER
    bool is_string() const noexcept final { return std::is_same_v<value_type, std::string>; }

    TOML_CONST_INLINE_GETTER
    bool is_integer() const noexcept final { return std::is_same_v<value_type, int64_t>; }

    TOML_CONST_INLINE_GETTER
    bool is_floating_point() const noexcept final { return std::is_same_v<value_type, double>; }

    TOML_CONST_INLINE_GETTER
    bool is_number() const noexcept final { return impl::is_one_of<value_type, int64_t, double>; }

    TOML_CONST_INLINE_GETTER
    bool is_boolean() const noexcept final { return std::is_same_v<value_type, bool>; }

    TOML_CONST_INLINE_GETTER
    bool is_date() const noexcept final { return std::is_same_v<value_type, date>; }

    TOML_CONST_INLINE_GETTER
    bool is_time() const noexcept final { return std::is_same_v<value_type, time>; }

    TOML_CONST_INLINE_GETTER
    bool is_date_time() const noexcept final { return std::is_same_v<value_type, date_time>; }

    TOML_CONST_INLINE_GETTER
    table* as_table() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    array* as_array() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    value<std::string>* as_string() noexcept final { return as_value<std::string>(this); }

    TOML_CONST_INLINE_GETTER
    value<int64_t>* as_integer() noexcept final { return as_value<int64_t>(this); }

    TOML_CONST_INLINE_GETTER
    value<double>* as_floating_point() noexcept final { return as_value<double>(this); }

    TOML_CONST_INLINE_GETTER
    value<bool>* as_boolean() noexcept final { return as_value<bool>(this); }

    TOML_CONST_INLINE_GETTER
    value<date>* as_date() noexcept final { return as_value<date>(this); }

    TOML_CONST_INLINE_GETTER
    value<time>* as_time() noexcept final { return as_value<time>(this); }

    TOML_CONST_INLINE_GETTER
    value<date_time>* as_date_time() noexcept final { return as_value<date_time>(this); }

    TOML_CONST_INLINE_GETTER
    const table* as_table() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const array* as_array() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const value<std::string>* as_string() const noexcept final { return as_value<std::string>(this); }

    TOML_CONST_INLINE_GETTER
    const value<int64_t>* as_integer() const noexcept final { return as_value<int64_t>(this); }

    TOML_CONST_INLINE_GETTER
    const value<double>* as_floating_point() const noexcept final { return as_value<double>(this); }

    TOML_CONST_INLINE_GETTER
    const value<bool>* as_boolean() const noexcept final { return as_value<bool>(this); }

    TOML_CONST_INLINE_GETTER
    const value<date>* as_date() const noexcept final { return as_value<date>(this); }

    TOML_CONST_INLINE_GETTER
    const value<time>* as_time() const noexcept final { return as_value<time>(this); }

    TOML_CONST_INLINE_GETTER
    const value<date_time>* as_date_time() const noexcept final { return as_value<date_time>(this); }

    TOML_PURE_INLINE_GETTER
    value_type& get() & noexcept { return val_; }

    TOML_PURE_INLINE_GETTER
    value_type&& get() && noexcept { return static_cast<value_type&&>(val_); }

    TOML_PURE_INLINE_GETTER
    const value_type& get() const& noexcept { return val_; }

    TOML_PURE_INLINE_GETTER
    const value_type&& get() const&& noexcept { return static_cast<const value_type&&>(val_); }

    TOML_PURE_INLINE_GETTER
    value_type& operator*() & noexcept { return val_; }

    TOML_PURE_INLINE_GETTER
    value_type&& operator*() && noexcept { return static_cast<value_type&&>(val_); }

    TOML_PURE_INLINE_GETTER
    const value_type& operator*() const& noexcept { return val_; }

    TOML_PURE_INLINE_GETTER
    const value_type&& operator*() const&& noexcept { return static_cast<const value_type&&>(val_); }

    TOML_PURE_INLINE_GETTER
    explicit operator value_type&() & noexcept { return val_; }

    TOML_PURE_INLINE_GETTER
    explicit operator value_type&&() && noexcept { return static_cast<value_type&&>(val_); }

    TOML_PURE_INLINE_GETTER
    explicit operator const value_type&() const& noexcept { return val_; }

    TOML_PURE_INLINE_GETTER
    explicit operator const value_type&&() && noexcept { return static_cast<const value_type&&>(val_); }

    TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
    TOML_PURE_INLINE_GETTER
    value_type* operator->() noexcept { return &val_; }

    TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
    TOML_PURE_INLINE_GETTER
    const value_type* operator->() const noexcept { return &val_; }

    TOML_NODISCARD
    value_flags flags() const noexcept { return flags_; }

    value& flags(value_flags new_flags) noexcept {
      flags_ = new_flags;
      return *this;
    }

    value& operator=(value_arg rhs) noexcept {
      if constexpr (std::is_same_v<value_type, std::string>)
        val_.assign(rhs);
      else
        val_ = rhs;
      return *this;
    }

    TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type)
    value& operator=(std::string&& rhs) noexcept {
      val_ = std::move(rhs);
      return *this;
    }

    TOML_PURE_GETTER
    friend bool operator==(const value& lhs, value_arg rhs) noexcept {
      if constexpr (std::is_same_v<value_type, double>) {
        const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan;
        const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan;
        if (lhs_nan != rhs_nan)
          return false;
        if (lhs_nan)
          return true;
      }
      return lhs.val_ == rhs;
    }
    TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, );

    TOML_PURE_GETTER
    friend bool operator<(const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; }

    TOML_PURE_GETTER
    friend bool operator<(value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; }

    TOML_PURE_GETTER
    friend bool operator<=(const value& lhs, value_arg rhs) noexcept { return lhs.val_ <= rhs; }

    TOML_PURE_GETTER
    friend bool operator<=(value_arg lhs, const value& rhs) noexcept { return lhs <= rhs.val_; }

    TOML_PURE_GETTER
    friend bool operator>(const value& lhs, value_arg rhs) noexcept { return lhs.val_ > rhs; }

    TOML_PURE_GETTER
    friend bool operator>(value_arg lhs, const value& rhs) noexcept { return lhs > rhs.val_; }

    TOML_PURE_GETTER
    friend bool operator>=(const value& lhs, value_arg rhs) noexcept { return lhs.val_ >= rhs; }

    TOML_PURE_GETTER
    friend bool operator>=(value_arg lhs, const value& rhs) noexcept { return lhs >= rhs.val_; }

    template <typename T> TOML_PURE_GETTER 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>
    TOML_PURE_INLINE_GETTER friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept {
      return !(lhs == rhs);
    }

    template <typename T> TOML_PURE_GETTER 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> TOML_PURE_GETTER 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> TOML_PURE_GETTER 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> TOML_PURE_GETTER 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>;
    }

#if TOML_ENABLE_FORMATTERS

    friend std::ostream& operator<<(std::ostream& lhs, const value& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }

#endif
  };

  template <typename T> value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
  template <typename T> value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>;

  template <typename T>
  TOML_NODISCARD inline decltype(auto) node::get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>) {
    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_ENABLE_WINDOWS_COMPAT
        return widen(str);
#else
        static_assert(always_false<T>, "Evaluated unreachable branch!");
#endif
      }

#if TOML_HAS_CHAR8

      // 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(always_false<T>, "Evaluated unreachable branch!");

#endif
    } else
      return static_cast<T>(*ref_cast<native_type_of<T>>());
  }

  template <typename T>
  TOML_NODISCARD inline optional<T> node::value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>) {
    using namespace impl;

    static_assert(
        !is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
        "Retrieving values as wide-character strings with node::value_exact() is only "
        "supported on Windows with TOML_ENABLE_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>
  TOML_NODISCARD inline optional<T> node::value() const noexcept(impl::value_retrieval_is_nothrow<T>) {
    using namespace impl;

    static_assert(
        !is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
        "Retrieving values as wide-character strings with node::value() is only "
        "supported on Windows with TOML_ENABLE_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 (impl::fpclassify(val) == fp_class::ok
                && (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 (impl::fpclassify(val) == fp_class::ok && 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>
  TOML_NODISCARD inline auto node::value_or(T && default_value) const noexcept(impl::value_retrieval_is_nothrow<T>) {
    using namespace impl;

    static_assert(
        !is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
        "Retrieving values as wide-character strings with node::value_or() is only "
        "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."
    );

    if constexpr (is_wide_string<T>) {
#if TOML_ENABLE_WINDOWS_COMPAT

      if (type() == node_type::string)
        return widen(*ref_cast<std::string>());
      return std::wstring{static_cast<T&&>(default_value)};

#else

      static_assert(always_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>;

      // clang-format off

			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_ENABLE_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 integral type"
				TOML_SA_LIST_SEP "any floating-point type"
				TOML_SA_LIST_END

				TOML_SA_LIST_NXT "A compatible view type"
				TOML_SA_LIST_BEG "std::string_view"
				#if TOML_HAS_CHAR8
				TOML_SA_LIST_SEP "std::u8string_view"
				#endif
				#if TOML_ENABLE_WINDOWS_COMPAT
				TOML_SA_LIST_SEP "std::wstring_view"
				#endif
				TOML_SA_LIST_SEP "const char*"
				#if TOML_HAS_CHAR8
				TOML_SA_LIST_SEP "const char8_t*"
				#endif
				#if TOML_ENABLE_WINDOWS_COMPAT
				TOML_SA_LIST_SEP "const wchar_t*"
				#endif
				TOML_SA_LIST_END
			);

      // clang-format on

      // 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 static_cast<T&&>(default_value);
      }
    }
  }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/make_node.hpp  ****************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  template <typename T>
  TOML_NODISCARD TOML_ATTR(returns_nonnull) auto* make_node_impl_specialized(
      T && val, [[maybe_unused]] value_flags flags
  ) {
    using unwrapped_type = unwrap_node<remove_cvref<T>>;
    static_assert(!std::is_same_v<unwrapped_type, node>);
    static_assert(!is_node_view<unwrapped_type>);

    // arrays + tables - invoke copy/move ctor
    if constexpr (is_one_of<unwrapped_type, array, table>) {
      return new unwrapped_type(static_cast<T&&>(val));
    }

    // values
    else {
      using native_type = native_type_of<unwrapped_type>;
      using value_type = value<native_type>;

      value_type* out;

      // copy/move ctor
      if constexpr (std::is_same_v<remove_cvref<T>, value_type>) {
        out = new value_type{static_cast<T&&>(val), flags};
      }

      // creating from raw value
      else {
        static_assert(
            !is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
            "Instantiating values from wide-character strings is only "
            "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."
        );

        if constexpr (!is_losslessly_convertible_to_native<unwrapped_type>) {
          if constexpr (std::is_same_v<native_type, int64_t>)
            static_assert(always_false<T>, "Integral value initializers must be losslessly convertible to int64_t");
          else if constexpr (std::is_same_v<native_type, double>)
            static_assert(
                always_false<T>, "Floating-point value initializers must be losslessly convertible to double"
            );
          else
            static_assert(
                always_false<T>, "Value initializers must be losslessly convertible to one of the TOML value types"
            );
        }

        if constexpr (is_wide_string<T>) {
#if TOML_ENABLE_WINDOWS_COMPAT
          out = new value_type{narrow(static_cast<T&&>(val))};
#else
          static_assert(always_false<T>, "Evaluated unreachable branch!");
#endif
        } else
          out = new value_type{static_cast<T&&>(val)};

        if (flags != preserve_source_value_flags)
          out->flags(flags);
      }

      return out;
    }
  }

  template <typename T> TOML_NODISCARD auto* make_node_impl(T && val, value_flags flags = preserve_source_value_flags) {
    using unwrapped_type = unwrap_node<remove_cvref<T>>;
    if constexpr (std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>) {
      if constexpr (is_node_view<unwrapped_type>) {
        if (!val)
          return static_cast<toml::node*>(nullptr);
      }

      return static_cast<T&&>(val).visit([flags](auto&& concrete) {
        return static_cast<toml::node*>(make_node_impl_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
      });
    } else
      return make_node_impl_specialized(static_cast<T&&>(val), flags);
  }

  template <typename T>
  TOML_NODISCARD auto* make_node_impl(inserter<T> && val, value_flags flags = preserve_source_value_flags) {
    return make_node_impl(static_cast<T&&>(val.value), flags);
  }

  template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
  struct inserted_type_of_ {
    using type = std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
  };

  template <typename T> struct inserted_type_of_<inserter<T>, false> {
    using type = typename inserted_type_of_<remove_cvref<T>>::type;
  };

  template <typename T> struct inserted_type_of_<T, false> {
    using type = void;
  };

  template <typename T> TOML_NODISCARD node_ptr make_node(T && val, value_flags flags = preserve_source_value_flags) {
    return node_ptr{make_node_impl(static_cast<T&&>(val), flags)};
  }

  template <typename... T> struct emplaced_type_of_ {
    using type = void;
  };

  template <typename T> struct emplaced_type_of_<T> {
    using type = std::conditional_t<
        is_one_of<T, node, node_view<node>, node_view<const node>>, void, typename inserted_type_of_<T>::type>;
  };

  template <typename T> struct emplaced_type_of_<inserter<T>> {
    using type = typename emplaced_type_of_<remove_cvref<T>>::type;
  };

  template <typename... T> using emplaced_type_of = typename emplaced_type_of_<remove_cvref<T>...>::type;
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  template <typename T>
  using inserted_type_of = POXY_IMPLEMENTATION_DETAIL(typename impl::inserted_type_of_<impl::remove_cvref<T>>::type);
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/array.hpp  ********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
#if TOML_GCC && TOML_GCC <= 7
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1
#else
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0
#endif
#endif

#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE                                                                  \
  "If you're seeing this error it's because you're using one of toml++'s for_each() functions on a compiler with "     \
  "known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or bool-convertible) value from the "    \
  "for_each() callable causes spurious compilation failures, while returning nothing (void) works fine. "              \
  "If you believe this message is incorrect for your compiler, you can try your luck by #defining "                    \
  "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know at "                   \
  "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for early-exiting from "   \
  "for_each(), you can suppress this error by #defining TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED "           \
  "and moving on with your life."
#endif

TOML_IMPL_NAMESPACE_START {
  template <bool IsConst> class TOML_TRIVIAL_ABI array_iterator {
  private:
    template <bool> friend class array_iterator;

    using mutable_vector_iterator = std::vector<node_ptr>::iterator;
    using const_vector_iterator = std::vector<node_ptr>::const_iterator;
    using vector_iterator = std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;

    mutable vector_iterator iter_;

  public:
    using value_type = std::conditional_t<IsConst, const node, node>;
    using reference = value_type&;
    using pointer = value_type*;
    using difference_type = ptrdiff_t;
    using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;

    TOML_NODISCARD_CTOR
    array_iterator() noexcept = default;

    TOML_NODISCARD_CTOR
    explicit array_iterator(mutable_vector_iterator iter) noexcept //
        : iter_{iter} {}

    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
    TOML_NODISCARD_CTOR
    explicit array_iterator(const_vector_iterator iter) noexcept //
        : iter_{iter} {}

    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
    TOML_NODISCARD_CTOR
    array_iterator(const array_iterator<false>& other) noexcept //
        : iter_{other.iter_} {}

    TOML_NODISCARD_CTOR
    array_iterator(const array_iterator&) noexcept = default;

    array_iterator& operator=(const array_iterator&) noexcept = default;

    array_iterator& operator++() noexcept // ++pre
    {
      ++iter_;
      return *this;
    }

    array_iterator operator++(int) noexcept // post++
    {
      array_iterator out{iter_};
      ++iter_;
      return out;
    }

    array_iterator& operator--() noexcept // --pre
    {
      --iter_;
      return *this;
    }

    array_iterator operator--(int) noexcept // post--
    {
      array_iterator out{iter_};
      --iter_;
      return out;
    }

    TOML_PURE_INLINE_GETTER
    reference operator*() const noexcept { return *iter_->get(); }

    TOML_PURE_INLINE_GETTER
    pointer operator->() const noexcept { return iter_->get(); }

    TOML_PURE_INLINE_GETTER
    explicit operator const vector_iterator&() const noexcept { return iter_; }

    TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
    TOML_PURE_INLINE_GETTER
    explicit operator const const_vector_iterator() const noexcept { return iter_; }

    array_iterator& operator+=(ptrdiff_t rhs) noexcept {
      iter_ += rhs;
      return *this;
    }

    array_iterator& operator-=(ptrdiff_t rhs) noexcept {
      iter_ -= rhs;
      return *this;
    }

    TOML_NODISCARD
    friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept {
      return array_iterator{lhs.iter_ + rhs};
    }

    TOML_NODISCARD
    friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept {
      return array_iterator{rhs.iter_ + lhs};
    }

    TOML_NODISCARD
    friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept {
      return array_iterator{lhs.iter_ - rhs};
    }

    TOML_PURE_INLINE_GETTER
    friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ - rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ == rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ != rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ < rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ <= rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ > rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept {
      return lhs.iter_ >= rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    reference operator[](ptrdiff_t idx) const noexcept { return *(iter_ + idx)->get(); }
  };

  struct array_init_elem {
    mutable node_ptr value;

    template <typename T>
    TOML_NODISCARD_CTOR array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) //
        : value{make_node(static_cast<T&&>(val), flags)} {}
  };
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);

  using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);

  class TOML_EXPORTED_CLASS array : public node {
  private:
    using vector_type = std::vector<impl::node_ptr>;
    using vector_iterator = typename vector_type::iterator;
    using const_vector_iterator = typename vector_type::const_iterator;
    vector_type elems_;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    array(const impl::array_init_elem*, const impl::array_init_elem*);

    TOML_NODISCARD_CTOR
    array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
        : array{elems.begin(), elems.end()} {}

    TOML_EXPORTED_MEMBER_FUNCTION
    void preinsertion_resize(size_t idx, size_t count);

    TOML_EXPORTED_MEMBER_FUNCTION
    void insert_at_back(impl::node_ptr&&);

    TOML_EXPORTED_MEMBER_FUNCTION
    vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&);

    template <typename T> void emplace_back_if_not_empty_view(T&& val, value_flags flags) {
      if constexpr (is_node_view<T>) {
        if (!val)
          return;
      }
      insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
    }

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    size_t total_leaf_count() const noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    void flatten_child(array&& child, size_t& dest_index) noexcept;

  public:
    using value_type = node;
    using size_type = size_t;
    using difference_type = ptrdiff_t;
    using reference = node&;
    using const_reference = const node&;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    array() noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    ~array() noexcept;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    array(const array&);

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    array(array&& other) noexcept;

    TOML_CONSTRAINED_TEMPLATE(
        (sizeof...(ElemTypes) > 0 || !std::is_same_v<impl::remove_cvref<ElemType>, array>), typename ElemType,
        typename... ElemTypes
    )
    TOML_NODISCARD_CTOR
    explicit array(ElemType&& val, ElemTypes&&... vals)
        : array{
              std::false_type{},
              std::initializer_list<impl::array_init_elem>{
                  static_cast<ElemType&&>(val), static_cast<ElemTypes&&>(vals)...
              }
          } {}

    TOML_EXPORTED_MEMBER_FUNCTION
    array& operator=(const array&);

    TOML_EXPORTED_MEMBER_FUNCTION
    array& operator=(array&& rhs) noexcept;

    TOML_CONST_INLINE_GETTER
    node_type type() const noexcept final { return node_type::array; }

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    bool is_homogeneous(node_type ntype) const noexcept final;

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;

    template <typename ElemType = void> TOML_PURE_GETTER bool is_homogeneous() const noexcept {
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
      static_assert(
          std::is_void_v<type> || toml::is_value<type> || toml::is_container<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>);
    }
    TOML_CONST_INLINE_GETTER
    bool is_table() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_array() const noexcept final { return true; }

    TOML_PURE_GETTER
    bool is_array_of_tables() const noexcept final { return is_homogeneous(node_type::table); }

    TOML_CONST_INLINE_GETTER
    bool is_value() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_string() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_integer() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_floating_point() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_number() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_boolean() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_date() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_time() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_date_time() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    table* as_table() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    array* as_array() noexcept final { return this; }

    TOML_CONST_INLINE_GETTER
    toml::value<std::string>* as_string() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<int64_t>* as_integer() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<double>* as_floating_point() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<bool>* as_boolean() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<date>* as_date() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<time>* as_time() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<date_time>* as_date_time() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const table* as_table() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const array* as_array() const noexcept final { return this; }

    TOML_CONST_INLINE_GETTER
    const toml::value<std::string>* as_string() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<int64_t>* as_integer() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<double>* as_floating_point() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<bool>* as_boolean() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<date>* as_date() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<time>* as_time() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<date_time>* as_date_time() const noexcept final { return nullptr; }

    TOML_PURE_INLINE_GETTER
    node* get(size_t index) noexcept { return index < elems_.size() ? elems_[index].get() : nullptr; }

    TOML_PURE_INLINE_GETTER
    const node* get(size_t index) const noexcept { return const_cast<array&>(*this).get(index); }

    template <typename ElemType> TOML_NODISCARD impl::wrap_node<ElemType>* get_as(size_t index) noexcept {
      if (auto val = get(index))
        return val->template as<ElemType>();
      return nullptr;
    }

    template <typename ElemType> TOML_NODISCARD const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept {
      return const_cast<array&>(*this).template get_as<ElemType>(index);
    }

    using node::operator[]; // inherit operator[toml::path]
    TOML_NODISCARD
    node& operator[](size_t index) noexcept { return *elems_[index]; }

    TOML_NODISCARD
    const node& operator[](size_t index) const noexcept { return *elems_[index]; }

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node& at(size_t index);

    TOML_NODISCARD
    const node& at(size_t index) const { return const_cast<array&>(*this).at(index); }

    TOML_NODISCARD
    node& front() noexcept { return *elems_.front(); }

    TOML_NODISCARD
    const node& front() const noexcept { return *elems_.front(); }

    TOML_NODISCARD
    node& back() noexcept { return *elems_.back(); }

    TOML_NODISCARD
    const node& back() const noexcept { return *elems_.back(); }

    using iterator = array_iterator;

    using const_iterator = const_array_iterator;

    TOML_NODISCARD
    iterator begin() noexcept { return iterator{elems_.begin()}; }

    TOML_NODISCARD
    const_iterator begin() const noexcept { return const_iterator{elems_.cbegin()}; }

    TOML_NODISCARD
    const_iterator cbegin() const noexcept { return const_iterator{elems_.cbegin()}; }

    TOML_NODISCARD
    iterator end() noexcept { return iterator{elems_.end()}; }

    TOML_NODISCARD
    const_iterator end() const noexcept { return const_iterator{elems_.cend()}; }

    TOML_NODISCARD
    const_iterator cend() const noexcept { return const_iterator{elems_.cend()}; }

  private:
    template <typename T, typename Array>
    using for_each_elem_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;

    template <typename Func, typename Array, typename T>
    using can_for_each = std::disjunction<
        std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
        std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
        std::is_invocable<Func, for_each_elem_ref<T, Array>>>;

    template <typename Func, typename Array, typename T>
    using can_for_each_nothrow = std::conditional_t<
        // first form
        std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
        std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
        std::conditional_t<
            // second form
            std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
            std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
            std::conditional_t<
                // third form
                std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
                std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>, std::false_type>>>;

    template <typename Func, typename Array>
    using can_for_each_any = std::disjunction<
        can_for_each<Func, Array, table>, can_for_each<Func, Array, array>, can_for_each<Func, Array, std::string>,
        can_for_each<Func, Array, int64_t>, can_for_each<Func, Array, double>, can_for_each<Func, Array, bool>,
        can_for_each<Func, Array, date>, can_for_each<Func, Array, time>, can_for_each<Func, Array, date_time>>;

    template <typename Func, typename Array, typename T>
    using for_each_is_nothrow_one = std::disjunction<
        std::negation<can_for_each<Func, Array, T>>, //
        can_for_each_nothrow<Func, Array, T>>;

    template <typename Func, typename Array>
    using for_each_is_nothrow = std::conjunction<
        for_each_is_nothrow_one<Func, Array, table>, for_each_is_nothrow_one<Func, Array, array>,
        for_each_is_nothrow_one<Func, Array, std::string>, for_each_is_nothrow_one<Func, Array, int64_t>,
        for_each_is_nothrow_one<Func, Array, double>, for_each_is_nothrow_one<Func, Array, bool>,
        for_each_is_nothrow_one<Func, Array, date>, for_each_is_nothrow_one<Func, Array, time>,
        for_each_is_nothrow_one<Func, Array, date_time>>;

    template <typename Func, typename Array>
    static void do_for_each(Func&& visitor, Array&& arr) //
        noexcept(for_each_is_nothrow<Func&&, Array&&>::value) {
      static_assert(
          can_for_each_any<Func&&, Array&&>::value,
          "TOML array for_each visitors must be invocable for at least one of the toml::node "
          "specializations:" TOML_SA_NODE_TYPE_LIST
      );

      for (size_t i = 0; i < arr.size(); i++) {
        using node_ref = impl::copy_cvref<toml::node, Array&&>;
        static_assert(std::is_reference_v<node_ref>);

#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN

#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
        static_assert(
            impl::always_false<Func, Array, node_ref>, //
            TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
        );
#endif

        static_cast<node_ref>(static_cast<Array&&>(arr)[i])
            .visit([&]([[maybe_unused]] auto&& elem) //
                   noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value) {
                     using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
                     static_assert(std::is_reference_v<elem_ref>);

                     // func(elem, i)
                     if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>) {
                       static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
                     }

                     // func(i, elem)
                     else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>) {
                       static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
                     }

                     // func(elem)
                     else if constexpr (std::is_invocable_v<Func&&, elem_ref>) {
                       static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
                     }
                   });

#else
        const auto keep_going =
            static_cast<node_ref>(static_cast<Array&&>(arr)[i])
                .visit([&]([[maybe_unused]] auto&& elem) //
                       noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value) {
                         using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
                         static_assert(std::is_reference_v<elem_ref>);

                         // func(elem, i)
                         if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>) {
                           using return_type = decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));

                           if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
                             return static_cast<bool>(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
                           } else {
                             static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
                             return true;
                           }
                         }

                         // func(i, elem)
                         else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>) {
                           using return_type = decltype(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));

                           if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
                             return static_cast<bool>(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
                           } else {
                             static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
                             return true;
                           }
                         }

                         // func(elem)
                         else if constexpr (std::is_invocable_v<Func&&, elem_ref>) {
                           using return_type = decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));

                           if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
                             return static_cast<bool>(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
                           } else {
                             static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
                             return true;
                           }
                         }

                         // visitor not compatible with this particular type
                         else
                           return true;
                       });

        if (!keep_going)
          return;
#endif
      }
    }

  public:
    template <typename Func>
    array& for_each(Func&& visitor) & //
        noexcept(for_each_is_nothrow<Func&&, array&>::value) {
      do_for_each(static_cast<Func&&>(visitor), *this);
      return *this;
    }

    template <typename Func>
    array&& for_each(Func&& visitor) && //
        noexcept(for_each_is_nothrow<Func&&, array&&>::value) {
      do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
      return static_cast<array&&>(*this);
    }

    template <typename Func>
    const array& for_each(Func&& visitor) const& //
        noexcept(for_each_is_nothrow<Func&&, const array&>::value) {
      do_for_each(static_cast<Func&&>(visitor), *this);
      return *this;
    }

    template <typename Func>
    const array&& for_each(Func&& visitor) const&& //
        noexcept(for_each_is_nothrow<Func&&, const array&&>::value) {
      do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
      return static_cast<const array&&>(*this);
    }

    TOML_NODISCARD
    bool empty() const noexcept { return elems_.empty(); }

    TOML_NODISCARD
    size_t size() const noexcept { return elems_.size(); }

    TOML_NODISCARD
    size_t max_size() const noexcept { return elems_.max_size(); }

    TOML_NODISCARD
    size_t capacity() const noexcept { return elems_.capacity(); }

    TOML_EXPORTED_MEMBER_FUNCTION
    void reserve(size_t new_capacity);

    TOML_EXPORTED_MEMBER_FUNCTION
    void shrink_to_fit();

    TOML_EXPORTED_MEMBER_FUNCTION
    void truncate(size_t new_size);

    template <typename ElemType>
    void
    resize(size_t new_size, ElemType&& default_init_val, value_flags default_init_flags = preserve_source_value_flags) {
      static_assert(
          !is_node_view<ElemType>,
          "The default element type argument to toml::array::resize may not be toml::node_view."
      );

      if (!new_size)
        clear();
      else if (new_size > elems_.size())
        insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
      else
        truncate(new_size);
    }

    TOML_EXPORTED_MEMBER_FUNCTION
    iterator erase(const_iterator pos) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    iterator erase(const_iterator first, const_iterator last) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    array& flatten() &;

    array&& flatten() && { return static_cast<toml::array&&>(this->flatten()); }

    TOML_EXPORTED_MEMBER_FUNCTION
    array& prune(bool recursive = true) & noexcept;

    array&& prune(bool recursive = true) && noexcept { return static_cast<toml::array&&>(this->prune(recursive)); }

    TOML_EXPORTED_MEMBER_FUNCTION
    void pop_back() noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    void clear() noexcept;

    template <typename ElemType>
    iterator insert(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags) {
      if constexpr (is_node_view<ElemType>) {
        if (!val)
          return end();
      }
      return iterator{insert_at(const_vector_iterator{pos}, impl::make_node(static_cast<ElemType&&>(val), flags))};
    }

    template <typename ElemType>
    iterator insert(const_iterator pos, size_t count, ElemType&& val, value_flags flags = preserve_source_value_flags) {
      if constexpr (is_node_view<ElemType>) {
        if (!val)
          return end();
      }
      switch (count) {
      case 0:
        return iterator{elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
      case 1:
        return insert(pos, static_cast<ElemType&&>(val), flags);
      default: {
        const auto start_idx = static_cast<size_t>(const_vector_iterator{pos} - elems_.cbegin());
        preinsertion_resize(start_idx, count);
        size_t i = start_idx;
        for (size_t e = start_idx + count - 1u; i < e; i++)
          elems_[i] = impl::make_node(val, flags);

        elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
        return iterator{elems_.begin() + static_cast<ptrdiff_t>(start_idx)};
      }
      }
    }

    template <typename Iter>
    iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = preserve_source_value_flags) {
      const auto distance = std::distance(first, last);
      if (distance <= 0)
        return iterator{elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
      else {
        auto count = distance;
        using deref_type = decltype(*first);
        if constexpr (is_node_view<deref_type>) {
          for (auto it = first; it != last; it++)
            if (!(*it))
              count--;
          if (!count)
            return iterator{elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin())};
        }
        const auto start_idx = static_cast<size_t>(const_vector_iterator{pos} - elems_.cbegin());
        preinsertion_resize(start_idx, static_cast<size_t>(count));
        size_t i = start_idx;
        for (auto it = first; it != last; it++) {
          if constexpr (is_node_view<deref_type>) {
            if (!(*it))
              continue;
          }
          if constexpr (std::is_rvalue_reference_v<deref_type>)
            elems_[i++] = impl::make_node(std::move(*it), flags);
          else
            elems_[i++] = impl::make_node(*it, flags);
        }
        return iterator{elems_.begin() + static_cast<ptrdiff_t>(start_idx)};
      }
    }

    template <typename ElemType>
    iterator
    insert(const_iterator pos, std::initializer_list<ElemType> ilist, value_flags flags = preserve_source_value_flags) {
      return insert(pos, ilist.begin(), ilist.end(), flags);
    }

    template <typename ElemType = void, typename... Args> iterator emplace(const_iterator pos, Args&&... args) {
      using raw_elem_type = impl::remove_cvref<ElemType>;
      using elem_type = std::conditional_t<
          std::is_void_v<raw_elem_type>, //
          impl::emplaced_type_of<Args&&...>, raw_elem_type>;

      using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
      static_assert(
          impl::is_native<type> || impl::is_one_of<type, table, array>,
          "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
      );

      return iterator{
          insert_at(const_vector_iterator{pos}, impl::node_ptr{new impl::wrap_node<type>{static_cast<Args&&>(args)...}})
      };
    }

    template <typename ElemType>
    iterator replace(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags) {
      TOML_ASSERT(pos >= cbegin() && pos < cend());

      if constexpr (is_node_view<ElemType>) {
        if (!val)
          return end();
      }

      const auto it = elems_.begin() + (const_vector_iterator{pos} - elems_.cbegin());
      *it = impl::make_node(static_cast<ElemType&&>(val), flags);
      return iterator{it};
    }

    template <typename ElemType> void push_back(ElemType&& val, value_flags flags = preserve_source_value_flags) {
      emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
    }

    template <typename ElemType = void, typename... Args> decltype(auto) emplace_back(Args&&... args) {
      using raw_elem_type = impl::remove_cvref<ElemType>;
      using elem_type = std::conditional_t<
          std::is_void_v<raw_elem_type>, //
          impl::emplaced_type_of<Args&&...>, raw_elem_type>;

      static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
          && sizeof...(Args) == 1u                                                      //
          && impl::first_is_same<impl::node_ptr&&, Args&&...>;

      using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;

      static_assert(
          moving_node_ptr                                       //
              || impl::is_native<unwrapped_type>                //
              || impl::is_one_of<unwrapped_type, table, array>, //
          "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
      );

      if constexpr (moving_node_ptr) {
        insert_at_back(static_cast<Args&&>(args)...);
        return *elems_.back();
      } else {
        auto ptr = new impl::wrap_node<unwrapped_type>{static_cast<Args&&>(args)...};
        insert_at_back(impl::node_ptr{ptr});
        return *ptr;
      }
    }

  private:
    TOML_NODISCARD
    TOML_EXPORTED_STATIC_FUNCTION
    static bool TOML_CALLCONV equal(const array&, const array&) noexcept;

    template <typename T> TOML_NODISCARD static bool equal_to_container(const array& lhs, const T& rhs) noexcept {
      using element_type = std::remove_const_t<typename T::value_type>;
      static_assert(
          impl::is_losslessly_convertible_to_native<element_type>,
          "Container element type must be losslessly convertible one of the native TOML value types"
      );

      if (lhs.size() != rhs.size())
        return false;
      if (rhs.size() == 0u)
        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;
    }

  public:
    TOML_NODISCARD
    friend bool operator==(const array& lhs, const array& rhs) noexcept { return equal(lhs, rhs); }

    TOML_NODISCARD
    friend bool operator!=(const array& lhs, const array& rhs) noexcept { return !equal(lhs, rhs); }

    template <typename T>
    TOML_NODISCARD friend bool operator==(const array& lhs, const std::initializer_list<T>& rhs) noexcept {
      return equal_to_container(lhs, rhs);
    }
    TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>);

    template <typename T> TOML_NODISCARD friend bool operator==(const array& lhs, const std::vector<T>& rhs) noexcept {
      return equal_to_container(lhs, rhs);
    }
    TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>);

#if TOML_ENABLE_FORMATTERS

    friend std::ostream& operator<<(std::ostream& lhs, const array& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }

#endif
  };
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/key.hpp  **********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  class key {
  private:
    std::string key_;
    source_region source_;

  public:
    TOML_NODISCARD_CTOR
    key() noexcept = default;

    TOML_NODISCARD_CTOR
    explicit key(std::string_view k, source_region&& src = {}) //
        : key_{k}, source_{std::move(src)} {}

    TOML_NODISCARD_CTOR
    explicit key(std::string_view k, const source_region& src) //
        : key_{k}, source_{src} {}

    TOML_NODISCARD_CTOR
    explicit key(std::string&& k, source_region&& src = {}) noexcept //
        : key_{std::move(k)}, source_{std::move(src)} {}

    TOML_NODISCARD_CTOR
    explicit key(std::string&& k, const source_region& src) noexcept //
        : key_{std::move(k)}, source_{src} {}

    TOML_NODISCARD_CTOR
    explicit key(const char* k, source_region&& src = {}) //
        : key_{k}, source_{std::move(src)} {}

    TOML_NODISCARD_CTOR
    explicit key(const char* k, const source_region& src) //
        : key_{k}, source_{src} {}

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD_CTOR
    explicit key(std::wstring_view k, source_region&& src = {}) //
        : key_{impl::narrow(k)}, source_{std::move(src)} {}

    TOML_NODISCARD_CTOR
    explicit key(std::wstring_view k, const source_region& src) //
        : key_{impl::narrow(k)}, source_{src} {}

#endif

    TOML_PURE_INLINE_GETTER
    std::string_view str() const noexcept { return std::string_view{key_}; }

    TOML_PURE_INLINE_GETTER
    /*implicit*/ operator std::string_view() const noexcept { return str(); }

    TOML_PURE_INLINE_GETTER
    bool empty() const noexcept { return key_.empty(); }

    TOML_PURE_INLINE_GETTER
    const char* data() const noexcept { return key_.data(); }

    TOML_PURE_INLINE_GETTER
    size_t length() const noexcept { return key_.length(); }

    TOML_PURE_INLINE_GETTER
    const source_region& source() const noexcept { return source_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator==(const key& lhs, const key& rhs) noexcept { return lhs.key_ == rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(const key& lhs, const key& rhs) noexcept { return lhs.key_ != rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator<(const key& lhs, const key& rhs) noexcept { return lhs.key_ < rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator<=(const key& lhs, const key& rhs) noexcept { return lhs.key_ <= rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator>(const key& lhs, const key& rhs) noexcept { return lhs.key_ > rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator>=(const key& lhs, const key& rhs) noexcept { return lhs.key_ >= rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator==(const key& lhs, std::string_view rhs) noexcept { return lhs.key_ == rhs; }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(const key& lhs, std::string_view rhs) noexcept { return lhs.key_ != rhs; }

    TOML_PURE_INLINE_GETTER
    friend bool operator<(const key& lhs, std::string_view rhs) noexcept { return lhs.key_ < rhs; }

    TOML_PURE_INLINE_GETTER
    friend bool operator<=(const key& lhs, std::string_view rhs) noexcept { return lhs.key_ <= rhs; }

    TOML_PURE_INLINE_GETTER
    friend bool operator>(const key& lhs, std::string_view rhs) noexcept { return lhs.key_ > rhs; }

    TOML_PURE_INLINE_GETTER
    friend bool operator>=(const key& lhs, std::string_view rhs) noexcept { return lhs.key_ >= rhs; }

    TOML_PURE_INLINE_GETTER
    friend bool operator==(std::string_view lhs, const key& rhs) noexcept { return lhs == rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(std::string_view lhs, const key& rhs) noexcept { return lhs != rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator<(std::string_view lhs, const key& rhs) noexcept { return lhs < rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator<=(std::string_view lhs, const key& rhs) noexcept { return lhs <= rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator>(std::string_view lhs, const key& rhs) noexcept { return lhs > rhs.key_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator>=(std::string_view lhs, const key& rhs) noexcept { return lhs >= rhs.key_; }

    using const_iterator = const char*;

    using iterator = const_iterator;

    TOML_PURE_INLINE_GETTER
    const_iterator begin() const noexcept { return key_.data(); }

    TOML_PURE_INLINE_GETTER
    const_iterator end() const noexcept { return key_.data() + key_.length(); }

    friend std::ostream& operator<<(std::ostream& lhs, const key& rhs) {
      impl::print_to_stream(lhs, rhs.key_);
      return lhs;
    }
  };

  template <typename T> inline constexpr bool is_key = std::is_same_v<impl::remove_cvref<T>, toml::key>;

  template <typename T>
  inline constexpr bool is_key_or_convertible = is_key<T> //
      || impl::is_constructible_or_convertible<toml::key, T>;
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/std_map.hpp  ******************************************************************************************

TOML_DISABLE_WARNINGS;
#include <iterator>
#include <map>
TOML_ENABLE_WARNINGS;

//********  impl/table.hpp  ********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  template <bool IsConst> struct table_proxy_pair {
    using value_type = std::conditional_t<IsConst, const node, node>;

    const toml::key& first;
    value_type& second;
  };

  template <bool IsConst> class table_iterator {
  private:
    template <bool> friend class table_iterator;

    using proxy_type = table_proxy_pair<IsConst>;
    using mutable_map_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator;
    using const_map_iterator = std::map<toml::key, node_ptr, std::less<>>::const_iterator;
    using map_iterator = std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>;

    mutable map_iterator iter_;
    alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)];
    mutable bool proxy_instantiated_ = false;

    TOML_NODISCARD
    proxy_type* get_proxy() const noexcept {
      if (!proxy_instantiated_) {
        auto p = ::new (static_cast<void*>(proxy_)) proxy_type{iter_->first, *iter_->second.get()};
        proxy_instantiated_ = true;
        return p;
      } else
        return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_));
    }

  public:
    TOML_NODISCARD_CTOR
    table_iterator() noexcept = default;

    TOML_NODISCARD_CTOR
    explicit table_iterator(mutable_map_iterator iter) noexcept //
        : iter_{iter} {}

    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
    TOML_NODISCARD_CTOR
    explicit table_iterator(const_map_iterator iter) noexcept //
        : iter_{iter} {}

    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
    TOML_NODISCARD_CTOR
    table_iterator(const table_iterator<false>& other) noexcept //
        : iter_{other.iter_} {}

    TOML_NODISCARD_CTOR
    table_iterator(const table_iterator& other) noexcept //
        : iter_{other.iter_} {}

    table_iterator& operator=(const table_iterator& rhs) noexcept {
      iter_ = rhs.iter_;
      proxy_instantiated_ = false;
      return *this;
    }

    using value_type = table_proxy_pair<IsConst>;
    using reference = value_type&;
    using pointer = value_type*;
    using difference_type = typename std::iterator_traits<map_iterator>::difference_type;
    using iterator_category = typename std::iterator_traits<map_iterator>::iterator_category;

    table_iterator& operator++() noexcept // ++pre
    {
      ++iter_;
      proxy_instantiated_ = false;
      return *this;
    }

    table_iterator operator++(int) noexcept // post++
    {
      table_iterator out{iter_};
      ++iter_;
      proxy_instantiated_ = false;
      return out;
    }

    table_iterator& operator--() noexcept // --pre
    {
      --iter_;
      proxy_instantiated_ = false;
      return *this;
    }

    table_iterator operator--(int) noexcept // post--
    {
      table_iterator out{iter_};
      --iter_;
      proxy_instantiated_ = false;
      return out;
    }

    TOML_PURE_INLINE_GETTER
    reference operator*() const noexcept { return *get_proxy(); }

    TOML_PURE_INLINE_GETTER
    pointer operator->() const noexcept { return get_proxy(); }

    TOML_PURE_INLINE_GETTER
    explicit operator const map_iterator&() const noexcept { return iter_; }

    TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
    TOML_PURE_INLINE_GETTER
    explicit operator const const_map_iterator() const noexcept { return iter_; }

    TOML_PURE_INLINE_GETTER
    friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept {
      return lhs.iter_ == rhs.iter_;
    }

    TOML_PURE_INLINE_GETTER
    friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept {
      return lhs.iter_ != rhs.iter_;
    }
  };

  struct table_init_pair {
    mutable toml::key key;
    mutable node_ptr value;

    template <typename K, typename V>
    TOML_NODISCARD_CTOR table_init_pair(K&& k, V&& v, value_flags flags = preserve_source_value_flags) //
        : key{static_cast<K&&>(k)}, value{make_node(static_cast<V&&>(v), flags)} {}
  };
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  using table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>);

  using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>);

  class TOML_EXPORTED_CLASS table : public node {
  private:
    using map_type = std::map<toml::key, impl::node_ptr, std::less<>>;
    using map_pair = std::pair<const toml::key, impl::node_ptr>;
    using map_iterator = typename map_type::iterator;
    using const_map_iterator = typename map_type::const_iterator;
    map_type map_;

    bool inline_ = false;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    table(const impl::table_init_pair*, const impl::table_init_pair*);

  public:
    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    table() noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    ~table() noexcept;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    table(const table&);

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    table(table&& other) noexcept;

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    explicit table(std::initializer_list<impl::table_init_pair> kvps) //
        : table(kvps.begin(), kvps.end()) {}

    TOML_EXPORTED_MEMBER_FUNCTION
    table& operator=(const table&);

    TOML_EXPORTED_MEMBER_FUNCTION
    table& operator=(table&& rhs) noexcept;

    TOML_CONST_INLINE_GETTER
    node_type type() const noexcept final { return node_type::table; }

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    bool is_homogeneous(node_type ntype) const noexcept final;

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;

    template <typename ElemType = void> TOML_PURE_GETTER bool is_homogeneous() const noexcept {
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
      static_assert(
          std::is_void_v<type> || toml::is_value<type> || toml::is_container<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>);
    }
    TOML_CONST_INLINE_GETTER
    bool is_table() const noexcept final { return true; }

    TOML_CONST_INLINE_GETTER
    bool is_array() const noexcept final { return false; }

    TOML_PURE_GETTER
    bool is_array_of_tables() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_value() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_string() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_integer() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_floating_point() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_number() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_boolean() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_date() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_time() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    bool is_date_time() const noexcept final { return false; }

    TOML_CONST_INLINE_GETTER
    table* as_table() noexcept final { return this; }

    TOML_CONST_INLINE_GETTER
    array* as_array() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<std::string>* as_string() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<int64_t>* as_integer() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<double>* as_floating_point() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<bool>* as_boolean() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<date>* as_date() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<time>* as_time() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    toml::value<date_time>* as_date_time() noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const table* as_table() const noexcept final { return this; }

    TOML_CONST_INLINE_GETTER
    const array* as_array() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<std::string>* as_string() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<int64_t>* as_integer() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<double>* as_floating_point() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<bool>* as_boolean() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<date>* as_date() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<time>* as_time() const noexcept final { return nullptr; }

    TOML_CONST_INLINE_GETTER
    const toml::value<date_time>* as_date_time() const noexcept final { return nullptr; }

    TOML_PURE_INLINE_GETTER
    bool is_inline() const noexcept { return inline_; }

    void is_inline(bool val) noexcept { inline_ = val; }

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    node* get(std::string_view key) noexcept;

    TOML_PURE_INLINE_GETTER
    const node* get(std::string_view key) const noexcept { return const_cast<table&>(*this).get(key); }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node* get(std::wstring_view key) {
      if (empty())
        return nullptr;

      return get(impl::narrow(key));
    }

    TOML_NODISCARD
    const node* get(std::wstring_view key) const { return const_cast<table&>(*this).get(key); }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    template <typename T> TOML_PURE_GETTER impl::wrap_node<T>* get_as(std::string_view key) noexcept {
      const auto n = this->get(key);
      return n ? n->template as<T>() : nullptr;
    }

    template <typename T> TOML_PURE_GETTER const impl::wrap_node<T>* get_as(std::string_view key) const noexcept {
      return const_cast<table&>(*this).template get_as<T>(key);
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    template <typename T> TOML_NODISCARD impl::wrap_node<T>* get_as(std::wstring_view key) {
      if (empty())
        return nullptr;

      return get_as<T>(impl::narrow(key));
    }

    template <typename T> TOML_NODISCARD const impl::wrap_node<T>* get_as(std::wstring_view key) const {
      return const_cast<table&>(*this).template get_as<T>(key);
    }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    node& at(std::string_view key);

    TOML_NODISCARD
    const node& at(std::string_view key) const { return const_cast<table&>(*this).at(key); }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node& at(std::wstring_view key) { return at(impl::narrow(key)); }

    TOML_NODISCARD
    const node& at(std::wstring_view key) const { return const_cast<table&>(*this).at(key); }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    using iterator = toml::table_iterator;

    using const_iterator = toml::const_table_iterator;

    TOML_PURE_INLINE_GETTER
    iterator begin() noexcept { return iterator{map_.begin()}; }

    TOML_PURE_INLINE_GETTER
    const_iterator begin() const noexcept { return const_iterator{map_.cbegin()}; }

    TOML_PURE_INLINE_GETTER
    const_iterator cbegin() const noexcept { return const_iterator{map_.cbegin()}; }

    TOML_PURE_INLINE_GETTER
    iterator end() noexcept { return iterator{map_.end()}; }

    TOML_PURE_INLINE_GETTER
    const_iterator end() const noexcept { return const_iterator{map_.cend()}; }

    TOML_PURE_INLINE_GETTER
    const_iterator cend() const noexcept { return const_iterator{map_.cend()}; }

  private:
    template <typename T, typename Table>
    using for_each_value_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Table>;

    template <typename Func, typename Table, typename T>
    using can_for_each = std::disjunction<
        std::is_invocable<Func, const key&, for_each_value_ref<T, Table>>, //
        std::is_invocable<Func, for_each_value_ref<T, Table>>>;

    template <typename Func, typename Table, typename T>
    using can_for_each_nothrow = std::conditional_t<
        // first form
        std::is_invocable_v<Func, const key&, for_each_value_ref<T, Table>>,
        std::is_nothrow_invocable<Func, const key&, for_each_value_ref<T, Table>>,
        std::conditional_t<
            // second form
            std::is_invocable_v<Func, for_each_value_ref<T, Table>>,
            std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>, std::false_type>>;

    template <typename Func, typename Table>
    using can_for_each_any = std::disjunction<
        can_for_each<Func, Table, table>, can_for_each<Func, Table, array>, can_for_each<Func, Table, std::string>,
        can_for_each<Func, Table, int64_t>, can_for_each<Func, Table, double>, can_for_each<Func, Table, bool>,
        can_for_each<Func, Table, date>, can_for_each<Func, Table, time>, can_for_each<Func, Table, date_time>>;

    template <typename Func, typename Table, typename T>
    using for_each_is_nothrow_one = std::disjunction<
        std::negation<can_for_each<Func, Table, T>>, //
        can_for_each_nothrow<Func, Table, T>>;

    template <typename Func, typename Table>
    using for_each_is_nothrow = std::conjunction<
        for_each_is_nothrow_one<Func, Table, table>, for_each_is_nothrow_one<Func, Table, array>,
        for_each_is_nothrow_one<Func, Table, std::string>, for_each_is_nothrow_one<Func, Table, int64_t>,
        for_each_is_nothrow_one<Func, Table, double>, for_each_is_nothrow_one<Func, Table, bool>,
        for_each_is_nothrow_one<Func, Table, date>, for_each_is_nothrow_one<Func, Table, time>,
        for_each_is_nothrow_one<Func, Table, date_time>>;

    template <typename Func, typename Table>
    static void do_for_each(Func&& visitor, Table&& tbl) //
        noexcept(for_each_is_nothrow<Func&&, Table&&>::value) {
      static_assert(
          can_for_each_any<Func&&, Table&&>::value,
          "TOML table for_each visitors must be invocable for at least one of the toml::node "
          "specializations:" TOML_SA_NODE_TYPE_LIST
      );

      using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>;

      for (kvp_type& kvp : tbl.map_) {
        using node_ref = impl::copy_cvref<toml::node, Table&&>;
        static_assert(std::is_reference_v<node_ref>);

#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN

#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
        static_assert(
            impl::always_false<Func, Table, kvp_type, node_ref>, //
            TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
        );
#endif

        static_cast<node_ref>(*kvp.second)
            .visit([&]([[maybe_unused]] auto&& v) //
                   noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value) {
                     using value_ref = for_each_value_ref<decltype(v), Table&&>;
                     static_assert(std::is_reference_v<value_ref>);

                     // func(key, val)
                     if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>) {
                       static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v));
                     }

                     // func(val)
                     else if constexpr (std::is_invocable_v<Func&&, value_ref>) {
                       static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
                     }
                   });

#else
        const auto keep_going =
            static_cast<node_ref>(*kvp.second)
                .visit(
                    [&]([[maybe_unused]] auto&& v) //
                    noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value) {
                      using value_ref = for_each_value_ref<decltype(v), Table&&>;
                      static_assert(std::is_reference_v<value_ref>);

                      // func(key, val)
                      if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>) {
                        using return_type = decltype(static_cast<Func&&>(visitor)(
                            static_cast<const key&>(kvp.first), static_cast<value_ref>(v)
                        ));

                        if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
                          return static_cast<bool>(static_cast<Func&&>(visitor)(
                              static_cast<const key&>(kvp.first), static_cast<value_ref>(v)
                          ));
                        } else {
                          static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v));
                          return true;
                        }
                      }

                      // func(val)
                      else if constexpr (std::is_invocable_v<Func&&, value_ref>) {
                        using return_type = decltype(static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));

                        if constexpr (impl::is_constructible_or_convertible<bool, return_type>) {
                          return static_cast<bool>(static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
                        } else {
                          static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
                          return true;
                        }
                      }

                      // visitor not compatible with this particular type
                      else
                        return true;
                    }
                );

        if (!keep_going)
          return;
#endif
      }
    }

  public:
    template <typename Func>
    table& for_each(Func&& visitor) & //
        noexcept(for_each_is_nothrow<Func&&, table&>::value) {
      do_for_each(static_cast<Func&&>(visitor), *this);
      return *this;
    }

    template <typename Func>
    table&& for_each(Func&& visitor) && //
        noexcept(for_each_is_nothrow<Func&&, table&&>::value) {
      do_for_each(static_cast<Func&&>(visitor), static_cast<table&&>(*this));
      return static_cast<table&&>(*this);
    }

    template <typename Func>
    const table& for_each(Func&& visitor) const& //
        noexcept(for_each_is_nothrow<Func&&, const table&>::value) {
      do_for_each(static_cast<Func&&>(visitor), *this);
      return *this;
    }

    template <typename Func>
    const table&& for_each(Func&& visitor) const&& //
        noexcept(for_each_is_nothrow<Func&&, const table&&>::value) {
      do_for_each(static_cast<Func&&>(visitor), static_cast<const table&&>(*this));
      return static_cast<const table&&>(*this);
    }

    TOML_PURE_INLINE_GETTER
    bool empty() const noexcept { return map_.empty(); }

    TOML_PURE_INLINE_GETTER
    size_t size() const noexcept { return map_.size(); }

  private:
    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    map_iterator get_lower_bound(std::string_view) noexcept;

  public:
    TOML_PURE_GETTER
    iterator lower_bound(std::string_view key) noexcept { return iterator{get_lower_bound(key)}; }

    TOML_PURE_GETTER
    const_iterator lower_bound(std::string_view key) const noexcept {
      return const_iterator{const_cast<table&>(*this).get_lower_bound(key)};
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    iterator lower_bound(std::wstring_view key) {
      if (empty())
        return end();

      return lower_bound(impl::narrow(key));
    }

    TOML_NODISCARD
    const_iterator lower_bound(std::wstring_view key) const {
      if (empty())
        return end();

      return lower_bound(impl::narrow(key));
    }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    iterator find(std::string_view key) noexcept;

    TOML_PURE_GETTER
    TOML_EXPORTED_MEMBER_FUNCTION
    const_iterator find(std::string_view key) const noexcept;

    TOML_PURE_GETTER
    bool contains(std::string_view key) const noexcept { return get(key) != nullptr; }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    iterator find(std::wstring_view key) {
      if (empty())
        return end();

      return find(impl::narrow(key));
    }

    TOML_NODISCARD
    const_iterator find(std::wstring_view key) const { return find(impl::narrow(key)); }

    TOML_NODISCARD
    bool contains(std::wstring_view key) const { return contains(impl::narrow(key)); }

#endif // TOML_ENABLE_WINDOWS_COMPAT

  private:
    TOML_EXPORTED_MEMBER_FUNCTION
    map_iterator erase(const_map_iterator) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    map_iterator erase(const_map_iterator, const_map_iterator) noexcept;

  public:
    iterator erase(iterator pos) noexcept { return iterator{erase(const_map_iterator{pos})}; }

    iterator erase(const_iterator pos) noexcept { return iterator{erase(const_map_iterator{pos})}; }

    iterator erase(const_iterator begin, const_iterator end) noexcept {
      return iterator{erase(const_map_iterator{begin}, const_map_iterator{end})};
    }

    TOML_EXPORTED_MEMBER_FUNCTION
    size_t erase(std::string_view key) noexcept;

#if TOML_ENABLE_WINDOWS_COMPAT

    size_t erase(std::wstring_view key) {
      if (empty())
        return false;

      return erase(impl::narrow(key));
    }

#endif // TOML_ENABLE_WINDOWS_COMPAT

    TOML_EXPORTED_MEMBER_FUNCTION
    table& prune(bool recursive = true) & noexcept;

    table&& prune(bool recursive = true) && noexcept { return static_cast<toml::table&&>(this->prune(recursive)); }

    TOML_EXPORTED_MEMBER_FUNCTION
    void clear() noexcept;

  private:
    TOML_EXPORTED_MEMBER_FUNCTION
    map_iterator insert_with_hint(const_iterator, key&&, impl::node_ptr&&);

  public:
    TOML_CONSTRAINED_TEMPLATE(
        (is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), typename ValueType = void,
        typename KeyType, typename... ValueArgs
    )
    iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args) {
      static_assert(
          !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
          "Emplacement using wide-character keys is only supported on Windows with "
          "TOML_ENABLE_WINDOWS_COMPAT enabled."
      );

      using raw_value_type = impl::remove_cvref<ValueType>;
      using value_type =
          std::conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;

      if constexpr (impl::is_wide_string<KeyType>) {
#if TOML_ENABLE_WINDOWS_COMPAT
        return emplace_hint<value_type>(
            hint, impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueArgs&&>(args)...
        );
#else
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
#endif
      } else {
        static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
            && sizeof...(ValueArgs) == 1u                                                  //
            && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;

        static_assert(
            moving_node_ptr                                       //
                || impl::is_native<unwrapped_type>                //
                || impl::is_one_of<unwrapped_type, table, array>, //
            "ValueType argument of table::emplace_hint() must be one "
            "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
        );

        map_iterator ipos = insert_with_hint(hint, toml::key{static_cast<KeyType&&>(key)}, nullptr);

        // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
        // so now we have to construct the actual value
        if (!ipos->second) {
          if constexpr (moving_node_ptr)
            ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
          else {
#if TOML_COMPILER_HAS_EXCEPTIONS
            try {
#endif
              ipos->second.reset(new impl::wrap_node<unwrapped_type>{static_cast<ValueArgs&&>(args)...});
#if TOML_COMPILER_HAS_EXCEPTIONS
            } catch (...) {
              erase(const_map_iterator{ipos}); // strong exception guarantee
              throw;
            }
#endif
          }
        }
        return iterator{ipos};
      }
    }

    TOML_CONSTRAINED_TEMPLATE(
        (is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), typename KeyType, typename ValueType
    )
    std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val, value_flags flags = preserve_source_value_flags) {
      static_assert(
          !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
          "Insertion using wide-character keys is only supported on Windows with "
          "TOML_ENABLE_WINDOWS_COMPAT enabled."
      );

      if constexpr (is_node_view<ValueType>) {
        if (!val)
          return {end(), false};
      }

      if constexpr (impl::is_wide_string<KeyType>) {
#if TOML_ENABLE_WINDOWS_COMPAT
        return insert(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), flags);
#else
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
#endif
      } else {
        const auto key_view = std::string_view{key};
        map_iterator ipos = get_lower_bound(key_view);
        if (ipos == map_.end() || ipos->first != key_view) {
          ipos = insert_with_hint(
              const_iterator{ipos}, toml::key{static_cast<KeyType&&>(key)},
              impl::make_node(static_cast<ValueType&&>(val), flags)
          );
          return {iterator{ipos}, true};
        }
        return {iterator{ipos}, false};
      }
    }

    TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), typename Iter)
    void insert(Iter begin, Iter end, value_flags flags = preserve_source_value_flags) {
      if (begin == end)
        return;
      for (auto it = begin; it != end; it++) {
        if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
          insert(std::move((*it).first), std::move((*it).second), flags);
        else
          insert((*it).first, (*it).second, flags);
      }
    }

    TOML_CONSTRAINED_TEMPLATE(
        (is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), typename KeyType, typename ValueType
    )
    std::pair<iterator, bool>
    insert_or_assign(KeyType&& key, ValueType&& val, value_flags flags = preserve_source_value_flags) {
      static_assert(
          !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
          "Insertion using wide-character keys is only supported on Windows with "
          "TOML_ENABLE_WINDOWS_COMPAT enabled."
      );

      if constexpr (is_node_view<ValueType>) {
        if (!val)
          return {end(), false};
      }

      if constexpr (impl::is_wide_string<KeyType>) {
#if TOML_ENABLE_WINDOWS_COMPAT
        return insert_or_assign(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), flags);
#else
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
#endif
      } else {
        const auto key_view = std::string_view{key};
        map_iterator ipos = get_lower_bound(key_view);
        if (ipos == map_.end() || ipos->first != key_view) {
          ipos = insert_with_hint(
              const_iterator{ipos}, toml::key{static_cast<KeyType&&>(key)},
              impl::make_node(static_cast<ValueType&&>(val), flags)
          );
          return {iterator{ipos}, true};
        } else {
          (*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags);
          return {iterator{ipos}, false};
        }
      }
    }

    TOML_CONSTRAINED_TEMPLATE(
        (is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>), typename ValueType = void,
        typename KeyType, typename... ValueArgs
    )
    std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args) {
      static_assert(
          !impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
          "Emplacement using wide-character keys is only supported on Windows with "
          "TOML_ENABLE_WINDOWS_COMPAT enabled."
      );

      using raw_value_type = impl::remove_cvref<ValueType>;
      using value_type =
          std::conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;

      if constexpr (impl::is_wide_string<KeyType>) {
#if TOML_ENABLE_WINDOWS_COMPAT
        return emplace<value_type>(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueArgs&&>(args)...);
#else
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
#endif
      } else {
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
        static_assert(
            (impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
            "ValueType argument of table::emplace() must be one "
            "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST
        );

        const auto key_view = std::string_view{key};
        auto ipos = get_lower_bound(key_view);
        if (ipos == map_.end() || ipos->first != key_view) {
          ipos = insert_with_hint(
              const_iterator{ipos}, toml::key{static_cast<KeyType&&>(key)},
              impl::node_ptr{new impl::wrap_node<unwrapped_type>{static_cast<ValueArgs&&>(args)...}}
          );
          return {iterator{ipos}, true};
        }
        return {iterator{ipos}, false};
      }
    }

    using node::operator[]; // inherit operator[toml::path]

    TOML_NODISCARD
    node_view<node> operator[](std::string_view key) noexcept { return node_view<node>{get(key)}; }

    TOML_NODISCARD
    node_view<const node> operator[](std::string_view key) const noexcept { return node_view<const node>{get(key)}; }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node_view<node> operator[](std::wstring_view key) { return node_view<node>{get(key)}; }

    TOML_NODISCARD
    node_view<const node> operator[](std::wstring_view key) const { return node_view<const node>{get(key)}; }

#endif // TOML_ENABLE_WINDOWS_COMPAT

  private:
    TOML_PURE_GETTER
    TOML_EXPORTED_STATIC_FUNCTION
    static bool TOML_CALLCONV equal(const table&, const table&) noexcept;

  public:
    TOML_NODISCARD
    friend bool operator==(const table& lhs, const table& rhs) noexcept { return equal(lhs, rhs); }

    TOML_NODISCARD
    friend bool operator!=(const table& lhs, const table& rhs) noexcept { return !equal(lhs, rhs); }

#if TOML_ENABLE_FORMATTERS

    friend std::ostream& operator<<(std::ostream& lhs, const table& rhs) {
      impl::print_to_stream(lhs, rhs);
      return lhs;
    }

#endif
  };
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/unicode_autogenerated.hpp  ****************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

#if TOML_GCC && TOML_GCC < 9
#pragma GCC push_options
#pragma GCC optimize("O1") // codegen bugs
#endif

// the functions in this namespace block are automatically generated by a tool - they are not meant to be hand-edited

TOML_IMPL_NAMESPACE_START {
  TOML_CONST_GETTER
  constexpr bool is_ascii_horizontal_whitespace(char32_t c) noexcept { return c == U'\t' || c == U' '; }

  TOML_CONST_GETTER
  constexpr bool is_non_ascii_horizontal_whitespace(char32_t c) noexcept {
    // 20 code units from 8 ranges (spanning a search area of 65120)

    if (c < U'\xA0' || c > U'\uFEFF')
      return false;

    const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xA0ull) / 0x3FAull;
    if ((1ull << child_index_0) & 0x7FFFFFFFFFFFF75Eull)
      return false;
    if (c == U'\xA0' || c == U'\u3000' || c == U'\uFEFF')
      return true;
    switch (child_index_0) {
    case 0x05:
      return c == U'\u1680' || c == U'\u180E';
    case 0x07:
      return (U'\u2000' <= c && c <= U'\u200B') || (U'\u205F' <= c && c <= U'\u2060') || c == U'\u202F';
    default:
      TOML_UNREACHABLE;
    }

    TOML_UNREACHABLE;
  }

  TOML_CONST_GETTER
  constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept { return c >= U'\n' && c <= U'\r'; }

  TOML_CONST_GETTER
  constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept {
    return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
  }

  TOML_CONST_GETTER
  constexpr bool is_ascii_bare_key_character(char32_t c) noexcept {
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
    if TOML_UNLIKELY (c == U'+')
      return true;
#endif
    // 64 code units from 5 ranges (spanning a search area of 78)

    if (c < U'-' || c > U'z')
      return false;

    return (((static_cast<uint_least64_t>(c) - 0x2Dull) / 0x40ull) != 0ull)
        || ((1ull << (static_cast<uint_least64_t>(c) - 0x2Dull)) & 0xFFF43FFFFFF01FF9ull);
  }

#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)

  TOML_CONST_GETTER
  constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept {
    // 971732 code units from 16 ranges (spanning a search area of 982862)

    if (c < U'\xB2' || c > U'\U000EFFFF')
      return false;

    const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xB2ull) / 0x3BFEull;
    if ((1ull << child_index_0) & 0xFFFFFFFFFFFFFFE6ull)
      return true;
    switch (child_index_0) {
    case 0x00: // [0] 00B2 - 3CAF
    {
      // 12710 code units from 13 ranges (spanning a search area of 15358)

      TOML_ASSUME(c >= U'\xB2' && c <= U'\u3CAF');

      constexpr uint_least64_t bitmask_table_1[] = {
          0xFFFFFFDFFFFFDC83u, 0xFFFFFFFFFFFFFFDFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFEFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0x000000000C003FFFu, 0xC000000000006000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0x000000003FFFFFFFu, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
          0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
          0x0000000000000000u, 0x0000000000000000u, 0xFFFFC00000000000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0x0000000000003FFFu, 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, 0xFFFFFFFFFFFFC000u, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFF8000u,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
          0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu,
      };
      return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xB2ull) / 0x40ull]
          & (0x1ull << ((static_cast<uint_least64_t>(c) - 0xB2ull) % 0x40ull));
    }
    case 0x03:
      return c <= U'\uD7FF';
    case 0x04:
      return (U'\uF900' <= c && c <= U'\uFDCF') || (U'\uFDF0' <= c && c <= U'\uFFFD') || U'\U00010000' <= c;
    default:
      TOML_UNREACHABLE;
    }

    TOML_UNREACHABLE;
  }

#endif // TOML_LANG_UNRELEASED
}
TOML_IMPL_NAMESPACE_END;

#if TOML_GCC && TOML_GCC < 9
#pragma GCC pop_options
#endif

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/unicode.hpp  ******************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  TOML_CONST_GETTER
  constexpr bool is_string_delimiter(char32_t c) noexcept { return c == U'"' || c == U'\''; }

  TOML_CONST_GETTER
  constexpr bool is_ascii_letter(char32_t c) noexcept { return (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'); }

  TOML_CONST_GETTER
  constexpr bool is_binary_digit(char32_t c) noexcept { return c == U'0' || c == U'1'; }

  TOML_CONST_GETTER
  constexpr bool is_octal_digit(char32_t c) noexcept { return (c >= U'0' && c <= U'7'); }

  TOML_CONST_GETTER
  constexpr bool is_decimal_digit(char32_t c) noexcept { return (c >= U'0' && c <= U'9'); }

  TOML_CONST_GETTER
  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> TOML_CONST_GETTER constexpr uint_least32_t hex_to_dec(const T c) noexcept {
    if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
      return c >= 0x41u               // >= 'A'
          ? 10u + (c | 0x20u) - 0x61u // - 'a'
          : c - 0x30u                 // - '0'
          ;
    else
      return hex_to_dec(static_cast<uint_least32_t>(c));
  }

  TOML_CONST_GETTER
  constexpr bool is_horizontal_whitespace(char32_t c) noexcept {
    return is_ascii_horizontal_whitespace(c) || is_non_ascii_horizontal_whitespace(c);
  }

  TOML_CONST_GETTER
  constexpr bool is_vertical_whitespace(char32_t c) noexcept {
    return is_ascii_vertical_whitespace(c) || is_non_ascii_vertical_whitespace(c);
  }

  TOML_CONST_GETTER
  constexpr bool is_whitespace(char32_t c) noexcept { return is_horizontal_whitespace(c) || is_vertical_whitespace(c); }

  TOML_CONST_GETTER
  constexpr bool is_bare_key_character(char32_t c) noexcept {
    return is_ascii_bare_key_character(c)
#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
        || is_non_ascii_bare_key_character(c)
#endif
        ;
  }

  TOML_CONST_GETTER
  constexpr bool is_value_terminator(char32_t c) noexcept {
    return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
  }

  TOML_CONST_GETTER
  constexpr bool is_control_character(char c) noexcept { return c <= '\u001F' || c == '\u007F'; }

  TOML_CONST_GETTER
  constexpr bool is_control_character(char32_t c) noexcept { return c <= U'\u001F' || c == U'\u007F'; }

  TOML_CONST_GETTER
  constexpr bool is_nontab_control_character(char32_t c) noexcept {
    return c <= U'\u0008' || (c >= U'\u000A' && c <= U'\u001F') || c == U'\u007F';
  }

  TOML_CONST_GETTER
  constexpr bool is_unicode_surrogate(char32_t c) noexcept { return c >= 0xD800u && c <= 0xDFFF; }

  struct utf8_decoder {
    // 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
    };

    TOML_PURE_INLINE_GETTER
    constexpr bool error() const noexcept { return state == uint_least32_t{12u}; }

    TOML_PURE_INLINE_GETTER
    constexpr bool has_code_point() const noexcept { return state == uint_least32_t{}; }

    TOML_PURE_INLINE_GETTER
    constexpr bool needs_more_input() const noexcept { return !has_code_point() && !error(); }

    constexpr void operator()(uint8_t byte) noexcept {
      TOML_ASSERT_ASSUME(!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_ALWAYS_INLINE
    constexpr void operator()(char c) noexcept { operator()(static_cast<uint8_t>(c)); }

    TOML_ALWAYS_INLINE
    constexpr void reset() noexcept { state = {}; }
  };

  TOML_PURE_GETTER
  TOML_ATTR(nonnull)
  bool is_ascii(const char* str, size_t len) noexcept;
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/parse_error.hpp  **************************************************************************************

#if TOML_ENABLE_PARSER

//********  impl/std_except.hpp  ***************************************************************************************

TOML_DISABLE_WARNINGS;
#if TOML_EXCEPTIONS
#include <stdexcept>
#endif
TOML_ENABLE_WARNINGS;

//********  impl/parse_error.hpp  **************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

#if TOML_DOXYGEN || !TOML_EXCEPTIONS
#define TOML_PARSE_ERROR_BASE
#else
#define TOML_PARSE_ERROR_BASE	 : public std::runtime_error
#endif

TOML_NAMESPACE_START {
  TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);

  class parse_error TOML_PARSE_ERROR_BASE {
  private:
#if !TOML_EXCEPTIONS
    std::string description_;
#endif
    source_region source_;

  public:
#if TOML_EXCEPTIONS

    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}} {}

#else

    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}} {}

#endif

    TOML_NODISCARD
    std::string_view description() const noexcept {
#if TOML_EXCEPTIONS
      return std::string_view{what()};
#else
      return description_;
#endif
    }

    TOML_NODISCARD
    const source_region& source() const noexcept { return source_; }

    friend std::ostream& operator<<(std::ostream& lhs, const parse_error& rhs) {
      impl::print_to_stream(lhs, rhs.description());
      impl::print_to_stream(lhs, "\n\t(error occurred at "sv);
      impl::print_to_stream(lhs, rhs.source());
      impl::print_to_stream(lhs, ")"sv);
      return lhs;
    }
  };

  TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_NAMESPACE_END;

#undef TOML_PARSE_ERROR_BASE

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_PARSER

//********  impl/parse_result.hpp  *************************************************************************************

#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_ABI_NAMESPACE_START(noex);

  class parse_result {
  private:
    struct storage_t {
      static constexpr size_t size =
          (sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(toml::table));
      static constexpr size_t align =
          (alignof(toml::table) < alignof(parse_error) ? alignof(parse_error) : alignof(toml::table));

      alignas(align) unsigned char bytes[size];
    };

    alignas(storage_t::align) mutable storage_t storage_;
    bool err_;

    template <typename Type> TOML_NODISCARD TOML_ALWAYS_INLINE static Type* get_as(storage_t& s) noexcept {
      return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
    }

    void destroy() noexcept {
      if (err_)
        get_as<parse_error>(storage_)->~parse_error();
      else
        get_as<toml::table>(storage_)->~table();
    }

  public:
    TOML_NODISCARD_CTOR
    parse_result() noexcept //
        : err_{true} {
      ::new (static_cast<void*>(storage_.bytes)) parse_error{std::string{}, source_region{}};
    }

    TOML_NODISCARD_CTOR
    explicit parse_result(toml::table&& tbl) noexcept //
        : err_{false} {
      ::new (static_cast<void*>(storage_.bytes)) toml::table{std::move(tbl)};
    }

    TOML_NODISCARD_CTOR
    explicit parse_result(parse_error&& err) noexcept //
        : err_{true} {
      ::new (static_cast<void*>(storage_.bytes)) parse_error{std::move(err)};
    }

    TOML_NODISCARD_CTOR
    parse_result(parse_result&& res) noexcept //
        : err_{res.err_} {
      if (err_)
        ::new (static_cast<void*>(storage_.bytes)) parse_error{std::move(res).error()};
      else
        ::new (static_cast<void*>(storage_.bytes)) toml::table{std::move(res).table()};
    }

    parse_result& operator=(parse_result&& rhs) noexcept {
      if (err_ != rhs.err_) {
        destroy();
        err_ = rhs.err_;
        if (err_)
          ::new (static_cast<void*>(storage_.bytes)) parse_error{std::move(rhs).error()};
        else
          ::new (static_cast<void*>(storage_.bytes)) toml::table{std::move(rhs).table()};
      } else {
        if (err_)
          error() = std::move(rhs).error();
        else
          table() = std::move(rhs).table();
      }
      return *this;
    }

    ~parse_result() noexcept { destroy(); }

    TOML_NODISCARD
    bool succeeded() const noexcept { return !err_; }

    TOML_NODISCARD
    bool failed() const noexcept { return err_; }

    TOML_NODISCARD
    explicit operator bool() const noexcept { return !err_; }

    TOML_NODISCARD
    toml::table& table() & noexcept {
      TOML_ASSERT_ASSUME(!err_);
      return *get_as<toml::table>(storage_);
    }

    TOML_NODISCARD
    toml::table&& table() && noexcept {
      TOML_ASSERT_ASSUME(!err_);
      return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
    }

    TOML_NODISCARD
    const toml::table& table() const& noexcept {
      TOML_ASSERT_ASSUME(!err_);
      return *get_as<const toml::table>(storage_);
    }

    TOML_NODISCARD
    /* implicit */ operator toml::table&() noexcept { return table(); }

    TOML_NODISCARD
    /* implicit */ operator toml::table&&() noexcept { return std::move(table()); }

    TOML_NODISCARD
    /* implicit */ operator const toml::table&() const noexcept { return table(); }

    TOML_NODISCARD
    parse_error& error() & noexcept {
      TOML_ASSERT_ASSUME(err_);
      return *get_as<parse_error>(storage_);
    }

    TOML_NODISCARD
    parse_error&& error() && noexcept {
      TOML_ASSERT_ASSUME(err_);
      return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
    }

    TOML_NODISCARD
    const parse_error& error() const& noexcept {
      TOML_ASSERT_ASSUME(err_);
      return *get_as<const parse_error>(storage_);
    }

    TOML_NODISCARD
    explicit operator parse_error&() noexcept { return error(); }

    TOML_NODISCARD
    explicit operator parse_error&&() noexcept { return std::move(error()); }

    TOML_NODISCARD
    explicit operator const parse_error&() const noexcept { return error(); }

    using iterator = table_iterator;

    using const_iterator = const_table_iterator;

    TOML_NODISCARD
    table_iterator begin() noexcept { return err_ ? table_iterator{} : table().begin(); }

    TOML_NODISCARD
    const_table_iterator begin() const noexcept { return err_ ? const_table_iterator{} : table().begin(); }

    TOML_NODISCARD
    const_table_iterator cbegin() const noexcept { return err_ ? const_table_iterator{} : table().cbegin(); }

    TOML_NODISCARD
    table_iterator end() noexcept { return err_ ? table_iterator{} : table().end(); }

    TOML_NODISCARD
    const_table_iterator end() const noexcept { return err_ ? const_table_iterator{} : table().end(); }

    TOML_NODISCARD
    const_table_iterator cend() const noexcept { return err_ ? const_table_iterator{} : table().cend(); }

    TOML_NODISCARD
    node_view<node> at_path(std::string_view path) noexcept { return err_ ? node_view<node>{} : table().at_path(path); }

    TOML_NODISCARD
    node_view<const node> at_path(std::string_view path) const noexcept {
      return err_ ? node_view<const node>{} : table().at_path(path);
    }

    TOML_NODISCARD
    node_view<node> at_path(const toml::path& path) noexcept {
      return err_ ? node_view<node>{} : table().at_path(path);
    }

    TOML_NODISCARD
    node_view<const node> at_path(const toml::path& path) const noexcept {
      return err_ ? node_view<const node>{} : table().at_path(path);
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node_view<node> at_path(std::wstring_view path) { return err_ ? node_view<node>{} : table().at_path(path); }

    TOML_NODISCARD
    node_view<const node> at_path(std::wstring_view path) const {
      return err_ ? node_view<const node>{} : table().at_path(path);
    }

#endif

    TOML_NODISCARD
    node_view<node> operator[](const toml::path& path) noexcept { return err_ ? node_view<node>{} : table()[path]; }

    TOML_NODISCARD
    node_view<const node> operator[](const toml::path& path) const noexcept {
      return err_ ? node_view<const node>{} : table()[path];
    }

    TOML_NODISCARD
    node_view<node> operator[](std::string_view key) noexcept { return err_ ? node_view<node>{} : table()[key]; }

    TOML_NODISCARD
    node_view<const node> operator[](std::string_view key) const noexcept {
      return err_ ? node_view<const node>{} : table()[key];
    }

#if TOML_ENABLE_WINDOWS_COMPAT

    TOML_NODISCARD
    node_view<node> operator[](std::wstring_view key) { return err_ ? node_view<node>{} : table()[key]; }

    TOML_NODISCARD
    node_view<const node> operator[](std::wstring_view key) const {
      return err_ ? node_view<const node>{} : table()[key];
    }

#endif // TOML_ENABLE_WINDOWS_COMPAT

#if TOML_ENABLE_FORMATTERS

    friend std::ostream& operator<<(std::ostream& os, const parse_result& result) {
      return result.err_ ? (os << result.error()) : (os << result.table());
    }

#endif
  };

  TOML_ABI_NAMESPACE_END;
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS

//********  impl/parser.hpp  *******************************************************************************************

#if TOML_ENABLE_PARSER

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path = {});

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse_file(std::string_view file_path);

#if TOML_HAS_CHAR8

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path = {});

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse_file(std::u8string_view file_path);

#endif // TOML_HAS_CHAR8

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path);

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse_file(std::wstring_view file_path);

#endif // TOML_ENABLE_WINDOWS_COMPAT

#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path);

#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path = {});

  TOML_NODISCARD
  TOML_EXPORTED_FREE_FUNCTION
  parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path);

  TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS

  inline namespace literals {
    TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex);

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    parse_result operator"" _toml(const char* str, size_t len) { return parse(std::string_view{str, len}); }

#if TOML_HAS_CHAR8

    TOML_NODISCARD
    TOML_ALWAYS_INLINE
    parse_result operator"" _toml(const char8_t* str, size_t len) { return parse(std::u8string_view{str, len}); }

#endif // TOML_HAS_CHAR8

    TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
  } // namespace literals
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_PARSER

//********  impl/formatter.hpp  ****************************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  struct formatter_constants {
    format_flags mandatory_flags;
    format_flags ignored_flags;

    std::string_view float_pos_inf;
    std::string_view float_neg_inf;
    std::string_view float_nan;

    std::string_view bool_true;
    std::string_view bool_false;
  };

  struct formatter_config {
    format_flags flags;
    std::string_view indent;
  };

  class TOML_EXPORTED_CLASS formatter {
  private:
    const node* source_;
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
    const parse_result* result_;
#endif
    const formatter_constants* constants_;
    formatter_config config_;
    size_t indent_columns_;
    format_flags int_format_mask_;
    std::ostream* stream_; //
    int indent_;           // these are set in attach()
    bool naked_newline_;   //

  protected:
    TOML_PURE_INLINE_GETTER
    const node& source() const noexcept { return *source_; }

    TOML_PURE_INLINE_GETTER
    std::ostream& stream() const noexcept { return *stream_; }

    TOML_PURE_INLINE_GETTER
    int indent() const noexcept { return indent_; }

    void indent(int level) noexcept { indent_ = level; }

    void increase_indent() noexcept { indent_++; }

    void decrease_indent() noexcept { indent_--; }

    TOML_PURE_INLINE_GETTER
    size_t indent_columns() const noexcept { return indent_columns_; }

    TOML_PURE_INLINE_GETTER
    bool indent_array_elements() const noexcept { return !!(config_.flags & format_flags::indent_array_elements); }

    TOML_PURE_INLINE_GETTER
    bool indent_sub_tables() const noexcept { return !!(config_.flags & format_flags::indent_sub_tables); }

    TOML_PURE_INLINE_GETTER
    bool literal_strings_allowed() const noexcept { return !!(config_.flags & format_flags::allow_literal_strings); }

    TOML_PURE_INLINE_GETTER
    bool multi_line_strings_allowed() const noexcept {
      return !!(config_.flags & format_flags::allow_multi_line_strings);
    }

    TOML_PURE_INLINE_GETTER
    bool real_tabs_in_strings_allowed() const noexcept {
      return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
    }

    TOML_PURE_INLINE_GETTER
    bool unicode_strings_allowed() const noexcept { return !!(config_.flags & format_flags::allow_unicode_strings); }

    TOML_PURE_INLINE_GETTER
    bool terse_kvps() const noexcept { return !!(config_.flags & format_flags::terse_key_value_pairs); }

    TOML_EXPORTED_MEMBER_FUNCTION
    void attach(std::ostream& stream) noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    void detach() noexcept;

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_newline(bool force = false);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_indent();

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_unformatted(char);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_unformatted(std::string_view);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_string(
        std::string_view str, bool allow_multi_line = true, bool allow_bare = false,
        bool allow_literal_whitespace = true
    );

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<std::string>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<int64_t>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<double>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<bool>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<date>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<time>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const value<date_time>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_value(const node&, node_type);

    TOML_NODISCARD
    TOML_EXPORTED_MEMBER_FUNCTION
    bool dump_failed_parse_result();

    TOML_NODISCARD_CTOR
    TOML_EXPORTED_MEMBER_FUNCTION
    formatter(const node*, const parse_result*, const formatter_constants&, const formatter_config&) noexcept;
  };
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

//********  impl/toml_formatter.hpp  ***********************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  class TOML_EXPORTED_CLASS toml_formatter : impl::formatter {
  private:
    using base = impl::formatter;
    std::vector<const key*> key_path_;
    bool pending_table_separator_ = false;

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_pending_table_separator();

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const key&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_inline(const toml::table&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const toml::array&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const toml::table&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print();

    static constexpr impl::formatter_constants constants = {
        format_flags::none, // mandatory
        format_flags::none, // ignored
        "inf"sv,
        "-inf"sv,
        "nan"sv,
        "true"sv,
        "false"sv
    };

  public:
    static constexpr format_flags default_flags = constants.mandatory_flags //
        | format_flags::allow_literal_strings                               //
        | format_flags::allow_multi_line_strings                            //
        | format_flags::allow_unicode_strings                               //
        | format_flags::allow_real_tabs_in_strings                          //
        | format_flags::allow_binary_integers                               //
        | format_flags::allow_octal_integers                                //
        | format_flags::allow_hexadecimal_integers                          //
        | format_flags::indentation;

    TOML_NODISCARD_CTOR
    explicit toml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
        : base{&source, nullptr, constants, {flags, "    "sv}} {}

#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)

    TOML_NODISCARD_CTOR
    explicit toml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
        : base{nullptr, &result, constants, {flags, "    "sv}} {}

#endif

    friend std::ostream& operator<<(std::ostream& lhs, toml_formatter& rhs) {
      rhs.attach(lhs);
      rhs.key_path_.clear();
      rhs.print();
      rhs.detach();
      return lhs;
    }

    friend std::ostream& operator<<(std::ostream& lhs, toml_formatter&& rhs) {
      return lhs << rhs; // as lvalue
    }
  };
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

//********  impl/json_formatter.hpp  ***********************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  class TOML_EXPORTED_CLASS json_formatter : impl::formatter {
  private:
    using base = impl::formatter;

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const toml::table&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const toml::array&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print();

    static constexpr impl::formatter_constants constants = {
        format_flags::quote_dates_and_times,                                          // mandatory
        format_flags::allow_literal_strings | format_flags::allow_multi_line_strings, // ignored
        "Infinity"sv,
        "-Infinity"sv,
        "NaN"sv,
        "true"sv,
        "false"sv
    };

  public:
    static constexpr format_flags default_flags = constants.mandatory_flags //
        | format_flags::quote_infinities_and_nans                           //
        | format_flags::allow_unicode_strings                               //
        | format_flags::indentation;

    TOML_NODISCARD_CTOR
    explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
        : base{&source, nullptr, constants, {flags, "    "sv}} {}

#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)

    TOML_NODISCARD_CTOR
    explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
        : base{nullptr, &result, constants, {flags, "    "sv}} {}

#endif

    friend std::ostream& operator<<(std::ostream& lhs, json_formatter& rhs) {
      rhs.attach(lhs);
      rhs.print();
      rhs.detach();
      return lhs;
    }

    friend std::ostream& operator<<(std::ostream& lhs, json_formatter&& rhs) {
      return lhs << rhs; // as lvalue
    }
  };
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

//********  impl/yaml_formatter.hpp  ***********************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  class TOML_EXPORTED_CLASS yaml_formatter : impl::formatter {
  private:
    using base = impl::formatter;

    TOML_EXPORTED_MEMBER_FUNCTION
    void print_yaml_string(const value<std::string>&);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const toml::table&, bool = false);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print(const toml::array&, bool = false);

    TOML_EXPORTED_MEMBER_FUNCTION
    void print();

    static constexpr impl::formatter_constants constants = {
        //
        format_flags::quote_dates_and_times | format_flags::indentation, // mandatory
        format_flags::allow_multi_line_strings,                          // ignored
        ".inf"sv,
        "-.inf"sv,
        ".NAN"sv,
        "true"sv,
        "false"sv
    };

  public:
    static constexpr format_flags default_flags = constants.mandatory_flags //
        | format_flags::allow_literal_strings                               //
        | format_flags::allow_unicode_strings                               //
        | format_flags::allow_octal_integers                                //
        | format_flags::allow_hexadecimal_integers;

    TOML_NODISCARD_CTOR
    explicit yaml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
        : base{&source, nullptr, constants, {flags, "  "sv}} {}

#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)

    TOML_NODISCARD_CTOR
    explicit yaml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
        : base{nullptr, &result, constants, {flags, "  "sv}} {}

#endif

    friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter& rhs) {
      rhs.attach(lhs);
      rhs.print();
      rhs.detach();
      return lhs;
    }

    friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter&& rhs) {
      return lhs << rhs; // as lvalue
    }
  };
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

#if TOML_IMPLEMENTATION

//********  impl/std_string.inl  ***************************************************************************************

#if TOML_WINDOWS

#ifndef _WINDOWS_
#if TOML_INCLUDE_WINDOWS_H
#include <Windows.h>
#else

extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(
    unsigned int CodePage, unsigned long dwFlags, const wchar_t* lpWideCharStr, int cchWideChar, char* lpMultiByteStr,
    int cbMultiByte, const char* lpDefaultChar, int* lpUsedDefaultChar
);

extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(
    unsigned int CodePage, unsigned long dwFlags, const char* lpMultiByteStr, int cbMultiByte, wchar_t* lpWideCharStr,
    int cchWideChar
);

#endif // TOML_INCLUDE_WINDOWS_H
#endif // _WINDOWS_

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  std::string narrow(std::wstring_view str) {
    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_EXTERNAL_LINKAGE
  std::wstring widen(std::string_view str) {
    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;
  }

#if TOML_HAS_CHAR8

  TOML_EXTERNAL_LINKAGE
  std::wstring widen(std::u8string_view str) {
    if (str.empty())
      return {};

    return widen(std::string_view{reinterpret_cast<const char*>(str.data()), str.length()});
  }

#endif // TOML_HAS_CHAR8
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_WINDOWS

//********  impl/print_to_stream.inl  **********************************************************************************

TOML_DISABLE_WARNINGS;
#include <ostream>
#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;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_ANON_NAMESPACE_START {
  template <typename T> inline constexpr size_t charconv_buffer_length = 0;

  template <> inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")

  template <> inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")

  template <> inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")

  template <> inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")

  template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")

  template <> inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")

  template <> inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")

  template <> inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")

  template <> inline constexpr size_t charconv_buffer_length<float> = 64;

  template <> inline constexpr size_t charconv_buffer_length<double> = 64;

  template <typename T>
  TOML_INTERNAL_LINKAGE void print_integer_to_stream(
      std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0
  ) {
    if (!val) {
      if (!min_digits)
        min_digits = 1;

      for (size_t i = 0; i < min_digits; i++)
        stream.put('0');

      return;
    }

    static constexpr auto value_flags_mask =
        value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
    format &= value_flags_mask;

    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);
    for (size_t i = len; i < min_digits; i++)
      stream.put('0');
    if (base == 16) {
      for (size_t i = 0; i < len; i++)
        if (buf[i] >= 'a')
          buf[i] -= 32;
    }
    impl::print_to_stream(stream, buf, len);

#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 (base == 2) {
      const auto len = sizeof(T) * CHAR_BIT;
      for (size_t i = len; i < min_digits; i++)
        stream.put('0');

      bool found_one = false;
      const auto v = static_cast<unsigned_type>(val);
      unsigned_type mask = unsigned_type{1} << (len - 1u);
      for (size_t i = 0; i < len; i++) {
        if ((v & mask)) {
          stream.put('1');
          found_one = true;
        } else if (found_one)
          stream.put('0');
        mask >>= 1;
      }
    } else {
      std::ostringstream ss;
      ss.imbue(std::locale::classic());
      ss << std::uppercase << std::setbase(base);
      if (min_digits)
        ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
      ss << static_cast<cast_type>(val);
      const auto str = std::move(ss).str();
      impl::print_to_stream(stream, str);
    }

#endif
  }

  template <typename T>
  TOML_INTERNAL_LINKAGE void print_floating_point_to_stream(
      std::ostream & stream, T val, value_flags format, [[maybe_unused]] bool relaxed_precision
  ) {
    switch (impl::fpclassify(val)) {
    case impl::fp_class::neg_inf:
      impl::print_to_stream(stream, "-inf"sv);
      break;

    case impl::fp_class::pos_inf:
      impl::print_to_stream(stream, "inf"sv);
      break;

    case impl::fp_class::nan:
      impl::print_to_stream(stream, "nan"sv);
      break;

    case impl::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

      const auto hex = !!(format & value_flags::format_as_hexadecimal);
      char buf[charconv_buffer_length<T>];
      auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
                     : std::to_chars(buf, buf + sizeof(buf), val);
      auto str = std::string_view{buf, static_cast<size_t>(res.ptr - buf)};

      char buf2[charconv_buffer_length<T>];
      if (!hex && relaxed_precision) {
        res = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
        const auto str2 = std::string_view{buf2, static_cast<size_t>(res.ptr - buf2)};
        if (str2.length() < str.length())
          str = str2;
      }

      impl::print_to_stream(stream, str);
      if (!hex && needs_decimal_point(str))
        toml::impl::print_to_stream(stream, ".0"sv);

#else

      std::ostringstream ss;
      ss.imbue(std::locale::classic());
      if (!relaxed_precision)
        ss.precision(std::numeric_limits<T>::max_digits10);
      if (!!(format & value_flags::format_as_hexadecimal))
        ss << std::hexfloat;
      ss << val;
      const auto str = std::move(ss).str();
      impl::print_to_stream(stream, str);
      if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
        impl::print_to_stream(stream, ".0"sv);

#endif
    } break;

    default:
      TOML_UNREACHABLE;
    }
  }
}
TOML_ANON_NAMESPACE_END;

TOML_IMPL_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  TOML_ATTR(nonnull)
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const char* val, size_t len) {
    stream.write(val, static_cast<std::streamsize>(len));
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, std::string_view val) {
    stream.write(val.data(), static_cast<std::streamsize>(val.length()));
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const std::string& val) {
    stream.write(val.data(), static_cast<std::streamsize>(val.length()));
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, char val) { stream.put(val); }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, signed char val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, signed short val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, signed int val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(
      std::ostream & stream, signed long long val, value_flags format, size_t min_digits
  ) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned char val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned short val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned int val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long val, value_flags format, size_t min_digits) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(
      std::ostream & stream, unsigned long long val, value_flags format, size_t min_digits
  ) {
    TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, float val, value_flags format, bool relaxed_precision) {
    TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, double val, value_flags format, bool relaxed_precision) {
    TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val) {
    print_to_stream(stream, val ? "true"sv : "false"sv);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date& val) {
    print_to_stream(stream, val.year, {}, 4);
    stream.put('-');
    print_to_stream(stream, val.month, {}, 2);
    stream.put('-');
    print_to_stream(stream, val.day, {}, 2);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time& val) {
    print_to_stream(stream, val.hour, {}, 2);
    stream.put(':');
    print_to_stream(stream, val.minute, {}, 2);
    stream.put(':');
    print_to_stream(stream, val.second, {}, 2);
    if (val.nanosecond && val.nanosecond <= 999999999u) {
      stream.put('.');
      auto ns = val.nanosecond;
      size_t digits = 9u;
      while (ns % 10u == 0u) {
        ns /= 10u;
        digits--;
      }
      print_to_stream(stream, ns, {}, digits);
    }
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time_offset& val) {
    if (!val.minutes) {
      stream.put('Z');
      return;
    }

    auto mins = static_cast<int>(val.minutes);
    if (mins < 0) {
      stream.put('-');
      mins = -mins;
    } else
      stream.put('+');
    const auto hours = mins / 60;
    if (hours) {
      print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
      mins -= hours * 60;
    } else
      print_to_stream(stream, "00"sv);
    stream.put(':');
    print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date_time& val) {
    print_to_stream(stream, val.date);
    stream.put('T');
    print_to_stream(stream, val.time);
    if (val.offset)
      print_to_stream(stream, *val.offset);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_position& val) {
    print_to_stream(stream, "line "sv);
    print_to_stream(stream, val.line);
    print_to_stream(stream, ", column "sv);
    print_to_stream(stream, val.column);
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_region& val) {
    print_to_stream(stream, val.begin);
    if (val.path) {
      print_to_stream(stream, " of '"sv);
      print_to_stream(stream, *val.path);
      stream.put('\'');
    }
  }

#if TOML_ENABLE_FORMATTERS

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const array& arr) { stream << toml_formatter{arr}; }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const table& tbl) { stream << toml_formatter{tbl}; }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<std::string>& val) {
    stream << toml_formatter{val};
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<int64_t>& val) {
    stream << toml_formatter{val};
  }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<double>& val) { stream << toml_formatter{val}; }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<bool>& val) { stream << toml_formatter{val}; }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date>& val) { stream << toml_formatter{val}; }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<time>& val) { stream << toml_formatter{val}; }

  TOML_EXTERNAL_LINKAGE
  void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date_time>& val) {
    stream << toml_formatter{val};
  }

#endif
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/node.inl  *********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  node::node() noexcept = default;

  TOML_EXTERNAL_LINKAGE
  node::~node() noexcept = default;

  TOML_EXTERNAL_LINKAGE
  node::node(node && other) noexcept //
      : source_{std::exchange(other.source_, {})} {}

  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::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 {
    if (&rhs != this)
      source_ = std::exchange(rhs.source_, {});
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  node_view<node> node::at_path(std::string_view path) noexcept { return toml::at_path(*this, path); }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> node::at_path(std::string_view path) const noexcept { return toml::at_path(*this, path); }

  TOML_EXTERNAL_LINKAGE
  node_view<node> node::at_path(const path& p) noexcept { return toml::at_path(*this, p); }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> node::at_path(const path& p) const noexcept { return toml::at_path(*this, p); }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  node_view<node> node::at_path(std::wstring_view path) { return toml::at_path(*this, path); }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> node::at_path(std::wstring_view path) const { return toml::at_path(*this, path); }

#endif // TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  node_view<node> node::operator[](const path& p) noexcept { return toml::at_path(*this, p); }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> node::operator[](const path& p) const noexcept { return toml::at_path(*this, p); }
}
TOML_NAMESPACE_END;

TOML_IMPL_NAMESPACE_START {
  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool TOML_CALLCONV node_deep_equality(const node* lhs, const node* rhs) noexcept {
    // both same or both null
    if (lhs == rhs)
      return true;

    // lhs null != rhs null or different types
    if ((!lhs != !rhs) || lhs->type() != rhs->type())
      return false;

    return lhs->visit([=](auto& l) noexcept {
      using concrete_type = remove_cvref<decltype(l)>;

      return l == *(rhs->as<concrete_type>());
    });
  }
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/at_path.inl  ******************************************************************************************

TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
#include <charconv>
#else
#include <sstream>
#endif
TOML_ENABLE_WARNINGS;
TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  bool TOML_CALLCONV parse_path(
      const std::string_view path, void* const data, const parse_path_callback<std::string_view> on_key,
      const parse_path_callback<size_t> on_index
  ) {
    // a blank string is a valid path; it's just one component representing the "" key
    if (path.empty())
      return on_key(data, ""sv);

    size_t pos = 0;
    const auto end = path.length();
    bool prev_was_array_indexer = false;
    bool prev_was_dot = true; // invisible root 'dot'

    while (pos < end) {
      // start of an array indexer
      if (path[pos] == '[') {
        // find first digit in index
        size_t index_start = pos + 1u;
        while (true) {
          if TOML_UNLIKELY (index_start >= path.length())
            return false;

          const auto c = path[index_start];
          if TOML_LIKELY (c >= '0' && c <= '9')
            break;
          else if (c == ' ' || c == '\t')
            index_start++;
          else
            return false;
        }
        TOML_ASSERT(path[index_start] >= '0');
        TOML_ASSERT(path[index_start] <= '9');

        // find end of index (first non-digit character)
        size_t index_end = index_start + 1u;
        while (true) {
          // if an array indexer is missing the trailing ']' at the end of the string, permissively accept it
          if TOML_UNLIKELY (index_end >= path.length())
            break;

          const auto c = path[index_end];
          if (c >= '0' && c <= '9')
            index_end++;
          else if (c == ']' || c == ' ' || c == '\t' || c == '.' || c == '[')
            break;
          else
            return false;
        }
        TOML_ASSERT(path[index_end - 1u] >= '0');
        TOML_ASSERT(path[index_end - 1u] <= '9');

        // move pos to after indexer (char after closing ']' or permissively EOL/subkey '.'/next opening '[')
        pos = index_end;
        while (true) {
          if TOML_UNLIKELY (pos >= path.length())
            break;

          const auto c = path[pos];
          if (c == ']') {
            pos++;
            break;
          } else if TOML_UNLIKELY (c == '.' || c == '[')
            break;
          else if (c == '\t' || c == ' ')
            pos++;
          else
            return false;
        }

        // get array index substring
        auto index_str = path.substr(index_start, index_end - index_start);

        // parse the actual array index to an integer type
        size_t index;
        if (index_str.length() == 1u)
          index = static_cast<size_t>(index_str[0] - '0');
        else {
#if TOML_INT_CHARCONV

          auto fc_result = std::from_chars(index_str.data(), index_str.data() + index_str.length(), index);
          if (fc_result.ec != std::errc{})
            return false;

#else

          std::stringstream ss;
          ss.imbue(std::locale::classic());
          ss.write(index_str.data(), static_cast<std::streamsize>(index_str.length()));
          if (!(ss >> index))
            return false;

#endif
        }

        prev_was_dot = false;
        prev_was_array_indexer = true;

        if (!on_index(data, index))
          return false;
      }

      // start of a new table child
      else if (path[pos] == '.') {
        // a dot immediately following another dot (or at the beginning of the string) is as if we'd asked
        // for an empty child in between, e.g.
        //
        //     foo..bar
        //
        // is equivalent to
        //
        //     "foo".""."bar"
        //
        if (prev_was_dot && !on_key(data, ""sv))
          return false;

        pos++;
        prev_was_dot = true;
        prev_was_array_indexer = false;
      }

      // an errant closing ']'
      else if TOML_UNLIKELY (path[pos] == ']')
        return false;

      // some regular subkey
      else {
        const auto subkey_start = pos;
        const auto subkey_len = impl::min(path.find_first_of(".[]"sv, subkey_start + 1u), path.length()) - subkey_start;
        const auto subkey = path.substr(subkey_start, subkey_len);

        // a regular subkey segment immediately after an array indexer is OK if it was all whitespace, e.g.:
        //
        //     "foo[0]  .bar"
        //            ^^ skip this
        //
        // otherwise its an error (since it would have to be preceeded by a dot)
        if (prev_was_array_indexer) {
          auto non_ws = subkey.find_first_not_of(" \t");
          if (non_ws == std::string_view::npos) {
            pos += subkey_len;
            prev_was_dot = false;
            prev_was_array_indexer = false;
            continue;
          } else
            return false;
        }

        pos += subkey_len;
        prev_was_dot = false;
        prev_was_array_indexer = false;

        if (!on_key(data, subkey))
          return false;
      }
    }

    // Last character was a '.', which implies an empty string key at the end of the path
    if (prev_was_dot && !on_key(data, ""sv))
      return false;

    return true;
  }
}
TOML_IMPL_NAMESPACE_END;

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept {
    // early-exit sanity-checks
    if (root.is_value())
      return {};
    if (auto tbl = root.as_table(); tbl && tbl->empty())
      return {};
    if (auto arr = root.as_array(); arr && arr->empty())
      return {};

    node* current = &root;

    static constexpr auto on_key = [](void* data, std::string_view key) noexcept -> bool {
      auto& curr = *static_cast<node**>(data);
      TOML_ASSERT_ASSUME(curr);

      const auto current_table = curr->as<table>();
      if (!current_table)
        return false;

      curr = current_table->get(key);
      return curr != nullptr;
    };

    static constexpr auto on_index = [](void* data, size_t index) noexcept -> bool {
      auto& curr = *static_cast<node**>(data);
      TOML_ASSERT_ASSUME(curr);

      const auto current_array = curr->as<array>();
      if (!current_array)
        return false;

      curr = current_array->get(index);
      return curr != nullptr;
    };

    if (!impl::parse_path(path, &current, on_key, on_index))
      current = nullptr;

    return node_view{current};
  }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept {
    return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path) {
    // these are the same top-level checks from the narrow-string version;
    // they're hoisted up here to avoid doing the wide -> narrow conversion where it would not be necessary
    // (avoids an allocation)
    if (root.is_value())
      return {};
    if (auto tbl = root.as_table(); tbl && tbl->empty())
      return {};
    if (auto arr = root.as_array(); arr && arr->empty())
      return {};

    return at_path(root, impl::narrow(path));
  }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path) {
    return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
  }

#endif // TOML_ENABLE_WINDOWS_COMPAT
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/path.inl  *********************************************************************************************

TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
#include <charconv>
#endif
#include <sstream>
TOML_ENABLE_WARNINGS;
TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  path_component::path_component() //
      : type_{path_component_type::key} {
    store_key("", value_storage_);
  }

  TOML_EXTERNAL_LINKAGE
  path_component::path_component(size_t index) noexcept //
      : type_(path_component_type::array_index) {
    store_index(index, value_storage_);
  }

  TOML_EXTERNAL_LINKAGE
  path_component::path_component(std::string_view key) //
      : type_(path_component_type::key) {
    store_key(key, value_storage_);
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  path_component::path_component(std::wstring_view key) //
      : path_component(impl::narrow(key)) {}

#endif

  TOML_EXTERNAL_LINKAGE
  path_component::path_component(const path_component& pc) //
      : type_{pc.type_} {
    if (type_ == path_component_type::array_index)
      store_index(pc.index(), value_storage_);
    else
      store_key(pc.key(), value_storage_);
  }

  TOML_EXTERNAL_LINKAGE
  path_component::path_component(path_component && pc) noexcept //
      : type_{pc.type_} {
    if (type_ == path_component_type::array_index)
      store_index(pc.index_ref(), value_storage_);
    else
      store_key(std::move(pc.key_ref()), value_storage_);
  }

  TOML_EXTERNAL_LINKAGE
  path_component& path_component::operator=(const path_component& rhs) {
    if (type_ != rhs.type_) {
      destroy();

      type_ = rhs.type_;
      if (type_ == path_component_type::array_index)
        store_index(rhs.index(), value_storage_);
      else
        store_key(rhs.key(), value_storage_);
    } else {
      if (type_ == path_component_type::array_index)
        index_ref() = rhs.index();
      else
        key_ref() = rhs.key();
    }
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path_component& path_component::operator=(path_component&& rhs) noexcept {
    if (type_ != rhs.type_) {
      destroy();

      type_ = rhs.type_;
      if (type_ == path_component_type::array_index)
        store_index(rhs.index(), value_storage_);
      else
        store_key(std::move(rhs.key_ref()), value_storage_);
    } else {
      if (type_ == path_component_type::array_index)
        index_ref() = rhs.index();
      else
        key_ref() = std::move(rhs.key_ref());
    }
    return *this;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept {
    // Different comparison depending on contents
    if (lhs.type_ != rhs.type_)
      return false;

    if (lhs.type_ == path_component_type::array_index)
      return lhs.index() == rhs.index();
    else // path_component_type::key
      return lhs.key() == rhs.key();
  }

  TOML_EXTERNAL_LINKAGE
  path_component& path_component::operator=(size_t new_index) noexcept {
    // If currently a key, string will need to be destroyed regardless
    destroy();

    type_ = path_component_type::array_index;
    store_index(new_index, value_storage_);

    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path_component& path_component::operator=(std::string_view new_key) {
    if (type_ == path_component_type::key)
      key_ref() = new_key;
    else {
      type_ = path_component_type::key;
      store_key(new_key, value_storage_);
    }

    return *this;
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  path_component& path_component::operator=(std::wstring_view new_key) {
    if (type_ == path_component_type::key)
      key_ref() = impl::narrow(new_key);
    else {
      type_ = path_component_type::key;
      store_key(impl::narrow(new_key), value_storage_);
    }

    return *this;
  }

#endif
}
TOML_NAMESPACE_END;

TOML_ANON_NAMESPACE_START {
  TOML_INTERNAL_LINKAGE
  bool parse_path_into(std::string_view path_str, std::vector<path_component> & components) {
    using components_type = std::remove_reference_t<decltype(components)>;

    const auto original_size = components.size();

    static constexpr auto on_key = [](void* data, std::string_view key) -> bool {
      auto& comps = *static_cast<components_type*>(data);
      comps.emplace_back(key);
      return true;
    };

    static constexpr auto on_index = [](void* data, size_t index) -> bool {
      auto& comps = *static_cast<components_type*>(data);
      comps.emplace_back(index);
      return true;
    };

    if (!impl::parse_path(path_str, &components, on_key, on_index)) {
      components.resize(original_size);
      return false;
    }

    return true;
  }
}
TOML_ANON_NAMESPACE_END;

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  void path::print_to(std::ostream & os) const {
    bool root = true;
    for (const auto& component : components_) {
      if (component.type() == path_component_type::key) // key
      {
        if (!root)
          impl::print_to_stream(os, '.');
        impl::print_to_stream(os, component.key());
      } else if (component.type() == path_component_type::array_index) // array
      {
        impl::print_to_stream(os, '[');
        impl::print_to_stream(os, component.index());
        impl::print_to_stream(os, ']');
      }
      root = false;
    }
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept {
    return lhs.components_ == rhs.components_;
  }

  TOML_EXTERNAL_LINKAGE
  path::path(std::string_view str) //
  {
    TOML_ANON_NAMESPACE::parse_path_into(str, components_);
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  path::path(std::wstring_view str) //
      : path(impl::narrow(str)) {}

#endif

  TOML_EXTERNAL_LINKAGE
  path& path::operator=(std::string_view rhs) {
    components_.clear();
    TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
    return *this;
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  path& path::operator=(std::wstring_view rhs) { return assign(impl::narrow(rhs)); }

#endif

  TOML_EXTERNAL_LINKAGE
  path& path::operator+=(const path& rhs) {
    components_.insert(components_.cend(), rhs.begin(), rhs.end());
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path& path::operator+=(path&& rhs) {
    components_.insert(
        components_.end(), std::make_move_iterator(rhs.components_.begin()),
        std::make_move_iterator(rhs.components_.end())
    );
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path& path::operator+=(std::string_view str) {
    TOML_ANON_NAMESPACE::parse_path_into(str, components_);
    return *this;
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  path& path::operator+=(std::wstring_view str) { return *this += impl::narrow(str); }

#endif

  TOML_EXTERNAL_LINKAGE
  path& path::prepend(const path& source) {
    components_.insert(components_.begin(), source.components_.begin(), source.components_.end());
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path& path::prepend(path && source) {
    components_.insert(
        components_.begin(), std::make_move_iterator(source.components_.begin()),
        std::make_move_iterator(source.components_.end())
    );
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path& path::prepend(std::string_view source) { return prepend(path{source}); }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  path& path::prepend(std::wstring_view source) { return prepend(impl::narrow(source)); }

#endif

  TOML_EXTERNAL_LINKAGE
  std::string path::str() const {
    if (empty())
      return "";

    std::ostringstream ss;
    print_to(ss);
    return std::move(ss).str();
  }

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  std::wstring path::wide_str() const { return impl::widen(str()); }

#endif

  TOML_EXTERNAL_LINKAGE
  void path::clear() noexcept { components_.clear(); }

  TOML_EXTERNAL_LINKAGE
  path& path::truncate(size_t n) {
    n = n > components_.size() ? components_.size() : n;

    auto it_end = components_.end();
    components_.erase(it_end - static_cast<int>(n), it_end);

    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  path path::truncated(size_t n) const {
    path truncated_path{};

    n = n > components_.size() ? components_.size() : n;

    // Copy all components except one
    // Need at least two path components to have a parent, since if there is
    // only one path component, the parent is the root/null path ""
    truncated_path.components_.insert(
        truncated_path.components_.begin(), components_.begin(), components_.end() - static_cast<int>(n)
    );

    return truncated_path;
  }

  TOML_EXTERNAL_LINKAGE
  path path::parent() const { return truncated(1); }

  TOML_EXTERNAL_LINKAGE
  path path::leaf(size_t n) const {
    path leaf_path{};

    n = n > components_.size() ? components_.size() : n;

    if (n > 0) {
      leaf_path.components_.insert(
          leaf_path.components_.begin(), components_.end() - static_cast<int>(n), components_.end()
      );
    }

    return leaf_path;
  }

  TOML_EXTERNAL_LINKAGE
  path path::subpath(std::vector<path_component>::const_iterator start, std::vector<path_component>::const_iterator end)
      const {
    if (start >= end)
      return {};

    path subpath;
    subpath.components_.insert(subpath.components_.begin(), start, end);
    return subpath;
  }

  TOML_EXTERNAL_LINKAGE
  path path::subpath(size_t start, size_t length) const {
    return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length));
  }
}
TOML_NAMESPACE_END;

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept {
    // early-exit sanity-checks
    if (root.is_value())
      return {};
    if (auto tbl = root.as_table(); tbl && tbl->empty())
      return {};
    if (auto arr = root.as_array(); arr && arr->empty())
      return {};

    node* current = &root;

    for (const auto& component : path) {
      auto type = component.type();
      if (type == path_component_type::array_index) {
        const auto current_array = current->as<array>();
        if (!current_array)
          return {}; // not an array, using array index doesn't work

        current = current_array->get(component.index());
      } else if (type == path_component_type::key) {
        const auto current_table = current->as<table>();
        if (!current_table)
          return {};

        current = current_table->get(component.key());
      } else {
        // Error: invalid component
        return {};
      }

      if (!current)
        return {}; // not found
    }

    return node_view{current};
  }

  TOML_EXTERNAL_LINKAGE
  node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept {
    return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
  }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/array.inl  ********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  array::array() noexcept {
#if TOML_LIFETIME_HOOKS
    TOML_ARRAY_CREATED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  array::~array() noexcept {
#if TOML_LIFETIME_HOOKS
    TOML_ARRAY_DESTROYED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  array::array(const impl::array_init_elem* b, const impl::array_init_elem* e) {
#if TOML_LIFETIME_HOOKS
    TOML_ARRAY_CREATED;
#endif

    TOML_ASSERT_ASSUME(b);
    TOML_ASSERT_ASSUME(e);
    TOML_ASSERT_ASSUME(b <= e);

    if TOML_UNLIKELY (b == e)
      return;

    size_t cap{};
    for (auto it = b; it != e; it++) {
      if (it->value)
        cap++;
    }
    if TOML_UNLIKELY (!cap)
      return;

    elems_.reserve(cap);
    for (; b != e; b++) {
      if (b->value)
        elems_.push_back(std::move(b->value));
    }
  }

  TOML_EXTERNAL_LINKAGE
  array::array(const array& other) //
      : node(other) {
    elems_.reserve(other.elems_.size());
    for (const auto& elem : other)
      elems_.emplace_back(impl::make_node(elem));

#if TOML_LIFETIME_HOOKS
    TOML_ARRAY_CREATED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  array::array(array && other) noexcept //
      : node(std::move(other)), elems_(std::move(other.elems_)) {
#if TOML_LIFETIME_HOOKS
    TOML_ARRAY_CREATED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  array& array::operator=(const array& rhs) {
    if (&rhs != this) {
      node::operator=(rhs);
      elems_.clear();
      elems_.reserve(rhs.elems_.size());
      for (const auto& elem : rhs)
        elems_.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));
      elems_ = std::move(rhs.elems_);
    }
    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  void array::preinsertion_resize(size_t idx, size_t count) {
    TOML_ASSERT(idx <= elems_.size());
    TOML_ASSERT_ASSUME(count >= 1u);
    const auto old_size = elems_.size();
    const auto new_size = old_size + count;
    const auto inserting_at_end = idx == old_size;
    elems_.resize(new_size);
    if (!inserting_at_end) {
      for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
        elems_[right] = std::move(elems_[left]);
    }
  }

  TOML_EXTERNAL_LINKAGE
  void array::insert_at_back(impl::node_ptr && elem) {
    TOML_ASSERT(elem);
    elems_.push_back(std::move(elem));
  }

  TOML_EXTERNAL_LINKAGE
  array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem) {
    return elems_.insert(pos, std::move(elem));
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool array::is_homogeneous(node_type ntype) const noexcept {
    if (elems_.empty())
      return false;

    if (ntype == node_type::none)
      ntype = elems_[0]->type();

    for (const auto& val : elems_)
      if (val->type() != ntype)
        return false;

    return true;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept {
    if (elems_.empty()) {
      first_nonmatch = {};
      return false;
    }
    if (ntype == node_type::none)
      ntype = elems_[0]->type();
    for (const auto& val : elems_) {
      if (val->type() != ntype) {
        first_nonmatch = val.get();
        return false;
      }
    }
    return true;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept {
    node* fnm = nullptr;
    const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
    first_nonmatch = fnm;
    return result;
  }

  TOML_EXTERNAL_LINKAGE
  node& array::at(size_t index) {
#if TOML_COMPILER_HAS_EXCEPTIONS

    return *elems_.at(index);

#else

    auto n = get(index);
    TOML_ASSERT_ASSUME(n && "element index not found in array!");
    return *n;

#endif
  }

  TOML_EXTERNAL_LINKAGE
  void array::reserve(size_t new_capacity) { elems_.reserve(new_capacity); }

  TOML_EXTERNAL_LINKAGE
  void array::shrink_to_fit() { elems_.shrink_to_fit(); }

  TOML_EXTERNAL_LINKAGE
  void array::truncate(size_t new_size) {
    if (new_size < elems_.size())
      elems_.resize(new_size);
  }

  TOML_EXTERNAL_LINKAGE
  array::iterator array::erase(const_iterator pos) noexcept {
    return iterator{elems_.erase(const_vector_iterator{pos})};
  }

  TOML_EXTERNAL_LINKAGE
  array::iterator array::erase(const_iterator first, const_iterator last) noexcept {
    return iterator{elems_.erase(const_vector_iterator{first}, const_vector_iterator{last})};
  }

  TOML_EXTERNAL_LINKAGE
  size_t array::total_leaf_count() const noexcept {
    size_t leaves{};
    for (size_t i = 0, e = elems_.size(); i < e; i++) {
      auto arr = elems_[i]->as_array();
      leaves += arr ? arr->total_leaf_count() : size_t{1};
    }
    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.elems_[i]->type();
      if (type == node_type::array) {
        array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
        if (!arr.empty())
          flatten_child(std::move(arr), dest_index);
      } else
        elems_[dest_index++] = std::move(child.elems_[i]);
    }
  }

  TOML_EXTERNAL_LINKAGE
  array& array::flatten() & {
    if (elems_.empty())
      return *this;

    bool requires_flattening = false;
    size_t size_after_flattening = elems_.size();
    for (size_t i = elems_.size(); i-- > 0u;) {
      auto arr = elems_[i]->as_array();
      if (!arr)
        continue;
      size_after_flattening--; // discount the array itself
      const auto leaf_count = arr->total_leaf_count();
      if (leaf_count > 0u) {
        requires_flattening = true;
        size_after_flattening += leaf_count;
      } else
        elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
    }

    if (!requires_flattening)
      return *this;

    elems_.reserve(size_after_flattening);

    size_t i = 0;
    while (i < elems_.size()) {
      auto arr = elems_[i]->as_array();
      if (!arr) {
        i++;
        continue;
      }

      impl::node_ptr arr_storage = std::move(elems_[i]);
      const auto leaf_count = arr->total_leaf_count();
      if (leaf_count > 1u)
        preinsertion_resize(i + 1u, leaf_count - 1u);
      flatten_child(std::move(*arr), i); // increments i
    }

    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  array& array::prune(bool recursive) & noexcept {
    if (elems_.empty())
      return *this;

    for (size_t i = elems_.size(); i-- > 0u;) {
      if (auto arr = elems_[i]->as_array()) {
        if (recursive)
          arr->prune(true);
        if (arr->empty())
          elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
      } else if (auto tbl = elems_[i]->as_table()) {
        if (recursive)
          tbl->prune(true);
        if (tbl->empty())
          elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
      }
    }

    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  void array::pop_back() noexcept { elems_.pop_back(); }

  TOML_EXTERNAL_LINKAGE
  void array::clear() noexcept { elems_.clear(); }

  TOML_EXTERNAL_LINKAGE
  bool TOML_CALLCONV array::equal(const array& lhs, const array& rhs) noexcept {
    if (&lhs == &rhs)
      return true;
    if (lhs.elems_.size() != rhs.elems_.size())
      return false;
    for (size_t i = 0, e = lhs.elems_.size(); i < e; i++) {
      const auto lhs_type = lhs.elems_[i]->type();
      const node& rhs_ = *rhs.elems_[i];
      const auto rhs_type = rhs_.type();
      if (lhs_type != rhs_type)
        return false;

      const bool equal = lhs.elems_[i]->visit([&](const auto& lhs_) noexcept {
        return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
      });
      if (!equal)
        return false;
    }
    return true;
  }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/table.inl  ********************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  table::table() noexcept {
#if TOML_LIFETIME_HOOKS
    TOML_TABLE_CREATED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  table::~table() noexcept {
#if TOML_LIFETIME_HOOKS
    TOML_TABLE_DESTROYED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  table::table(const impl::table_init_pair* b, const impl::table_init_pair* e) {
#if TOML_LIFETIME_HOOKS
    TOML_TABLE_CREATED;
#endif

    TOML_ASSERT_ASSUME(b);
    TOML_ASSERT_ASSUME(e);
    TOML_ASSERT_ASSUME(b <= e);

    if TOML_UNLIKELY (b == e)
      return;

    for (; b != e; b++) {
      if (!b->value) // empty node_views
        continue;

      map_.insert_or_assign(std::move(b->key), std::move(b->value));
    }
  }

  TOML_EXTERNAL_LINKAGE
  table::table(const table& other) //
      : node(other), inline_{other.inline_} {
    for (auto&& [k, v] : other.map_)
      map_.emplace_hint(map_.end(), k, impl::make_node(*v));

#if TOML_LIFETIME_HOOKS
    TOML_TABLE_CREATED;
#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
    TOML_TABLE_CREATED;
#endif
  }

  TOML_EXTERNAL_LINKAGE
  table& table::operator=(const table& rhs) {
    if (&rhs != this) {
      node::operator=(rhs);
      map_.clear();
      for (auto&& [k, v] : rhs.map_)
        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_PURE_GETTER
  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 (auto&& [k, v] : map_) {
      TOML_UNUSED(k);
      if (v->type() != ntype)
        return false;
    }

    return true;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool table::is_homogeneous(node_type ntype, node * &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_) {
      TOML_UNUSED(k);
      if (v->type() != ntype) {
        first_nonmatch = v.get();
        return false;
      }
    }
    return true;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept {
    node* fnm = nullptr;
    const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
    first_nonmatch = fnm;
    return result;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  node* table::get(std::string_view key) noexcept {
    if (auto it = map_.find(key); it != map_.end())
      return it->second.get();
    return nullptr;
  }

  TOML_EXTERNAL_LINKAGE
  node& table::at(std::string_view key) {
    auto n = get(key);

#if TOML_COMPILER_HAS_EXCEPTIONS

    if (!n) {
      auto err = "key '"s;
      err.append(key);
      err.append("' not found in table"sv);
      throw std::out_of_range{err};
    }

#else

    TOML_ASSERT_ASSUME(n && "key not found in table!");

#endif

    return *n;
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  table::map_iterator table::get_lower_bound(std::string_view key) noexcept { return map_.lower_bound(key); }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  table::iterator table::find(std::string_view key) noexcept { return iterator{map_.find(key)}; }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  table::const_iterator table::find(std::string_view key) const noexcept { return const_iterator{map_.find(key)}; }

  TOML_EXTERNAL_LINKAGE
  table::map_iterator table::erase(const_map_iterator pos) noexcept { return map_.erase(pos); }

  TOML_EXTERNAL_LINKAGE
  table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept {
    return map_.erase(begin, end);
  }

  TOML_EXTERNAL_LINKAGE
  size_t table::erase(std::string_view key) noexcept {
    if (auto it = map_.find(key); it != map_.end()) {
      map_.erase(it);
      return size_t{1};
    }
    return size_t{};
  }

  TOML_EXTERNAL_LINKAGE
  table& table::prune(bool recursive) & noexcept {
    if (map_.empty())
      return *this;

    for (auto it = map_.begin(); it != map_.end();) {
      if (auto arr = it->second->as_array()) {
        if (recursive)
          arr->prune(true);

        if (arr->empty()) {
          it = map_.erase(it);
          continue;
        }
      } else if (auto tbl = it->second->as_table()) {
        if (recursive)
          tbl->prune(true);

        if (tbl->empty()) {
          it = map_.erase(it);
          continue;
        }
      }
      it++;
    }

    return *this;
  }

  TOML_EXTERNAL_LINKAGE
  void table::clear() noexcept { map_.clear(); }

  TOML_EXTERNAL_LINKAGE
  table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v) {
    return map_.emplace_hint(const_map_iterator{hint}, std::move(k), std::move(v));
  }

  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool TOML_CALLCONV table::equal(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_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/simd.hpp  *********************************************************************************************

#if TOML_ENABLE_SIMD

#if defined(__SSE2__)                                                                                                  \
    || (defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))
#define TOML_HAS_SSE2 1
#endif

#if defined(__SSE4_1__) || (defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__)))
#define TOML_HAS_SSE4_1 1
#endif

#endif // TOML_ENABLE_SIMD

#ifndef TOML_HAS_SSE2
#define TOML_HAS_SSE2 0
#endif
#ifndef TOML_HAS_SSE4_1
#define TOML_HAS_SSE4_1 0
#endif

TOML_DISABLE_WARNINGS;
#if TOML_HAS_SSE4_1
#include <smmintrin.h>
#endif
#if TOML_HAS_SSE2
#include <emmintrin.h>
#endif
TOML_ENABLE_WARNINGS;

//********  impl/unicode.inl  ******************************************************************************************

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  TOML_PURE_GETTER
  TOML_EXTERNAL_LINKAGE
  bool is_ascii(const char* str, size_t len) noexcept {
    const char* const end = str + len;

#if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
    {
      constexpr size_t chars_per_vector = 128u / CHAR_BIT;

      if (const size_t simdable = len - (len % chars_per_vector)) {
        __m128i mask = _mm_setzero_si128();
        for (const char* const e = str + simdable; str < e; str += chars_per_vector) {
          const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
          mask = _mm_or_si128(mask, current_bytes);
        }
        const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);

#if TOML_HAS_SSE4_1
        if (!_mm_testz_si128(has_error, has_error))
          return false;
#else
        if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
          return false;
#endif
      }
    }
#endif

    for (; str < end; str++)
      if (static_cast<unsigned char>(*str) > 127u)
        return false;

    return true;
  }
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

//********  impl/parser.inl  *******************************************************************************************

#if TOML_ENABLE_PARSER

TOML_DISABLE_WARNINGS;
#include <fstream>
#include <istream>
#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;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_ANON_NAMESPACE_START {
  template <typename T> class utf8_byte_stream;

  TOML_INTERNAL_LINKAGE
  constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;

  template <typename Char> class utf8_byte_stream<std::basic_string_view<Char>> {
    static_assert(sizeof(Char) == 1);

  private:
    std::basic_string_view<Char> source_;
    size_t position_ = {};

  public:
    TOML_NODISCARD_CTOR
    explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept //
        : source_{sv} {
      // skip bom
      if (source_.length() >= 3u && memcmp(utf8_byte_order_mark.data(), source_.data(), 3u) == 0)
        position_ += 3u;
    }

    TOML_CONST_INLINE_GETTER
    constexpr bool error() const noexcept { return false; }

    TOML_PURE_INLINE_GETTER
    constexpr bool eof() const noexcept { return position_ >= source_.length(); }

    TOML_PURE_INLINE_GETTER
    explicit constexpr operator bool() const noexcept { return !eof(); }

    TOML_PURE_INLINE_GETTER
    constexpr bool peek_eof() const noexcept { return eof(); }

    TOML_NODISCARD
    TOML_ATTR(nonnull)
    size_t operator()(void* dest, size_t num) noexcept {
      TOML_ASSERT_ASSUME(!eof());

      num = impl::min(position_ + num, source_.length()) - position_;
      std::memcpy(dest, source_.data() + position_, num);
      position_ += num;
      return num;
    }
  };

  template <> class utf8_byte_stream<std::istream> {
  private:
    std::istream* source_;

  public:
    TOML_NODISCARD_CTOR
    explicit utf8_byte_stream(std::istream& stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) //
        : source_{&stream} {
      if (!*this) // eof, 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, 3u) == 0))
        return;

      source_->clear();
      source_->seekg(initial_pos, std::istream::beg);
    }

    TOML_PURE_INLINE_GETTER
    bool error() const noexcept { return !!(source_->rdstate() & std::istream::badbit); }

    TOML_PURE_INLINE_GETTER
    bool eof() const noexcept { return !!(source_->rdstate() & std::istream::eofbit); }

    TOML_PURE_INLINE_GETTER
    explicit operator bool() const noexcept {
      return !(source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
    }

    TOML_NODISCARD
    bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
      return eof() || source_->peek() == std::istream::traits_type::eof();
    }

    TOML_NODISCARD
    TOML_ATTR(nonnull)
    size_t operator()(void* dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
      TOML_ASSERT(*this);

      source_->read(static_cast<char*>(dest), static_cast<std::streamsize>(num));
      return static_cast<size_t>(source_->gcount());
    }
  };

  struct utf8_codepoint {
    char32_t value;
    char bytes[4];
    size_t count;
    source_position position;

    TOML_PURE_INLINE_GETTER
    constexpr operator const char32_t&() const noexcept { return value; }

    TOML_PURE_INLINE_GETTER
    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>);

  struct TOML_ABSTRACT_INTERFACE utf8_reader_interface {
    TOML_NODISCARD
    virtual const source_path_ptr& source_path() const noexcept = 0;

    TOML_NODISCARD
    virtual const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;

    TOML_NODISCARD
    virtual bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;

#if !TOML_EXCEPTIONS

    TOML_NODISCARD
    virtual optional<parse_error>&& error() noexcept = 0;

#endif

    virtual ~utf8_reader_interface() noexcept = default;
  };

#if TOML_EXCEPTIONS
#define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
#define utf8_reader_return_after_error(...) static_assert(true)
#define utf8_reader_error_check(...) static_assert(true)
#else
#define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
#define utf8_reader_return_after_error(...) return __VA_ARGS__
#define utf8_reader_error_check(...)                                                                                   \
  do {                                                                                                                 \
    if TOML_UNLIKELY (err_)                                                                                            \
      return __VA_ARGS__;                                                                                              \
  } while (false)

#endif

#if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
#define TOML_OVERALIGNED
#else
#define TOML_OVERALIGNED alignas(32)
#endif

  template <typename T> class TOML_EMPTY_BASES utf8_reader final : public utf8_reader_interface {
  private:
    static constexpr size_t block_capacity = 32;
    utf8_byte_stream<T> stream_;
    source_position next_pos_ = {1, 1};

    impl::utf8_decoder decoder_;
    struct currently_decoding_t {
      char bytes[4];
      size_t count;
    } currently_decoding_;

    struct codepoints_t {
      TOML_OVERALIGNED utf8_codepoint buffer[block_capacity];
      size_t current;
      size_t count;
    } codepoints_;

    source_path_ptr source_path_;

#if !TOML_EXCEPTIONS
    optional<parse_error> err_;
#endif

    bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
      TOML_ASSERT(stream_);

      TOML_OVERALIGNED char raw_bytes[block_capacity];
      size_t raw_bytes_read;

      // read the next raw (encoded) block in from the stream
      if constexpr (noexcept(stream_(raw_bytes, block_capacity)) || !TOML_EXCEPTIONS) {
        raw_bytes_read = stream_(raw_bytes, block_capacity);
      }
#if TOML_EXCEPTIONS
      else {
        try {
          raw_bytes_read = stream_(raw_bytes, block_capacity);
        } catch (const std::exception& exc) {
          throw parse_error{exc.what(), next_pos_, source_path_};
        } catch (...) {
          throw parse_error{"An unspecified error occurred", next_pos_, source_path_};
        }
      }
#endif // TOML_EXCEPTIONS

      // handle a zero-byte read
      if TOML_UNLIKELY (!raw_bytes_read) {
        if (stream_.eof()) {
          // EOF only sets the error state if the decoder wants more input, otherwise
          // a zero-byte read might have just caused the underlying stream to realize it's exhaused and set
          // the EOF flag, and that's totally fine
          if (decoder_.needs_more_input())
            utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence", next_pos_, source_path_);
        } else {
          utf8_reader_error("Reading from the underlying stream failed - zero bytes read", next_pos_, source_path_);
        }
        return false;
      }

      TOML_ASSERT_ASSUME(raw_bytes_read);
      std::memset(&codepoints_, 0, sizeof(codepoints_));

      // helper for calculating decoded codepoint line+cols
      const auto calc_positions = [&]() noexcept {
        for (size_t i = 0; i < codepoints_.count; i++) {
          auto& cp = codepoints_.buffer[i];
          cp.position = next_pos_;

          if (cp == U'\n') {
            next_pos_.line++;
            next_pos_.column = source_index{1};
          } else
            next_pos_.column++;
        }
      };

      // decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
      const auto ascii_fast_path = !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);

      // ASCII fast-path
      if (ascii_fast_path) {
        decoder_.reset();
        currently_decoding_.count = {};

        codepoints_.count = raw_bytes_read;
        for (size_t i = 0; i < codepoints_.count; i++) {
          auto& cp = codepoints_.buffer[i];
          cp.value = static_cast<char32_t>(raw_bytes[i]);
          cp.bytes[0] = raw_bytes[i];
          cp.count = 1u;
        }
      }

      // UTF-8 slow-path
      else {
        // helper for getting precise error location
        const auto error_pos = [&]() noexcept -> const source_position& { //
          return codepoints_.count ? codepoints_.buffer[codepoints_.count - 1u].position : next_pos_;
        };

        for (size_t i = 0; i < raw_bytes_read; i++) {
          decoder_(static_cast<uint8_t>(raw_bytes[i]));
          if TOML_UNLIKELY (decoder_.error()) {
            calc_positions();
            utf8_reader_error("Encountered invalid utf-8 sequence", error_pos(), source_path_);
            utf8_reader_return_after_error(false);
          }

          currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];

          if (decoder_.has_code_point()) {
            auto& cp = codepoints_.buffer[codepoints_.count++];

            cp.value = decoder_.codepoint;
            cp.count = currently_decoding_.count;
            std::memcpy(cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
            currently_decoding_.count = {};
          } else if TOML_UNLIKELY (currently_decoding_.count == 4u) {
            calc_positions();
            utf8_reader_error("Encountered overlong utf-8 sequence", error_pos(), source_path_);
            utf8_reader_return_after_error(false);
          }
        }
        if TOML_UNLIKELY (decoder_.needs_more_input() && stream_.eof()) {
          calc_positions();
          utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence", error_pos(), source_path_);
          utf8_reader_return_after_error(false);
        }
      }

      TOML_ASSERT_ASSUME(codepoints_.count);
      calc_positions();

      // handle general I/O errors
      // (down here so the next_pos_ benefits from calc_positions())
      if TOML_UNLIKELY (stream_.error()) {
        utf8_reader_error("An I/O error occurred while reading from the underlying stream", next_pos_, source_path_);
        utf8_reader_return_after_error(false);
      }

      return true;
    }

  public:
    template <typename U, typename String = std::string_view>
    TOML_NODISCARD_CTOR explicit utf8_reader(
        U&& source, String&& source_path = {}
    ) noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
        : stream_{static_cast<U&&>(source)} {
      currently_decoding_.count = {};

      codepoints_.current = {};
      codepoints_.count = {};

      if (!source_path.empty())
        source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
    }

    TOML_PURE_INLINE_GETTER
    const source_path_ptr& source_path() const noexcept final { return source_path_; }

    TOML_NODISCARD
    const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final {
      utf8_reader_error_check({});

      if (codepoints_.current == codepoints_.count) {
        if TOML_UNLIKELY (!stream_ || !read_next_block())
          return nullptr;

        TOML_ASSERT_ASSUME(!codepoints_.current);
      }
      TOML_ASSERT_ASSUME(codepoints_.count);
      TOML_ASSERT_ASSUME(codepoints_.count <= block_capacity);
      TOML_ASSERT_ASSUME(codepoints_.current < codepoints_.count);

      return &codepoints_.buffer[codepoints_.current++];
    }

    TOML_NODISCARD
    bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final { return stream_.peek_eof(); }

#if !TOML_EXCEPTIONS

    TOML_NODISCARD
    optional<parse_error>&& error() noexcept final { 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>>;

#if TOML_EXCEPTIONS
#define utf8_buffered_reader_error_check(...) static_assert(true)
#else
#define utf8_buffered_reader_error_check(...)                                                                          \
  do {                                                                                                                 \
    if TOML_UNLIKELY (reader_.error())                                                                                 \
      return __VA_ARGS__;                                                                                              \
  } while (false)

#endif

  class TOML_EMPTY_BASES utf8_buffered_reader {
  public:
    static constexpr size_t max_history_length = 128;

  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:
    TOML_NODISCARD_CTOR
    explicit utf8_buffered_reader(utf8_reader_interface& reader) noexcept //
        : reader_{reader} {}

    TOML_PURE_INLINE_GETTER
    const source_path_ptr& source_path() const noexcept { return reader_.source_path(); }

    TOML_NODISCARD
    const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
      utf8_buffered_reader_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_NODISCARD
    const utf8_codepoint* step_back(size_t count) noexcept {
      utf8_buffered_reader_error_check({});

      TOML_ASSERT_ASSUME(history_.count);
      TOML_ASSERT_ASSUME(negative_offset_ + count <= history_.count);

      negative_offset_ += count;

      return negative_offset_
          ? history_.buffer + ((history_.first + history_.count - negative_offset_) % history_buffer_size)
          : head_;
    }

    TOML_NODISCARD
    bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) { return reader_.peek_eof(); }

#if !TOML_EXCEPTIONS

    TOML_NODISCARD
    optional<parse_error>&& error() noexcept { return reader_.error(); }

#endif
  };
}
TOML_ANON_NAMESPACE_END;

#if TOML_EXCEPTIONS
#define TOML_RETURNS_BY_THROWING [[noreturn]]
#else
#define TOML_RETURNS_BY_THROWING
#endif

TOML_ANON_NAMESPACE_START {
  template <typename... T>
  TOML_CONST_GETTER TOML_INTERNAL_LINKAGE 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> {
    static constexpr auto scope_qualifier = "binary integer"sv;
    static constexpr auto is_digit = impl::is_binary_digit;
    static constexpr auto is_signed = false;
    static constexpr auto max_digits = 63;
    static constexpr auto prefix_codepoint = U'b';
    static constexpr auto prefix = "b"sv;
    static constexpr auto full_prefix = "0b"sv;
  };
  template <> struct parse_integer_traits<8> {
    static constexpr auto scope_qualifier = "octal integer"sv;
    static constexpr auto is_digit = impl::is_octal_digit;
    static constexpr auto is_signed = false;
    static constexpr auto max_digits = 21; // strlen("777777777777777777777")
    static constexpr auto prefix_codepoint = U'o';
    static constexpr auto prefix = "o"sv;
    static constexpr auto full_prefix = "0o"sv;
  };
  template <> struct parse_integer_traits<10> {
    static constexpr auto scope_qualifier = "decimal integer"sv;
    static constexpr auto is_digit = impl::is_decimal_digit;
    static constexpr auto is_signed = true;
    static constexpr auto max_digits = 19; // strlen("9223372036854775807")
    static constexpr auto full_prefix = ""sv;
  };
  template <> struct parse_integer_traits<16> {
    static constexpr auto scope_qualifier = "hexadecimal integer"sv;
    static constexpr auto is_digit = impl::is_hexadecimal_digit;
    static constexpr auto is_signed = false;
    static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
    static constexpr auto prefix_codepoint = U'x';
    static constexpr auto prefix = "x"sv;
    static constexpr auto full_prefix = "0x"sv;
  };

  TOML_PURE_GETTER
  TOML_INTERNAL_LINKAGE
  std::string_view to_sv(node_type val) noexcept { return impl::node_type_friendly_names[impl::unwrap_enum(val)]; }

  TOML_PURE_GETTER
  TOML_INTERNAL_LINKAGE
  std::string_view to_sv(const std::string& str) noexcept { return std::string_view{str}; }

  TOML_CONST_GETTER
  TOML_INTERNAL_LINKAGE
  std::string_view to_sv(bool val) noexcept {
    using namespace std::string_view_literals;

    return val ? "true"sv : "false"sv;
  }

  TOML_PURE_GETTER
  TOML_INTERNAL_LINKAGE
  std::string_view to_sv(const utf8_codepoint& cp) noexcept {
    if (cp.value <= U'\x1F')
      return impl::control_char_escapes[cp.value];
    else if (cp.value == U'\x7F')
      return "\\u007F"sv;
    else
      return std::string_view{cp.bytes, cp.count};
  }

  TOML_PURE_GETTER
  TOML_INTERNAL_LINKAGE
  std::string_view to_sv(const utf8_codepoint* cp) noexcept {
    if (cp)
      return to_sv(*cp);
    return ""sv;
  }

  struct escaped_codepoint {
    const utf8_codepoint& cp;
  };

  template <typename T>
  TOML_ATTR(nonnull)
  TOML_INTERNAL_LINKAGE void concatenate(char*& write_pos, char* const buf_end, const T& arg) noexcept {
    if TOML_UNLIKELY (write_pos >= buf_end)
      return;

    using arg_type = impl::remove_cvref<T>;

    // string views
    if constexpr (std::is_same_v<arg_type, 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;
    }

    // doubles
    else if constexpr (std::is_same_v<arg_type, double>) {
#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_type>::max_digits10);
      ss << arg;
      concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
    }

    // 64-bit integers
    else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_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_type>, int64_t, uint64_t>;
      ss << static_cast<cast_type>(arg);
      concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
    }

    // escaped_codepoint
    else if constexpr (std::is_same_v<arg_type, escaped_codepoint>) {
      if (arg.cp.value <= U'\x7F')
        concatenate(write_pos, buf_end, to_sv(arg.cp));
      else {
        auto val = static_cast<uint_least32_t>(arg.cp.value);
        const auto digits = val > 0xFFFFu ? 8u : 4u;
        constexpr auto mask = uint_least32_t{0xFu};
        char buf[10] = {'\\', digits > 4 ? 'U' : 'u'};
        for (auto i = 2u + digits; i-- > 2u;) {
          const auto hexdig = val & mask;
          buf[i] = static_cast<char>(hexdig >= 0xAu ? ('A' + (hexdig - 0xAu)) : ('0' + hexdig));
          val >>= 4;
        }
        concatenate(write_pos, buf_end, std::string_view{buf, digits + 2u});
      }
    }

    // all other floats (fallback - coerce to double)
    else if constexpr (std::is_floating_point_v<arg_type>)
      concatenate(write_pos, buf_end, static_cast<double>(arg));

    // all other integers (fallback - coerce to (u)int64_t)
    else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>) {
      using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
      concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
    }

    else {
      static_assert(
          impl::always_false<T>,
          "concatenate() inputs are limited to std::string_views, integers, floats, and escaped_codepoint"
      );
    }
  }

  struct error_builder {
    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

    TOML_NODISCARD_CTOR
    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 source_position& pos, const source_path_ptr& source_path) const {
      *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
    }

    TOML_DELETE_DEFAULTS(error_builder);
  };

  struct parse_scope {
    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_; }

    TOML_DELETE_DEFAULTS(parse_scope);
  };
#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__)

  struct parse_key_buffer {
    std::string buffer;
    std::vector<std::pair<size_t, size_t>> segments;
    std::vector<source_position> starts;
    std::vector<source_position> ends;

    void clear() noexcept {
      buffer.clear();
      segments.clear();
      starts.clear();
      ends.clear();
    }

    void push_back(std::string_view segment, source_position b, source_position e) {
      segments.push_back({buffer.length(), segment.length()});
      buffer.append(segment);
      starts.push_back(b);
      ends.push_back(e);
    }

    TOML_PURE_INLINE_GETTER
    std::string_view operator[](size_t i) const noexcept {
      return std::string_view{buffer.c_str() + segments[i].first, segments[i].second};
    }

    TOML_PURE_INLINE_GETTER
    std::string_view back() const noexcept { return (*this)[segments.size() - 1u]; }

    TOML_PURE_INLINE_GETTER
    bool empty() const noexcept { return segments.empty(); }

    TOML_PURE_INLINE_GETTER
    size_t size() const noexcept { return segments.size(); }
  };

  struct depth_counter_scope {
    size_t& depth_;

    TOML_NODISCARD_CTOR
    explicit depth_counter_scope(size_t& depth) noexcept //
        : depth_{depth} {
      depth_++;
    }

    ~depth_counter_scope() noexcept { depth_--; }

    TOML_DELETE_DEFAULTS(depth_counter_scope);
  };

  struct parsed_string {
    std::string_view value;
    bool was_multi_line;
  };

  struct table_vector_scope {
    std::vector<table*>& tables;

    TOML_NODISCARD_CTOR
    explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
        : tables{tables_} {
      tables.push_back(&tbl);
    }

    ~table_vector_scope() noexcept { tables.pop_back(); }

    TOML_DELETE_DEFAULTS(table_vector_scope);
  };
}
TOML_ANON_NAMESPACE_END;

#if 1 // parser helper macros

// 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++.

#define is_eof() !cp
#define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
#define return_if_eof(...)                                                                                             \
  do {                                                                                                                 \
    if TOML_UNLIKELY (is_eof())                                                                                        \
      return __VA_ARGS__;                                                                                              \
  } while (false)

#if TOML_EXCEPTIONS
#define is_error() false
#define return_after_error(...) TOML_UNREACHABLE
#define assert_not_error() static_assert(true)
#define return_if_error(...) static_assert(true)
#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 TOML_UNLIKELY (is_error())                                                                                      \
      return __VA_ARGS__;                                                                                              \
  } while (false)
#define return_if_error_or_eof(...)                                                                                    \
  do {                                                                                                                 \
    if TOML_UNLIKELY (is_eof() || is_error())                                                                          \
      return __VA_ARGS__;                                                                                              \
  } while (false)
#endif

#if defined(TOML_BREAK_AT_PARSE_ERRORS) && TOML_BREAK_AT_PARSE_ERRORS
#if defined(__has_builtin)
#if __has_builtin(__builtin_debugtrap)
#define parse_error_break() __builtin_debugtrap()
#elif __has_builtin(__debugbreak)
#define parse_error_break() __debugbreak()
#endif
#endif
#ifndef parse_error_break
#if TOML_MSVC || TOML_ICC
#define parse_error_break() __debugbreak()
#else
#define parse_error_break() TOML_ASSERT(false)
#endif
#endif
#else
#define parse_error_break() static_assert(true)
#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 TOML_UNLIKELY (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)

#endif // parser helper macros

TOML_IMPL_NAMESPACE_START {
  TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);

  class parser {
  private:
    static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES;

    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<table*> open_inline_tables;
    std::vector<array*> table_arrays;
    parse_key_buffer key_buffer;
    std::string string_buffer;
    std::string recording_buffer; // for diagnostics
    bool recording = false, recording_whitespace = true;
    std::string_view current_scope;
    size_t nested_values = {};
#if !TOML_EXCEPTIONS
    mutable optional<parse_error> err;
#endif

    TOML_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 {
      static_assert(sizeof...(T) > 0);
      return_if_error();

      error_builder builder{current_scope};
      (builder.append(reason), ...);

      parse_error_break();

#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 {
      set_error_at(current_position(1), reason...);
    }

    void go_back(size_t count = 1) noexcept {
      return_if_error();
      TOML_ASSERT_ASSUME(count);

      cp = reader.step_back(count);
      prev_pos = cp->position;
    }

    void advance() {
      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))
          recording_buffer.append(cp->bytes, cp->count);
      }
    }

    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->bytes, cp->count);
    }

    void stop_recording(size_t pop_bytes = 0) noexcept {
      return_if_error();

      recording = false;
      if (pop_bytes) {
        if (pop_bytes >= recording_buffer.length())
          recording_buffer.clear();
        else if (pop_bytes == 1u)
          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() {
      return_if_error_or_eof({});

      bool consumed = false;
      while (!is_eof() && is_horizontal_whitespace(*cp)) {
        if TOML_UNLIKELY (!is_ascii_horizontal_whitespace(*cp))
          set_error_and_return_default("expected space or tab, saw '"sv, escaped_codepoint{*cp}, "'"sv);

        consumed = true;
        advance_and_return_if_error({});
      }
      return consumed;
    }

    bool consume_line_break() {
      return_if_error_or_eof({});

      if TOML_UNLIKELY (is_match(*cp, U'\v', U'\f'))
        set_error_and_return_default(R"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);

      if (*cp == U'\r') {
        advance_and_return_if_error({}); // skip \r

        if TOML_UNLIKELY (is_eof())
          set_error_and_return_default("expected '\\n' after '\\r', saw EOF"sv);

        if TOML_UNLIKELY (*cp != U'\n')
          set_error_and_return_default("expected '\\n' after '\\r', saw '"sv, escaped_codepoint{*cp}, "'"sv);
      } else if (*cp != U'\n')
        return false;

      advance_and_return_if_error({}); // skip \n
      return true;
    }

    bool consume_rest_of_line() {
      return_if_error_or_eof({});

      do {
        if (is_ascii_vertical_whitespace(*cp))
          return consume_line_break();
        else
          advance();
        return_if_error({});
      } while (!is_eof());

      return true;
    }

    bool consume_comment() {
      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 TOML_LANG_AT_LEAST(1, 0, 0)

        // toml/issues/567 (disallow non-TAB control characters in comments)
        if TOML_UNLIKELY (is_nontab_control_character(*cp))
          set_error_and_return_default(
              "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv
          );

        // toml/pull/720 (disallow surrogates in comments)
        else if TOML_UNLIKELY (is_unicode_surrogate(*cp))
          set_error_and_return_default("unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
#endif

        advance_and_return_if_error({});
      }

      return true;
    }

    TOML_NODISCARD
    bool consume_expected_sequence(std::u32string_view seq) {
      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> TOML_NODISCARD bool consume_digit_sequence(T* digits, size_t len) {
      return_if_error({});
      TOML_ASSERT_ASSUME(digits);
      TOML_ASSERT_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> TOML_NODISCARD size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len) {
      return_if_error({});
      TOML_ASSERT_ASSUME(buffer);
      TOML_ASSERT_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;
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    std::string_view parse_basic_string(bool multi_line) {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(*cp == U'"');
      push_parse_scope("string"sv);

      // skip the '"'
      advance_and_return_if_error_or_eof({});

      // multi-line 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({});
      }

      auto& str = string_buffer;
      str.clear();
      bool escaped = false;
      bool skipping_whitespace = false;
      do {
        if (escaped) {
          escaped = false;

          // handle 'line ending slashes' in multi-line mode
          if (multi_line && is_whitespace(*cp)) {
            consume_leading_whitespace();

            if TOML_UNLIKELY (!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 skip_escaped_codepoint = true;
          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;

#if TOML_LANG_UNRELEASED // toml/pull/790 (\e shorthand for \x1B)
          case U'e':
            str += '\x1B';
            break;
#else
          case U'e':
            set_error_and_return_default("escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
#endif

#if TOML_LANG_UNRELEASED // toml/pull/796 (\xHH unicode scalar sequences)
          case U'x':
            [[fallthrough]];
#else
          case U'x':
            set_error_and_return_default("escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
#endif

          // unicode scalar sequences
          case U'u':
            [[fallthrough]];
          case U'U': {
            push_parse_scope("unicode scalar sequence"sv);
            advance_and_return_if_error_or_eof({});
            skip_escaped_codepoint = false;

            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 TOML_UNLIKELY (!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 TOML_UNLIKELY (is_unicode_surrogate(sequence_value))
              set_error_and_return_default("unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
            else if TOML_UNLIKELY (sequence_value > 0x10FFFFu)
              set_error_and_return_default("values greater than U+10FFFF are invalid"sv);

            if (sequence_value < 0x80) {
              str += static_cast<char>(sequence_value);
            } else if (sequence_value < 0x800u) {
              str += static_cast<char>((sequence_value >> 6) | 0xC0u);
              str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
            } else if (sequence_value < 0x10000u) {
              str += static_cast<char>((sequence_value >> 12) | 0xE0u);
              str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
              str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
            } else if (sequence_value < 0x110000u) {
              str += static_cast<char>((sequence_value >> 18) | 0xF0u);
              str += static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
              str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
              str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
            }
            break;
          }

            // ???
            TOML_UNLIKELY_CASE
          default:
            set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
          }

          if (skip_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;
              do {
                advance_and_return_if_error({});
                lookaheads++;
                if (!is_eof() && *cp == U'"')
                  consecutive_delimiters++;
                else
                  break;
              } while (lookaheads < 4u);

              switch (consecutive_delimiters) {
              // """ " (one quote somewhere in a ML string)
              case 1:
                str += '"';
                skipping_whitespace = false;
                continue;

              // """ "" (two quotes somewhere in a ML string)
              case 2:
                str.append("\"\""sv);
                skipping_whitespace = false;
                continue;

              // """ """ (the end of the string)
              case 3:
                return str;

              // """ """" (one at the end of the string)
              case 4:
                str += '"';
                return str;

              // """ """"" (two quotes at the end of the string)
              case 5:
                str.append("\"\""sv);
                advance_and_return_if_error({}); // skip the last '"'
                return str;

              default:
                TOML_UNREACHABLE;
              }
            } 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_ascii_vertical_whitespace(*cp)) {
            consume_line_break();
            return_if_error({});
            if (!skipping_whitespace)
              str += '\n';
            continue;
          }

          // handle control characters
          if TOML_UNLIKELY (is_nontab_control_character(*cp))
            set_error_and_return_default(
                "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv
            );

#if TOML_LANG_AT_LEAST(1, 0, 0)

          // handle surrogates in strings
          if TOML_UNLIKELY (is_unicode_surrogate(*cp))
            set_error_and_return_default("unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
#endif

          if (multi_line) {
            if (!skipping_whitespace || !is_horizontal_whitespace(*cp)) {
              skipping_whitespace = false;
              str.append(cp->bytes, cp->count);
            }
          } else
            str.append(cp->bytes, cp->count);

          advance_and_return_if_error({});
        }
      } while (!is_eof());

      set_error_and_return_default("encountered end-of-file"sv);
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    std::string_view parse_literal_string(bool multi_line) {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(*cp == U'\'');
      push_parse_scope("literal string"sv);

      // skip the delimiter
      advance_and_return_if_error_or_eof({});

      // multi-line 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({});
      }

      auto& str = string_buffer;
      str.clear();
      do {
        return_if_error({});

        // handle closing delimiters
        if (*cp == U'\'') {
          if (multi_line) {
            size_t lookaheads = {};
            size_t consecutive_delimiters = 1;
            do {
              advance_and_return_if_error({});
              lookaheads++;
              if (!is_eof() && *cp == U'\'')
                consecutive_delimiters++;
              else
                break;
            } while (lookaheads < 4u);

            switch (consecutive_delimiters) {
            // ''' ' (one quote somewhere in a ML string)
            case 1:
              str += '\'';
              continue;

            // ''' '' (two quotes somewhere in a ML string)
            case 2:
              str.append("''"sv);
              continue;

            // ''' ''' (the end of the string)
            case 3:
              return str;

            // ''' '''' (one at the end of the string)
            case 4:
              str += '\'';
              return str;

            // ''' ''''' (two quotes at the end of the string)
            case 5:
              str.append("''"sv);
              advance_and_return_if_error({}); // skip the last '
              return str;

            default:
              TOML_UNREACHABLE;
            }
          } else {
            advance_and_return_if_error({}); // skip the closing delimiter
            return str;
          }
        }

        // handle line endings in multi-line mode
        if (multi_line && is_ascii_vertical_whitespace(*cp)) {
          consume_line_break();
          return_if_error({});
          str += '\n';
          continue;
        }

        // handle control characters
        if TOML_UNLIKELY (is_nontab_control_character(*cp))
          set_error_and_return_default("control characters other than TAB (U+0009) are explicitly prohibited"sv);

#if TOML_LANG_AT_LEAST(1, 0, 0)

        // handle surrogates in strings
        if TOML_UNLIKELY (is_unicode_surrogate(*cp))
          set_error_and_return_default("unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
#endif

        str.append(cp->bytes, cp->count);
        advance_and_return_if_error({});
      } while (!is_eof());

      set_error_and_return_default("encountered end-of-file"sv);
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    parsed_string parse_string() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_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(2u);

        return {first == U'\'' ? parse_literal_string(false) : parse_basic_string(false), false};
      }
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    std::string_view parse_bare_key_segment() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(is_bare_key_character(*cp));

      string_buffer.clear();

      while (!is_eof()) {
        if (!is_bare_key_character(*cp))
          break;

        string_buffer.append(cp->bytes, cp->count);
        advance_and_return_if_error({});
      }

      return string_buffer;
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    bool parse_boolean() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_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;
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    double parse_inf_or_nan() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_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_NODISCARD
    TOML_NEVER_INLINE
    double parse_float() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_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[utf8_buffered_reader::max_history_length];
      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 TOML_UNLIKELY (prev && *prev == U'_' && !is_decimal_digit(*cp))
          set_error_and_return_default("underscores must be followed by digits"sv);
        else if TOML_UNLIKELY (length == sizeof(chars))
          set_error_and_return_default(
              "exceeds length limit of "sv, sizeof(chars), " digits"sv,
              (seen_exponent ? ""sv : " (consider using exponent notation)"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);

        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) {
          TOML_LIKELY_CASE
        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
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    double parse_hex_float() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_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 == 0u && fragments[1].length == 0u)
            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, 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 == 0u) {
        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 ? 10u : 16u;

        // 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 - 1u; 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> TOML_NODISCARD TOML_NEVER_INLINE int64_t parse_integer() {
      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({});

        if (!traits::is_digit(*cp))
          set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
      }

      // consume digits
      char digits[utf8_buffered_reader::max_history_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 TOML_UNLIKELY (prev && *prev == U'_' && !traits::is_digit(*cp))
          set_error_and_return_default("underscores must be followed by digits"sv);
        else if TOML_UNLIKELY (!traits::is_digit(*cp))
          set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
        else if TOML_UNLIKELY (length == sizeof(digits))
          set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
        else
          digits[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);
      }

      // single digits can be converted trivially
      if (length == 1u) {
        int64_t result;

        if constexpr (base == 16)
          result = static_cast<int64_t>(hex_to_dec(digits[0]));
        else
          result = static_cast<int64_t>(digits[0] - '0');

        if constexpr (traits::is_signed)
          result *= sign;

        return result;
      }

      // bin, oct and hex allow leading zeroes so trim them first
      const char* end = digits + length;
      const char* msd = digits;
      if constexpr (base != 10) {
        while (msd < end && *msd == '0')
          msd++;
        if (msd == end)
          return 0ll;
      }

      // decimal integers do not allow leading zeroes
      else {
        if TOML_UNLIKELY (digits[0] == '0')
          set_error_and_return_default("leading zeroes are prohibited"sv);
      }

      // range check
      if TOML_UNLIKELY (static_cast<size_t>(end - msd) > traits::max_digits)
        set_error_and_return_default(
            "'"sv, traits::full_prefix, std::string_view{digits, length}, "' is not representable in 64 bits"sv
        );

      // do the thing
      {
        uint64_t result = {};
        {
          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
        static constexpr auto i64_max = static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
        if TOML_UNLIKELY (result > i64_max + (sign < 0 ? 1u : 0u))
          set_error_and_return_default(
              "'"sv, traits::full_prefix, std::string_view{digits, length}, "' is not representable in 64 bits"sv
          );

        if constexpr (traits::is_signed) {
          // avoid signed multiply UB when parsing INT64_MIN
          if TOML_UNLIKELY (sign < 0 && result == i64_max + 1u)
            return (std::numeric_limits<int64_t>::min)();

          return static_cast<int64_t>(result) * sign;
        } else
          return static_cast<int64_t>(result);
      }
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    date parse_date(bool part_of_datetime = false) {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
      push_parse_scope("date"sv);

      // "YYYY"
      uint32_t digits[4];
      if (!consume_digit_sequence(digits, 4u))
        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, 2u))
        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, 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, 2u))
        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, max_days_in_month, " (inclusive), saw "sv, 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 {year, month, day};
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    time parse_time(bool part_of_datetime = false) {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
      push_parse_scope("time"sv);

      static constexpr size_t max_digits = 64; // far more than necessary but needed to allow fractional
                                               // millisecond truncation per the spec
      uint32_t digits[max_digits];

      // "HH"
      if (!consume_digit_sequence(digits, 2u))
        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, 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, 2u))
        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, minute);
      auto time = toml::time{hour, 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', 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, 2u))
        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, second);
      time.second = static_cast<decltype(time.second)>(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', 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"
      size_t 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, 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 = impl::min<size_t>(digit_count, 9u); i-- > 0u;) {
        value += digits[i] * place;
        place *= 10u;
      }
      for (auto i = digit_count; i < 9u; i++) // implicit zeros
        value *= 10u;
      time.nanosecond = value;
      return time;
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    date_time parse_date_time() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_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({});

      // ' ', 'T' or 't'
      if (!is_match(*cp, U' ', U'T', U't'))
        set_error_and_return_default("expected space, 'T' 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' or 'z')
      time_offset offset{};
      if (is_match(*cp, U'Z', 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, 2u))
          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, 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, 2u))
          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, minute);
        offset.minutes = static_cast<decltype(offset.minutes)>((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_NODISCARD
    node_ptr parse_array();

    TOML_NODISCARD
    node_ptr parse_inline_table();

    TOML_NODISCARD
    node_ptr parse_value_known_prefixes() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(!is_control_character(*cp));
      TOML_ASSERT_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 node_ptr{new value{parse_float()}};

      // strings
      case U'"':
        [[fallthrough]];
      case U'\'':
        return node_ptr{new value{parse_string().value}};

      default: {
        const auto cp_upper = static_cast<uint_least32_t>(cp->value) & ~0x20u;

        // bools
        if (cp_upper == 70u || cp_upper == 84u) // F or T
          return node_ptr{new value{parse_boolean()}};

        // inf/nan
        else if (cp_upper == 73u || cp_upper == 78u) // I or N
          return node_ptr{new value{parse_inf_or_nan()}};

        else
          return nullptr;
      }
      }
      TOML_UNREACHABLE;
    }

    TOML_NODISCARD
    node_ptr parse_value() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
      push_parse_scope("value"sv);

      const depth_counter_scope depth_counter{nested_values};
      if TOML_UNLIKELY (nested_values > max_nested_values)
        set_error_and_return_default(
            "exceeded maximum nested value depth of "sv, max_nested_values, " (TOML_MAX_NESTED_VALUES)"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 {
        TOML_ASSERT_ASSUME(!is_control_character(*cp));
        TOML_ASSERT_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 TOML_CLOSED_FLAGS_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,
          signs_msk = has_plus | has_minus,
          bdigit_msk = has_digits | begins_digit,
          bzero_msk = bdigit_msk | begins_zero,
        };
        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(begins_digit);
          if (*cp == U'0')
            add_trait(begins_zero);
        } 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 = [&]() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
          if (is_eof())
            return;
          TOML_ASSERT_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)) {
                TOML_ASSERT_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 == 2u && has_any(begins_zero))
                    add_trait(has_b);
                  break;

                case U'e':
                  if (char_count > 1u
                      && 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 == 2u && 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 == 2u && has_any(begins_zero))
                      || (char_count == 3u && 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':') {
                TOML_ASSERT_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 - 1u)
                   && !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 == 10u                                    //
            && (traits | begins_zero) == (bzero_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 = 10u;
          };

          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 == 12u)
              backpedal();
          }
        }

        // set the reader back to where we started
        go_back(advance_count);

        // if after scanning ahead we still only have one value character,
        // the only valid value type is an integer.
        if (char_count == 1u) {
          if (has_any(begins_digit)) {
            val.reset(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({});
        TOML_ASSERT_ASSUME(char_count >= 2u);

        // 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.reset(new value{parse_hex_float()});
        else if (has_any(has_x | has_o | has_b)) {
          int64_t i;
          value_flags flags;
          if (has_any(has_x)) {
            i = parse_integer<16>();
            flags = value_flags::format_as_hexadecimal;
          } else if (has_any(has_o)) {
            i = parse_integer<8>();
            flags = value_flags::format_as_octal;
          } else // has_b
          {
            i = parse_integer<2>();
            flags = value_flags::format_as_binary;
          }
          return_if_error({});

          val.reset(new value{i});
          val->ref_cast<int64_t>().flags(flags);
        } else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
          val.reset(new value{parse_float()});
        else if (has_any(begins_sign)) {
          // single-digit signed integers
          if (char_count == 2u && has_any(has_digits)) {
            val.reset(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.reset(new value{parse_float()});

          // signed infinity or nan
          else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
            val.reset(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.reset(new value{parse_integer<2>()});
          val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
          break;

        // octal integers
        // 0o10
        case bzero_msk | has_o:
          val.reset(new value{parse_integer<8>()});
          val->ref_cast<int64_t>().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: {
          // if the value was so long we exhausted the history buffer it's reasonable to assume
          // there was more and the value's actual type is impossible to identify without making the
          // buffer bigger (since it could have actually been a float), so emit an error.
          //
          // (this will likely only come up during fuzzing and similar scenarios)
          static constexpr size_t max_numeric_value_length = utf8_buffered_reader::max_history_length - 2u;
          if TOML_UNLIKELY (!eof_while_scanning && advance_count > max_numeric_value_length)
            set_error_and_return_default(
                "numeric value too long to identify type - cannot exceed "sv, max_numeric_value_length, " characters"sv
            );

          val.reset(new value{parse_integer<10>()});
          break;
        }

        // hexadecimal integers
        // 0x10
        case bzero_msk | has_x:
          val.reset(new value{parse_integer<16>()});
          val->ref_cast<int64_t>().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.reset(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.reset(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.reset(new value{parse_time()});
          break;

        // local dates
        // YYYY-MM-DD
        case bzero_msk | has_minus:
          [[fallthrough]];
        case bdigit_msk | has_minus:
          val.reset(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.reset(new value{parse_date_time()});
          break;
        }
      } while (false);

      if (!val) {
        set_error_at(begin_pos, "could not determine value type"sv);
        return_after_error({});
      }

      val->source_ = {begin_pos, current_position(1), reader.source_path()};
      return val;
    }

    TOML_NEVER_INLINE
    bool parse_key() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(is_bare_key_character(*cp) || is_string_delimiter(*cp));
      push_parse_scope("key"sv);

      key_buffer.clear();
      recording_whitespace = false;

      while (!is_error()) {
        std::string_view key_segment;
        const auto key_begin = current_position();

        // bare_key_segment
        if (is_bare_key_character(*cp))
          key_segment = parse_bare_key_segment();

        // "quoted key segment"
        else if (is_string_delimiter(*cp)) {
          const auto begin_pos = cp->position;

          recording_whitespace = true;
          parsed_string 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_buffer.empty() ? ""sv : "dotted "sv, "keys"sv
            );
            return_after_error({});
          } else
            key_segment = str.value;
        }

        // ???
        else
          set_error_and_return_default(
              "expected bare key starting character or string delimiter, saw '"sv, to_sv(*cp), "'"sv
          );

        const auto key_end = current_position();

        // whitespace following the key segment
        consume_leading_whitespace();

        // store segment
        key_buffer.push_back(key_segment, key_begin, key_end);

        // eof or no more key to come
        if (is_eof() || *cp != U'.')
          break;

        // was a dotted key - go around again
        advance_and_return_if_error_or_eof({});
        consume_leading_whitespace();
        set_error_and_return_if_eof({});
      }
      return_if_error({});

      return true;
    }

    TOML_NODISCARD
    key make_key(size_t segment_index) const {
      TOML_ASSERT(key_buffer.size() > segment_index);

      return key{
          key_buffer[segment_index],
          source_region{key_buffer.starts[segment_index], key_buffer.ends[segment_index], root.source().path}
      };
    }

    TOML_NODISCARD
    TOML_NEVER_INLINE
    table* parse_table_header() {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(*cp == U'[');
      push_parse_scope("table header"sv);

      const source_position header_begin_pos = cp->position;
      source_position header_end_pos;
      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();
        parse_key();
        stop_recording(1u);
        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_buffer.empty());

      // check if each parent is a table/table array, or can be created implicitly as a table.
      table* parent = &root;
      for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++) {
        const std::string_view segment = key_buffer[i];
        auto pit = parent->lower_bound(segment);

        // parent already existed
        if (pit != parent->end() && pit->first == segment) {
          node& p = pit->second;

          if (auto tbl = p.as_table()) {
            // adding to closed inline tables is illegal
            if (tbl->is_inline() && !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
              set_error_and_return_default(
                  "cannot insert '"sv, to_sv(recording_buffer), "' into existing inline table"sv
              );

            parent = tbl;
          } else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr)) {
            // table arrays are a special case;
            // the spec dictates we select the most recently declared element in the array.
            TOML_ASSERT(!arr->empty());
            TOML_ASSERT(arr->back().is_table());
            parent = &arr->back().ref_cast<table>();
          } else {
            if (!is_arr && p.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(p.type()), " '"sv, to_sv(recording_buffer), "' as "sv,
                  is_arr ? "array-of-tables"sv : "table"sv
              );
          }
        }

        // need to create a new implicit table
        else {
          pit = parent->emplace_hint<table>(pit, make_key(i));
          table& p = pit->second.ref_cast<table>();
          p.source_ = {header_begin_pos, header_end_pos, reader.source_path()};

          implicit_tables.push_back(&p);
          parent = &p;
        }
      }

      const auto last_segment = key_buffer.back();
      auto it = parent->lower_bound(last_segment);

      // 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.
      if (it != parent->end() && it->first == last_segment) {
        node& matching_node = it->second;
        if (auto arr = matching_node.as_array();
            is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr)) {
          table& tbl = arr->emplace_back<table>();
          tbl.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
          return &tbl;
        }

        else if (auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty()) {
          if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl); found) {
            bool ok = true;
            if (!tbl->empty()) {
              for (auto& [_, child] : *tbl) {
                if (!child.is_table() && !child.is_array_of_tables()) {
                  ok = false;
                  break;
                }
              }
            }

            if (ok) {
              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_at(header_begin_pos, "cannot redefine existing table '"sv, to_sv(recording_buffer), "'"sv);
          return_after_error({});
        } else {
          set_error_at(
              header_begin_pos, "cannot redefine existing "sv, to_sv(matching_node.type()), " '"sv,
              to_sv(recording_buffer), "' as "sv, is_arr ? "array-of-tables"sv : "table"sv
          );
          return_after_error({});
        }
      }

      // there was no matching node, sweet - we can freely instantiate a new table/table array.
      else {
        auto last_key = make_key(key_buffer.size() - 1u);

        // 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) {
          it = parent->emplace_hint<array>(it, std::move(last_key));
          array& tbl_arr = it->second.ref_cast<array>();
          table_arrays.push_back(&tbl_arr);
          tbl_arr.source_ = {header_begin_pos, header_end_pos, reader.source_path()};

          table& tbl = tbl_arr.emplace_back<table>();
          tbl.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
          return &tbl;
        }

        // otherwise we're just making a table
        else {
          it = parent->emplace_hint<table>(it, std::move(last_key));
          table& tbl = it->second.ref_cast<table>();
          tbl.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
          return &tbl;
        }
      }
    }

    TOML_NEVER_INLINE
    bool parse_key_value_pair_and_insert(table* tbl) {
      return_if_error({});
      assert_not_eof();
      TOML_ASSERT_ASSUME(is_string_delimiter(*cp) || is_bare_key_character(*cp));
      push_parse_scope("key-value pair"sv);

      // read the key into the key buffer
      start_recording();
      parse_key();
      stop_recording(1u);
      return_if_error({});
      TOML_ASSERT(key_buffer.size() >= 1u);

      // 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({});

      // check that the next character could actually be a value
      if (is_value_terminator(*cp))
        set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);

      // if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
      // and set the target table to the second-to-last one in the chain
      if (key_buffer.size() > 1u) {
        for (size_t i = 0; i < key_buffer.size() - 1u; i++) {
          const std::string_view segment = key_buffer[i];
          auto pit = tbl->lower_bound(segment);

          // parent already existed
          if (pit != tbl->end() && pit->first == segment) {
            table* p = pit->second.as_table();

            // redefinition
            if TOML_UNLIKELY (
                !p
                || !(
                    impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
                    || impl::find(implicit_tables.begin(), implicit_tables.end(), p)
                )
            ) {
              set_error_at(
                  key_buffer.starts[i], "cannot redefine existing "sv, to_sv(pit->second.type()),
                  " as dotted key-value pair"sv
              );
              return_after_error({});
            }

            tbl = p;
          }

          // need to create a new implicit table
          else {
            pit = tbl->emplace_hint<table>(pit, make_key(i));
            table& p = pit->second.ref_cast<table>();
            p.source_ = pit->first.source();

            dotted_key_tables.push_back(&p);
            tbl = &p;
          }
        }
      }

      // ensure this isn't a redefinition
      const std::string_view last_segment = key_buffer.back();
      auto it = tbl->lower_bound(last_segment);
      if (it != tbl->end() && it->first == last_segment) {
        set_error("cannot redefine existing "sv, to_sv(it->second.type()), " '"sv, to_sv(recording_buffer), "'"sv);
        return_after_error({});
      }

      // create the key first since the key buffer will likely get overwritten during value parsing (inline
      // tables)
      auto last_key = make_key(key_buffer.size() - 1u);

      // now we can actually parse the value
      node_ptr val = parse_value();
      return_if_error({});

      tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
      return true;
    }

    void parse_document() {
      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.is_inline()) // inline tables (and all their inline descendants) are already correctly
                             // terminated
          return;

        auto end = nde.source_.end;
        for (auto&& [k, v] : tbl) {
          TOML_UNUSED(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) {
          update_region_ends(v);
          if (end < v.source_.end)
            end = v.source_.end;
        }
        nde.source_.end = end;
      }
    }

  public:
    parser(utf8_reader_interface&& reader_) //
        : 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_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_EXTERNAL_LINKAGE
  node_ptr parser::parse_array() {
    return_if_error({});
    assert_not_eof();
    TOML_ASSERT_ASSUME(*cp == U'[');
    push_parse_scope("array"sv);

    // skip opening '['
    advance_and_return_if_error_or_eof({});

    node_ptr arr_ptr{new array{}};
    array& arr = arr_ptr->ref_cast<array>();
    enum class TOML_CLOSED_ENUM parse_type : int { none, comma, val };
    parse_type prev = parse_type::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 == parse_type::val) {
          prev = parse_type::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 == parse_type::val) {
          set_error_and_return_default("expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
          continue;
        }
        prev = parse_type::val;

        auto val = parse_value();
        return_if_error({});

        if (!arr.capacity())
          arr.reserve(4u);
        arr.emplace_back<node_ptr>(std::move(val));
      }
    }

    return_if_error({});
    return arr_ptr;
  }

  TOML_EXTERNAL_LINKAGE
  node_ptr parser::parse_inline_table() {
    return_if_error({});
    assert_not_eof();
    TOML_ASSERT_ASSUME(*cp == U'{');
    push_parse_scope("inline table"sv);

    // skip opening '{'
    advance_and_return_if_error_or_eof({});

    node_ptr tbl_ptr{new table{}};
    table& tbl = tbl_ptr->ref_cast<table>();
    tbl.is_inline(true);
    table_vector_scope table_scope{open_inline_tables, tbl};

    enum class TOML_CLOSED_ENUM parse_type : int { none, comma, kvp };
    parse_type prev = parse_type::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 == parse_type::kvp) {
          prev = parse_type::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 == parse_type::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 == parse_type::kvp)
          set_error_and_return_default("expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
        else {
          prev = parse_type::kvp;
          parse_key_value_pair_and_insert(&tbl);
        }
      }

      else
        set_error_and_return_default("expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
    }

    return_if_error({});
    return tbl_ptr;
  }

  TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_IMPL_NAMESPACE_END;

#undef TOML_RETURNS_BY_THROWING
#undef advance_and_return_if_error
#undef advance_and_return_if_error_or_eof
#undef assert_not_eof
#undef assert_not_error
#undef is_eof
#undef is_error
#undef parse_error_break
#undef push_parse_scope
#undef push_parse_scope_1
#undef push_parse_scope_2
#undef return_after_error
#undef return_if_eof
#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 utf8_buffered_reader_error_check
#undef utf8_reader_error
#undef utf8_reader_error_check
#undef utf8_reader_return_after_error

TOML_ANON_NAMESPACE_START {
  TOML_NODISCARD
  TOML_INTERNAL_LINKAGE
  parse_result do_parse(utf8_reader_interface && reader) { return impl::parser{std::move(reader)}; }

  TOML_NODISCARD
  TOML_INTERNAL_LINKAGE
  parse_result do_parse_file(std::string_view file_path) {
#if TOML_EXCEPTIONS
#define TOML_PARSE_FILE_ERROR(msg, path)                                                                               \
  throw parse_error{msg, source_position{}, std::make_shared<const std::string>(std::move(path))}
#else
#define TOML_PARSE_FILE_ERROR(msg, path)                                                                               \
  return parse_result {                                                                                                \
    parse_error { msg, source_position{}, std::make_shared<const std::string>(std::move(path)) }                       \
  }
#endif

    std::string file_path_str(file_path);

    // open file with a custom-sized stack buffer
    std::ifstream file;
    TOML_OVERALIGNED char file_buffer[sizeof(void*) * 1024u];
    file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
#if TOML_WINDOWS
    file.open(impl::widen(file_path_str).c_str(), std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
#else
    file.open(file_path_str, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
#endif
    if (!file.is_open())
      TOML_PARSE_FILE_ERROR("File could not be opened for reading", file_path_str);

    // get size
    const auto file_size = file.tellg();
    if (file_size == -1)
      TOML_PARSE_FILE_ERROR("Could not determine file size", file_path_str);
    file.seekg(0, std::ifstream::beg);

    // read the whole file into memory first if the file isn't too large
    constexpr auto large_file_threshold = 1024 * 1024 * 2; // 2 MB
    if (file_size <= large_file_threshold) {
      std::vector<char> 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::string_view{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));

#undef TOML_PARSE_FILE_ERROR
  }
}
TOML_ANON_NAMESPACE_END;

TOML_NAMESPACE_START {
  TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse_file(std::string_view file_path) {
    return TOML_ANON_NAMESPACE::do_parse_file(file_path);
  }

#if TOML_HAS_CHAR8

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse_file(std::u8string_view file_path) {
    std::string file_path_str;
    file_path_str.resize(file_path.length());
    memcpy(file_path_str.data(), file_path.data(), file_path.length());
    return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
  }

#endif // TOML_HAS_CHAR8

#if TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
  }

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse_file(std::wstring_view file_path) {
    return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
  }

#endif // TOML_ENABLE_WINDOWS_COMPAT

#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT

  TOML_EXTERNAL_LINKAGE
  parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path) {
    return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
  }

#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT

  TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_NAMESPACE_END;

#undef TOML_OVERALIGNED

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_PARSER

//********  impl/formatter.inl  ****************************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_IMPL_NAMESPACE_START {
  enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned {
    none,
    line_breaks = 1u << 0,   // \n
    tabs = 1u << 1,          // \t
    control_chars = 1u << 2, // also includes non-ascii vertical whitespace
    single_quotes = 1u << 3,
    non_bare = 1u << 4,  // anything not satisfying "is bare key character"
    non_ascii = 1u << 5, // any codepoint >= 128

    all = (non_ascii << 1u) - 1u
  };
  TOML_MAKE_FLAGS(formatted_string_traits);

  TOML_EXTERNAL_LINKAGE
  formatter::formatter(
      const node* source_node, const parse_result* source_pr, const formatter_constants& constants,
      const formatter_config& config
  ) noexcept //
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
      : source_{source_pr && *source_pr ? &source_pr->table() : source_node}, result_{source_pr},
#else
      : source_{source_pr ? source_pr : source_node},
#endif
        constants_{&constants}, config_{config} {
    TOML_ASSERT_ASSUME(source_);

    config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;

    indent_columns_ = {};
    for (auto c : config_.indent)
      indent_columns_ += c == '\t' ? 4u : 1u;

    int_format_mask_ = config_.flags
        & (format_flags::allow_binary_integers
           | format_flags::allow_octal_integers
           | format_flags::allow_hexadecimal_integers);
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::attach(std::ostream & stream) noexcept {
    indent_ = {};
    naked_newline_ = true;
    stream_ = &stream;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::detach() noexcept { stream_ = nullptr; }

  TOML_EXTERNAL_LINKAGE
  void formatter::print_newline(bool force) {
    if (!naked_newline_ || force) {
      print_to_stream(*stream_, '\n');
      naked_newline_ = true;
    }
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print_indent() {
    for (int i = 0; i < indent_; i++) {
      print_to_stream(*stream_, config_.indent);
      naked_newline_ = false;
    }
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print_unformatted(char c) {
    print_to_stream(*stream_, c);
    naked_newline_ = false;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print_unformatted(std::string_view str) {
    print_to_stream(*stream_, str);
    naked_newline_ = false;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print_string(
      std::string_view str, bool allow_multi_line, bool allow_bare, bool allow_literal_whitespace
  ) {
    if (str.empty()) {
      print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
      return;
    }

    // pre-scan the string to determine how we should output it
    formatted_string_traits traits = {};

    if (!allow_bare)
      traits |= formatted_string_traits::non_bare;
    bool unicode_allowed = unicode_strings_allowed();

    // ascii fast path
    if (is_ascii(str.data(), str.length())) {
      for (auto c : str) {
        switch (c) {
        case '\n':
          traits |= formatted_string_traits::line_breaks;
          break;
        case '\t':
          traits |= formatted_string_traits::tabs;
          break;
        case '\'':
          traits |= formatted_string_traits::single_quotes;
          break;
        default: {
          if TOML_UNLIKELY (is_control_character(c))
            traits |= formatted_string_traits::control_chars;

          if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
            traits |= formatted_string_traits::non_bare;
          break;
        }
        }

        static constexpr auto all_ascii_traits = formatted_string_traits::all & ~formatted_string_traits::non_ascii;
        if (traits == all_ascii_traits)
          break;
      }
    }

    // unicode slow path
    else {
      traits |= formatted_string_traits::non_ascii;
      utf8_decoder decoder;

      // if the unicode is malformed just treat the string as a single-line non-literal and
      // escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
      const auto bad_unicode = [&]() noexcept {
        traits &= ~formatted_string_traits::line_breaks;
        traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
        unicode_allowed = false;
      };

      for (auto c : str) {
        decoder(c);

        if TOML_UNLIKELY (decoder.error()) {
          bad_unicode();
          break;
        }

        if (!decoder.has_code_point())
          continue;

        switch (decoder.codepoint) {
        case U'\n':
          traits |= formatted_string_traits::line_breaks;
          break;
        case U'\t':
          traits |= formatted_string_traits::tabs;
          break;
        case U'\'':
          traits |= formatted_string_traits::single_quotes;
          break;
        default: {
          if TOML_UNLIKELY (
              is_control_character(decoder.codepoint) || is_non_ascii_vertical_whitespace(decoder.codepoint)
          )
            traits |= formatted_string_traits::control_chars;

          if (!is_bare_key_character(decoder.codepoint))
            traits |= formatted_string_traits::non_bare;
          break;
        }
        }
      }

      if (decoder.needs_more_input())
        bad_unicode();
    }

    // strings with line breaks, tabs, and single-quotes can't be bare
    if (!!(traits
           & (formatted_string_traits::line_breaks
              | formatted_string_traits::tabs
              | formatted_string_traits::single_quotes)))
      traits |= formatted_string_traits::non_bare;

    // if the string meets the requirements of being 'bare' we can emit a bare string
    // (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
    if (!(traits & formatted_string_traits::non_bare)
        && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed)) {
      print_unformatted(str);
      return;
    }
    const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();

    // determine if this should be a multi-line string (triple-quotes)
    const auto multi_line = allow_literal_whitespace //
        && allow_multi_line                          //
        && multi_line_strings_allowed()              //
        && !!(traits & formatted_string_traits::line_breaks);

    // determine if this should be a literal string (single-quotes with no escaping)
    const auto literal = literal_strings_allowed()                            //
        && !(traits & formatted_string_traits::control_chars)                 //
        && (!(traits & formatted_string_traits::single_quotes) || multi_line) //
        && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed)   //
        && (!(traits & formatted_string_traits::line_breaks) || multi_line)   //
        && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);

    // literal strings (single quotes, no escape codes)
    if (literal) {
      const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
      print_unformatted(quot);
      print_unformatted(str);
      print_unformatted(quot);
      return;
    }

    // anything from here down is a non-literal string, so requires iteration and escaping.
    print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);

    // ascii fast path
    if (!(traits & formatted_string_traits::non_ascii)) {
      for (auto c : str) {
        switch (c) {
        case '"':
          print_to_stream(*stream_, R"(\")"sv);
          break;
        case '\\':
          print_to_stream(*stream_, R"(\\)"sv);
          break;
        case '\x7F':
          print_to_stream(*stream_, R"(\u007F)"sv);
          break;
        case '\t':
          print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv);
          break;
        case '\n':
          print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv);
          break;
        default: {
          // control characters from lookup table
          if TOML_UNLIKELY (c >= '\x00' && c <= '\x1F')
            print_to_stream(*stream_, control_char_escapes[c]);

          // regular characters
          else
            print_to_stream(*stream_, c);
        }
        }
      }
    }

    // unicode slow path
    else {
      utf8_decoder decoder;
      const char* cp_start = str.data();
      const char* cp_end = cp_start;
      for (auto c : str) {
        decoder(c);
        cp_end++;

        // if the decoder encounters malformed unicode just emit raw bytes and
        if (decoder.error()) {
          while (cp_start != cp_end) {
            print_to_stream(*stream_, R"(\u00)"sv);
            print_to_stream(*stream_, static_cast<uint8_t>(*cp_start), value_flags::format_as_hexadecimal, 2);
            cp_start++;
          }
          decoder.reset();
          continue;
        }

        if (!decoder.has_code_point())
          continue;

        switch (decoder.codepoint) {
        case U'"':
          print_to_stream(*stream_, R"(\")"sv);
          break;
        case U'\\':
          print_to_stream(*stream_, R"(\\)"sv);
          break;
        case U'\x7F':
          print_to_stream(*stream_, R"(\u007F)"sv);
          break;
        case U'\t':
          print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv);
          break;
        case U'\n':
          print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv);
          break;
        default: {
          // control characters from lookup table
          if TOML_UNLIKELY (decoder.codepoint <= U'\x1F')
            print_to_stream(*stream_, control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);

          // escaped unicode characters
          else if (
              decoder.codepoint > U'\x7F' && (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint))
          ) {
            if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu) {
              print_to_stream(*stream_, R"(\U)"sv);
              print_to_stream(
                  *stream_, static_cast<uint_least32_t>(decoder.codepoint), value_flags::format_as_hexadecimal, 8
              );
            } else {
              print_to_stream(*stream_, R"(\u)"sv);
              print_to_stream(
                  *stream_, static_cast<uint_least32_t>(decoder.codepoint), value_flags::format_as_hexadecimal, 4
              );
            }
          }

          // regular characters
          else
            print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
        }
        }

        cp_start = cp_end;
      }
    }

    print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<std::string>& val) { print_string(val.get()); }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<int64_t>& val) {
    naked_newline_ = false;

    if (*val >= 0 && !!int_format_mask_) {
      static constexpr auto value_flags_mask =
          value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;

      const auto fmt = val.flags() & value_flags_mask;
      switch (fmt) {
      case value_flags::format_as_binary:
        if (!!(int_format_mask_ & format_flags::allow_binary_integers)) {
          print_to_stream(*stream_, "0b"sv);
          print_to_stream(*stream_, *val, fmt);
          return;
        }
        break;

      case value_flags::format_as_octal:
        if (!!(int_format_mask_ & format_flags::allow_octal_integers)) {
          print_to_stream(*stream_, "0o"sv);
          print_to_stream(*stream_, *val, fmt);
          return;
        }
        break;

      case value_flags::format_as_hexadecimal:
        if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers)) {
          print_to_stream(*stream_, "0x"sv);
          print_to_stream(*stream_, *val, fmt);
          return;
        }
        break;

      default:
        break;
      }
    }

    // fallback to decimal
    print_to_stream(*stream_, *val);
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<double>& val) {
    const std::string_view* inf_nan = nullptr;
    switch (fpclassify(*val)) {
    case fp_class::neg_inf:
      inf_nan = &constants_->float_neg_inf;
      break;
    case fp_class::pos_inf:
      inf_nan = &constants_->float_pos_inf;
      break;
    case fp_class::nan:
      inf_nan = &constants_->float_nan;
      break;
    case fp_class::ok:
      print_to_stream(*stream_, *val, value_flags::none, !!(config_.flags & format_flags::relaxed_float_precision));
      break;
    default:
      TOML_UNREACHABLE;
    }

    if (inf_nan) {
      if (!!(config_.flags & format_flags::quote_infinities_and_nans))
        print_to_stream_bookended(*stream_, *inf_nan, '"');
      else
        print_to_stream(*stream_, *inf_nan);
    }

    naked_newline_ = false;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<bool>& val) {
    print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<date>& val) {
    if (!!(config_.flags & format_flags::quote_dates_and_times))
      print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
    else
      print_to_stream(*stream_, *val);
    naked_newline_ = false;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<time>& val) {
    if (!!(config_.flags & format_flags::quote_dates_and_times))
      print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
    else
      print_to_stream(*stream_, *val);
    naked_newline_ = false;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::print(const value<date_time>& val) {
    if (!!(config_.flags & format_flags::quote_dates_and_times))
      print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
    else
      print_to_stream(*stream_, *val);
    naked_newline_ = false;
  }

  TOML_EXTERNAL_LINKAGE
  void formatter::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;
    default:
      TOML_UNREACHABLE;
    }
  }

#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS

  TOML_EXTERNAL_LINKAGE
  bool formatter::dump_failed_parse_result() {
    if (result_ && !(*result_)) {
      stream() << result_->error();
      return true;
    }
    return false;
  }

#else

  TOML_EXTERNAL_LINKAGE
  TOML_ATTR(const)
  bool formatter::dump_failed_parse_result() { return false; }

#endif
}
TOML_IMPL_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

//********  impl/toml_formatter.inl  ***********************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_DISABLE_ARITHMETIC_WARNINGS;

TOML_ANON_NAMESPACE_START {
  TOML_INTERNAL_LINKAGE
  size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept {
    switch (node.type()) {
    case node_type::table: {
      auto& tbl = *reinterpret_cast<const table*>(&node);
      if (tbl.empty())
        return 2u;        // "{}"
      size_t weight = 3u; // "{ }"
      for (auto&& [k, v] : tbl) {
        weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // +  ", "
        if (weight >= line_wrap_cols)
          break;
      }
      return weight;
    }

    case node_type::array: {
      auto& arr = *reinterpret_cast<const array*>(&node);
      if (arr.empty())
        return 2u;        // "[]"
      size_t weight = 3u; // "[ ]"
      for (auto& elem : arr) {
        weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // +  ", "
        if (weight >= line_wrap_cols)
          break;
      }
      return weight;
    }

    case node_type::string: {
      // todo: proper utf8 decoding?
      // todo: tab awareness?
      auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
      return str.length() + 2u; // + ""
    }

    case node_type::integer: {
      auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
      if (!val)
        return 1u;
      size_t weight = {};
      if (val < 0) {
        weight += 1u;
        val *= -1;
      }
      return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
    }

    case node_type::floating_point: {
      auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
      if (val == 0.0)
        return 3u;        // "0.0"
      size_t weight = 2u; // ".0"
      if (val < 0.0) {
        weight += 1u;
        val *= -1.0;
      }
      return weight + static_cast<size_t>(log10(val)) + 1u;
      break;
    }

    case node_type::boolean:
      return 5u;
    case node_type::date:
      [[fallthrough]];
    case node_type::time:
      return 10u;
    case node_type::date_time:
      return 30u;
    case node_type::none:
      TOML_UNREACHABLE;
    default:
      TOML_UNREACHABLE;
    }

    TOML_UNREACHABLE;
  }

  TOML_INTERNAL_LINKAGE
  bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept {
    return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols;
  }
}
TOML_ANON_NAMESPACE_END;

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  void toml_formatter::print_pending_table_separator() {
    if (pending_table_separator_) {
      print_newline(true);
      print_newline(true);
      pending_table_separator_ = false;
    }
  }

  TOML_EXTERNAL_LINKAGE
  void toml_formatter::print(const key& k) { print_string(k.str(), false, true, false); }

  TOML_EXTERNAL_LINKAGE
  void toml_formatter::print_inline(const table& tbl) {
    if (tbl.empty()) {
      print_unformatted("{}"sv);
      return;
    }

    print_unformatted("{ "sv);

    bool first = false;
    for (auto&& [k, v] : tbl) {
      if (first)
        print_unformatted(", "sv);
      first = true;

      print(k);
      if (terse_kvps())
        print_unformatted("="sv);
      else
        print_unformatted(" = "sv);

      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:
        print_value(v, type);
      }
    }

    print_unformatted(" }"sv);
  }

  TOML_EXTERNAL_LINKAGE
  void toml_formatter::print(const array& arr) {
    if (arr.empty()) {
      print_unformatted("[]"sv);
      return;
    }

    const auto original_indent = indent();
    const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
        arr, 120u, indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent)
    );

    print_unformatted("["sv);

    if (multiline) {
      if (original_indent < 0)
        indent(0);
      if (indent_array_elements())
        increase_indent();
    } else
      print_unformatted(' ');

    for (size_t i = 0; i < arr.size(); i++) {
      if (i > 0u) {
        print_unformatted(',');
        if (!multiline)
          print_unformatted(' ');
      }

      if (multiline) {
        print_newline(true);
        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:
        print_value(v, type);
      }
    }
    if (multiline) {
      indent(original_indent);
      print_newline(true);
      print_indent();
    } else
      print_unformatted(' ');

    print_unformatted("]"sv);
  }

  TOML_EXTERNAL_LINKAGE
  void toml_formatter::print(const table& tbl) {
    static constexpr auto is_non_inline_array_of_tables = [](const node& n) noexcept {
      const auto arr = n.as_array();
      if (!arr || !arr->is_array_of_tables())
        return false;

      return !reinterpret_cast<const table*>(&(*arr)[0])->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;

      pending_table_separator_ = true;
      print_newline();
      print_indent();
      print(k);
      if (terse_kvps())
        print_unformatted("="sv);
      else
        print_unformatted(" = "sv);
      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:
        print_value(v, type);
      }
    }

    const auto print_key_path = [&]() {
      size_t i{};
      for (const auto k : key_path_) {
        if (i++)
          print_unformatted('.');
        print(*k);
      }
    };

    // 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) {
        TOML_UNUSED(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 == 0u && (child_table_count > 0u || child_table_array_count > 0u))
        skip_self = true;

      key_path_.push_back(&k);

      if (!skip_self) {
        print_pending_table_separator();
        if (indent_sub_tables())
          increase_indent();
        print_indent();
        print_unformatted("["sv);
        print_key_path();
        print_unformatted("]"sv);
        pending_table_separator_ = true;
      }

      print(child_tbl);

      key_path_.pop_back();
      if (!skip_self && indent_sub_tables())
        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);

      if (indent_sub_tables())
        increase_indent();
      key_path_.push_back(&k);

      for (size_t i = 0; i < arr.size(); i++) {
        print_pending_table_separator();
        print_indent();
        print_unformatted("[["sv);
        print_key_path();
        print_unformatted("]]"sv);
        pending_table_separator_ = true;
        print(*reinterpret_cast<const table*>(&arr[i]));
      }

      key_path_.pop_back();
      if (indent_sub_tables())
        decrease_indent();
    }
  }

  TOML_EXTERNAL_LINKAGE
  void toml_formatter::print() {
    if (dump_failed_parse_result())
      return;

    switch (auto source_type = source().type()) {
    case node_type::table: {
      auto& tbl = *reinterpret_cast<const table*>(&source());
      if (tbl.is_inline())
        print_inline(tbl);
      else {
        decrease_indent(); // so root kvps and tables have the same indent
        print(tbl);
      }
      break;
    }

    case node_type::array:
      print(*reinterpret_cast<const array*>(&source()));
      break;

    default:
      print_value(source(), source_type);
    }
  }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

//********  impl/json_formatter.inl  ***********************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  void json_formatter::print(const toml::table& tbl) {
    if (tbl.empty()) {
      print_unformatted("{}"sv);
      return;
    }

    print_unformatted('{');

    if (indent_sub_tables())
      increase_indent();
    bool first = false;
    for (auto&& [k, v] : tbl) {
      if (first)
        print_unformatted(',');
      first = true;
      print_newline(true);
      print_indent();

      print_string(k.str(), false);
      if (terse_kvps())
        print_unformatted(":"sv);
      else
        print_unformatted(" : "sv);

      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:
        print_value(v, type);
      }
    }
    if (indent_sub_tables())
      decrease_indent();
    print_newline(true);
    print_indent();

    print_unformatted('}');
  }

  TOML_EXTERNAL_LINKAGE
  void json_formatter::print(const toml::array& arr) {
    if (arr.empty()) {
      print_unformatted("[]"sv);
      return;
    }

    print_unformatted('[');
    if (indent_array_elements())
      increase_indent();
    for (size_t i = 0; i < arr.size(); i++) {
      if (i > 0u)
        print_unformatted(',');
      print_newline(true);
      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:
        print_value(v, type);
      }
    }
    if (indent_array_elements())
      decrease_indent();
    print_newline(true);
    print_indent();
    print_unformatted(']');
  }

  TOML_EXTERNAL_LINKAGE
  void json_formatter::print() {
    if (dump_failed_parse_result())
      return;

    switch (auto source_type = source().type()) {
    case node_type::table:
      print(*reinterpret_cast<const table*>(&source()));
      break;
    case node_type::array:
      print(*reinterpret_cast<const array*>(&source()));
      break;
    default:
      print_value(source(), source_type);
    }
  }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

//********  impl/yaml_formatter.inl  ***********************************************************************************

#if TOML_ENABLE_FORMATTERS

TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

TOML_NAMESPACE_START {
  TOML_EXTERNAL_LINKAGE
  void yaml_formatter::print_yaml_string(const value<std::string>& str) {
    if (str->empty()) {
      base::print(str);
      return;
    }

    bool contains_newline = false;
    for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
      contains_newline = *c == '\n';

    if (contains_newline) {
      print_unformatted("|-"sv);

      increase_indent();

      auto line_end = str->c_str() - 1u;
      const auto end = str->c_str() + str->length();
      while (line_end != end) {
        auto line_start = line_end + 1u;
        line_end = line_start;
        for (; line_end != end && *line_end != '\n'; line_end++)
          ;

        if TOML_LIKELY (line_start != line_end || line_end != end) {
          print_newline();
          print_indent();
          print_unformatted(std::string_view{line_start, static_cast<size_t>(line_end - line_start)});
        }
      }

      decrease_indent();
    } else
      print_string(*str, false, true);
  }

  TOML_EXTERNAL_LINKAGE
  void yaml_formatter::print(const toml::table& tbl, bool parent_is_array) {
    if (tbl.empty()) {
      print_unformatted("{}"sv);
      return;
    }

    increase_indent();

    for (auto&& [k, v] : tbl) {
      if (!parent_is_array) {
        print_newline();
        print_indent();
      }
      parent_is_array = false;

      print_string(k.str(), false, true);
      if (terse_kvps())
        print_unformatted(":"sv);
      else
        print_unformatted(": "sv);

      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;
      case node_type::string:
        print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v));
        break;
      default:
        print_value(v, type);
      }
    }

    decrease_indent();
  }

  TOML_EXTERNAL_LINKAGE
  void yaml_formatter::print(const toml::array& arr, bool parent_is_array) {
    if (arr.empty()) {
      print_unformatted("[]"sv);
      return;
    }

    increase_indent();

    for (auto&& v : arr) {
      if (!parent_is_array) {
        print_newline();
        print_indent();
      }
      parent_is_array = false;

      print_unformatted("- "sv);

      const auto type = v.type();
      TOML_ASSUME(type != node_type::none);
      switch (type) {
      case node_type::table:
        print(*reinterpret_cast<const table*>(&v), true);
        break;
      case node_type::array:
        print(*reinterpret_cast<const array*>(&v), true);
        break;
      case node_type::string:
        print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v));
        break;
      default:
        print_value(v, type);
      }
    }

    decrease_indent();
  }

  TOML_EXTERNAL_LINKAGE
  void yaml_formatter::print() {
    if (dump_failed_parse_result())
      return;

    switch (auto source_type = source().type()) {
    case node_type::table:
      decrease_indent(); // so root kvps and tables have the same indent
      print(*reinterpret_cast<const table*>(&source()));
      break;

    case node_type::array:
      print(*reinterpret_cast<const array*>(&source()));
      break;

    case node_type::string:
      print_yaml_string(*reinterpret_cast<const value<std::string>*>(&source()));
      break;

    default:
      print_value(source(), source_type);
    }
  }
}
TOML_NAMESPACE_END;

#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

#endif // TOML_ENABLE_FORMATTERS

#endif // TOML_IMPLEMENTATION

TOML_POP_WARNINGS;

// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_ABI_NAMESPACE_BOOL
#undef TOML_ABI_NAMESPACE_END
#undef TOML_ABI_NAMESPACE_START
#undef TOML_ABI_NAMESPACES
#undef TOML_ABSTRACT_INTERFACE
#undef TOML_ALWAYS_INLINE
#undef TOML_ANON_NAMESPACE
#undef TOML_ANON_NAMESPACE_END
#undef TOML_ANON_NAMESPACE_START
#undef TOML_ARCH_AMD64
#undef TOML_ARCH_ARM
#undef TOML_ARCH_ARM32
#undef TOML_ARCH_ARM64
#undef TOML_ARCH_BITNESS
#undef TOML_ARCH_ITANIUM
#undef TOML_ARCH_X64
#undef TOML_ARCH_X86
#undef TOML_ASSERT
#undef TOML_ASSERT_ASSUME
#undef TOML_ASSUME
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_ATTR
#undef TOML_CLANG
#undef TOML_CLANG_VERSION
#undef TOML_CLOSED_ENUM
#undef TOML_CLOSED_FLAGS_ENUM
#undef TOML_COMPILER_HAS_EXCEPTIONS
#undef TOML_COMPILER_HAS_RTTI
#undef TOML_CONST
#undef TOML_CONST_GETTER
#undef TOML_CONST_INLINE_GETTER
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_CPP
#undef TOML_DECLSPEC
#undef TOML_DELETE_DEFAULTS
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_11
#undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNINGS
#undef TOML_DISABLE_WARNINGS
#undef TOML_DOXYGEN
#undef TOML_EMPTY_BASES
#undef TOML_ENABLE_IF
#undef TOML_ENABLE_WARNINGS
#undef TOML_EVAL_BOOL_0
#undef TOML_EVAL_BOOL_1
#undef TOML_EXTERNAL_LINKAGE
#undef TOML_FLAGS_ENUM
#undef TOML_FLOAT_CHARCONV
#undef TOML_FLOAT128
#undef TOML_FLOAT16_DIG
#undef TOML_FLOAT16_LIMITS_SET
#undef TOML_FLOAT16_MANT_DIG
#undef TOML_FLOAT16_MAX_10_EXP
#undef TOML_FLOAT16_MAX_EXP
#undef TOML_FLOAT16_MIN_10_EXP
#undef TOML_FLOAT16_MIN_EXP
#undef TOML_GCC
#undef TOML_GCC_LIKE
#undef TOML_HAS_ATTR
#undef TOML_HAS_BUILTIN
#undef TOML_HAS_CHAR8
#undef TOML_HAS_CPP_ATTR
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#undef TOML_HAS_FEATURE
#undef TOML_HAS_INCLUDE
#undef TOML_HAS_SSE2
#undef TOML_HAS_SSE4_1
#undef TOML_HIDDEN_CONSTRAINT
#undef TOML_ICC
#undef TOML_ICC_CL
#undef TOML_IMPL_NAMESPACE_END
#undef TOML_IMPL_NAMESPACE_START
#undef TOML_IMPLEMENTATION
#undef TOML_INCLUDE_WINDOWS_H
#undef TOML_INLINE_GETTER
#undef TOML_INT_CHARCONV
#undef TOML_INT128
#undef TOML_INTELLISENSE
#undef TOML_INTERNAL_LINKAGE
#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_LIKELY_CASE
#undef TOML_LINUX
#undef TOML_MAKE_FLAGS
#undef TOML_MAKE_FLAGS_
#undef TOML_MAKE_FLAGS_1
#undef TOML_MAKE_FLAGS_2
#undef TOML_MAKE_STRING
#undef TOML_MAKE_STRING_1
#undef TOML_MAKE_VERSION
#undef TOML_MSVC
#undef TOML_MSVC_LIKE
#undef TOML_NAMESPACE
#undef TOML_NEVER_INLINE
#undef TOML_NODISCARD
#undef TOML_NODISCARD_CTOR
#undef TOML_OPEN_ENUM
#undef TOML_OPEN_FLAGS_ENUM
#undef TOML_PARSER_TYPENAME
#undef TOML_POP_WARNINGS
#undef TOML_PRAGMA_CLANG
#undef TOML_PRAGMA_CLANG_GE_10
#undef TOML_PRAGMA_CLANG_GE_11
#undef TOML_PRAGMA_CLANG_GE_8
#undef TOML_PRAGMA_CLANG_GE_9
#undef TOML_PRAGMA_GCC
#undef TOML_PRAGMA_ICC
#undef TOML_PRAGMA_MSVC
#undef TOML_PURE
#undef TOML_PURE_GETTER
#undef TOML_PURE_INLINE_GETTER
#undef TOML_PUSH_WARNINGS
#undef TOML_REQUIRES
#undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
#undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
#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_UNIX
#undef TOML_UNLIKELY
#undef TOML_UNLIKELY_CASE
#undef TOML_UNREACHABLE
#undef TOML_UNUSED
#undef TOML_WINDOWS
#endif

#endif // TOMLPLUSPLUS_HPP
