diff options
| author | Amlal EL Mahrouss <amlalelmahrouss@icloud.com> | 2024-10-09 07:25:04 +0200 |
|---|---|---|
| committer | Amlal EL Mahrouss <amlalelmahrouss@icloud.com> | 2024-10-09 07:25:04 +0200 |
| commit | 35bf67c51b620b96827b75b0548f56d08415bb90 (patch) | |
| tree | 2c57462a5fc2c981c1159c367df5c943c3c827ed /inc | |
| parent | 518a6da50bfb86e938b2bbf850e3740fa824e832 (diff) | |
IMP: Add Windows version of BTB. Also separate vendor libs from include
directory.
Signed-off-by: Amlal EL Mahrouss <amlalelmahrouss@icloud.com>
Diffstat (limited to 'inc')
| -rw-r--r-- | inc/json.hxx | 24766 | ||||
| -rw-r--r-- | inc/json_fwd.hxx | 176 | ||||
| -rw-r--r-- | inc/toml.hxx | 17788 |
3 files changed, 0 insertions, 42730 deletions
diff --git a/inc/json.hxx b/inc/json.hxx deleted file mode 100644 index a858728..0000000 --- a/inc/json.hxx +++ /dev/null @@ -1,24766 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - -/****************************************************************************\ - * Note on documentation: The source files contain links to the online * - * documentation of the public API at https://json.nlohmann.me. This URL * - * contains the most recent documentation and should also be applicable to * - * previous versions; documentation for deprecated functions is not * - * removed, but marked deprecated. See "Generate documentation" section in * - * file docs/README.md. * -\****************************************************************************/ - -#ifndef INCLUDE_NLOHMANN_JSON_HPP_ -#define INCLUDE_NLOHMANN_JSON_HPP_ - -#include <algorithm> // all_of, find, for_each -#include <cstddef> // nullptr_t, ptrdiff_t, size_t -#include <functional> // hash, less -#include <initializer_list> // initializer_list -#ifndef JSON_NO_IO - #include <iosfwd> // istream, ostream -#endif // JSON_NO_IO -#include <iterator> // random_access_iterator_tag -#include <memory> // unique_ptr -#include <string> // string, stoi, to_string -#include <utility> // declval, forward, move, pair, swap -#include <vector> // vector - -// #include <nlohmann/adl_serializer.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <utility> - -// #include <nlohmann/detail/abi_macros.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// This file contains all macro definitions affecting or depending on the ABI - -#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK - #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) - #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 - #warning "Already included a different version of the library!" - #endif - #endif -#endif - -#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) - -#ifndef JSON_DIAGNOSTICS - #define JSON_DIAGNOSTICS 0 -#endif - -#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON - #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 -#endif - -#if JSON_DIAGNOSTICS - #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag -#else - #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS -#endif - -#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON - #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp -#else - #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON -#endif - -#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION - #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 -#endif - -// Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) - -#define NLOHMANN_JSON_ABI_TAGS \ - NLOHMANN_JSON_ABI_TAGS_CONCAT( \ - NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ - NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) - -// Construct the namespace version component -#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ - _v ## major ## _ ## minor ## _ ## patch -#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ - NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) - -#if NLOHMANN_JSON_NAMESPACE_NO_VERSION -#define NLOHMANN_JSON_NAMESPACE_VERSION -#else -#define NLOHMANN_JSON_NAMESPACE_VERSION \ - NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ - NLOHMANN_JSON_VERSION_MINOR, \ - NLOHMANN_JSON_VERSION_PATCH) -#endif - -// Combine namespace components -#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b -#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ - NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) - -#ifndef NLOHMANN_JSON_NAMESPACE -#define NLOHMANN_JSON_NAMESPACE \ - nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ - NLOHMANN_JSON_ABI_TAGS, \ - NLOHMANN_JSON_NAMESPACE_VERSION) -#endif - -#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN -#define NLOHMANN_JSON_NAMESPACE_BEGIN \ - namespace nlohmann \ - { \ - inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ - NLOHMANN_JSON_ABI_TAGS, \ - NLOHMANN_JSON_NAMESPACE_VERSION) \ - { -#endif - -#ifndef NLOHMANN_JSON_NAMESPACE_END -#define NLOHMANN_JSON_NAMESPACE_END \ - } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ - } // namespace nlohmann -#endif - -// #include <nlohmann/detail/conversions/from_json.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // transform -#include <array> // array -#include <forward_list> // forward_list -#include <iterator> // inserter, front_inserter, end -#include <map> // map -#include <string> // string -#include <tuple> // tuple, make_tuple -#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible -#include <unordered_map> // unordered_map -#include <utility> // pair, declval -#include <valarray> // valarray - -// #include <nlohmann/detail/exceptions.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstddef> // nullptr_t -#include <exception> // exception -#if JSON_DIAGNOSTICS - #include <numeric> // accumulate -#endif -#include <stdexcept> // runtime_error -#include <string> // to_string -#include <vector> // vector - -// #include <nlohmann/detail/value_t.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <array> // array -#include <cstddef> // size_t -#include <cstdint> // uint8_t -#include <string> // string - -// #include <nlohmann/detail/macro_scope.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <utility> // declval, pair -// #include <nlohmann/detail/meta/detected.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <type_traits> - -// #include <nlohmann/detail/meta/void_t.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename ...Ts> struct make_void -{ - using type = void; -}; -template<typename ...Ts> using void_t = typename make_void<Ts...>::type; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -// https://en.cppreference.com/w/cpp/experimental/is_detected -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - nonesuch(nonesuch const&&) = delete; - void operator=(nonesuch const&) = delete; - void operator=(nonesuch&&) = delete; -}; - -template<class Default, - class AlwaysVoid, - template<class...> class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template<class Default, template<class...> class Op, class... Args> -struct detector<Default, void_t<Op<Args...>>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op<Args...>; -}; - -template<template<class...> class Op, class... Args> -using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; - -template<template<class...> class Op, class... Args> -struct is_detected_lazy : is_detected<Op, Args...> { }; - -template<template<class...> class Op, class... Args> -using detected_t = typename detector<nonesuch, void, Op, Args...>::type; - -template<class Default, template<class...> class Op, class... Args> -using detected_or = detector<Default, void, Op, Args...>; - -template<class Default, template<class...> class Op, class... Args> -using detected_or_t = typename detected_or<Default, Op, Args...>::type; - -template<class Expected, template<class...> class Op, class... Args> -using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; - -template<class To, template<class...> class Op, class... Args> -using is_detected_convertible = - std::is_convertible<detected_t<Op, Args...>, To>; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/thirdparty/hedley/hedley.hpp> - - -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com> -// SPDX-License-Identifier: MIT - -/* Hedley - https://nemequ.github.io/hedley - * Created by Evan Nemerson <evan@nemerson.com> - */ - -#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) -#if defined(JSON_HEDLEY_VERSION) - #undef JSON_HEDLEY_VERSION -#endif -#define JSON_HEDLEY_VERSION 15 - -#if defined(JSON_HEDLEY_STRINGIFY_EX) - #undef JSON_HEDLEY_STRINGIFY_EX -#endif -#define JSON_HEDLEY_STRINGIFY_EX(x) #x - -#if defined(JSON_HEDLEY_STRINGIFY) - #undef JSON_HEDLEY_STRINGIFY -#endif -#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) - -#if defined(JSON_HEDLEY_CONCAT_EX) - #undef JSON_HEDLEY_CONCAT_EX -#endif -#define JSON_HEDLEY_CONCAT_EX(a,b) a##b - -#if defined(JSON_HEDLEY_CONCAT) - #undef JSON_HEDLEY_CONCAT -#endif -#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) - -#if defined(JSON_HEDLEY_CONCAT3_EX) - #undef JSON_HEDLEY_CONCAT3_EX -#endif -#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c - -#if defined(JSON_HEDLEY_CONCAT3) - #undef JSON_HEDLEY_CONCAT3 -#endif -#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) - -#if defined(JSON_HEDLEY_VERSION_ENCODE) - #undef JSON_HEDLEY_VERSION_ENCODE -#endif -#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) - -#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) - #undef JSON_HEDLEY_VERSION_DECODE_MAJOR -#endif -#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) - -#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) - #undef JSON_HEDLEY_VERSION_DECODE_MINOR -#endif -#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) - -#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) - #undef JSON_HEDLEY_VERSION_DECODE_REVISION -#endif -#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) - -#if defined(JSON_HEDLEY_GNUC_VERSION) - #undef JSON_HEDLEY_GNUC_VERSION -#endif -#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#elif defined(__GNUC__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) -#endif - -#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) - #undef JSON_HEDLEY_GNUC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_GNUC_VERSION) - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_MSVC_VERSION) - #undef JSON_HEDLEY_MSVC_VERSION -#endif -#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) -#elif defined(_MSC_FULL_VER) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) -#elif defined(_MSC_VER) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) -#endif - -#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) - #undef JSON_HEDLEY_MSVC_VERSION_CHECK -#endif -#if !defined(JSON_HEDLEY_MSVC_VERSION) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) -#elif defined(_MSC_VER) && (_MSC_VER >= 1400) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) -#elif defined(_MSC_VER) && (_MSC_VER >= 1200) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) -#else - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) -#endif - -#if defined(JSON_HEDLEY_INTEL_VERSION) - #undef JSON_HEDLEY_INTEL_VERSION -#endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) -#elif defined(__INTEL_COMPILER) && !defined(__ICL) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) -#endif - -#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_INTEL_VERSION) - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_INTEL_CL_VERSION) - #undef JSON_HEDLEY_INTEL_CL_VERSION -#endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) - #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) -#endif - -#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_INTEL_CL_VERSION) - #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_PGI_VERSION) - #undef JSON_HEDLEY_PGI_VERSION -#endif -#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) - #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) -#endif - -#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) - #undef JSON_HEDLEY_PGI_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_PGI_VERSION) - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_SUNPRO_VERSION) - #undef JSON_HEDLEY_SUNPRO_VERSION -#endif -#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) -#elif defined(__SUNPRO_C) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) -#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) -#elif defined(__SUNPRO_CC) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) -#endif - -#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) - #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_SUNPRO_VERSION) - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION -#endif -#if defined(__EMSCRIPTEN__) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) -#endif - -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_ARM_VERSION) - #undef JSON_HEDLEY_ARM_VERSION -#endif -#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) -#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) -#endif - -#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) - #undef JSON_HEDLEY_ARM_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_ARM_VERSION) - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_IBM_VERSION) - #undef JSON_HEDLEY_IBM_VERSION -#endif -#if defined(__ibmxl__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) -#elif defined(__xlC__) && defined(__xlC_ver__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) -#elif defined(__xlC__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) -#endif - -#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) - #undef JSON_HEDLEY_IBM_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_IBM_VERSION) - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_VERSION) - #undef JSON_HEDLEY_TI_VERSION -#endif -#if \ - defined(__TI_COMPILER_VERSION__) && \ - ( \ - defined(__TMS470__) || defined(__TI_ARM__) || \ - defined(__MSP430__) || \ - defined(__TMS320C2000__) \ - ) -#if (__TI_COMPILER_VERSION__ >= 16000000) - #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif -#endif - -#if defined(JSON_HEDLEY_TI_VERSION_CHECK) - #undef JSON_HEDLEY_TI_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_VERSION) - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL2000_VERSION) - #undef JSON_HEDLEY_TI_CL2000_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) - #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL2000_VERSION) - #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL430_VERSION) - #undef JSON_HEDLEY_TI_CL430_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) - #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL430_VERSION) - #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) - #undef JSON_HEDLEY_TI_ARMCL_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) - #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) - #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) - #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL6X_VERSION) - #undef JSON_HEDLEY_TI_CL6X_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) - #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL6X_VERSION) - #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL7X_VERSION) - #undef JSON_HEDLEY_TI_CL7X_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) - #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL7X_VERSION) - #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) - #undef JSON_HEDLEY_TI_CLPRU_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) - #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) - #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_CRAY_VERSION) - #undef JSON_HEDLEY_CRAY_VERSION -#endif -#if defined(_CRAYC) - #if defined(_RELEASE_PATCHLEVEL) - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) - #else - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) - #endif -#endif - -#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) - #undef JSON_HEDLEY_CRAY_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_CRAY_VERSION) - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_IAR_VERSION) - #undef JSON_HEDLEY_IAR_VERSION -#endif -#if defined(__IAR_SYSTEMS_ICC__) - #if __VER__ > 1000 - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) - #else - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) - #endif -#endif - -#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) - #undef JSON_HEDLEY_IAR_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_IAR_VERSION) - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TINYC_VERSION) - #undef JSON_HEDLEY_TINYC_VERSION -#endif -#if defined(__TINYC__) - #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) -#endif - -#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) - #undef JSON_HEDLEY_TINYC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_DMC_VERSION) - #undef JSON_HEDLEY_DMC_VERSION -#endif -#if defined(__DMC__) - #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) -#endif - -#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) - #undef JSON_HEDLEY_DMC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_DMC_VERSION) - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_COMPCERT_VERSION) - #undef JSON_HEDLEY_COMPCERT_VERSION -#endif -#if defined(__COMPCERT_VERSION__) - #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) -#endif - -#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) - #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_COMPCERT_VERSION) - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_PELLES_VERSION) - #undef JSON_HEDLEY_PELLES_VERSION -#endif -#if defined(__POCC__) - #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) -#endif - -#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) - #undef JSON_HEDLEY_PELLES_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_PELLES_VERSION) - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_MCST_LCC_VERSION) - #undef JSON_HEDLEY_MCST_LCC_VERSION -#endif -#if defined(__LCC__) && defined(__LCC_MINOR__) - #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) -#endif - -#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) - #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_MCST_LCC_VERSION) - #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_GCC_VERSION) - #undef JSON_HEDLEY_GCC_VERSION -#endif -#if \ - defined(JSON_HEDLEY_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(JSON_HEDLEY_INTEL_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_ARM_VERSION) && \ - !defined(JSON_HEDLEY_CRAY_VERSION) && \ - !defined(JSON_HEDLEY_TI_VERSION) && \ - !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ - !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ - !defined(__COMPCERT__) && \ - !defined(JSON_HEDLEY_MCST_LCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION -#endif - -#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_GCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_ATTRIBUTE -#endif -#if \ - defined(__has_attribute) && \ - ( \ - (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ - ) -# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) -#else -# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE -#endif -#if defined(__has_attribute) - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE -#endif -#if defined(__has_attribute) - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE -#endif -#if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS -#endif -#if !defined(__cplusplus) || !defined(__has_cpp_attribute) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#elif \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_IAR_VERSION) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) -#else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE -#endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE -#endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_BUILTIN) - #undef JSON_HEDLEY_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) -#else - #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) - #undef JSON_HEDLEY_GNUC_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) -#else - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) - #undef JSON_HEDLEY_GCC_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) -#else - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_FEATURE) - #undef JSON_HEDLEY_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) -#else - #define JSON_HEDLEY_HAS_FEATURE(feature) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) - #undef JSON_HEDLEY_GNUC_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) -#else - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) - #undef JSON_HEDLEY_GCC_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) -#else - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_EXTENSION) - #undef JSON_HEDLEY_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) -#else - #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) - #undef JSON_HEDLEY_GNUC_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) -#else - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) - #undef JSON_HEDLEY_GCC_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) -#else - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_WARNING) - #undef JSON_HEDLEY_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) -#else - #define JSON_HEDLEY_HAS_WARNING(warning) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) - #undef JSON_HEDLEY_GNUC_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_WARNING) - #undef JSON_HEDLEY_GCC_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) - #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_PRAGMA(value) __pragma(value) -#else - #define JSON_HEDLEY_PRAGMA(value) -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) - #undef JSON_HEDLEY_DIAGNOSTIC_PUSH -#endif -#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) - #undef JSON_HEDLEY_DIAGNOSTIC_POP -#endif -#if defined(__clang__) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) - #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_PUSH - #define JSON_HEDLEY_DIAGNOSTIC_POP -#endif - -/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ -#endif -#if defined(__cplusplus) -# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") -# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") -# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# endif -# else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# endif -# endif -#endif -#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x -#endif - -#if defined(JSON_HEDLEY_CONST_CAST) - #undef JSON_HEDLEY_CONST_CAST -#endif -#if defined(__cplusplus) -# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr)) -#elif \ - JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_REINTERPRET_CAST) - #undef JSON_HEDLEY_REINTERPRET_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr)) -#else - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_STATIC_CAST) - #undef JSON_HEDLEY_STATIC_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr)) -#else - #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_CPP_CAST) - #undef JSON_HEDLEY_CPP_CAST -#endif -#if defined(__cplusplus) -# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") -# define JSON_HEDLEY_CPP_CAST(T, expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - ((T) (expr)) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) -# define JSON_HEDLEY_CPP_CAST(T, expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("diag_suppress=Pe137") \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) -# endif -#else -# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#endif - -#if defined(JSON_HEDLEY_DEPRECATED) - #undef JSON_HEDLEY_DEPRECATED -#endif -#if defined(JSON_HEDLEY_DEPRECATED_FOR) - #undef JSON_HEDLEY_DEPRECATED_FOR -#endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif \ - (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) -#elif defined(__cplusplus) && (__cplusplus >= 201402L) - #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") -#else - #define JSON_HEDLEY_DEPRECATED(since) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) -#endif - -#if defined(JSON_HEDLEY_UNAVAILABLE) - #undef JSON_HEDLEY_UNAVAILABLE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) -#else - #define JSON_HEDLEY_UNAVAILABLE(available_since) -#endif - -#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT -#endif -#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) -#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) -#elif defined(_Check_return_) /* SAL */ - #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ -#else - #define JSON_HEDLEY_WARN_UNUSED_RESULT - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) -#endif - -#if defined(JSON_HEDLEY_SENTINEL) - #undef JSON_HEDLEY_SENTINEL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) -#else - #define JSON_HEDLEY_SENTINEL(position) -#endif - -#if defined(JSON_HEDLEY_NO_RETURN) - #undef JSON_HEDLEY_NO_RETURN -#endif -#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NO_RETURN __noreturn -#elif \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define JSON_HEDLEY_NO_RETURN _Noreturn -#elif defined(__cplusplus) && (__cplusplus >= 201103L) - #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#else - #define JSON_HEDLEY_NO_RETURN -#endif - -#if defined(JSON_HEDLEY_NO_ESCAPE) - #undef JSON_HEDLEY_NO_ESCAPE -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) - #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) -#else - #define JSON_HEDLEY_NO_ESCAPE -#endif - -#if defined(JSON_HEDLEY_UNREACHABLE) - #undef JSON_HEDLEY_UNREACHABLE -#endif -#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #undef JSON_HEDLEY_UNREACHABLE_RETURN -#endif -#if defined(JSON_HEDLEY_ASSUME) - #undef JSON_HEDLEY_ASSUME -#endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_ASSUME(expr) __assume(expr) -#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) - #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) - #else - #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) - #endif -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif defined(JSON_HEDLEY_ASSUME) - #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) -#endif -#if !defined(JSON_HEDLEY_ASSUME) - #if defined(JSON_HEDLEY_UNREACHABLE) - #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) - #else - #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) - #endif -#endif -#if defined(JSON_HEDLEY_UNREACHABLE) - #if \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) - #else - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() - #endif -#else - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) -#endif -#if !defined(JSON_HEDLEY_UNREACHABLE) - #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) -#endif - -JSON_HEDLEY_DIAGNOSTIC_PUSH -#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") - #pragma clang diagnostic ignored "-Wpedantic" -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) - #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -#endif -#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) - #if defined(__clang__) - #pragma clang diagnostic ignored "-Wvariadic-macros" - #elif defined(JSON_HEDLEY_GCC_VERSION) - #pragma GCC diagnostic ignored "-Wvariadic-macros" - #endif -#endif -#if defined(JSON_HEDLEY_NON_NULL) - #undef JSON_HEDLEY_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) -#else - #define JSON_HEDLEY_NON_NULL(...) -#endif -JSON_HEDLEY_DIAGNOSTIC_POP - -#if defined(JSON_HEDLEY_PRINTF_FORMAT) - #undef JSON_HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) -#else - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) -#endif - -#if defined(JSON_HEDLEY_CONSTEXPR) - #undef JSON_HEDLEY_CONSTEXPR -#endif -#if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) - #endif -#endif -#if !defined(JSON_HEDLEY_CONSTEXPR) - #define JSON_HEDLEY_CONSTEXPR -#endif - -#if defined(JSON_HEDLEY_PREDICT) - #undef JSON_HEDLEY_PREDICT -#endif -#if defined(JSON_HEDLEY_LIKELY) - #undef JSON_HEDLEY_LIKELY -#endif -#if defined(JSON_HEDLEY_UNLIKELY) - #undef JSON_HEDLEY_UNLIKELY -#endif -#if defined(JSON_HEDLEY_UNPREDICTABLE) - #undef JSON_HEDLEY_UNPREDICTABLE -#endif -#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) - #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) -#elif \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#else -# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) -# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) -#endif -#if !defined(JSON_HEDLEY_UNPREDICTABLE) - #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) -#endif - -#if defined(JSON_HEDLEY_MALLOC) - #undef JSON_HEDLEY_MALLOC -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_MALLOC __declspec(restrict) -#else - #define JSON_HEDLEY_MALLOC -#endif - -#if defined(JSON_HEDLEY_PURE) - #undef JSON_HEDLEY_PURE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PURE __attribute__((__pure__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") -#elif defined(__cplusplus) && \ - ( \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ - ) -# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") -#else -# define JSON_HEDLEY_PURE -#endif - -#if defined(JSON_HEDLEY_CONST) - #undef JSON_HEDLEY_CONST -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_CONST __attribute__((__const__)) -#elif \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_CONST _Pragma("no_side_effect") -#else - #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE -#endif - -#if defined(JSON_HEDLEY_RESTRICT) - #undef JSON_HEDLEY_RESTRICT -#endif -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT restrict -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_RESTRICT __restrict -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT _Restrict -#else - #define JSON_HEDLEY_RESTRICT -#endif - -#if defined(JSON_HEDLEY_INLINE) - #undef JSON_HEDLEY_INLINE -#endif -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) - #define JSON_HEDLEY_INLINE inline -#elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) - #define JSON_HEDLEY_INLINE __inline__ -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_INLINE __inline -#else - #define JSON_HEDLEY_INLINE -#endif - -#if defined(JSON_HEDLEY_ALWAYS_INLINE) - #undef JSON_HEDLEY_ALWAYS_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_ALWAYS_INLINE __forceinline -#elif defined(__cplusplus) && \ - ( \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ - ) -# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") -#else -# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE -#endif - -#if defined(JSON_HEDLEY_NEVER_INLINE) - #undef JSON_HEDLEY_NEVER_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#else - #define JSON_HEDLEY_NEVER_INLINE -#endif - -#if defined(JSON_HEDLEY_PRIVATE) - #undef JSON_HEDLEY_PRIVATE -#endif -#if defined(JSON_HEDLEY_PUBLIC) - #undef JSON_HEDLEY_PUBLIC -#endif -#if defined(JSON_HEDLEY_IMPORT) - #undef JSON_HEDLEY_IMPORT -#endif -#if defined(_WIN32) || defined(__CYGWIN__) -# define JSON_HEDLEY_PRIVATE -# define JSON_HEDLEY_PUBLIC __declspec(dllexport) -# define JSON_HEDLEY_IMPORT __declspec(dllimport) -#else -# if \ - JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - ( \ - defined(__TI_EABI__) && \ - ( \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ - ) \ - ) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) -# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) -# else -# define JSON_HEDLEY_PRIVATE -# define JSON_HEDLEY_PUBLIC -# endif -# define JSON_HEDLEY_IMPORT extern -#endif - -#if defined(JSON_HEDLEY_NO_THROW) - #undef JSON_HEDLEY_NO_THROW -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NO_THROW __declspec(nothrow) -#else - #define JSON_HEDLEY_NO_THROW -#endif - -#if defined(JSON_HEDLEY_FALL_THROUGH) - #undef JSON_HEDLEY_FALL_THROUGH -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) -#elif defined(__fallthrough) /* SAL */ - #define JSON_HEDLEY_FALL_THROUGH __fallthrough -#else - #define JSON_HEDLEY_FALL_THROUGH -#endif - -#if defined(JSON_HEDLEY_RETURNS_NON_NULL) - #undef JSON_HEDLEY_RETURNS_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) -#elif defined(_Ret_notnull_) /* SAL */ - #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ -#else - #define JSON_HEDLEY_RETURNS_NON_NULL -#endif - -#if defined(JSON_HEDLEY_ARRAY_PARAM) - #undef JSON_HEDLEY_ARRAY_PARAM -#endif -#if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_ARRAY_PARAM(name) (name) -#else - #define JSON_HEDLEY_ARRAY_PARAM(name) -#endif - -#if defined(JSON_HEDLEY_IS_CONSTANT) - #undef JSON_HEDLEY_IS_CONSTANT -#endif -#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) - #undef JSON_HEDLEY_REQUIRE_CONSTEXPR -#endif -/* JSON_HEDLEY_IS_CONSTEXPR_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ -#if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #undef JSON_HEDLEY_IS_CONSTEXPR_ -#endif -#if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) -#endif -#if !defined(__cplusplus) -# if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) -#if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) -#else - #include <stdint.h> - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) -#endif -# elif \ - ( \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ - !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_IAR_VERSION)) || \ - (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) -#if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) -#else - #include <stdint.h> - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) -#endif -# elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - defined(JSON_HEDLEY_INTEL_VERSION) || \ - defined(JSON_HEDLEY_TINYC_VERSION) || \ - defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ - defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ - defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ - defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ - defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ - defined(__clang__) -# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ -((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) -# endif -#endif -#if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) -#else - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) (0) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) -#endif - -#if defined(JSON_HEDLEY_BEGIN_C_DECLS) - #undef JSON_HEDLEY_BEGIN_C_DECLS -#endif -#if defined(JSON_HEDLEY_END_C_DECLS) - #undef JSON_HEDLEY_END_C_DECLS -#endif -#if defined(JSON_HEDLEY_C_DECL) - #undef JSON_HEDLEY_C_DECL -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { - #define JSON_HEDLEY_END_C_DECLS } - #define JSON_HEDLEY_C_DECL extern "C" -#else - #define JSON_HEDLEY_BEGIN_C_DECLS - #define JSON_HEDLEY_END_C_DECLS - #define JSON_HEDLEY_C_DECL -#endif - -#if defined(JSON_HEDLEY_STATIC_ASSERT) - #undef JSON_HEDLEY_STATIC_ASSERT -#endif -#if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) -#else -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) -#endif - -#if defined(JSON_HEDLEY_NULL) - #undef JSON_HEDLEY_NULL -#endif -#if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) - #elif defined(NULL) - #define JSON_HEDLEY_NULL NULL - #else - #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) - #endif -#elif defined(NULL) - #define JSON_HEDLEY_NULL NULL -#else - #define JSON_HEDLEY_NULL ((void*) 0) -#endif - -#if defined(JSON_HEDLEY_MESSAGE) - #undef JSON_HEDLEY_MESSAGE -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_MESSAGE(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(message msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) -#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#else -# define JSON_HEDLEY_MESSAGE(msg) -#endif - -#if defined(JSON_HEDLEY_WARNING) - #undef JSON_HEDLEY_WARNING -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_WARNING(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(clang warning msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#else -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) -#endif - -#if defined(JSON_HEDLEY_REQUIRE) - #undef JSON_HEDLEY_REQUIRE -#endif -#if defined(JSON_HEDLEY_REQUIRE_MSG) - #undef JSON_HEDLEY_REQUIRE_MSG -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) -# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") -# define JSON_HEDLEY_REQUIRE(expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) -# endif -#else -# define JSON_HEDLEY_REQUIRE(expr) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) -#endif - -#if defined(JSON_HEDLEY_FLAGS) - #undef JSON_HEDLEY_FLAGS -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) - #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) -#else - #define JSON_HEDLEY_FLAGS -#endif - -#if defined(JSON_HEDLEY_FLAGS_CAST) - #undef JSON_HEDLEY_FLAGS_CAST -#endif -#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) -# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) -#endif - -#if defined(JSON_HEDLEY_EMPTY_BASES) - #undef JSON_HEDLEY_EMPTY_BASES -#endif -#if \ - (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) -#else - #define JSON_HEDLEY_EMPTY_BASES -#endif - -/* Remaining macros are deprecated. */ - -#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK -#endif -#if defined(__clang__) - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) -#else - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) - #undef JSON_HEDLEY_CLANG_HAS_BUILTIN -#endif -#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) - -#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) - #undef JSON_HEDLEY_CLANG_HAS_FEATURE -#endif -#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) - -#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) - #undef JSON_HEDLEY_CLANG_HAS_EXTENSION -#endif -#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) - -#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) - #undef JSON_HEDLEY_CLANG_HAS_WARNING -#endif -#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) - -#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ - - -// This file contains all internal macro definitions (except those affecting ABI) -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// #include <nlohmann/detail/abi_macros.hpp> - - -// exclude unsupported compilers -#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) - #if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #endif -#endif - -// C++ language standard detection -// if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - #define JSON_HAS_CPP_20 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 - #endif - // the cpp 11 flag is always specified because it is the minimal required version - #define JSON_HAS_CPP_11 -#endif - -#ifdef __has_include - #if __has_include(<version>) - #include <version> - #endif -#endif - -#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) - #ifdef JSON_HAS_CPP_17 - #if defined(__cpp_lib_filesystem) - #define JSON_HAS_FILESYSTEM 1 - #elif defined(__cpp_lib_experimental_filesystem) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #elif !defined(__has_include) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #elif __has_include(<filesystem>) - #define JSON_HAS_FILESYSTEM 1 - #elif __has_include(<experimental/filesystem>) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #endif - - // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ - #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support - #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support - #if defined(__clang_major__) && __clang_major__ < 7 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support - #if defined(_MSC_VER) && _MSC_VER < 1914 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before iOS 13 - #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before macOS Catalina - #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - #endif -#endif - -#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 -#endif - -#ifndef JSON_HAS_FILESYSTEM - #define JSON_HAS_FILESYSTEM 0 -#endif - -#ifndef JSON_HAS_THREE_WAY_COMPARISON - #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ - && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L - #define JSON_HAS_THREE_WAY_COMPARISON 1 - #else - #define JSON_HAS_THREE_WAY_COMPARISON 0 - #endif -#endif - -#ifndef JSON_HAS_RANGES - // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error - #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 - #define JSON_HAS_RANGES 0 - #elif defined(__cpp_lib_ranges) - #define JSON_HAS_RANGES 1 - #else - #define JSON_HAS_RANGES 0 - #endif -#endif - -#ifndef JSON_HAS_STATIC_RTTI - #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 - #define JSON_HAS_STATIC_RTTI 1 - #else - #define JSON_HAS_STATIC_RTTI 0 - #endif -#endif - -#ifdef JSON_HAS_CPP_17 - #define JSON_INLINE_VARIABLE inline -#else - #define JSON_INLINE_VARIABLE -#endif - -#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) - #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] -#else - #define JSON_NO_UNIQUE_ADDRESS -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdocumentation" - #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -#endif - -// allow disabling exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) - #define JSON_INTERNAL_CATCH(exception) catch(exception) -#else - #include <cstdlib> - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) - #define JSON_INTERNAL_CATCH(exception) if(false) -#endif - -// override exception macros -#if defined(JSON_THROW_USER) - #undef JSON_THROW - #define JSON_THROW JSON_THROW_USER -#endif -#if defined(JSON_TRY_USER) - #undef JSON_TRY - #define JSON_TRY JSON_TRY_USER -#endif -#if defined(JSON_CATCH_USER) - #undef JSON_CATCH - #define JSON_CATCH JSON_CATCH_USER - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_CATCH_USER -#endif -#if defined(JSON_INTERNAL_CATCH_USER) - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER -#endif - -// allow overriding assert -#if !defined(JSON_ASSERT) - #include <cassert> // assert - #define JSON_ASSERT(x) assert(x) -#endif - -// allow to access some private functions (needed by the test suite) -#if defined(JSON_TESTS_PRIVATE) - #define JSON_PRIVATE_UNLESS_TESTED public -#else - #define JSON_PRIVATE_UNLESS_TESTED private -#endif - -/*! -@brief macro to briefly define a mapping between an enum and JSON -@def NLOHMANN_JSON_SERIALIZE_ENUM -@since version 3.4.0 -*/ -#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ - template<typename BasicJsonType> \ - inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ - { \ - return ej_pair.first == e; \ - }); \ - j = ((it != std::end(m)) ? it : std::begin(m))->second; \ - } \ - template<typename BasicJsonType> \ - inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ - { \ - return ej_pair.second == j; \ - }); \ - e = ((it != std::end(m)) ? it : std::begin(m))->first; \ - } - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template<template<typename, typename, typename...> class ObjectType, \ - template<typename, typename...> class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template<typename> class AllocatorType, \ - template<typename, typename = void> class JSONSerializer, \ - class BinaryType, \ - class CustomBaseClass> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json<ObjectType, ArrayType, StringType, BooleanType, \ - NumberIntegerType, NumberUnsignedType, NumberFloatType, \ - AllocatorType, JSONSerializer, BinaryType, CustomBaseClass> - -// Macros to simplify conversion from/to types - -#define NLOHMANN_JSON_EXPAND( x ) x -#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME -#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ - NLOHMANN_JSON_PASTE64, \ - NLOHMANN_JSON_PASTE63, \ - NLOHMANN_JSON_PASTE62, \ - NLOHMANN_JSON_PASTE61, \ - NLOHMANN_JSON_PASTE60, \ - NLOHMANN_JSON_PASTE59, \ - NLOHMANN_JSON_PASTE58, \ - NLOHMANN_JSON_PASTE57, \ - NLOHMANN_JSON_PASTE56, \ - NLOHMANN_JSON_PASTE55, \ - NLOHMANN_JSON_PASTE54, \ - NLOHMANN_JSON_PASTE53, \ - NLOHMANN_JSON_PASTE52, \ - NLOHMANN_JSON_PASTE51, \ - NLOHMANN_JSON_PASTE50, \ - NLOHMANN_JSON_PASTE49, \ - NLOHMANN_JSON_PASTE48, \ - NLOHMANN_JSON_PASTE47, \ - NLOHMANN_JSON_PASTE46, \ - NLOHMANN_JSON_PASTE45, \ - NLOHMANN_JSON_PASTE44, \ - NLOHMANN_JSON_PASTE43, \ - NLOHMANN_JSON_PASTE42, \ - NLOHMANN_JSON_PASTE41, \ - NLOHMANN_JSON_PASTE40, \ - NLOHMANN_JSON_PASTE39, \ - NLOHMANN_JSON_PASTE38, \ - NLOHMANN_JSON_PASTE37, \ - NLOHMANN_JSON_PASTE36, \ - NLOHMANN_JSON_PASTE35, \ - NLOHMANN_JSON_PASTE34, \ - NLOHMANN_JSON_PASTE33, \ - NLOHMANN_JSON_PASTE32, \ - NLOHMANN_JSON_PASTE31, \ - NLOHMANN_JSON_PASTE30, \ - NLOHMANN_JSON_PASTE29, \ - NLOHMANN_JSON_PASTE28, \ - NLOHMANN_JSON_PASTE27, \ - NLOHMANN_JSON_PASTE26, \ - NLOHMANN_JSON_PASTE25, \ - NLOHMANN_JSON_PASTE24, \ - NLOHMANN_JSON_PASTE23, \ - NLOHMANN_JSON_PASTE22, \ - NLOHMANN_JSON_PASTE21, \ - NLOHMANN_JSON_PASTE20, \ - NLOHMANN_JSON_PASTE19, \ - NLOHMANN_JSON_PASTE18, \ - NLOHMANN_JSON_PASTE17, \ - NLOHMANN_JSON_PASTE16, \ - NLOHMANN_JSON_PASTE15, \ - NLOHMANN_JSON_PASTE14, \ - NLOHMANN_JSON_PASTE13, \ - NLOHMANN_JSON_PASTE12, \ - NLOHMANN_JSON_PASTE11, \ - NLOHMANN_JSON_PASTE10, \ - NLOHMANN_JSON_PASTE9, \ - NLOHMANN_JSON_PASTE8, \ - NLOHMANN_JSON_PASTE7, \ - NLOHMANN_JSON_PASTE6, \ - NLOHMANN_JSON_PASTE5, \ - NLOHMANN_JSON_PASTE4, \ - NLOHMANN_JSON_PASTE3, \ - NLOHMANN_JSON_PASTE2, \ - NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) -#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) -#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) -#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) -#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) -#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) -#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) -#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) -#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) -#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) -#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) -#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) -#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) -#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) -#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) -#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) -#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) -#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) -#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) -#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) -#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) -#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) -#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) -#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) -#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) -#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) -#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) -#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) -#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) -#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) -#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) -#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) -#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) -#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) -#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) -#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) -#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) -#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) -#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) -#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) -#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) -#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) -#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) -#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) -#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) -#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) -#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) -#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) -#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) -#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) -#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) -#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) -#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) -#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) -#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) -#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) -#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) -#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) -#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) -#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) -#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) -#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) -#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) -#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) - -#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; -#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); -#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); - -/*! -@brief macro -@def NLOHMANN_DEFINE_TYPE_INTRUSIVE -@since version 3.9.0 -*/ -#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - -#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } - -#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } - -/*! -@brief macro -@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE -@since version 3.9.0 -*/ -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } - -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } - -// inspired from https://stackoverflow.com/a/26745591 -// allows to call any std function as if (e.g. with begin): -// using std::begin; begin(x); -// -// it allows using the detected idiom to retrieve the return type -// of such an expression -#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ - namespace detail { \ - using std::std_name; \ - \ - template<typename... T> \ - using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ - } \ - \ - namespace detail2 { \ - struct std_name##_tag \ - { \ - }; \ - \ - template<typename... T> \ - std_name##_tag std_name(T&&...); \ - \ - template<typename... T> \ - using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ - \ - template<typename... T> \ - struct would_call_std_##std_name \ - { \ - static constexpr auto const value = ::nlohmann::detail:: \ - is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \ - }; \ - } /* namespace detail2 */ \ - \ - template<typename... T> \ - struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \ - { \ - } - -#ifndef JSON_USE_IMPLICIT_CONVERSIONS - #define JSON_USE_IMPLICIT_CONVERSIONS 1 -#endif - -#if JSON_USE_IMPLICIT_CONVERSIONS - #define JSON_EXPLICIT -#else - #define JSON_EXPLICIT explicit -#endif - -#ifndef JSON_DISABLE_ENUM_SERIALIZATION - #define JSON_DISABLE_ENUM_SERIALIZATION 0 -#endif - -#ifndef JSON_USE_GLOBAL_UDLS - #define JSON_USE_GLOBAL_UDLS 1 -#endif - -#if JSON_HAS_THREE_WAY_COMPARISON - #include <compare> // partial_ordering -#endif - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - binary, ///< binary array (ordered collection of bytes) - discarded ///< discarded by the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string < binary -- furthermore, each type is not smaller than itself -- discarded values are not comparable -- binary is represented as a b"" string in python and directly comparable to a - string; however, making a binary array directly comparable with a string would - be surprising behavior in a JSON file. - -@since version 1.0.0 -*/ -#if JSON_HAS_THREE_WAY_COMPARISON - inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* -#else - inline bool operator<(const value_t lhs, const value_t rhs) noexcept -#endif -{ - static constexpr std::array<std::uint8_t, 9> order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, - 6 /* binary */ - } - }; - - const auto l_index = static_cast<std::size_t>(lhs); - const auto r_index = static_cast<std::size_t>(rhs); -#if JSON_HAS_THREE_WAY_COMPARISON - if (l_index < order.size() && r_index < order.size()) - { - return order[l_index] <=> order[r_index]; // *NOPAD* - } - return std::partial_ordering::unordered; -#else - return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; -#endif -} - -// GCC selects the built-in operator< over an operator rewritten from -// a user-defined spaceship operator -// Clang, MSVC, and ICC select the rewritten candidate -// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) -#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - return std::is_lt(lhs <=> rhs); // *NOPAD* -} -#endif - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/string_escape.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/*! -@brief replace all occurrences of a substring by another string - -@param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t -@param[in] f the substring to replace with @a t -@param[in] t the string to replace @a f - -@pre The search string @a f must not be empty. **This precondition is -enforced with an assertion.** - -@since version 2.0.0 -*/ -template<typename StringType> -inline void replace_substring(StringType& s, const StringType& f, - const StringType& t) -{ - JSON_ASSERT(!f.empty()); - for (auto pos = s.find(f); // find first occurrence of f - pos != StringType::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} -} - -/*! - * @brief string escaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to escape - * @return escaped string - * - * Note the order of escaping "~" to "~0" and "/" to "~1" is important. - */ -template<typename StringType> -inline StringType escape(StringType s) -{ - replace_substring(s, StringType{"~"}, StringType{"~0"}); - replace_substring(s, StringType{"/"}, StringType{"~1"}); - return s; -} - -/*! - * @brief string unescaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to unescape - * @return unescaped string - * - * Note the order of escaping "~1" to "/" and "~0" to "~" is important. - */ -template<typename StringType> -static void unescape(StringType& s) -{ - replace_substring(s, StringType{"~1"}, StringType{"/"}); - replace_substring(s, StringType{"~0"}, StringType{"~"}); -} - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/input/position_t.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstddef> // size_t - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; - - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-FileCopyrightText: 2018 The Abseil Authors -// SPDX-License-Identifier: MIT - - - -#include <array> // array -#include <cstddef> // size_t -#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include <utility> // index_sequence, make_index_sequence, index_sequence_for - -// #include <nlohmann/detail/macro_scope.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename T> -using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; - -#ifdef JSON_HAS_CPP_14 - -// the following utilities are natively available in C++14 -using std::enable_if_t; -using std::index_sequence; -using std::make_index_sequence; -using std::index_sequence_for; - -#else - -// alias templates to reduce boilerplate -template<bool B, typename T = void> -using enable_if_t = typename std::enable_if<B, T>::type; - -// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h -// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. - -//// START OF CODE FROM GOOGLE ABSEIL - -// integer_sequence -// -// Class template representing a compile-time integer sequence. An instantiation -// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its -// type through its template arguments (which is a common need when -// working with C++11 variadic templates). `absl::integer_sequence` is designed -// to be a drop-in replacement for C++14's `std::integer_sequence`. -// -// Example: -// -// template< class T, T... Ints > -// void user_function(integer_sequence<T, Ints...>); -// -// int main() -// { -// // user_function's `T` will be deduced to `int` and `Ints...` -// // will be deduced to `0, 1, 2, 3, 4`. -// user_function(make_integer_sequence<int, 5>()); -// } -template <typename T, T... Ints> -struct integer_sequence -{ - using value_type = T; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -// index_sequence -// -// A helper template for an `integer_sequence` of `size_t`, -// `absl::index_sequence` is designed to be a drop-in replacement for C++14's -// `std::index_sequence`. -template <size_t... Ints> -using index_sequence = integer_sequence<size_t, Ints...>; - -namespace utility_internal -{ - -template <typename Seq, size_t SeqSize, size_t Rem> -struct Extend; - -// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. -template <typename T, T... Ints, size_t SeqSize> -struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> -{ - using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; -}; - -template <typename T, T... Ints, size_t SeqSize> -struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> -{ - using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; -}; - -// Recursion helper for 'make_integer_sequence<T, N>'. -// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'. -template <typename T, size_t N> -struct Gen -{ - using type = - typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; -}; - -template <typename T> -struct Gen<T, 0> -{ - using type = integer_sequence<T>; -}; - -} // namespace utility_internal - -// Compile-time sequences of integers - -// make_integer_sequence -// -// This template alias is equivalent to -// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in -// replacement for C++14's `std::make_integer_sequence`. -template <typename T, T N> -using make_integer_sequence = typename utility_internal::Gen<T, N>::type; - -// make_index_sequence -// -// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, -// and is designed to be a drop-in replacement for C++14's -// `std::make_index_sequence`. -template <size_t N> -using make_index_sequence = make_integer_sequence<size_t, N>; - -// index_sequence_for -// -// Converts a typename pack into an index sequence of the same length, and -// is designed to be a drop-in replacement for C++14's -// `std::index_sequence_for()` -template <typename... Ts> -using index_sequence_for = make_index_sequence<sizeof...(Ts)>; - -//// END OF CODE FROM GOOGLE ABSEIL - -#endif - -// dispatch utility (taken from ranges-v3) -template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -// taken from ranges-v3 -template<typename T> -struct static_const -{ - static JSON_INLINE_VARIABLE constexpr T value{}; -}; - -#ifndef JSON_HAS_CPP_17 - template<typename T> - constexpr T static_const<T>::value; -#endif - -template<typename T, typename... Args> -inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args) -{ - return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}}; -} - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/meta/type_traits.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <limits> // numeric_limits -#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type -#include <utility> // declval -#include <tuple> // tuple -#include <string> // char_traits - -// #include <nlohmann/detail/iterators/iterator_traits.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <iterator> // random_access_iterator_tag - -// #include <nlohmann/detail/abi_macros.hpp> - -// #include <nlohmann/detail/meta/void_t.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename It, typename = void> -struct iterator_types {}; - -template<typename It> -struct iterator_types < - It, - void_t<typename It::difference_type, typename It::value_type, typename It::pointer, - typename It::reference, typename It::iterator_category >> -{ - using difference_type = typename It::difference_type; - using value_type = typename It::value_type; - using pointer = typename It::pointer; - using reference = typename It::reference; - using iterator_category = typename It::iterator_category; -}; - -// This is required as some compilers implement std::iterator_traits in a way that -// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. -template<typename T, typename = void> -struct iterator_traits -{ -}; - -template<typename T> -struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >> - : iterator_types<T> -{ -}; - -template<typename T> -struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> -{ - using iterator_category = std::random_access_iterator_tag; - using value_type = T; - using difference_type = ptrdiff_t; - using pointer = T*; - using reference = T&; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/call_std/begin.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/macro_scope.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/meta/call_std/end.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/macro_scope.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/detected.hpp> - -// #include <nlohmann/json_fwd.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - -#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ - #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ - - #include <cstdint> // int64_t, uint64_t - #include <map> // map - #include <memory> // allocator - #include <string> // string - #include <vector> // vector - - // #include <nlohmann/detail/abi_macros.hpp> - - - /*! - @brief namespace for Niels Lohmann - @see https://github.com/nlohmann - @since version 1.0.0 - */ - NLOHMANN_JSON_NAMESPACE_BEGIN - - /*! - @brief default JSONSerializer template argument - - This serializer ignores the template arguments and uses ADL - ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) - for serialization. - */ - template<typename T = void, typename SFINAE = void> - struct adl_serializer; - - /// a class to store JSON values - /// @sa https://json.nlohmann.me/api/basic_json/ - template<template<typename U, typename V, typename... Args> class ObjectType = - std::map, - template<typename U, typename... Args> class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template<typename U> class AllocatorType = std::allocator, - template<typename T, typename SFINAE = void> class JSONSerializer = - adl_serializer, - class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError - class CustomBaseClass = void> - class basic_json; - - /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document - /// @sa https://json.nlohmann.me/api/json_pointer/ - template<typename RefStringType> - class json_pointer; - - /*! - @brief default specialization - @sa https://json.nlohmann.me/api/json/ - */ - using json = basic_json<>; - - /// @brief a minimal map-like container that preserves insertion order - /// @sa https://json.nlohmann.me/api/ordered_map/ - template<class Key, class T, class IgnoredLess, class Allocator> - struct ordered_map; - - /// @brief specialization that maintains the insertion order of object keys - /// @sa https://json.nlohmann.me/api/ordered_json/ - using ordered_json = basic_json<nlohmann::ordered_map>; - - NLOHMANN_JSON_NAMESPACE_END - -#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ - - -NLOHMANN_JSON_NAMESPACE_BEGIN -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ - -///////////// -// helpers // -///////////// - -// Note to maintainers: -// -// Every trait in this file expects a non CV-qualified type. -// The only exceptions are in the 'aliases for detected' section -// (i.e. those of the form: decltype(T::member_function(std::declval<T>()))) -// -// In this case, T has to be properly CV-qualified to constraint the function arguments -// (e.g. to_json(BasicJsonType&, const T&)) - -template<typename> struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; - -// used by exceptions create() member functions -// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t -// false_type otherwise -template<typename BasicJsonContext> -struct is_basic_json_context : - std::integral_constant < bool, - is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value - || std::is_same<BasicJsonContext, std::nullptr_t>::value > -{}; - -////////////////////// -// json_ref helpers // -////////////////////// - -template<typename> -class json_ref; - -template<typename> -struct is_json_ref : std::false_type {}; - -template<typename T> -struct is_json_ref<json_ref<T>> : std::true_type {}; - -////////////////////////// -// aliases for detected // -////////////////////////// - -template<typename T> -using mapped_type_t = typename T::mapped_type; - -template<typename T> -using key_type_t = typename T::key_type; - -template<typename T> -using value_type_t = typename T::value_type; - -template<typename T> -using difference_type_t = typename T::difference_type; - -template<typename T> -using pointer_t = typename T::pointer; - -template<typename T> -using reference_t = typename T::reference; - -template<typename T> -using iterator_category_t = typename T::iterator_category; - -template<typename T, typename... Args> -using to_json_function = decltype(T::to_json(std::declval<Args>()...)); - -template<typename T, typename... Args> -using from_json_function = decltype(T::from_json(std::declval<Args>()...)); - -template<typename T, typename U> -using get_template_function = decltype(std::declval<T>().template get<U>()); - -// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists -template<typename BasicJsonType, typename T, typename = void> -struct has_from_json : std::false_type {}; - -// trait checking if j.get<T> is valid -// use this trait instead of std::is_constructible or std::is_convertible, -// both rely on, or make use of implicit conversions, and thus fail when T -// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) -template <typename BasicJsonType, typename T> -struct is_getable -{ - static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value; -}; - -template<typename BasicJsonType, typename T> -struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> -{ - using serializer = typename BasicJsonType::template json_serializer<T, void>; - - static constexpr bool value = - is_detected_exact<void, from_json_function, serializer, - const BasicJsonType&, T&>::value; -}; - -// This trait checks if JSONSerializer<T>::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template<typename BasicJsonType, typename T, typename = void> -struct has_non_default_from_json : std::false_type {}; - -template<typename BasicJsonType, typename T> -struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> -{ - using serializer = typename BasicJsonType::template json_serializer<T, void>; - - static constexpr bool value = - is_detected_exact<T, from_json_function, serializer, - const BasicJsonType&>::value; -}; - -// This trait checks if BasicJsonType::json_serializer<T>::to_json exists -// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. -template<typename BasicJsonType, typename T, typename = void> -struct has_to_json : std::false_type {}; - -template<typename BasicJsonType, typename T> -struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> -{ - using serializer = typename BasicJsonType::template json_serializer<T, void>; - - static constexpr bool value = - is_detected_exact<void, to_json_function, serializer, BasicJsonType&, - T>::value; -}; - -template<typename T> -using detect_key_compare = typename T::key_compare; - -template<typename T> -struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {}; - -// obtains the actual object key comparator -template<typename BasicJsonType> -struct actual_object_comparator -{ - using object_t = typename BasicJsonType::object_t; - using object_comparator_t = typename BasicJsonType::default_object_comparator_t; - using type = typename std::conditional < has_key_compare<object_t>::value, - typename object_t::key_compare, object_comparator_t>::type; -}; - -template<typename BasicJsonType> -using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type; - -///////////////// -// char_traits // -///////////////// - -// Primary template of char_traits calls std char_traits -template<typename T> -struct char_traits : std::char_traits<T> -{}; - -// Explicitly define char traits for unsigned char since it is not standard -template<> -struct char_traits<unsigned char> : std::char_traits<char> -{ - using char_type = unsigned char; - using int_type = uint64_t; - - // Redefine to_int_type function - static int_type to_int_type(char_type c) noexcept - { - return static_cast<int_type>(c); - } - - static char_type to_char_type(int_type i) noexcept - { - return static_cast<char_type>(i); - } - - static constexpr int_type eof() noexcept - { - return static_cast<int_type>(EOF); - } -}; - -// Explicitly define char traits for signed char since it is not standard -template<> -struct char_traits<signed char> : std::char_traits<char> -{ - using char_type = signed char; - using int_type = uint64_t; - - // Redefine to_int_type function - static int_type to_int_type(char_type c) noexcept - { - return static_cast<int_type>(c); - } - - static char_type to_char_type(int_type i) noexcept - { - return static_cast<char_type>(i); - } - - static constexpr int_type eof() noexcept - { - return static_cast<int_type>(EOF); - } -}; - -/////////////////// -// is_ functions // -/////////////////// - -// https://en.cppreference.com/w/cpp/types/conjunction -template<class...> struct conjunction : std::true_type { }; -template<class B> struct conjunction<B> : B { }; -template<class B, class... Bn> -struct conjunction<B, Bn...> -: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {}; - -// https://en.cppreference.com/w/cpp/types/negation -template<class B> struct negation : std::integral_constant < bool, !B::value > { }; - -// Reimplementation of is_constructible and is_default_constructible, due to them being broken for -// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). -// This causes compile errors in e.g. clang 3.5 or gcc 4.9. -template <typename T> -struct is_default_constructible : std::is_default_constructible<T> {}; - -template <typename T1, typename T2> -struct is_default_constructible<std::pair<T1, T2>> - : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; - -template <typename T1, typename T2> -struct is_default_constructible<const std::pair<T1, T2>> - : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; - -template <typename... Ts> -struct is_default_constructible<std::tuple<Ts...>> - : conjunction<is_default_constructible<Ts>...> {}; - -template <typename... Ts> -struct is_default_constructible<const std::tuple<Ts...>> - : conjunction<is_default_constructible<Ts>...> {}; - -template <typename T, typename... Args> -struct is_constructible : std::is_constructible<T, Args...> {}; - -template <typename T1, typename T2> -struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {}; - -template <typename T1, typename T2> -struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {}; - -template <typename... Ts> -struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {}; - -template <typename... Ts> -struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {}; - -template<typename T, typename = void> -struct is_iterator_traits : std::false_type {}; - -template<typename T> -struct is_iterator_traits<iterator_traits<T>> -{ - private: - using traits = iterator_traits<T>; - - public: - static constexpr auto value = - is_detected<value_type_t, traits>::value && - is_detected<difference_type_t, traits>::value && - is_detected<pointer_t, traits>::value && - is_detected<iterator_category_t, traits>::value && - is_detected<reference_t, traits>::value; -}; - -template<typename T> -struct is_range -{ - private: - using t_ref = typename std::add_lvalue_reference<T>::type; - - using iterator = detected_t<result_of_begin, t_ref>; - using sentinel = detected_t<result_of_end, t_ref>; - - // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator - // and https://en.cppreference.com/w/cpp/iterator/sentinel_for - // but reimplementing these would be too much work, as a lot of other concepts are used underneath - static constexpr auto is_iterator_begin = - is_iterator_traits<iterator_traits<iterator>>::value; - - public: - static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin; -}; - -template<typename R> -using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>; - -template<typename T> -using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>; - -// The following implementation of is_complete_type is taken from -// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ -// and is written by Xiang Fan who agreed to using it in this library. - -template<typename T, typename = void> -struct is_complete_type : std::false_type {}; - -template<typename T> -struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; - -template<typename BasicJsonType, typename CompatibleObjectType, - typename = void> -struct is_compatible_object_type_impl : std::false_type {}; - -template<typename BasicJsonType, typename CompatibleObjectType> -struct is_compatible_object_type_impl < - BasicJsonType, CompatibleObjectType, - enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&& - is_detected<key_type_t, CompatibleObjectType>::value >> -{ - using object_t = typename BasicJsonType::object_t; - - // macOS's is_constructible does not play well with nonesuch... - static constexpr bool value = - is_constructible<typename object_t::key_type, - typename CompatibleObjectType::key_type>::value && - is_constructible<typename object_t::mapped_type, - typename CompatibleObjectType::mapped_type>::value; -}; - -template<typename BasicJsonType, typename CompatibleObjectType> -struct is_compatible_object_type - : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; - -template<typename BasicJsonType, typename ConstructibleObjectType, - typename = void> -struct is_constructible_object_type_impl : std::false_type {}; - -template<typename BasicJsonType, typename ConstructibleObjectType> -struct is_constructible_object_type_impl < - BasicJsonType, ConstructibleObjectType, - enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&& - is_detected<key_type_t, ConstructibleObjectType>::value >> -{ - using object_t = typename BasicJsonType::object_t; - - static constexpr bool value = - (is_default_constructible<ConstructibleObjectType>::value && - (std::is_move_assignable<ConstructibleObjectType>::value || - std::is_copy_assignable<ConstructibleObjectType>::value) && - (is_constructible<typename ConstructibleObjectType::key_type, - typename object_t::key_type>::value && - std::is_same < - typename object_t::mapped_type, - typename ConstructibleObjectType::mapped_type >::value)) || - (has_from_json<BasicJsonType, - typename ConstructibleObjectType::mapped_type>::value || - has_non_default_from_json < - BasicJsonType, - typename ConstructibleObjectType::mapped_type >::value); -}; - -template<typename BasicJsonType, typename ConstructibleObjectType> -struct is_constructible_object_type - : is_constructible_object_type_impl<BasicJsonType, - ConstructibleObjectType> {}; - -template<typename BasicJsonType, typename CompatibleStringType> -struct is_compatible_string_type -{ - static constexpr auto value = - is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; -}; - -template<typename BasicJsonType, typename ConstructibleStringType> -struct is_constructible_string_type -{ - // launder type through decltype() to fix compilation failure on ICPC -#ifdef __INTEL_COMPILER - using laundered_type = decltype(std::declval<ConstructibleStringType>()); -#else - using laundered_type = ConstructibleStringType; -#endif - - static constexpr auto value = - conjunction < - is_constructible<laundered_type, typename BasicJsonType::string_t>, - is_detected_exact<typename BasicJsonType::string_t::value_type, - value_type_t, laundered_type >>::value; -}; - -template<typename BasicJsonType, typename CompatibleArrayType, typename = void> -struct is_compatible_array_type_impl : std::false_type {}; - -template<typename BasicJsonType, typename CompatibleArrayType> -struct is_compatible_array_type_impl < - BasicJsonType, CompatibleArrayType, - enable_if_t < - is_detected<iterator_t, CompatibleArrayType>::value&& - is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&& -// special case for types like std::filesystem::path whose iterator's value_type are themselves -// c.f. https://github.com/nlohmann/json/pull/3073 - !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >> -{ - static constexpr bool value = - is_constructible<BasicJsonType, - range_value_t<CompatibleArrayType>>::value; -}; - -template<typename BasicJsonType, typename CompatibleArrayType> -struct is_compatible_array_type - : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; - -template<typename BasicJsonType, typename ConstructibleArrayType, typename = void> -struct is_constructible_array_type_impl : std::false_type {}; - -template<typename BasicJsonType, typename ConstructibleArrayType> -struct is_constructible_array_type_impl < - BasicJsonType, ConstructibleArrayType, - enable_if_t<std::is_same<ConstructibleArrayType, - typename BasicJsonType::value_type>::value >> - : std::true_type {}; - -template<typename BasicJsonType, typename ConstructibleArrayType> -struct is_constructible_array_type_impl < - BasicJsonType, ConstructibleArrayType, - enable_if_t < !std::is_same<ConstructibleArrayType, - typename BasicJsonType::value_type>::value&& - !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&& - is_default_constructible<ConstructibleArrayType>::value&& -(std::is_move_assignable<ConstructibleArrayType>::value || - std::is_copy_assignable<ConstructibleArrayType>::value)&& -is_detected<iterator_t, ConstructibleArrayType>::value&& -is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& -is_detected<range_value_t, ConstructibleArrayType>::value&& -// special case for types like std::filesystem::path whose iterator's value_type are themselves -// c.f. https://github.com/nlohmann/json/pull/3073 -!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&& - is_complete_type < - detected_t<range_value_t, ConstructibleArrayType >>::value >> -{ - using value_type = range_value_t<ConstructibleArrayType>; - - static constexpr bool value = - std::is_same<value_type, - typename BasicJsonType::array_t::value_type>::value || - has_from_json<BasicJsonType, - value_type>::value || - has_non_default_from_json < - BasicJsonType, - value_type >::value; -}; - -template<typename BasicJsonType, typename ConstructibleArrayType> -struct is_constructible_array_type - : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; - -template<typename RealIntegerType, typename CompatibleNumberIntegerType, - typename = void> -struct is_compatible_integer_type_impl : std::false_type {}; - -template<typename RealIntegerType, typename CompatibleNumberIntegerType> -struct is_compatible_integer_type_impl < - RealIntegerType, CompatibleNumberIntegerType, - enable_if_t < std::is_integral<RealIntegerType>::value&& - std::is_integral<CompatibleNumberIntegerType>::value&& - !std::is_same<bool, CompatibleNumberIntegerType>::value >> -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits<RealIntegerType>; - using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; - - static constexpr auto value = - is_constructible<RealIntegerType, - CompatibleNumberIntegerType>::value && - CompatibleLimits::is_integer && - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template<typename RealIntegerType, typename CompatibleNumberIntegerType> -struct is_compatible_integer_type - : is_compatible_integer_type_impl<RealIntegerType, - CompatibleNumberIntegerType> {}; - -template<typename BasicJsonType, typename CompatibleType, typename = void> -struct is_compatible_type_impl: std::false_type {}; - -template<typename BasicJsonType, typename CompatibleType> -struct is_compatible_type_impl < - BasicJsonType, CompatibleType, - enable_if_t<is_complete_type<CompatibleType>::value >> -{ - static constexpr bool value = - has_to_json<BasicJsonType, CompatibleType>::value; -}; - -template<typename BasicJsonType, typename CompatibleType> -struct is_compatible_type - : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; - -template<typename T1, typename T2> -struct is_constructible_tuple : std::false_type {}; - -template<typename T1, typename... Args> -struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {}; - -template<typename BasicJsonType, typename T> -struct is_json_iterator_of : std::false_type {}; - -template<typename BasicJsonType> -struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {}; - -template<typename BasicJsonType> -struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type -{}; - -// checks if a given type T is a template specialization of Primary -template<template <typename...> class Primary, typename T> -struct is_specialization_of : std::false_type {}; - -template<template <typename...> class Primary, typename... Args> -struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {}; - -template<typename T> -using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>; - -// checks if A and B are comparable using Compare functor -template<typename Compare, typename A, typename B, typename = void> -struct is_comparable : std::false_type {}; - -template<typename Compare, typename A, typename B> -struct is_comparable<Compare, A, B, void_t< -decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())), -decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>())) ->> : std::true_type {}; - -template<typename T> -using detect_is_transparent = typename T::is_transparent; - -// type trait to check if KeyType can be used as object key (without a BasicJsonType) -// see is_usable_as_basic_json_key_type below -template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, - bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> -using is_usable_as_key_type = typename std::conditional < - is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value - && !(ExcludeObjectKeyType && std::is_same<KeyType, - ObjectKeyType>::value) - && (!RequireTransparentComparator - || is_detected <detect_is_transparent, Comparator>::value) - && !is_json_pointer<KeyType>::value, - std::true_type, - std::false_type >::type; - -// type trait to check if KeyType can be used as object key -// true if: -// - KeyType is comparable with BasicJsonType::object_t::key_type -// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type -// - the comparator is transparent or RequireTransparentComparator is false -// - KeyType is not a JSON iterator or json_pointer -template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, - bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> -using is_usable_as_basic_json_key_type = typename std::conditional < - is_usable_as_key_type<typename BasicJsonType::object_comparator_t, - typename BasicJsonType::object_t::key_type, KeyTypeCVRef, - RequireTransparentComparator, ExcludeObjectKeyType>::value - && !is_json_iterator_of<BasicJsonType, KeyType>::value, - std::true_type, - std::false_type >::type; - -template<typename ObjectType, typename KeyType> -using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>())); - -// type trait to check if object_t has an erase() member functions accepting KeyType -template<typename BasicJsonType, typename KeyType> -using has_erase_with_key_type = typename std::conditional < - is_detected < - detect_erase_with_key_type, - typename BasicJsonType::object_t, KeyType >::value, - std::true_type, - std::false_type >::type; - -// a naive helper to check if a type is an ordered_map (exploits the fact that -// ordered_map inherits capacity() from std::vector) -template <typename T> -struct is_ordered_map -{ - using one = char; - - struct two - { - char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - }; - - template <typename C> static one test( decltype(&C::capacity) ) ; - template <typename C> static two test(...); - - enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) -}; - -// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) -template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 > -T conditional_static_cast(U value) -{ - return static_cast<T>(value); -} - -template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0> -T conditional_static_cast(U value) -{ - return value; -} - -template<typename... Types> -using all_integral = conjunction<std::is_integral<Types>...>; - -template<typename... Types> -using all_signed = conjunction<std::is_signed<Types>...>; - -template<typename... Types> -using all_unsigned = conjunction<std::is_unsigned<Types>...>; - -// there's a disjunction trait in another PR; replace when merged -template<typename... Types> -using same_sign = std::integral_constant < bool, - all_signed<Types...>::value || all_unsigned<Types...>::value >; - -template<typename OfType, typename T> -using never_out_of_range = std::integral_constant < bool, - (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType))) - || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >; - -template<typename OfType, typename T, - bool OfTypeSigned = std::is_signed<OfType>::value, - bool TSigned = std::is_signed<T>::value> -struct value_in_range_of_impl2; - -template<typename OfType, typename T> -struct value_in_range_of_impl2<OfType, T, false, false> -{ - static constexpr bool test(T val) - { - using CommonType = typename std::common_type<OfType, T>::type; - return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); - } -}; - -template<typename OfType, typename T> -struct value_in_range_of_impl2<OfType, T, true, false> -{ - static constexpr bool test(T val) - { - using CommonType = typename std::common_type<OfType, T>::type; - return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); - } -}; - -template<typename OfType, typename T> -struct value_in_range_of_impl2<OfType, T, false, true> -{ - static constexpr bool test(T val) - { - using CommonType = typename std::common_type<OfType, T>::type; - return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); - } -}; - -template<typename OfType, typename T> -struct value_in_range_of_impl2<OfType, T, true, true> -{ - static constexpr bool test(T val) - { - using CommonType = typename std::common_type<OfType, T>::type; - return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)()) - && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); - } -}; - -template<typename OfType, typename T, - bool NeverOutOfRange = never_out_of_range<OfType, T>::value, - typename = detail::enable_if_t<all_integral<OfType, T>::value>> -struct value_in_range_of_impl1; - -template<typename OfType, typename T> -struct value_in_range_of_impl1<OfType, T, false> -{ - static constexpr bool test(T val) - { - return value_in_range_of_impl2<OfType, T>::test(val); - } -}; - -template<typename OfType, typename T> -struct value_in_range_of_impl1<OfType, T, true> -{ - static constexpr bool test(T /*val*/) - { - return true; - } -}; - -template<typename OfType, typename T> -inline constexpr bool value_in_range_of(T val) -{ - return value_in_range_of_impl1<OfType, T>::test(val); -} - -template<bool Value> -using bool_constant = std::integral_constant<bool, Value>; - -/////////////////////////////////////////////////////////////////////////////// -// is_c_string -/////////////////////////////////////////////////////////////////////////////// - -namespace impl -{ - -template<typename T> -inline constexpr bool is_c_string() -{ - using TUnExt = typename std::remove_extent<T>::type; - using TUnCVExt = typename std::remove_cv<TUnExt>::type; - using TUnPtr = typename std::remove_pointer<T>::type; - using TUnCVPtr = typename std::remove_cv<TUnPtr>::type; - return - (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value) - || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value); -} - -} // namespace impl - -// checks whether T is a [cv] char */[cv] char[] C string -template<typename T> -struct is_c_string : bool_constant<impl::is_c_string<T>()> {}; - -template<typename T> -using is_c_string_uncvref = is_c_string<uncvref_t<T>>; - -/////////////////////////////////////////////////////////////////////////////// -// is_transparent -/////////////////////////////////////////////////////////////////////////////// - -namespace impl -{ - -template<typename T> -inline constexpr bool is_transparent() -{ - return is_detected<detect_is_transparent, T>::value; -} - -} // namespace impl - -// checks whether T has a member named is_transparent -template<typename T> -struct is_transparent : bool_constant<impl::is_transparent<T>()> {}; - -/////////////////////////////////////////////////////////////////////////////// - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/string_concat.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstring> // strlen -#include <string> // string -#include <utility> // forward - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/detected.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -inline std::size_t concat_length() -{ - return 0; -} - -template<typename... Args> -inline std::size_t concat_length(const char* cstr, const Args& ... rest); - -template<typename StringType, typename... Args> -inline std::size_t concat_length(const StringType& str, const Args& ... rest); - -template<typename... Args> -inline std::size_t concat_length(const char /*c*/, const Args& ... rest) -{ - return 1 + concat_length(rest...); -} - -template<typename... Args> -inline std::size_t concat_length(const char* cstr, const Args& ... rest) -{ - // cppcheck-suppress ignoredReturnValue - return ::strlen(cstr) + concat_length(rest...); -} - -template<typename StringType, typename... Args> -inline std::size_t concat_length(const StringType& str, const Args& ... rest) -{ - return str.size() + concat_length(rest...); -} - -template<typename OutStringType> -inline void concat_into(OutStringType& /*out*/) -{} - -template<typename StringType, typename Arg> -using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ())); - -template<typename StringType, typename Arg> -using detect_string_can_append = is_detected<string_can_append, StringType, Arg>; - -template<typename StringType, typename Arg> -using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ()); - -template<typename StringType, typename Arg> -using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>; - -template<typename StringType, typename Arg> -using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end())); - -template<typename StringType, typename Arg> -using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>; - -template<typename StringType, typename Arg> -using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size())); - -template<typename StringType, typename Arg> -using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>; - -template < typename OutStringType, typename Arg, typename... Args, - enable_if_t < !detect_string_can_append<OutStringType, Arg>::value - && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 > -inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest); - -template < typename OutStringType, typename Arg, typename... Args, - enable_if_t < !detect_string_can_append<OutStringType, Arg>::value - && !detect_string_can_append_op<OutStringType, Arg>::value - && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 > -inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest); - -template < typename OutStringType, typename Arg, typename... Args, - enable_if_t < !detect_string_can_append<OutStringType, Arg>::value - && !detect_string_can_append_op<OutStringType, Arg>::value - && !detect_string_can_append_iter<OutStringType, Arg>::value - && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 > -inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest); - -template<typename OutStringType, typename Arg, typename... Args, - enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0> -inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest) -{ - out.append(std::forward<Arg>(arg)); - concat_into(out, std::forward<Args>(rest)...); -} - -template < typename OutStringType, typename Arg, typename... Args, - enable_if_t < !detect_string_can_append<OutStringType, Arg>::value - && detect_string_can_append_op<OutStringType, Arg>::value, int > > -inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest) -{ - out += std::forward<Arg>(arg); - concat_into(out, std::forward<Args>(rest)...); -} - -template < typename OutStringType, typename Arg, typename... Args, - enable_if_t < !detect_string_can_append<OutStringType, Arg>::value - && !detect_string_can_append_op<OutStringType, Arg>::value - && detect_string_can_append_iter<OutStringType, Arg>::value, int > > -inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest) -{ - out.append(arg.begin(), arg.end()); - concat_into(out, std::forward<Args>(rest)...); -} - -template < typename OutStringType, typename Arg, typename... Args, - enable_if_t < !detect_string_can_append<OutStringType, Arg>::value - && !detect_string_can_append_op<OutStringType, Arg>::value - && !detect_string_can_append_iter<OutStringType, Arg>::value - && detect_string_can_append_data<OutStringType, Arg>::value, int > > -inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest) -{ - out.append(arg.data(), arg.size()); - concat_into(out, std::forward<Args>(rest)...); -} - -template<typename OutStringType = std::string, typename... Args> -inline OutStringType concat(Args && ... args) -{ - OutStringType str; - str.reserve(concat_length(args...)); - concat_into(str, std::forward<Args>(args)...); - return str; -} - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -//////////////// -// exceptions // -//////////////// - -/// @brief general exception of the @ref basic_json class -/// @sa https://json.nlohmann.me/api/basic_json/exception/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) - - protected: - JSON_HEDLEY_NON_NULL(3) - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) - - static std::string name(const std::string& ename, int id_) - { - return concat("[json.exception.", ename, '.', std::to_string(id_), "] "); - } - - static std::string diagnostics(std::nullptr_t /*leaf_element*/) - { - return ""; - } - - template<typename BasicJsonType> - static std::string diagnostics(const BasicJsonType* leaf_element) - { -#if JSON_DIAGNOSTICS - std::vector<std::string> tokens; - for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent) - { - switch (current->m_parent->type()) - { - case value_t::array: - { - for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i) - { - if (¤t->m_parent->m_data.m_value.array->operator[](i) == current) - { - tokens.emplace_back(std::to_string(i)); - break; - } - } - break; - } - - case value_t::object: - { - for (const auto& element : *current->m_parent->m_data.m_value.object) - { - if (&element.second == current) - { - tokens.emplace_back(element.first.c_str()); - break; - } - } - break; - } - - case value_t::null: // LCOV_EXCL_LINE - case value_t::string: // LCOV_EXCL_LINE - case value_t::boolean: // LCOV_EXCL_LINE - case value_t::number_integer: // LCOV_EXCL_LINE - case value_t::number_unsigned: // LCOV_EXCL_LINE - case value_t::number_float: // LCOV_EXCL_LINE - case value_t::binary: // LCOV_EXCL_LINE - case value_t::discarded: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - break; // LCOV_EXCL_LINE - } - } - - if (tokens.empty()) - { - return ""; - } - - auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, - [](const std::string & a, const std::string & b) - { - return concat(a, '/', detail::escape(b)); - }); - return concat('(', str, ") "); -#else - static_cast<void>(leaf_element); - return ""; -#endif - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/// @brief exception indicating a parse error -/// @sa https://json.nlohmann.me/api/basic_json/parse_error/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] pos the position where the error occurred (or with - chars_read_total=0 if the position cannot be - determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> - static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) - { - const std::string w = concat(exception::name("parse_error", id_), "parse error", - position_string(pos), ": ", exception::diagnostics(context), what_arg); - return {id_, pos.chars_read_total, w.c_str()}; - } - - template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) - { - const std::string w = concat(exception::name("parse_error", id_), "parse error", - (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), - ": ", exception::diagnostics(context), what_arg); - return {id_, byte_, w.c_str()}; - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} - - static std::string position_string(const position_t& pos) - { - return concat(" at line ", std::to_string(pos.lines_read + 1), - ", column ", std::to_string(pos.chars_read_current_line)); - } -}; - -/// @brief exception indicating errors with iterators -/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ -class invalid_iterator : public exception -{ - public: - template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> - static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context) - { - const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg); - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/// @brief exception indicating executing a member function with a wrong type -/// @sa https://json.nlohmann.me/api/basic_json/type_error/ -class type_error : public exception -{ - public: - template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> - static type_error create(int id_, const std::string& what_arg, BasicJsonContext context) - { - const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg); - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/// @brief exception indicating access out of the defined range -/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ -class out_of_range : public exception -{ - public: - template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> - static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context) - { - const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg); - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/// @brief exception indicating other library errors -/// @sa https://json.nlohmann.me/api/basic_json/other_error/ -class other_error : public exception -{ - public: - template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> - static other_error create(int id_, const std::string& what_arg, BasicJsonContext context) - { - const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg); - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/identity_tag.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -// dispatching helper struct -template <class T> struct identity_tag {}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/meta/std_fs.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/macro_scope.hpp> - - -#if JSON_HAS_EXPERIMENTAL_FILESYSTEM -#include <experimental/filesystem> -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ -namespace std_fs = std::experimental::filesystem; -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END -#elif JSON_HAS_FILESYSTEM -#include <filesystem> -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ -namespace std_fs = std::filesystem; -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END -#endif - -// #include <nlohmann/detail/meta/type_traits.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_null())) - { - JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j)); - } - n = nullptr; -} - -// overloads for basic_json template parameters -template < typename BasicJsonType, typename ArithmeticType, - enable_if_t < std::is_arithmetic<ArithmeticType>::value&& - !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, - int > = 0 > -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast<value_t>(j)) - { - case value_t::number_unsigned: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>()); - break; - } - case value_t::number_integer: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>()); - break; - } - case value_t::number_float: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>()); - break; - } - - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::string: - case value_t::boolean: - case value_t::binary: - case value_t::discarded: - default: - JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); - } -} - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) - { - JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j)); - } - b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>(); -} - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) - { - JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); - } - s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); -} - -template < - typename BasicJsonType, typename StringType, - enable_if_t < - std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value - && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value - && !std::is_same<typename BasicJsonType::string_t, StringType>::value - && !is_json_ref<StringType>::value, int > = 0 > -inline void from_json(const BasicJsonType& j, StringType& s) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) - { - JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); - } - - s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); -} - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -#if !JSON_DISABLE_ENUM_SERIALIZATION -template<typename BasicJsonType, typename EnumType, - enable_if_t<std::is_enum<EnumType>::value, int> = 0> -inline void from_json(const BasicJsonType& j, EnumType& e) -{ - typename std::underlying_type<EnumType>::type val; - get_arithmetic_value(j, val); - e = static_cast<EnumType>(val); -} -#endif // JSON_DISABLE_ENUM_SERIALIZATION - -// forward_list doesn't have an insert method -template<typename BasicJsonType, typename T, typename Allocator, - enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0> -inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - l.clear(); - std::transform(j.rbegin(), j.rend(), - std::front_inserter(l), [](const BasicJsonType & i) - { - return i.template get<T>(); - }); -} - -// valarray doesn't have an insert method -template<typename BasicJsonType, typename T, - enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0> -inline void from_json(const BasicJsonType& j, std::valarray<T>& l) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - l.resize(j.size()); - std::transform(j.begin(), j.end(), std::begin(l), - [](const BasicJsonType & elem) - { - return elem.template get<T>(); - }); -} - -template<typename BasicJsonType, typename T, std::size_t N> -auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) --> decltype(j.template get<T>(), void()) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get<T>(); - } -} - -template<typename BasicJsonType> -inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) -{ - arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); -} - -template<typename BasicJsonType, typename T, std::size_t N> -auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, - priority_tag<2> /*unused*/) --> decltype(j.template get<T>(), void()) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get<T>(); - } -} - -template<typename BasicJsonType, typename ConstructibleArrayType, - enable_if_t< - std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value, - int> = 0> -auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) --> decltype( - arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()), - j.template get<typename ConstructibleArrayType::value_type>(), - void()) -{ - using std::end; - - ConstructibleArrayType ret; - ret.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(ret, end(ret)), [](const BasicJsonType & i) - { - // get<BasicJsonType>() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get<typename ConstructibleArrayType::value_type>(); - }); - arr = std::move(ret); -} - -template<typename BasicJsonType, typename ConstructibleArrayType, - enable_if_t< - std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value, - int> = 0> -inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, - priority_tag<0> /*unused*/) -{ - using std::end; - - ConstructibleArrayType ret; - std::transform( - j.begin(), j.end(), std::inserter(ret, end(ret)), - [](const BasicJsonType & i) - { - // get<BasicJsonType>() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get<typename ConstructibleArrayType::value_type>(); - }); - arr = std::move(ret); -} - -template < typename BasicJsonType, typename ConstructibleArrayType, - enable_if_t < - is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&& - !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&& - !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&& - !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&& - !is_basic_json<ConstructibleArrayType>::value, - int > = 0 > -auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) --> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), -j.template get<typename ConstructibleArrayType::value_type>(), -void()) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - - from_json_array_impl(j, arr, priority_tag<3> {}); -} - -template < typename BasicJsonType, typename T, std::size_t... Idx > -std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j, - identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/) -{ - return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } }; -} - -template < typename BasicJsonType, typename T, std::size_t N > -auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag) --> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {})) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - - return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}); -} - -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) - { - JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j)); - } - - bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>(); -} - -template<typename BasicJsonType, typename ConstructibleObjectType, - enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0> -inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_object())) - { - JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j)); - } - - ConstructibleObjectType ret; - const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>(); - using value_type = typename ConstructibleObjectType::value_type; - std::transform( - inner_object->begin(), inner_object->end(), - std::inserter(ret, ret.begin()), - [](typename BasicJsonType::object_t::value_type const & p) - { - return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>()); - }); - obj = std::move(ret); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template < typename BasicJsonType, typename ArithmeticType, - enable_if_t < - std::is_arithmetic<ArithmeticType>::value&& - !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&& - !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&& - !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&& - !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, - int > = 0 > -inline void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast<value_t>(j)) - { - case value_t::number_unsigned: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>()); - break; - } - case value_t::number_integer: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>()); - break; - } - case value_t::number_float: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>()); - break; - } - case value_t::boolean: - { - val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>()); - break; - } - - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::string: - case value_t::binary: - case value_t::discarded: - default: - JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j)); - } -} - -template<typename BasicJsonType, typename... Args, std::size_t... Idx> -std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/) -{ - return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...); -} - -template < typename BasicJsonType, class A1, class A2 > -std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/) -{ - return {std::forward<BasicJsonType>(j).at(0).template get<A1>(), - std::forward<BasicJsonType>(j).at(1).template get<A2>()}; -} - -template<typename BasicJsonType, typename A1, typename A2> -inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/) -{ - p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {}); -} - -template<typename BasicJsonType, typename... Args> -std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/) -{ - return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {}); -} - -template<typename BasicJsonType, typename... Args> -inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/) -{ - t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {}); -} - -template<typename BasicJsonType, typename TupleRelated> -auto from_json(BasicJsonType&& j, TupleRelated&& t) --> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {})) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - - return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}); -} - -template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> -inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - m.clear(); - for (const auto& p : j) - { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); - } - m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>()); - } -} - -template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> -inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - m.clear(); - for (const auto& p : j) - { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); - } - m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>()); - } -} - -#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM -template<typename BasicJsonType> -inline void from_json(const BasicJsonType& j, std_fs::path& p) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) - { - JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); - } - p = *j.template get_ptr<const typename BasicJsonType::string_t*>(); -} -#endif - -struct from_json_fn -{ - template<typename BasicJsonType, typename T> - auto operator()(const BasicJsonType& j, T&& val) const - noexcept(noexcept(from_json(j, std::forward<T>(val)))) - -> decltype(from_json(j, std::forward<T>(val))) - { - return from_json(j, std::forward<T>(val)); - } -}; - -} // namespace detail - -#ifndef JSON_HAS_CPP_17 -/// namespace to hold default `from_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) -{ -#endif -JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers) - detail::static_const<detail::from_json_fn>::value; -#ifndef JSON_HAS_CPP_17 -} // namespace -#endif - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/conversions/to_json.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // copy -#include <iterator> // begin, end -#include <string> // string -#include <tuple> // tuple, get -#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type -#include <utility> // move, forward, declval, pair -#include <valarray> // valarray -#include <vector> // vector - -// #include <nlohmann/detail/iterators/iteration_proxy.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstddef> // size_t -#include <iterator> // input_iterator_tag -#include <string> // string, to_string -#include <tuple> // tuple_size, get, tuple_element -#include <utility> // move - -#if JSON_HAS_RANGES - #include <ranges> // enable_borrowed_range -#endif - -// #include <nlohmann/detail/abi_macros.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename string_type> -void int_to_string( string_type& target, std::size_t value ) -{ - // For ADL - using std::to_string; - target = to_string(value); -} -template<typename IteratorType> class iteration_proxy_value -{ - public: - using difference_type = std::ptrdiff_t; - using value_type = iteration_proxy_value; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::input_iterator_tag; - using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type; - - private: - /// the iterator - IteratorType anchor{}; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - /// last stringified array index - mutable std::size_t array_index_last = 0; - /// a string representation of the array index - mutable string_type array_index_str = "0"; - /// an empty string (to return a reference for primitive values) - string_type empty_str{}; - - public: - explicit iteration_proxy_value() = default; - explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) - noexcept(std::is_nothrow_move_constructible<IteratorType>::value - && std::is_nothrow_default_constructible<string_type>::value) - : anchor(std::move(it)) - , array_index(array_index_) - {} - - iteration_proxy_value(iteration_proxy_value const&) = default; - iteration_proxy_value& operator=(iteration_proxy_value const&) = default; - // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions - iteration_proxy_value(iteration_proxy_value&&) - noexcept(std::is_nothrow_move_constructible<IteratorType>::value - && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations) - iteration_proxy_value& operator=(iteration_proxy_value&&) - noexcept(std::is_nothrow_move_assignable<IteratorType>::value - && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations) - ~iteration_proxy_value() = default; - - /// dereference operator (needed for range-based for) - const iteration_proxy_value& operator*() const - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_value& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) - { - auto tmp = iteration_proxy_value(anchor, array_index); - ++anchor; - ++array_index; - return tmp; - } - - /// equality operator (needed for InputIterator) - bool operator==(const iteration_proxy_value& o) const - { - return anchor == o.anchor; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_value& o) const - { - return anchor != o.anchor; - } - - /// return key of the iterator - const string_type& key() const - { - JSON_ASSERT(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - if (array_index != array_index_last) - { - int_to_string( array_index_str, array_index ); - array_index_last = array_index; - } - return array_index_str; - } - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return empty_str; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } -}; - -/// proxy class for the items() function -template<typename IteratorType> class iteration_proxy -{ - private: - /// the container to iterate - typename IteratorType::pointer container = nullptr; - - public: - explicit iteration_proxy() = default; - - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) noexcept - : container(&cont) {} - - iteration_proxy(iteration_proxy const&) = default; - iteration_proxy& operator=(iteration_proxy const&) = default; - iteration_proxy(iteration_proxy&&) noexcept = default; - iteration_proxy& operator=(iteration_proxy&&) noexcept = default; - ~iteration_proxy() = default; - - /// return iterator begin (needed for range-based for) - iteration_proxy_value<IteratorType> begin() const noexcept - { - return iteration_proxy_value<IteratorType>(container->begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_value<IteratorType> end() const noexcept - { - return iteration_proxy_value<IteratorType>(container->end()); - } -}; - -// Structured Bindings Support -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0> -auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key()) -{ - return i.key(); -} -// Structured Bindings Support -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0> -auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value()) -{ - return i.value(); -} - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// The Addition to the STD Namespace is required to add -// Structured Bindings Support to the iteration_proxy_value class -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -namespace std -{ - -#if defined(__clang__) - // Fix: https://github.com/nlohmann/json/issues/1401 - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wmismatched-tags" -#endif -template<typename IteratorType> -class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp) - : public std::integral_constant<std::size_t, 2> {}; - -template<std::size_t N, typename IteratorType> -class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp) -{ - public: - using type = decltype( - get<N>(std::declval < - ::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); -}; -#if defined(__clang__) - #pragma clang diagnostic pop -#endif - -} // namespace std - -#if JSON_HAS_RANGES - template <typename IteratorType> - inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true; -#endif - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/std_fs.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -////////////////// -// constructors // -////////////////// - -/* - * Note all external_constructor<>::construct functions need to call - * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an - * allocated value (e.g., a string). See bug issue - * https://github.com/nlohmann/json/issues/2865 for more information. - */ - -template<value_t> struct external_constructor; - -template<> -struct external_constructor<value_t::boolean> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::boolean; - j.m_data.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::string> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value = s; - j.assert_invariant(); - } - - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value = std::move(s); - j.assert_invariant(); - } - - template < typename BasicJsonType, typename CompatibleStringType, - enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value, - int > = 0 > - static void construct(BasicJsonType& j, const CompatibleStringType& str) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::string; - j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::binary> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::binary; - j.m_data.m_value = typename BasicJsonType::binary_t(b); - j.assert_invariant(); - } - - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::binary; - j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b)); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::number_float> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_float; - j.m_data.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::number_unsigned> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_unsigned; - j.m_data.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::number_integer> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::number_integer; - j.m_data.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::array> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = arr; - j.set_parents(); - j.assert_invariant(); - } - - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = std::move(arr); - j.set_parents(); - j.assert_invariant(); - } - - template < typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value, - int > = 0 > - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr)); - j.set_parents(); - j.assert_invariant(); - } - - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const std::vector<bool>& arr) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; - j.m_data.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_data.m_value.array->push_back(x); - j.set_parent(j.m_data.m_value.array->back()); - } - j.assert_invariant(); - } - - template<typename BasicJsonType, typename T, - enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> - static void construct(BasicJsonType& j, const std::valarray<T>& arr) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::array; - j.m_data.m_value = value_t::array; - j.m_data.m_value.array->resize(arr.size()); - if (arr.size() > 0) - { - std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin()); - } - j.set_parents(); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor<value_t::object> -{ - template<typename BasicJsonType> - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value = obj; - j.set_parents(); - j.assert_invariant(); - } - - template<typename BasicJsonType> - static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) - { - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value = std::move(obj); - j.set_parents(); - j.assert_invariant(); - } - - template < typename BasicJsonType, typename CompatibleObjectType, - enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 > - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_data.m_value.destroy(j.m_data.m_type); - j.m_data.m_type = value_t::object; - j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj)); - j.set_parents(); - j.assert_invariant(); - } -}; - -///////////// -// to_json // -///////////// - -template<typename BasicJsonType, typename T, - enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0> -inline void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor<value_t::boolean>::construct(j, b); -} - -template < typename BasicJsonType, typename BoolRef, - enable_if_t < - ((std::is_same<std::vector<bool>::reference, BoolRef>::value - && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value) - || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value - && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>, - typename BasicJsonType::boolean_t >::value)) - && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 > -inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept -{ - external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b)); -} - -template<typename BasicJsonType, typename CompatibleString, - enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0> -inline void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor<value_t::string>::construct(j, s); -} - -template<typename BasicJsonType> -inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) -{ - external_constructor<value_t::string>::construct(j, std::move(s)); -} - -template<typename BasicJsonType, typename FloatType, - enable_if_t<std::is_floating_point<FloatType>::value, int> = 0> -inline void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); -} - -template<typename BasicJsonType, typename CompatibleNumberUnsignedType, - enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0> -inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val)); -} - -template<typename BasicJsonType, typename CompatibleNumberIntegerType, - enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0> -inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); -} - -#if !JSON_DISABLE_ENUM_SERIALIZATION -template<typename BasicJsonType, typename EnumType, - enable_if_t<std::is_enum<EnumType>::value, int> = 0> -inline void to_json(BasicJsonType& j, EnumType e) noexcept -{ - using underlying_type = typename std::underlying_type<EnumType>::type; - static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer; - external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e)); -} -#endif // JSON_DISABLE_ENUM_SERIALIZATION - -template<typename BasicJsonType> -inline void to_json(BasicJsonType& j, const std::vector<bool>& e) -{ - external_constructor<value_t::array>::construct(j, e); -} - -template < typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < is_compatible_array_type<BasicJsonType, - CompatibleArrayType>::value&& - !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&& - !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&& - !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&& - !is_basic_json<CompatibleArrayType>::value, - int > = 0 > -inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor<value_t::array>::construct(j, arr); -} - -template<typename BasicJsonType> -inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) -{ - external_constructor<value_t::binary>::construct(j, bin); -} - -template<typename BasicJsonType, typename T, - enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> -inline void to_json(BasicJsonType& j, const std::valarray<T>& arr) -{ - external_constructor<value_t::array>::construct(j, std::move(arr)); -} - -template<typename BasicJsonType> -inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) -{ - external_constructor<value_t::array>::construct(j, std::move(arr)); -} - -template < typename BasicJsonType, typename CompatibleObjectType, - enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 > -inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) -{ - external_constructor<value_t::object>::construct(j, obj); -} - -template<typename BasicJsonType> -inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) -{ - external_constructor<value_t::object>::construct(j, std::move(obj)); -} - -template < - typename BasicJsonType, typename T, std::size_t N, - enable_if_t < !std::is_constructible<typename BasicJsonType::string_t, - const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - int > = 0 > -inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -{ - external_constructor<value_t::array>::construct(j, arr); -} - -template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 > -inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p) -{ - j = { p.first, p.second }; -} - -// for https://github.com/nlohmann/json/pull/1134 -template<typename BasicJsonType, typename T, - enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0> -inline void to_json(BasicJsonType& j, const T& b) -{ - j = { {b.key(), b.value()} }; -} - -template<typename BasicJsonType, typename Tuple, std::size_t... Idx> -inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/) -{ - j = { std::get<Idx>(t)... }; -} - -template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> -inline void to_json(BasicJsonType& j, const T& t) -{ - to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); -} - -#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM -template<typename BasicJsonType> -inline void to_json(BasicJsonType& j, const std_fs::path& p) -{ - j = p.string(); -} -#endif - -struct to_json_fn -{ - template<typename BasicJsonType, typename T> - auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) - -> decltype(to_json(j, std::forward<T>(val)), void()) - { - return to_json(j, std::forward<T>(val)); - } -}; -} // namespace detail - -#ifndef JSON_HAS_CPP_17 -/// namespace to hold default `to_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) -{ -#endif -JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers) - detail::static_const<detail::to_json_fn>::value; -#ifndef JSON_HAS_CPP_17 -} // namespace -#endif - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/meta/identity_tag.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -/// @sa https://json.nlohmann.me/api/adl_serializer/ -template<typename ValueType, typename> -struct adl_serializer -{ - /// @brief convert a JSON value to any value type - /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ - template<typename BasicJsonType, typename TargetType = ValueType> - static auto from_json(BasicJsonType && j, TargetType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) - -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()) - { - ::nlohmann::from_json(std::forward<BasicJsonType>(j), val); - } - - /// @brief convert a JSON value to any value type - /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ - template<typename BasicJsonType, typename TargetType = ValueType> - static auto from_json(BasicJsonType && j) noexcept( - noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))) - -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})) - { - return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}); - } - - /// @brief convert any value type to a JSON value - /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ - template<typename BasicJsonType, typename TargetType = ValueType> - static auto to_json(BasicJsonType& j, TargetType && val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val)))) - -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void()) - { - ::nlohmann::to_json(j, std::forward<TargetType>(val)); - } -}; - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/byte_container_with_subtype.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstdint> // uint8_t, uint64_t -#include <tuple> // tie -#include <utility> // move - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -/// @brief an internal type for a backed binary type -/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ -template<typename BinaryType> -class byte_container_with_subtype : public BinaryType -{ - public: - using container_type = BinaryType; - using subtype_type = std::uint64_t; - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype() noexcept(noexcept(container_type())) - : container_type() - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) - : container_type(b) - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) - : container_type(b) - , m_subtype(subtype_) - , m_has_subtype(true) - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - , m_subtype(subtype_) - , m_has_subtype(true) - {} - - bool operator==(const byte_container_with_subtype& rhs) const - { - return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) == - std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype); - } - - bool operator!=(const byte_container_with_subtype& rhs) const - { - return !(rhs == *this); - } - - /// @brief sets the binary subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ - void set_subtype(subtype_type subtype_) noexcept - { - m_subtype = subtype_; - m_has_subtype = true; - } - - /// @brief return the binary subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ - constexpr subtype_type subtype() const noexcept - { - return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1); - } - - /// @brief return whether the value has a subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ - constexpr bool has_subtype() const noexcept - { - return m_has_subtype; - } - - /// @brief clears the binary subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ - void clear_subtype() noexcept - { - m_subtype = 0; - m_has_subtype = false; - } - - private: - subtype_type m_subtype = 0; - bool m_has_subtype = false; -}; - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/conversions/from_json.hpp> - -// #include <nlohmann/detail/conversions/to_json.hpp> - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/hash.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstdint> // uint8_t -#include <cstddef> // size_t -#include <functional> // hash - -// #include <nlohmann/detail/abi_macros.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -// boost::hash_combine -inline std::size_t combine(std::size_t seed, std::size_t h) noexcept -{ - seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); - return seed; -} - -/*! -@brief hash a JSON value - -The hash function tries to rely on std::hash where possible. Furthermore, the -type of the JSON value is taken into account to have different hash values for -null, 0, 0U, and false, etc. - -@tparam BasicJsonType basic_json specialization -@param j JSON value to hash -@return hash value of j -*/ -template<typename BasicJsonType> -std::size_t hash(const BasicJsonType& j) -{ - using string_t = typename BasicJsonType::string_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - const auto type = static_cast<std::size_t>(j.type()); - switch (j.type()) - { - case BasicJsonType::value_t::null: - case BasicJsonType::value_t::discarded: - { - return combine(type, 0); - } - - case BasicJsonType::value_t::object: - { - auto seed = combine(type, j.size()); - for (const auto& element : j.items()) - { - const auto h = std::hash<string_t> {}(element.key()); - seed = combine(seed, h); - seed = combine(seed, hash(element.value())); - } - return seed; - } - - case BasicJsonType::value_t::array: - { - auto seed = combine(type, j.size()); - for (const auto& element : j) - { - seed = combine(seed, hash(element)); - } - return seed; - } - - case BasicJsonType::value_t::string: - { - const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>()); - return combine(type, h); - } - - case BasicJsonType::value_t::boolean: - { - const auto h = std::hash<bool> {}(j.template get<bool>()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_integer: - { - const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_unsigned: - { - const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_float: - { - const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>()); - return combine(type, h); - } - - case BasicJsonType::value_t::binary: - { - auto seed = combine(type, j.get_binary().size()); - const auto h = std::hash<bool> {}(j.get_binary().has_subtype()); - seed = combine(seed, h); - seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype())); - for (const auto byte : j.get_binary()) - { - seed = combine(seed, std::hash<std::uint8_t> {}(byte)); - } - return seed; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } -} - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/input/binary_reader.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // generate_n -#include <array> // array -#include <cmath> // ldexp -#include <cstddef> // size_t -#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t -#include <cstdio> // snprintf -#include <cstring> // memcpy -#include <iterator> // back_inserter -#include <limits> // numeric_limits -#include <string> // char_traits, string -#include <utility> // make_pair, move -#include <vector> // vector - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/input/input_adapters.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <array> // array -#include <cstddef> // size_t -#include <cstring> // strlen -#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include <memory> // shared_ptr, make_shared, addressof -#include <numeric> // accumulate -#include <string> // string, char_traits -#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include <utility> // pair, declval - -#ifndef JSON_NO_IO - #include <cstdio> // FILE * - #include <istream> // istream -#endif // JSON_NO_IO - -// #include <nlohmann/detail/iterators/iterator_traits.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/// the supported input formats -enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata }; - -//////////////////// -// input adapters // -//////////////////// - -#ifndef JSON_NO_IO -/*! -Input adapter for stdio file access. This adapter read only 1 byte and do not use any - buffer. This adapter is a very low level adapter. -*/ -class file_input_adapter -{ - public: - using char_type = char; - - JSON_HEDLEY_NON_NULL(2) - explicit file_input_adapter(std::FILE* f) noexcept - : m_file(f) - { - JSON_ASSERT(m_file != nullptr); - } - - // make class move-only - file_input_adapter(const file_input_adapter&) = delete; - file_input_adapter(file_input_adapter&&) noexcept = default; - file_input_adapter& operator=(const file_input_adapter&) = delete; - file_input_adapter& operator=(file_input_adapter&&) = delete; - ~file_input_adapter() = default; - - std::char_traits<char>::int_type get_character() noexcept - { - return std::fgetc(m_file); - } - - private: - /// the file pointer to read from - std::FILE* m_file; -}; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter -{ - public: - using char_type = char; - - ~input_stream_adapter() - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags, except eof - if (is != nullptr) - { - is->clear(is->rdstate() & std::ios::eofbit); - } - } - - explicit input_stream_adapter(std::istream& i) - : is(&i), sb(i.rdbuf()) - {} - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&&) = delete; - - input_stream_adapter(input_stream_adapter&& rhs) noexcept - : is(rhs.is), sb(rhs.sb) - { - rhs.is = nullptr; - rhs.sb = nullptr; - } - - // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to - // ensure that std::char_traits<char>::eof() and the character 0xFF do not - // end up as the same value, e.g. 0xFFFFFFFF. - std::char_traits<char>::int_type get_character() - { - auto res = sb->sbumpc(); - // set eof manually, as we don't use the istream interface. - if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof())) - { - is->clear(is->rdstate() | std::ios::eofbit); - } - return res; - } - - private: - /// the associated input stream - std::istream* is = nullptr; - std::streambuf* sb = nullptr; -}; -#endif // JSON_NO_IO - -// General-purpose iterator-based adapter. It might not be as fast as -// theoretically possible for some containers, but it is extremely versatile. -template<typename IteratorType> -class iterator_input_adapter -{ - public: - using char_type = typename std::iterator_traits<IteratorType>::value_type; - - iterator_input_adapter(IteratorType first, IteratorType last) - : current(std::move(first)), end(std::move(last)) - {} - - typename char_traits<char_type>::int_type get_character() - { - if (JSON_HEDLEY_LIKELY(current != end)) - { - auto result = char_traits<char_type>::to_int_type(*current); - std::advance(current, 1); - return result; - } - - return char_traits<char_type>::eof(); - } - - private: - IteratorType current; - IteratorType end; - - template<typename BaseInputAdapter, size_t T> - friend struct wide_string_input_helper; - - bool empty() const - { - return current == end; - } -}; - -template<typename BaseInputAdapter, size_t T> -struct wide_string_input_helper; - -template<typename BaseInputAdapter> -struct wide_string_input_helper<BaseInputAdapter, 4> -{ - // UTF-32 - static void fill_buffer(BaseInputAdapter& input, - std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, - size_t& utf8_bytes_index, - size_t& utf8_bytes_filled) - { - utf8_bytes_index = 0; - - if (JSON_HEDLEY_UNLIKELY(input.empty())) - { - utf8_bytes[0] = std::char_traits<char>::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const auto wc = input.get_character(); - - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu)); - utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu)); - utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); - utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u)); - utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu)); - utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); - utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); - utf8_bytes_filled = 1; - } - } - } -}; - -template<typename BaseInputAdapter> -struct wide_string_input_helper<BaseInputAdapter, 2> -{ - // UTF-16 - static void fill_buffer(BaseInputAdapter& input, - std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, - size_t& utf8_bytes_index, - size_t& utf8_bytes_filled) - { - utf8_bytes_index = 0; - - if (JSON_HEDLEY_UNLIKELY(input.empty())) - { - utf8_bytes[0] = std::char_traits<char>::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const auto wc = input.get_character(); - - // UTF-16 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u))); - utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); - utf8_bytes_filled = 2; - } - else if (0xD800 > wc || wc >= 0xE000) - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u))); - utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); - utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); - utf8_bytes_filled = 3; - } - else - { - if (JSON_HEDLEY_UNLIKELY(!input.empty())) - { - const auto wc2 = static_cast<unsigned int>(input.get_character()); - const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u)); - utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); - utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); - utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu)); - utf8_bytes_filled = 4; - } - else - { - utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); - utf8_bytes_filled = 1; - } - } - } - } -}; - -// Wraps another input adapter to convert wide character types into individual bytes. -template<typename BaseInputAdapter, typename WideCharType> -class wide_string_input_adapter -{ - public: - using char_type = char; - - wide_string_input_adapter(BaseInputAdapter base) - : base_adapter(base) {} - - typename std::char_traits<char>::int_type get_character() noexcept - { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) - { - fill_buffer<sizeof(WideCharType)>(); - - JSON_ASSERT(utf8_bytes_filled > 0); - JSON_ASSERT(utf8_bytes_index == 0); - } - - // use buffer - JSON_ASSERT(utf8_bytes_filled > 0); - JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; - } - - private: - BaseInputAdapter base_adapter; - - template<size_t T> - void fill_buffer() - { - wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); - } - - /// a buffer for UTF-8 bytes - std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; - - /// index to the utf8_codes array for the next valid byte - std::size_t utf8_bytes_index = 0; - /// number of valid bytes in the utf8_codes array - std::size_t utf8_bytes_filled = 0; -}; - -template<typename IteratorType, typename Enable = void> -struct iterator_input_adapter_factory -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits<iterator_type>::value_type; - using adapter_type = iterator_input_adapter<iterator_type>; - - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(std::move(first), std::move(last)); - } -}; - -template<typename T> -struct is_iterator_of_multibyte -{ - using value_type = typename std::iterator_traits<T>::value_type; - enum - { - value = sizeof(value_type) > 1 - }; -}; - -template<typename IteratorType> -struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>> -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits<iterator_type>::value_type; - using base_adapter_type = iterator_input_adapter<iterator_type>; - using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>; - - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(base_adapter_type(std::move(first), std::move(last))); - } -}; - -// General purpose iterator-based input -template<typename IteratorType> -typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last) -{ - using factory_type = iterator_input_adapter_factory<IteratorType>; - return factory_type::create(first, last); -} - -// Convenience shorthand from container to iterator -// Enables ADL on begin(container) and end(container) -// Encloses the using declarations in namespace for not to leak them to outside scope - -namespace container_input_adapter_factory_impl -{ - -using std::begin; -using std::end; - -template<typename ContainerType, typename Enable = void> -struct container_input_adapter_factory {}; - -template<typename ContainerType> -struct container_input_adapter_factory< ContainerType, - void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>> - { - using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))); - - static adapter_type create(const ContainerType& container) -{ - return input_adapter(begin(container), end(container)); -} - }; - -} // namespace container_input_adapter_factory_impl - -template<typename ContainerType> -typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container) -{ - return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container); -} - -#ifndef JSON_NO_IO -// Special cases with fast paths -inline file_input_adapter input_adapter(std::FILE* file) -{ - return file_input_adapter(file); -} - -inline input_stream_adapter input_adapter(std::istream& stream) -{ - return input_stream_adapter(stream); -} - -inline input_stream_adapter input_adapter(std::istream&& stream) -{ - return input_stream_adapter(stream); -} -#endif // JSON_NO_IO - -using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>())); - -// Null-delimited strings, and the like. -template < typename CharT, - typename std::enable_if < - std::is_pointer<CharT>::value&& - !std::is_array<CharT>::value&& - std::is_integral<typename std::remove_pointer<CharT>::type>::value&& - sizeof(typename std::remove_pointer<CharT>::type) == 1, - int >::type = 0 > -contiguous_bytes_input_adapter input_adapter(CharT b) -{ - auto length = std::strlen(reinterpret_cast<const char*>(b)); - const auto* ptr = reinterpret_cast<const char*>(b); - return input_adapter(ptr, ptr + length); -} - -template<typename T, std::size_t N> -auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -{ - return input_adapter(array, array + N); -} - -// This class only handles inputs of input_buffer_adapter type. -// It's required so that expressions like {ptr, len} can be implicitly cast -// to the correct adapter. -class span_input_adapter -{ - public: - template < typename CharT, - typename std::enable_if < - std::is_pointer<CharT>::value&& - std::is_integral<typename std::remove_pointer<CharT>::type>::value&& - sizeof(typename std::remove_pointer<CharT>::type) == 1, - int >::type = 0 > - span_input_adapter(CharT b, std::size_t l) - : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {} - - template<class IteratorType, - typename std::enable_if< - std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - span_input_adapter(IteratorType first, IteratorType last) - : ia(input_adapter(first, last)) {} - - contiguous_bytes_input_adapter&& get() - { - return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) - } - - private: - contiguous_bytes_input_adapter ia; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/input/json_sax.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstddef> -#include <string> // string -#include <utility> // move -#include <vector> // vector - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -/*! -@brief SAX interface - -This class describes the SAX interface used by @ref nlohmann::json::sax_parse. -Each function is called in different situations while the input is parsed. The -boolean return value informs the parser whether to continue processing the -input. -*/ -template<typename BasicJsonType> -struct json_sax -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @brief a null value was read - @return whether parsing should proceed - */ - virtual bool null() = 0; - - /*! - @brief a boolean value was read - @param[in] val boolean value - @return whether parsing should proceed - */ - virtual bool boolean(bool val) = 0; - - /*! - @brief an integer number was read - @param[in] val integer value - @return whether parsing should proceed - */ - virtual bool number_integer(number_integer_t val) = 0; - - /*! - @brief an unsigned integer number was read - @param[in] val unsigned integer value - @return whether parsing should proceed - */ - virtual bool number_unsigned(number_unsigned_t val) = 0; - - /*! - @brief a floating-point number was read - @param[in] val floating-point value - @param[in] s raw token value - @return whether parsing should proceed - */ - virtual bool number_float(number_float_t val, const string_t& s) = 0; - - /*! - @brief a string value was read - @param[in] val string value - @return whether parsing should proceed - @note It is safe to move the passed string value. - */ - virtual bool string(string_t& val) = 0; - - /*! - @brief a binary value was read - @param[in] val binary value - @return whether parsing should proceed - @note It is safe to move the passed binary value. - */ - virtual bool binary(binary_t& val) = 0; - - /*! - @brief the beginning of an object was read - @param[in] elements number of object elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_object(std::size_t elements) = 0; - - /*! - @brief an object key was read - @param[in] val object key - @return whether parsing should proceed - @note It is safe to move the passed string. - */ - virtual bool key(string_t& val) = 0; - - /*! - @brief the end of an object was read - @return whether parsing should proceed - */ - virtual bool end_object() = 0; - - /*! - @brief the beginning of an array was read - @param[in] elements number of array elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_array(std::size_t elements) = 0; - - /*! - @brief the end of an array was read - @return whether parsing should proceed - */ - virtual bool end_array() = 0; - - /*! - @brief a parse error occurred - @param[in] position the position in the input where the error occurs - @param[in] last_token the last read token - @param[in] ex an exception object describing the error - @return whether parsing should proceed (must return false) - */ - virtual bool parse_error(std::size_t position, - const std::string& last_token, - const detail::exception& ex) = 0; - - json_sax() = default; - json_sax(const json_sax&) = default; - json_sax(json_sax&&) noexcept = default; - json_sax& operator=(const json_sax&) = default; - json_sax& operator=(json_sax&&) noexcept = default; - virtual ~json_sax() = default; -}; - -namespace detail -{ -/*! -@brief SAX implementation to create a JSON value from SAX events - -This class implements the @ref json_sax interface and processes the SAX events -to create a JSON value which makes it basically a DOM parser. The structure or -hierarchy of the JSON value is managed by the stack `ref_stack` which contains -a pointer to the respective array or object for each recursion depth. - -After successful parsing, the value that is passed by reference to the -constructor contains the parsed value. - -@tparam BasicJsonType the JSON type -*/ -template<typename BasicJsonType> -class json_sax_dom_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @param[in,out] r reference to a JSON value that is manipulated while - parsing - @param[in] allow_exceptions_ whether parse errors yield exceptions - */ - explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) - : root(r), allow_exceptions(allow_exceptions_) - {} - - // make class move-only - json_sax_dom_parser(const json_sax_dom_parser&) = delete; - json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; - json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - - if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(ref_stack.back()->is_object()); - - // add null at given key and store the reference for later - object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val)); - return true; - } - - bool end_object() - { - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(ref_stack.back()->is_object()); - - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - bool start_array(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - - if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool end_array() - { - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(ref_stack.back()->is_array()); - - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - template<class Exception> - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast<void>(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - */ - template<typename Value> - JSON_HEDLEY_RETURNS_NON_NULL - BasicJsonType* handle_value(Value&& v) - { - if (ref_stack.empty()) - { - root = BasicJsonType(std::forward<Value>(v)); - return &root; - } - - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v)); - return &(ref_stack.back()->m_data.m_value.array->back()); - } - - JSON_ASSERT(ref_stack.back()->is_object()); - JSON_ASSERT(object_element); - *object_element = BasicJsonType(std::forward<Value>(v)); - return object_element; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector<BasicJsonType*> ref_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - -template<typename BasicJsonType> -class json_sax_dom_callback_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using parser_callback_t = typename BasicJsonType::parser_callback_t; - using parse_event_t = typename BasicJsonType::parse_event_t; - - json_sax_dom_callback_parser(BasicJsonType& r, - const parser_callback_t cb, - const bool allow_exceptions_ = true) - : root(r), callback(cb), allow_exceptions(allow_exceptions_) - { - keep_stack.push_back(true); - } - - // make class move-only - json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_callback_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - // check callback for object start - const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::object, true); - ref_stack.push_back(val.second); - - // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - BasicJsonType k = BasicJsonType(val); - - // check callback for key - const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k); - key_keep_stack.push_back(keep); - - // add discarded value at given key and store the reference for later - if (keep && ref_stack.back()) - { - object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded); - } - - return true; - } - - bool end_object() - { - if (ref_stack.back()) - { - if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) - { - // discard object - *ref_stack.back() = discarded; - } - else - { - ref_stack.back()->set_parents(); - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) - { - // remove discarded value - for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) - { - if (it->is_discarded()) - { - ref_stack.back()->erase(it); - break; - } - } - } - - return true; - } - - bool start_array(std::size_t len) - { - const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::array, true); - ref_stack.push_back(val.second); - - // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); - } - - return true; - } - - bool end_array() - { - bool keep = true; - - if (ref_stack.back()) - { - keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); - if (keep) - { - ref_stack.back()->set_parents(); - } - else - { - // discard array - *ref_stack.back() = discarded; - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - // remove discarded value - if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) - { - ref_stack.back()->m_data.m_value.array->pop_back(); - } - - return true; - } - - template<class Exception> - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast<void>(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @param[in] v value to add to the JSON value we build during parsing - @param[in] skip_callback whether we should skip calling the callback - function; this is required after start_array() and - start_object() SAX events, because otherwise we would call the - callback function with an empty array or object, respectively. - - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - - @return pair of boolean (whether value should be kept) and pointer (to the - passed value in the ref_stack hierarchy; nullptr if not kept) - */ - template<typename Value> - std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false) - { - JSON_ASSERT(!keep_stack.empty()); - - // do not handle this value if we know it would be added to a discarded - // container - if (!keep_stack.back()) - { - return {false, nullptr}; - } - - // create value - auto value = BasicJsonType(std::forward<Value>(v)); - - // check callback - const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value); - - // do not handle this value if we just learnt it shall be discarded - if (!keep) - { - return {false, nullptr}; - } - - if (ref_stack.empty()) - { - root = std::move(value); - return {true, & root}; - } - - // skip this value if we already decided to skip the parent - // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (!ref_stack.back()) - { - return {false, nullptr}; - } - - // we now only expect arrays and objects - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - // array - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value)); - return {true, & (ref_stack.back()->m_data.m_value.array->back())}; - } - - // object - JSON_ASSERT(ref_stack.back()->is_object()); - // check if we should store an element for the current key - JSON_ASSERT(!key_keep_stack.empty()); - const bool store_element = key_keep_stack.back(); - key_keep_stack.pop_back(); - - if (!store_element) - { - return {false, nullptr}; - } - - JSON_ASSERT(object_element); - *object_element = std::move(value); - return {true, object_element}; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector<BasicJsonType*> ref_stack {}; - /// stack to manage which values to keep - std::vector<bool> keep_stack {}; // NOLINT(readability-redundant-member-init) - /// stack to manage which object keys to keep - std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init) - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// callback function - const parser_callback_t callback = nullptr; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; - /// a discarded value for the callback - BasicJsonType discarded = BasicJsonType::value_t::discarded; -}; - -template<typename BasicJsonType> -class json_sax_acceptor -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - bool null() - { - return true; - } - - bool boolean(bool /*unused*/) - { - return true; - } - - bool number_integer(number_integer_t /*unused*/) - { - return true; - } - - bool number_unsigned(number_unsigned_t /*unused*/) - { - return true; - } - - bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) - { - return true; - } - - bool string(string_t& /*unused*/) - { - return true; - } - - bool binary(binary_t& /*unused*/) - { - return true; - } - - bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) - { - return true; - } - - bool key(string_t& /*unused*/) - { - return true; - } - - bool end_object() - { - return true; - } - - bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) - { - return true; - } - - bool end_array() - { - return true; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) - { - return false; - } -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/input/lexer.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <array> // array -#include <clocale> // localeconv -#include <cstddef> // size_t -#include <cstdio> // snprintf -#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull -#include <initializer_list> // initializer_list -#include <string> // char_traits, string -#include <utility> // move -#include <vector> // vector - -// #include <nlohmann/detail/input/input_adapters.hpp> - -// #include <nlohmann/detail/input/position_t.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/////////// -// lexer // -/////////// - -template<typename BasicJsonType> -class lexer_base -{ - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - JSON_HEDLEY_RETURNS_NON_NULL - JSON_HEDLEY_CONST - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return "<uninitialized>"; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case token_type::value_unsigned: - case token_type::value_integer: - case token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return "<parse error>"; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - // LCOV_EXCL_START - default: // catch non-enum values - return "unknown token"; - // LCOV_EXCL_STOP - } - } -}; -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template<typename BasicJsonType, typename InputAdapterType> -class lexer : public lexer_base<BasicJsonType> -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using char_type = typename InputAdapterType::char_type; - using char_int_type = typename char_traits<char_type>::int_type; - - public: - using token_type = typename lexer_base<BasicJsonType>::token_type; - - explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept - : ia(std::move(adapter)) - , ignore_comments(ignore_comments_) - , decimal_point_char(static_cast<char_int_type>(get_decimal_point())) - {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - lexer& operator=(lexer&) = delete; - lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~lexer() = default; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - JSON_HEDLEY_PURE - static char get_decimal_point() noexcept - { - const auto* loc = localeconv(); - JSON_ASSERT(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - JSON_ASSERT(current == 'u'); - int codepoint = 0; - - const auto factors = { 12u, 8u, 4u, 0u }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' && current <= '9') - { - codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor); - } - else if (current >= 'A' && current <= 'F') - { - codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor); - } - else if (current >= 'a' && current <= 'f') - { - codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor); - } - else - { - return -1; - } - } - - JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list<char_int_type> ranges) - { - JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 8259. While - scanning, bytes are escaped and copied into buffer token_buffer. Then the - function returns successfully, token_buffer is *not* null-terminated (as it - may contain \0 bytes), and token_buffer.size() is the number of bytes in the - string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset token_buffer (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - JSON_ASSERT(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case char_traits<char_type>::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = static_cast<int>( - // high surrogate occupies the most significant 22 bits - (static_cast<unsigned int>(codepoint1) << 10u) - // low surrogate occupies the least significant 15 bits - + static_cast<unsigned int>(codepoint2) - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result, so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00u); - } - else - { - error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(static_cast<char_int_type>(codepoint)); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u))); - add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u))); - add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu))); - add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u))); - add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu))); - add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu))); - add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu))); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - { - error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; - return token_type::parse_error; - } - - case 0x01: - { - error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; - return token_type::parse_error; - } - - case 0x02: - { - error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; - return token_type::parse_error; - } - - case 0x03: - { - error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; - return token_type::parse_error; - } - - case 0x04: - { - error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; - return token_type::parse_error; - } - - case 0x05: - { - error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; - return token_type::parse_error; - } - - case 0x06: - { - error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; - return token_type::parse_error; - } - - case 0x07: - { - error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; - return token_type::parse_error; - } - - case 0x08: - { - error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; - return token_type::parse_error; - } - - case 0x09: - { - error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; - return token_type::parse_error; - } - - case 0x0A: - { - error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; - return token_type::parse_error; - } - - case 0x0B: - { - error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; - return token_type::parse_error; - } - - case 0x0C: - { - error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; - return token_type::parse_error; - } - - case 0x0D: - { - error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; - return token_type::parse_error; - } - - case 0x0E: - { - error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; - return token_type::parse_error; - } - - case 0x0F: - { - error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; - return token_type::parse_error; - } - - case 0x10: - { - error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; - return token_type::parse_error; - } - - case 0x11: - { - error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; - return token_type::parse_error; - } - - case 0x12: - { - error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; - return token_type::parse_error; - } - - case 0x13: - { - error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; - return token_type::parse_error; - } - - case 0x14: - { - error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; - return token_type::parse_error; - } - - case 0x15: - { - error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; - return token_type::parse_error; - } - - case 0x16: - { - error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; - return token_type::parse_error; - } - - case 0x17: - { - error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; - return token_type::parse_error; - } - - case 0x18: - { - error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; - return token_type::parse_error; - } - - case 0x19: - { - error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; - return token_type::parse_error; - } - - case 0x1A: - { - error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; - return token_type::parse_error; - } - - case 0x1B: - { - error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; - return token_type::parse_error; - } - - case 0x1C: - { - error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; - return token_type::parse_error; - } - - case 0x1D: - { - error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; - return token_type::parse_error; - } - - case 0x1E: - { - error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; - return token_type::parse_error; - } - - case 0x1F: - { - error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - /*! - * @brief scan a comment - * @return whether comment could be scanned successfully - */ - bool scan_comment() - { - switch (get()) - { - // single-line comments skip input until a newline or EOF is read - case '/': - { - while (true) - { - switch (get()) - { - case '\n': - case '\r': - case char_traits<char_type>::eof(): - case '\0': - return true; - - default: - break; - } - } - } - - // multi-line comments skip input until */ is read - case '*': - { - while (true) - { - switch (get()) - { - case char_traits<char_type>::eof(): - case '\0': - { - error_message = "invalid comment; missing closing '*/'"; - return false; - } - - case '*': - { - switch (get()) - { - case '/': - return true; - - default: - { - unget(); - continue; - } - } - } - - default: - continue; - } - } - } - - // unexpected character after reading '/' - default: - { - error_message = "invalid comment; expecting '/' or '*' after '/'"; - return false; - } - } - } - - JSON_HEDLEY_NON_NULL(2) - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - JSON_HEDLEY_NON_NULL(2) - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - JSON_HEDLEY_NON_NULL(2) - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 8259. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 8259. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in token_buffer. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() // lgtm [cpp/use-of-goto] - { - // reset token_buffer to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - // all other characters are rejected outside scan_number() - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(token_buffer.data(), &endptr, 10); - - // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_unsigned = static_cast<number_unsigned_t>(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(token_buffer.data(), &endptr, 10); - - // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_integer = static_cast<number_integer_t>(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, token_buffer.data(), &endptr); - - // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - JSON_HEDLEY_NON_NULL(2) - token_type scan_literal(const char_type* literal_text, const std::size_t length, - token_type return_type) - { - JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_HEDLEY_UNLIKELY(char_traits<char_type>::to_char_type(get()) != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset token_buffer; current character is beginning of token - void reset() noexcept - { - token_buffer.clear(); - token_string.clear(); - token_string.push_back(char_traits<char_type>::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `char_traits<char>::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - char_int_type get() - { - ++position.chars_read_total; - ++position.chars_read_current_line; - - if (next_unget) - { - // just reset the next_unget variable and work with current - next_unget = false; - } - else - { - current = ia.get_character(); - } - - if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof())) - { - token_string.push_back(char_traits<char_type>::to_char_type(current)); - } - - if (current == '\n') - { - ++position.lines_read; - position.chars_read_current_line = 0; - } - - return current; - } - - /*! - @brief unget current character (read it again on next get) - - We implement unget by setting variable next_unget to true. The input is not - changed - we just simulate ungetting by modifying chars_read_total, - chars_read_current_line, and token_string. The next call to get() will - behave as if the unget character is read again. - */ - void unget() - { - next_unget = true; - - --position.chars_read_total; - - // in case we "unget" a newline, we have to also decrement the lines_read - if (position.chars_read_current_line == 0) - { - if (position.lines_read > 0) - { - --position.lines_read; - } - } - else - { - --position.chars_read_current_line; - } - - if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof())) - { - JSON_ASSERT(!token_string.empty()); - token_string.pop_back(); - } - } - - /// add a character to token_buffer - void add(char_int_type c) - { - token_buffer.push_back(static_cast<typename string_t::value_type>(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - string_t& get_string() - { - return token_buffer; - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr position_t get_position() const noexcept - { - return position; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if (static_cast<unsigned char>(c) <= '\x1F') - { - // escape control characters - std::array<char, 9> cs{{}}; - static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - result += cs.data(); - } - else - { - // add character as is - result.push_back(static_cast<std::string::value_type>(c)); - } - } - - return result; - } - - /// return syntax error message - JSON_HEDLEY_RETURNS_NON_NULL - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - /*! - @brief skip the UTF-8 byte order mark - @return true iff there is no BOM or the correct BOM has been skipped - */ - bool skip_bom() - { - if (get() == 0xEF) - { - // check if we completely parse the BOM - return get() == 0xBB && get() == 0xBF; - } - - // the first character is not the beginning of the BOM; unget it to - // process is later - unget(); - return true; - } - - void skip_whitespace() - { - do - { - get(); - } - while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); - } - - token_type scan() - { - // initially, skip the BOM - if (position.chars_read_total == 0 && !skip_bom()) - { - error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; - return token_type::parse_error; - } - - // read next character and ignore whitespace - skip_whitespace(); - - // ignore comments - while (ignore_comments && current == '/') - { - if (!scan_comment()) - { - return token_type::parse_error; - } - - // skip following whitespace - skip_whitespace(); - } - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - { - std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}}; - return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); - } - case 'f': - { - std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}}; - return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); - } - case 'n': - { - std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}}; - return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); - } - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case char_traits<char_type>::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - InputAdapterType ia; - - /// whether comments should be ignored (true) or signaled as errors (false) - const bool ignore_comments = false; - - /// the current character - char_int_type current = char_traits<char_type>::eof(); - - /// whether the next get() call should just return current - bool next_unget = false; - - /// the start position of the current token - position_t position {}; - - /// raw input token string (for error messages) - std::vector<char_type> token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - string_t token_buffer {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char_int_type decimal_point_char = '.'; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/is_sax.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstdint> // size_t -#include <utility> // declval -#include <string> // string - -// #include <nlohmann/detail/abi_macros.hpp> - -// #include <nlohmann/detail/meta/detected.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename T> -using null_function_t = decltype(std::declval<T&>().null()); - -template<typename T> -using boolean_function_t = - decltype(std::declval<T&>().boolean(std::declval<bool>())); - -template<typename T, typename Integer> -using number_integer_function_t = - decltype(std::declval<T&>().number_integer(std::declval<Integer>())); - -template<typename T, typename Unsigned> -using number_unsigned_function_t = - decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>())); - -template<typename T, typename Float, typename String> -using number_float_function_t = decltype(std::declval<T&>().number_float( - std::declval<Float>(), std::declval<const String&>())); - -template<typename T, typename String> -using string_function_t = - decltype(std::declval<T&>().string(std::declval<String&>())); - -template<typename T, typename Binary> -using binary_function_t = - decltype(std::declval<T&>().binary(std::declval<Binary&>())); - -template<typename T> -using start_object_function_t = - decltype(std::declval<T&>().start_object(std::declval<std::size_t>())); - -template<typename T, typename String> -using key_function_t = - decltype(std::declval<T&>().key(std::declval<String&>())); - -template<typename T> -using end_object_function_t = decltype(std::declval<T&>().end_object()); - -template<typename T> -using start_array_function_t = - decltype(std::declval<T&>().start_array(std::declval<std::size_t>())); - -template<typename T> -using end_array_function_t = decltype(std::declval<T&>().end_array()); - -template<typename T, typename Exception> -using parse_error_function_t = decltype(std::declval<T&>().parse_error( - std::declval<std::size_t>(), std::declval<const std::string&>(), - std::declval<const Exception&>())); - -template<typename SAX, typename BasicJsonType> -struct is_sax -{ - private: - static_assert(is_basic_json<BasicJsonType>::value, - "BasicJsonType must be of type basic_json<...>"); - - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using exception_t = typename BasicJsonType::exception; - - public: - static constexpr bool value = - is_detected_exact<bool, null_function_t, SAX>::value && - is_detected_exact<bool, boolean_function_t, SAX>::value && - is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value && - is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value && - is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value && - is_detected_exact<bool, string_function_t, SAX, string_t>::value && - is_detected_exact<bool, binary_function_t, SAX, binary_t>::value && - is_detected_exact<bool, start_object_function_t, SAX>::value && - is_detected_exact<bool, key_function_t, SAX, string_t>::value && - is_detected_exact<bool, end_object_function_t, SAX>::value && - is_detected_exact<bool, start_array_function_t, SAX>::value && - is_detected_exact<bool, end_array_function_t, SAX>::value && - is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value; -}; - -template<typename SAX, typename BasicJsonType> -struct is_sax_static_asserts -{ - private: - static_assert(is_basic_json<BasicJsonType>::value, - "BasicJsonType must be of type basic_json<...>"); - - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using exception_t = typename BasicJsonType::exception; - - public: - static_assert(is_detected_exact<bool, null_function_t, SAX>::value, - "Missing/invalid function: bool null()"); - static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, - "Missing/invalid function: bool boolean(bool)"); - static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, - "Missing/invalid function: bool boolean(bool)"); - static_assert( - is_detected_exact<bool, number_integer_function_t, SAX, - number_integer_t>::value, - "Missing/invalid function: bool number_integer(number_integer_t)"); - static_assert( - is_detected_exact<bool, number_unsigned_function_t, SAX, - number_unsigned_t>::value, - "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); - static_assert(is_detected_exact<bool, number_float_function_t, SAX, - number_float_t, string_t>::value, - "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); - static_assert( - is_detected_exact<bool, string_function_t, SAX, string_t>::value, - "Missing/invalid function: bool string(string_t&)"); - static_assert( - is_detected_exact<bool, binary_function_t, SAX, binary_t>::value, - "Missing/invalid function: bool binary(binary_t&)"); - static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value, - "Missing/invalid function: bool start_object(std::size_t)"); - static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value, - "Missing/invalid function: bool key(string_t&)"); - static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value, - "Missing/invalid function: bool end_object()"); - static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value, - "Missing/invalid function: bool start_array(std::size_t)"); - static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value, - "Missing/invalid function: bool end_array()"); - static_assert( - is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value, - "Missing/invalid function: bool parse_error(std::size_t, const " - "std::string&, const exception&)"); -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/meta/type_traits.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/// how to treat CBOR tags -enum class cbor_tag_handler_t -{ - error, ///< throw a parse_error exception in case of a tag - ignore, ///< ignore tags - store ///< store tags as binary type -}; - -/*! -@brief determine system byte order - -@return true if and only if system's byte order is little endian - -@note from https://stackoverflow.com/a/1001328/266378 -*/ -static inline bool little_endianness(int num = 1) noexcept -{ - return *reinterpret_cast<char*>(&num) == 1; -} - -/////////////////// -// binary reader // -/////////////////// - -/*! -@brief deserialization of CBOR, MessagePack, and UBJSON values -*/ -template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>> -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using json_sax_t = SAX; - using char_type = typename InputAdapterType::char_type; - using char_int_type = typename char_traits<char_type>::int_type; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format) - { - (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; - } - - // make class move-only - binary_reader(const binary_reader&) = delete; - binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - binary_reader& operator=(const binary_reader&) = delete; - binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~binary_reader() = default; - - /*! - @param[in] format the binary format to parse - @param[in] sax_ a SAX event processor - @param[in] strict whether to expect the input to be consumed completed - @param[in] tag_handler how to treat CBOR tags - - @return whether parsing was successful - */ - JSON_HEDLEY_NON_NULL(3) - bool sax_parse(const input_format_t format, - json_sax_t* sax_, - const bool strict = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - sax = sax_; - bool result = false; - - switch (format) - { - case input_format_t::bson: - result = parse_bson_internal(); - break; - - case input_format_t::cbor: - result = parse_cbor_internal(true, tag_handler); - break; - - case input_format_t::msgpack: - result = parse_msgpack_internal(); - break; - - case input_format_t::ubjson: - case input_format_t::bjdata: - result = parse_ubjson_internal(); - break; - - case input_format_t::json: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - - // strict mode: next byte must be EOF - if (result && strict) - { - if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata) - { - get_ignore_noop(); - } - else - { - get(); - } - - if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof())) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, - exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr)); - } - } - - return result; - } - - private: - ////////// - // BSON // - ////////// - - /*! - @brief Reads in a BSON-object and passes it to the SAX-parser. - @return whether a valid BSON-value was passed to the SAX parser - */ - bool parse_bson_internal() - { - std::int32_t document_size{}; - get_number<std::int32_t, true>(input_format_t::bson, document_size); - - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) - { - return false; - } - - return sax->end_object(); - } - - /*! - @brief Parses a C-style string from the BSON input. - @param[in,out] result A reference to the string variable where the read - string is to be stored. - @return `true` if the \x00-byte indicating the end of the string was - encountered before the EOF; false` indicates an unexpected EOF. - */ - bool get_bson_cstr(string_t& result) - { - auto out = std::back_inserter(result); - while (true) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) - { - return false; - } - if (current == 0x00) - { - return true; - } - *out++ = static_cast<typename string_t::value_type>(current); - } - } - - /*! - @brief Parses a zero-terminated string of length @a len from the BSON - input. - @param[in] len The length (including the zero-byte at the end) of the - string to be read. - @param[in,out] result A reference to the string variable where the read - string is to be stored. - @tparam NumberType The type of the length @a len - @pre len >= 1 - @return `true` if the string was successfully parsed - */ - template<typename NumberType> - bool get_bson_string(const NumberType len, string_t& result) - { - if (JSON_HEDLEY_UNLIKELY(len < 1)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr)); - } - - return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof(); - } - - /*! - @brief Parses a byte array input of length @a len from the BSON input. - @param[in] len The length of the byte array to be read. - @param[in,out] result A reference to the binary variable where the read - array is to be stored. - @tparam NumberType The type of the length @a len - @pre len >= 0 - @return `true` if the byte array was successfully parsed - */ - template<typename NumberType> - bool get_bson_binary(const NumberType len, binary_t& result) - { - if (JSON_HEDLEY_UNLIKELY(len < 0)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr)); - } - - // All BSON binary values have a subtype - std::uint8_t subtype{}; - get_number<std::uint8_t>(input_format_t::bson, subtype); - result.set_subtype(subtype); - - return get_binary(input_format_t::bson, len, result); - } - - /*! - @brief Read a BSON document element of the given @a element_type. - @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html - @param[in] element_type_parse_position The position in the input stream, - where the `element_type` was read. - @warning Not all BSON element types are supported yet. An unsupported - @a element_type will give rise to a parse_error.114: - Unsupported BSON record type 0x... - @return whether a valid BSON-object/array was passed to the SAX parser - */ - bool parse_bson_element_internal(const char_int_type element_type, - const std::size_t element_type_parse_position) - { - switch (element_type) - { - case 0x01: // double - { - double number{}; - return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - case 0x02: // string - { - std::int32_t len{}; - string_t value; - return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); - } - - case 0x03: // object - { - return parse_bson_internal(); - } - - case 0x04: // array - { - return parse_bson_array(); - } - - case 0x05: // binary - { - std::int32_t len{}; - binary_t value; - return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); - } - - case 0x08: // boolean - { - return sax->boolean(get() != 0); - } - - case 0x0A: // null - { - return sax->null(); - } - - case 0x10: // int32 - { - std::int32_t value{}; - return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value); - } - - case 0x12: // int64 - { - std::int64_t value{}; - return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value); - } - - default: // anything else not supported (yet) - { - std::array<char, 3> cr{{}}; - static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - const std::string cr_str{cr.data()}; - return sax->parse_error(element_type_parse_position, cr_str, - parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); - } - } - } - - /*! - @brief Read a BSON element list (as specified in the BSON-spec) - - The same binary layout is used for objects and arrays, hence it must be - indicated with the argument @a is_array which one is expected - (true --> array, false --> object). - - @param[in] is_array Determines if the element list being read is to be - treated as an object (@a is_array == false), or as an - array (@a is_array == true). - @return whether a valid BSON-object/array was passed to the SAX parser - */ - bool parse_bson_element_list(const bool is_array) - { - string_t key; - - while (auto element_type = get()) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) - { - return false; - } - - const std::size_t element_type_parse_position = chars_read; - if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) - { - return false; - } - - if (!is_array && !sax->key(key)) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) - { - return false; - } - - // get_bson_cstr only appends - key.clear(); - } - - return true; - } - - /*! - @brief Reads an array from the BSON input and passes it to the SAX-parser. - @return whether a valid BSON-array was passed to the SAX parser - */ - bool parse_bson_array() - { - std::int32_t document_size{}; - get_number<std::int32_t, true>(input_format_t::bson, document_size); - - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) - { - return false; - } - - return sax->end_array(); - } - - ////////// - // CBOR // - ////////// - - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true) or whether the last read character should - be considered instead (false) - @param[in] tag_handler how CBOR tags should be treated - - @return whether a valid CBOR value was passed to the SAX parser - */ - bool parse_cbor_internal(const bool get_char, - const cbor_tag_handler_t tag_handler) - { - switch (get_char ? get() : current) - { - // EOF - case char_traits<char_type>::eof(): - return unexpect_eof(input_format_t::cbor, "value"); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return sax->number_unsigned(static_cast<number_unsigned_t>(current)); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - { - std::uint8_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - { - std::uint16_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - { - std::uint32_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - { - std::uint64_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current)); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - std::uint8_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - std::uint16_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - std::uint32_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - std::uint64_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - - static_cast<number_integer_t>(number)); - } - - // Binary data (0x00..0x17 bytes follow) - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: // Binary data (one-byte uint8_t for n follows) - case 0x59: // Binary data (two-byte uint16_t for n follow) - case 0x5A: // Binary data (four-byte uint32_t for n follow) - case 0x5B: // Binary data (eight-byte uint64_t for n follow) - case 0x5F: // Binary data (indefinite length) - { - binary_t b; - return get_cbor_binary(b) && sax->binary(b); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - string_t s; - return get_cbor_string(s) && sax->string(s); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - return get_cbor_array( - conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler); - - case 0x98: // array (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler); - } - - case 0x9F: // array (indefinite length) - return get_cbor_array(static_cast<std::size_t>(-1), tag_handler); - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler); - - case 0xB8: // map (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler); - } - - case 0xBF: // map (indefinite length) - return get_cbor_object(static_cast<std::size_t>(-1), tag_handler); - - case 0xC6: // tagged item - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD8: // tagged item (1 bytes follow) - case 0xD9: // tagged item (2 bytes follow) - case 0xDA: // tagged item (4 bytes follow) - case 0xDB: // tagged item (8 bytes follow) - { - switch (tag_handler) - { - case cbor_tag_handler_t::error: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); - } - - case cbor_tag_handler_t::ignore: - { - // ignore binary subtype - switch (current) - { - case 0xD8: - { - std::uint8_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - case 0xD9: - { - std::uint16_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - case 0xDA: - { - std::uint32_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - case 0xDB: - { - std::uint64_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - default: - break; - } - return parse_cbor_internal(true, tag_handler); - } - - case cbor_tag_handler_t::store: - { - binary_t b; - // use binary subtype and store in binary container - switch (current) - { - case 0xD8: - { - std::uint8_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); - break; - } - case 0xD9: - { - std::uint16_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); - break; - } - case 0xDA: - { - std::uint32_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); - break; - } - case 0xDB: - { - std::uint64_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype)); - break; - } - default: - return parse_cbor_internal(true, tag_handler); - } - get(); - return get_cbor_binary(b) && sax->binary(b); - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return false; // LCOV_EXCL_LINE - } - } - - case 0xF4: // false - return sax->boolean(false); - - case 0xF5: // true - return sax->boolean(true); - - case 0xF6: // null - return sax->null(); - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) - { - return false; - } - const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) - { - return false; - } - - const auto byte1 = static_cast<unsigned char>(byte1_raw); - const auto byte2 = static_cast<unsigned char>(byte2_raw); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2); - const double val = [&half] - { - const int exp = (half >> 10u) & 0x1Fu; - const unsigned int mant = half & 0x3FFu; - JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(mant <= 1024); - switch (exp) - { - case 0: - return std::ldexp(mant, -24); - case 31: - return (mant == 0) - ? std::numeric_limits<double>::infinity() - : std::numeric_limits<double>::quiet_NaN(); - default: - return std::ldexp(mant + 1024, exp - 25); - } - }(); - return sax->number_float((half & 0x8000u) != 0 - ? static_cast<number_float_t>(-val) - : static_cast<number_float_t>(val), ""); - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - float number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - double number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - default: // anything else (0xFF is handled inside the other types) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr)); - } - } - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @param[out] result created string - - @return whether string creation completed - */ - bool get_cbor_string(string_t& result) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) - { - return false; - } - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - while (get() != 0xFF) - { - string_t chunk; - if (!get_cbor_string(chunk)) - { - return false; - } - result.append(chunk); - } - return true; - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr)); - } - } - } - - /*! - @brief reads a CBOR byte array - - This function first reads starting bytes to determine the expected - byte array length and then copies this number of bytes into the byte array. - Additionally, CBOR's byte arrays with indefinite lengths are supported. - - @param[out] result created byte array - - @return whether byte array creation completed - */ - bool get_cbor_binary(binary_t& result) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) - { - return false; - } - - switch (current) - { - // Binary data (0x00..0x17 bytes follow) - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - { - return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result); - } - - case 0x58: // Binary data (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x59: // Binary data (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x5A: // Binary data (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x5B: // Binary data (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x5F: // Binary data (indefinite length) - { - while (get() != 0xFF) - { - binary_t chunk; - if (!get_cbor_binary(chunk)) - { - return false; - } - result.insert(result.end(), chunk.begin(), chunk.end()); - } - return true; - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr)); - } - } - } - - /*! - @param[in] len the length of the array or static_cast<std::size_t>(-1) for an - array of indefinite size - @param[in] tag_handler how CBOR tags should be treated - @return whether array creation completed - */ - bool get_cbor_array(const std::size_t len, - const cbor_tag_handler_t tag_handler) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) - { - return false; - } - - if (len != static_cast<std::size_t>(-1)) - { - for (std::size_t i = 0; i < len; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; - } - } - } - else - { - while (get() != 0xFF) - { - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) - { - return false; - } - } - } - - return sax->end_array(); - } - - /*! - @param[in] len the length of the object or static_cast<std::size_t>(-1) for an - object of indefinite size - @param[in] tag_handler how CBOR tags should be treated - @return whether object creation completed - */ - bool get_cbor_object(const std::size_t len, - const cbor_tag_handler_t tag_handler) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) - { - return false; - } - - if (len != 0) - { - string_t key; - if (len != static_cast<std::size_t>(-1)) - { - for (std::size_t i = 0; i < len; ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; - } - key.clear(); - } - } - else - { - while (get() != 0xFF) - { - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; - } - key.clear(); - } - } - } - - return sax->end_object(); - } - - ///////////// - // MsgPack // - ///////////// - - /*! - @return whether a valid MessagePack value was passed to the SAX parser - */ - bool parse_msgpack_internal() - { - switch (get()) - { - // EOF - case char_traits<char_type>::eof(): - return unexpect_eof(input_format_t::msgpack, "value"); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return sax->number_unsigned(static_cast<number_unsigned_t>(current)); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu)); - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu)); - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - { - string_t s; - return get_msgpack_string(s) && sax->string(s); - } - - case 0xC0: // nil - return sax->null(); - - case 0xC2: // false - return sax->boolean(false); - - case 0xC3: // true - return sax->boolean(true); - - case 0xC4: // bin 8 - case 0xC5: // bin 16 - case 0xC6: // bin 32 - case 0xC7: // ext 8 - case 0xC8: // ext 16 - case 0xC9: // ext 32 - case 0xD4: // fixext 1 - case 0xD5: // fixext 2 - case 0xD6: // fixext 4 - case 0xD7: // fixext 8 - case 0xD8: // fixext 16 - { - binary_t b; - return get_msgpack_binary(b) && sax->binary(b); - } - - case 0xCA: // float 32 - { - float number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - case 0xCB: // float 64 - { - double number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - case 0xCC: // uint 8 - { - std::uint8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xCD: // uint 16 - { - std::uint16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xCE: // uint 32 - { - std::uint32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xCF: // uint 64 - { - std::uint64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xD0: // int 8 - { - std::int8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xD1: // int 16 - { - std::int16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xD2: // int 32 - { - std::int32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xD3: // int 64 - { - std::int64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xDC: // array 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len)); - } - - case 0xDD: // array 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len)); - } - - case 0xDE: // map 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len)); - } - - case 0xDF: // map 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len)); - } - - // negative fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return sax->number_integer(static_cast<std::int8_t>(current)); - - default: // anything else - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr)); - } - } - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @param[out] result created string - - @return whether string creation completed - */ - bool get_msgpack_string(string_t& result) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) - { - return false; - } - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result); - } - - case 0xD9: // str 8 - { - std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); - } - - case 0xDA: // str 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); - } - - case 0xDB: // str 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr)); - } - } - } - - /*! - @brief reads a MessagePack byte array - - This function first reads starting bytes to determine the expected - byte array length and then copies this number of bytes into a byte array. - - @param[out] result created byte array - - @return whether byte array creation completed - */ - bool get_msgpack_binary(binary_t& result) - { - // helper function to set the subtype - auto assign_and_return_true = [&result](std::int8_t subtype) - { - result.set_subtype(static_cast<std::uint8_t>(subtype)); - return true; - }; - - switch (current) - { - case 0xC4: // bin 8 - { - std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); - } - - case 0xC5: // bin 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); - } - - case 0xC6: // bin 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); - } - - case 0xC7: // ext 8 - { - std::uint8_t len{}; - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && - assign_and_return_true(subtype); - } - - case 0xC8: // ext 16 - { - std::uint16_t len{}; - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && - assign_and_return_true(subtype); - } - - case 0xC9: // ext 32 - { - std::uint32_t len{}; - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && - assign_and_return_true(subtype); - } - - case 0xD4: // fixext 1 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 1, result) && - assign_and_return_true(subtype); - } - - case 0xD5: // fixext 2 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 2, result) && - assign_and_return_true(subtype); - } - - case 0xD6: // fixext 4 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 4, result) && - assign_and_return_true(subtype); - } - - case 0xD7: // fixext 8 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 8, result) && - assign_and_return_true(subtype); - } - - case 0xD8: // fixext 16 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 16, result) && - assign_and_return_true(subtype); - } - - default: // LCOV_EXCL_LINE - return false; // LCOV_EXCL_LINE - } - } - - /*! - @param[in] len the length of the array - @return whether array creation completed - */ - bool get_msgpack_array(const std::size_t len) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) - { - return false; - } - - for (std::size_t i = 0; i < len; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) - { - return false; - } - } - - return sax->end_array(); - } - - /*! - @param[in] len the length of the object - @return whether object creation completed - */ - bool get_msgpack_object(const std::size_t len) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) - { - return false; - } - - string_t key; - for (std::size_t i = 0; i < len; ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) - { - return false; - } - key.clear(); - } - - return sax->end_object(); - } - - //////////// - // UBJSON // - //////////// - - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - - @return whether a valid UBJSON value was passed to the SAX parser - */ - bool parse_ubjson_internal(const bool get_char = true) - { - return get_ubjson_value(get_char ? get_ignore_noop() : current); - } - - /*! - @brief reads a UBJSON string - - This function is either called after reading the 'S' byte explicitly - indicating a string, or in case of an object key where the 'S' byte can be - left out. - - @param[out] result created string - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - - @return whether string creation completed - */ - bool get_ubjson_string(string_t& result, const bool get_char = true) - { - if (get_char) - { - get(); // TODO(niels): may we ignore N here? - } - - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) - { - return false; - } - - switch (current) - { - case 'U': - { - std::uint8_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'i': - { - std::int8_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'I': - { - std::int16_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'l': - { - std::int32_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'L': - { - std::int64_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'u': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint16_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'm': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint32_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - case 'M': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint64_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - - default: - break; - } - auto last_token = get_token_string(); - std::string message; - - if (input_format != input_format_t::bjdata) - { - message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token; - } - else - { - message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token; - } - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr)); - } - - /*! - @param[out] dim an integer vector storing the ND array dimensions - @return whether reading ND array size vector is successful - */ - bool get_ubjson_ndarray_size(std::vector<size_t>& dim) - { - std::pair<std::size_t, char_int_type> size_and_type; - size_t dimlen = 0; - bool no_ndarray = true; - - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray))) - { - return false; - } - - if (size_and_type.first != npos) - { - if (size_and_type.second != 0) - { - if (size_and_type.second != 'N') - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second))) - { - return false; - } - dim.push_back(dimlen); - } - } - } - else - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray))) - { - return false; - } - dim.push_back(dimlen); - } - } - } - else - { - while (current != ']') - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current))) - { - return false; - } - dim.push_back(dimlen); - get_ignore_noop(); - } - } - return true; - } - - /*! - @param[out] result determined size - @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector - or ndarray dimension is not allowed; `false` means ndarray - is allowed; for output, `true` means an ndarray is found; - is_ndarray can only return `true` when its initial value - is `false` - @param[in] prefix type marker if already read, otherwise set to 0 - - @return whether size determination completed - */ - bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0) - { - if (prefix == 0) - { - prefix = get_ignore_noop(); - } - - switch (prefix) - { - case 'U': - { - std::uint8_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = static_cast<std::size_t>(number); - return true; - } - - case 'i': - { - std::int8_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - if (number < 0) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); - } - result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char - return true; - } - - case 'I': - { - std::int16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - if (number < 0) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); - } - result = static_cast<std::size_t>(number); - return true; - } - - case 'l': - { - std::int32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - if (number < 0) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); - } - result = static_cast<std::size_t>(number); - return true; - } - - case 'L': - { - std::int64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - if (number < 0) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, - exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr)); - } - if (!value_in_range_of<std::size_t>(number)) - { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "integer value overflow", "size"), nullptr)); - } - result = static_cast<std::size_t>(number); - return true; - } - - case 'u': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = static_cast<std::size_t>(number); - return true; - } - - case 'm': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = conditional_static_cast<std::size_t>(number); - return true; - } - - case 'M': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - if (!value_in_range_of<std::size_t>(number)) - { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, - exception_message(input_format, "integer value overflow", "size"), nullptr)); - } - result = detail::conditional_static_cast<std::size_t>(number); - return true; - } - - case '[': - { - if (input_format != input_format_t::bjdata) - { - break; - } - if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); - } - std::vector<size_t> dim; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) - { - return false; - } - if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector - { - result = dim.at(dim.size() - 1); - return true; - } - if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format - { - for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container - { - if ( i == 0 ) - { - result = 0; - return true; - } - } - - string_t key = "_ArraySize_"; - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size()))) - { - return false; - } - result = 1; - for (auto i : dim) - { - result *= i; - if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type() - { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr)); - } - if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i)))) - { - return false; - } - } - is_ndarray = true; - return sax->end_array(); - } - result = 0; - return true; - } - - default: - break; - } - auto last_token = get_token_string(); - std::string message; - - if (input_format != input_format_t::bjdata) - { - message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token; - } - else - { - message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token; - } - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr)); - } - - /*! - @brief determine the type and size for a container - - In the optimized UBJSON format, a type and a size can be provided to allow - for a more compact representation. - - @param[out] result pair of the size and the type - @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector - - @return whether pair creation completed - */ - bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false) - { - result.first = npos; // size - result.second = 0; // type - bool is_ndarray = false; - - get_ignore_noop(); - - if (current == '$') - { - result.second = get(); // must not ignore 'N', because 'N' maybe the type - if (input_format == input_format_t::bjdata - && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second))) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr)); - } - - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type"))) - { - return false; - } - - get_ignore_noop(); - if (JSON_HEDLEY_UNLIKELY(current != '#')) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value"))) - { - return false; - } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr)); - } - - const bool is_error = get_ubjson_size_value(result.first, is_ndarray); - if (input_format == input_format_t::bjdata && is_ndarray) - { - if (inside_ndarray) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, - exception_message(input_format, "ndarray can not be recursive", "size"), nullptr)); - } - result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters - } - return is_error; - } - - if (current == '#') - { - const bool is_error = get_ubjson_size_value(result.first, is_ndarray); - if (input_format == input_format_t::bjdata && is_ndarray) - { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read, - exception_message(input_format, "ndarray requires both type and size", "size"), nullptr)); - } - return is_error; - } - - return true; - } - - /*! - @param prefix the previously read or set type prefix - @return whether value creation completed - */ - bool get_ubjson_value(const char_int_type prefix) - { - switch (prefix) - { - case char_traits<char_type>::eof(): // EOF - return unexpect_eof(input_format, "value"); - - case 'T': // true - return sax->boolean(true); - case 'F': // false - return sax->boolean(false); - - case 'Z': // null - return sax->null(); - - case 'U': - { - std::uint8_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - - case 'i': - { - std::int8_t number{}; - return get_number(input_format, number) && sax->number_integer(number); - } - - case 'I': - { - std::int16_t number{}; - return get_number(input_format, number) && sax->number_integer(number); - } - - case 'l': - { - std::int32_t number{}; - return get_number(input_format, number) && sax->number_integer(number); - } - - case 'L': - { - std::int64_t number{}; - return get_number(input_format, number) && sax->number_integer(number); - } - - case 'u': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint16_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - - case 'm': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint32_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - - case 'M': - { - if (input_format != input_format_t::bjdata) - { - break; - } - std::uint64_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - - case 'h': - { - if (input_format != input_format_t::bjdata) - { - break; - } - const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - - const auto byte1 = static_cast<unsigned char>(byte1_raw); - const auto byte2 = static_cast<unsigned char>(byte2_raw); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1); - const double val = [&half] - { - const int exp = (half >> 10u) & 0x1Fu; - const unsigned int mant = half & 0x3FFu; - JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(mant <= 1024); - switch (exp) - { - case 0: - return std::ldexp(mant, -24); - case 31: - return (mant == 0) - ? std::numeric_limits<double>::infinity() - : std::numeric_limits<double>::quiet_NaN(); - default: - return std::ldexp(mant + 1024, exp - 25); - } - }(); - return sax->number_float((half & 0x8000u) != 0 - ? static_cast<number_float_t>(-val) - : static_cast<number_float_t>(val), ""); - } - - case 'd': - { - float number{}; - return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - case 'D': - { - double number{}; - return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), ""); - } - - case 'H': - { - return get_ubjson_high_precision_number(); - } - - case 'C': // char - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char"))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(current > 127)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr)); - } - string_t s(1, static_cast<typename string_t::value_type>(current)); - return sax->string(s); - } - - case 'S': // string - { - string_t s; - return get_ubjson_string(s) && sax->string(s); - } - - case '[': // array - return get_ubjson_array(); - - case '{': // object - return get_ubjson_object(); - - default: // anything else - break; - } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr)); - } - - /*! - @return whether array creation completed - */ - bool get_ubjson_array() - { - std::pair<std::size_t, char_int_type> size_and_type; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) - { - return false; - } - - // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata): - // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]} - - if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) - { - size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker - auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t) - { - return p.first < t; - }); - string_t key = "_ArrayType_"; - if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr)); - } - - string_t type = it->second; // sax->string() takes a reference - if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type))) - { - return false; - } - - if (size_and_type.second == 'C') - { - size_and_type.second = 'U'; - } - - key = "_ArrayData_"; - if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) )) - { - return false; - } - - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) - { - return false; - } - } - - return (sax->end_array() && sax->end_object()); - } - - if (size_and_type.first != npos) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) - { - return false; - } - - if (size_and_type.second != 0) - { - if (size_and_type.second != 'N') - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) - { - return false; - } - } - } - } - else - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) - { - return false; - } - } - } - } - else - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) - { - return false; - } - - while (current != ']') - { - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) - { - return false; - } - get_ignore_noop(); - } - } - - return sax->end_array(); - } - - /*! - @return whether object creation completed - */ - bool get_ubjson_object() - { - std::pair<std::size_t, char_int_type> size_and_type; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) - { - return false; - } - - // do not accept ND-array size in objects in BJData - if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr)); - } - - string_t key; - if (size_and_type.first != npos) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) - { - return false; - } - - if (size_and_type.second != 0) - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) - { - return false; - } - key.clear(); - } - } - else - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) - { - return false; - } - key.clear(); - } - } - } - else - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) - { - return false; - } - - while (current != '}') - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) - { - return false; - } - get_ignore_noop(); - key.clear(); - } - } - - return sax->end_object(); - } - - // Note, no reader for UBJSON binary types is implemented because they do - // not exist - - bool get_ubjson_high_precision_number() - { - // get size of following number string - std::size_t size{}; - bool no_ndarray = true; - auto res = get_ubjson_size_value(size, no_ndarray); - if (JSON_HEDLEY_UNLIKELY(!res)) - { - return res; - } - - // get number string - std::vector<char> number_vector; - for (std::size_t i = 0; i < size; ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - number_vector.push_back(static_cast<char>(current)); - } - - // parse number string - using ia_type = decltype(detail::input_adapter(number_vector)); - auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false); - const auto result_number = number_lexer.scan(); - const auto number_string = number_lexer.get_token_string(); - const auto result_remainder = number_lexer.scan(); - - using token_type = typename detail::lexer_base<BasicJsonType>::token_type; - - if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) - { - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, - exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); - } - - switch (result_number) - { - case token_type::value_integer: - return sax->number_integer(number_lexer.get_number_integer()); - case token_type::value_unsigned: - return sax->number_unsigned(number_lexer.get_number_unsigned()); - case token_type::value_float: - return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); - case token_type::uninitialized: - case token_type::literal_true: - case token_type::literal_false: - case token_type::literal_null: - case token_type::value_string: - case token_type::begin_array: - case token_type::begin_object: - case token_type::end_array: - case token_type::end_object: - case token_type::name_separator: - case token_type::value_separator: - case token_type::parse_error: - case token_type::end_of_input: - case token_type::literal_or_value: - default: - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, - exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); - } - } - - /////////////////////// - // Utility functions // - /////////////////////// - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `char_traits<char_type>::eof()` in that case. - - @return character read from the input - */ - char_int_type get() - { - ++chars_read; - return current = ia.get_character(); - } - - /*! - @return character read from the input after ignoring all 'N' entries - */ - char_int_type get_ignore_noop() - { - do - { - get(); - } - while (current == 'N'); - - return current; - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) - @param[out] result number of type @a NumberType - - @return whether conversion completed - - @note This function needs to respect the system's endianness, because - bytes in CBOR, MessagePack, and UBJSON are stored in network order - (big endian) and therefore need reordering on little endian systems. - On the other hand, BSON and BJData use little endian and should reorder - on big endian systems. - */ - template<typename NumberType, bool InputIsLittleEndian = false> - bool get_number(const input_format_t format, NumberType& result) - { - // step 1: read input into array with system's byte order - std::array<std::uint8_t, sizeof(NumberType)> vec{}; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) - { - return false; - } - - // reverse byte order prior to conversion if necessary - if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) - { - vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current); - } - else - { - vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return true; - } - - /*! - @brief create a string by reading characters from the input - - @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) - @param[in] len number of characters to read - @param[out] result string created by reading @a len bytes - - @return whether string creation completed - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref unexpect_eof() detects the end of - the input before we run out of string memory. - */ - template<typename NumberType> - bool get_string(const input_format_t format, - const NumberType len, - string_t& result) - { - bool success = true; - for (NumberType i = 0; i < len; i++) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) - { - success = false; - break; - } - result.push_back(static_cast<typename string_t::value_type>(current)); - } - return success; - } - - /*! - @brief create a byte array by reading bytes from the input - - @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) - @param[in] len number of bytes to read - @param[out] result byte array created by reading @a len bytes - - @return whether byte array creation completed - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref unexpect_eof() detects the end of - the input before we run out of memory. - */ - template<typename NumberType> - bool get_binary(const input_format_t format, - const NumberType len, - binary_t& result) - { - bool success = true; - for (NumberType i = 0; i < len; i++) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) - { - success = false; - break; - } - result.push_back(static_cast<std::uint8_t>(current)); - } - return success; - } - - /*! - @param[in] format the current format (for diagnostics) - @param[in] context further context information (for diagnostics) - @return whether the last read character is not EOF - */ - JSON_HEDLEY_NON_NULL(3) - bool unexpect_eof(const input_format_t format, const char* context) const - { - if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof())) - { - return sax->parse_error(chars_read, "<end of file>", - parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); - } - return true; - } - - /*! - @return a string representation of the last read byte - */ - std::string get_token_string() const - { - std::array<char, 3> cr{{}}; - static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - return std::string{cr.data()}; - } - - /*! - @param[in] format the current format - @param[in] detail a detailed error message - @param[in] context further context information - @return a message string to use in the parse_error exceptions - */ - std::string exception_message(const input_format_t format, - const std::string& detail, - const std::string& context) const - { - std::string error_msg = "syntax error while parsing "; - - switch (format) - { - case input_format_t::cbor: - error_msg += "CBOR"; - break; - - case input_format_t::msgpack: - error_msg += "MessagePack"; - break; - - case input_format_t::ubjson: - error_msg += "UBJSON"; - break; - - case input_format_t::bson: - error_msg += "BSON"; - break; - - case input_format_t::bjdata: - error_msg += "BJData"; - break; - - case input_format_t::json: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - - return concat(error_msg, ' ', context, ": ", detail); - } - - private: - static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1); - - /// input adapter - InputAdapterType ia; - - /// the current character - char_int_type current = char_traits<char_type>::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianness - const bool is_little_endian = little_endianness(); - - /// input format - const input_format_t input_format = input_format_t::json; - - /// the SAX parser - json_sax_t* sax = nullptr; - - // excluded markers in bjdata optimized type -#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \ - make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{') - -#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ - make_array<bjd_type>( \ - bjd_type{'C', "char"}, \ - bjd_type{'D', "double"}, \ - bjd_type{'I', "int16"}, \ - bjd_type{'L', "int64"}, \ - bjd_type{'M', "uint64"}, \ - bjd_type{'U', "uint8"}, \ - bjd_type{'d', "single"}, \ - bjd_type{'i', "int8"}, \ - bjd_type{'l', "int32"}, \ - bjd_type{'m', "uint32"}, \ - bjd_type{'u', "uint16"}) - - JSON_PRIVATE_UNLESS_TESTED: - // lookup tables - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) - const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers = - JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_; - - using bjd_type = std::pair<char_int_type, string_t>; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) - const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map = - JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_; - -#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ -#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ -}; - -#ifndef JSON_HAS_CPP_17 - template<typename BasicJsonType, typename InputAdapterType, typename SAX> - constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos; -#endif - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/input/input_adapters.hpp> - -// #include <nlohmann/detail/input/lexer.hpp> - -// #include <nlohmann/detail/input/parser.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cmath> // isfinite -#include <cstdint> // uint8_t -#include <functional> // function -#include <string> // string -#include <utility> // move -#include <vector> // vector - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/input/input_adapters.hpp> - -// #include <nlohmann/detail/input/json_sax.hpp> - -// #include <nlohmann/detail/input/lexer.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/is_sax.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ -//////////// -// parser // -//////////// - -enum class parse_event_t : std::uint8_t -{ - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value -}; - -template<typename BasicJsonType> -using parser_callback_t = - std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>; - -/*! -@brief syntax analysis - -This class implements a recursive descent parser. -*/ -template<typename BasicJsonType, typename InputAdapterType> -class parser -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using lexer_t = lexer<BasicJsonType, InputAdapterType>; - using token_type = typename lexer_t::token_type; - - public: - /// a parser reading from an input adapter - explicit parser(InputAdapterType&& adapter, - const parser_callback_t<BasicJsonType> cb = nullptr, - const bool allow_exceptions_ = true, - const bool skip_comments = false) - : callback(cb) - , m_lexer(std::move(adapter), skip_comments) - , allow_exceptions(allow_exceptions_) - { - // read first token - get_token(); - } - - /*! - @brief public parser interface - - @param[in] strict whether to expect the last token to be EOF - @param[in,out] result parsed JSON value - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse(const bool strict, BasicJsonType& result) - { - if (callback) - { - json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions); - sax_parse_internal(&sdp); - - // in strict mode, input must be completely read - if (strict && (get_token() != token_type::end_of_input)) - { - sdp.parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), - exception_message(token_type::end_of_input, "value"), nullptr)); - } - - // in case of an error, return discarded value - if (sdp.is_errored()) - { - result = value_t::discarded; - return; - } - - // set top-level value to null if it was discarded by the callback - // function - if (result.is_discarded()) - { - result = nullptr; - } - } - else - { - json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions); - sax_parse_internal(&sdp); - - // in strict mode, input must be completely read - if (strict && (get_token() != token_type::end_of_input)) - { - sdp.parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); - } - - // in case of an error, return discarded value - if (sdp.is_errored()) - { - result = value_t::discarded; - return; - } - } - - result.assert_invariant(); - } - - /*! - @brief public accept interface - - @param[in] strict whether to expect the last token to be EOF - @return whether the input is a proper JSON text - */ - bool accept(const bool strict = true) - { - json_sax_acceptor<BasicJsonType> sax_acceptor; - return sax_parse(&sax_acceptor, strict); - } - - template<typename SAX> - JSON_HEDLEY_NON_NULL(2) - bool sax_parse(SAX* sax, const bool strict = true) - { - (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; - const bool result = sax_parse_internal(sax); - - // strict mode: next byte must be EOF - if (result && strict && (get_token() != token_type::end_of_input)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); - } - - return result; - } - - private: - template<typename SAX> - JSON_HEDLEY_NON_NULL(2) - bool sax_parse_internal(SAX* sax) - { - // stack to remember the hierarchy of structured values we are parsing - // true = array; false = object - std::vector<bool> states; - // value to avoid a goto (see comment where set to true) - bool skip_to_state_evaluation = false; - - while (true) - { - if (!skip_to_state_evaluation) - { - // invariant: get_token() was called before each iteration - switch (last_token) - { - case token_type::begin_object: - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) - { - return false; - } - - // closing } -> we are done - if (get_token() == token_type::end_object) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) - { - return false; - } - break; - } - - // parse key - if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); - } - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } - - // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); - } - - // remember we are now inside an object - states.push_back(false); - - // parse values - get_token(); - continue; - } - - case token_type::begin_array: - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) - { - return false; - } - - // closing ] -> we are done - if (get_token() == token_type::end_array) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) - { - return false; - } - break; - } - - // remember we are now inside an array - states.push_back(true); - - // parse values (no need to call get_token) - continue; - } - - case token_type::value_float: - { - const auto res = m_lexer.get_number_float(); - - if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); - } - - if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) - { - return false; - } - - break; - } - - case token_type::literal_false: - { - if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) - { - return false; - } - break; - } - - case token_type::literal_null: - { - if (JSON_HEDLEY_UNLIKELY(!sax->null())) - { - return false; - } - break; - } - - case token_type::literal_true: - { - if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) - { - return false; - } - break; - } - - case token_type::value_integer: - { - if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) - { - return false; - } - break; - } - - case token_type::value_string: - { - if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) - { - return false; - } - break; - } - - case token_type::value_unsigned: - { - if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) - { - return false; - } - break; - } - - case token_type::parse_error: - { - // using "uninitialized" to avoid "expected" message - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr)); - } - case token_type::end_of_input: - { - if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), - "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); - } - - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); - } - case token_type::uninitialized: - case token_type::end_array: - case token_type::end_object: - case token_type::name_separator: - case token_type::value_separator: - case token_type::literal_or_value: - default: // the last token was unexpected - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); - } - } - } - else - { - skip_to_state_evaluation = false; - } - - // we reached this line after we successfully parsed a value - if (states.empty()) - { - // empty stack: we reached the end of the hierarchy: done - return true; - } - - if (states.back()) // array - { - // comma -> next value - if (get_token() == token_type::value_separator) - { - // parse a new value - get_token(); - continue; - } - - // closing ] - if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) - { - return false; - } - - // We are done with this array. Before we can parse a - // new value, we need to evaluate the new state first. - // By setting skip_to_state_evaluation to false, we - // are effectively jumping to the beginning of this if. - JSON_ASSERT(!states.empty()); - states.pop_back(); - skip_to_state_evaluation = true; - continue; - } - - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr)); - } - - // states.back() is false -> object - - // comma -> next value - if (get_token() == token_type::value_separator) - { - // parse key - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); - } - - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } - - // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); - } - - // parse values - get_token(); - continue; - } - - // closing } - if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) - { - return false; - } - - // We are done with this object. Before we can parse a - // new value, we need to evaluate the new state first. - // By setting skip_to_state_evaluation to false, we - // are effectively jumping to the beginning of this if. - JSON_ASSERT(!states.empty()); - states.pop_back(); - skip_to_state_evaluation = true; - continue; - } - - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr)); - } - } - - /// get next token from lexer - token_type get_token() - { - return last_token = m_lexer.scan(); - } - - std::string exception_message(const token_type expected, const std::string& context) - { - std::string error_msg = "syntax error "; - - if (!context.empty()) - { - error_msg += concat("while parsing ", context, ' '); - } - - error_msg += "- "; - - if (last_token == token_type::parse_error) - { - error_msg += concat(m_lexer.get_error_message(), "; last read: '", - m_lexer.get_token_string(), '\''); - } - else - { - error_msg += concat("unexpected ", lexer_t::token_type_name(last_token)); - } - - if (expected != token_type::uninitialized) - { - error_msg += concat("; expected ", lexer_t::token_type_name(expected)); - } - - return error_msg; - } - - private: - /// callback function - const parser_callback_t<BasicJsonType> callback = nullptr; - /// the type of the last read token - token_type last_token = token_type::uninitialized; - /// the lexer - lexer_t m_lexer; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/iterators/internal_iterator.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// #include <nlohmann/detail/abi_macros.hpp> - -// #include <nlohmann/detail/iterators/primitive_iterator.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstddef> // ptrdiff_t -#include <limits> // numeric_limits - -// #include <nlohmann/detail/macro_scope.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/* -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - private: - using difference_type = std::ptrdiff_t; - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - JSON_PRIVATE_UNLESS_TESTED: - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)(); - - public: - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type n) noexcept - { - auto result = *this; - result += n; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - primitive_iterator_t& operator++() noexcept - { - ++m_it; - return *this; - } - - primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) - { - auto result = *this; - ++m_it; - return result; - } - - primitive_iterator_t& operator--() noexcept - { - --m_it; - return *this; - } - - primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) - { - auto result = *this; - --m_it; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) noexcept - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) noexcept - { - m_it -= n; - return *this; - } -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/*! -@brief an iterator value - -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template<typename BasicJsonType> struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/iterators/iter_impl.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next -#include <type_traits> // conditional, is_const, remove_const - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/iterators/internal_iterator.hpp> - -// #include <nlohmann/detail/iterators/primitive_iterator.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -// forward declare, to be able to friend it later on -template<typename IteratorType> class iteration_proxy; -template<typename IteratorType> class iteration_proxy_value; - -/*! -@brief a template for a bidirectional iterator for the @ref basic_json class -This class implements a both iterators (iterator and const_iterator) for the -@ref basic_json class. -@note An iterator is called *initialized* when a pointer to a JSON value has - been set (e.g., by a constructor or a copy assignment). If the iterator is - default-constructed, it is *uninitialized* and most methods are undefined. - **The library uses assertions to detect calls on uninitialized iterators.** -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -@since version 1.0.0, simplified in version 2.0.9, change to bidirectional - iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) -*/ -template<typename BasicJsonType> -class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) -{ - /// the iterator with BasicJsonType of different const-ness - using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>; - /// allow basic_json to access private members - friend other_iter_impl; - friend BasicJsonType; - friend iteration_proxy<iter_impl>; - friend iteration_proxy_value<iter_impl>; - - using object_t = typename BasicJsonType::object_t; - using array_t = typename BasicJsonType::array_t; - // make sure BasicJsonType is basic_json or const basic_json - static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value, - "iter_impl only accepts (const) basic_json"); - // superficial check for the LegacyBidirectionalIterator named requirement - static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value - && std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value, - "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); - - public: - /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. - /// The C++ Standard has never required user-defined iterators to derive from std::iterator. - /// A user-defined iterator should provide publicly accessible typedefs named - /// iterator_category, value_type, difference_type, pointer, and reference. - /// Note that value_type is required to be non-const, even for constant iterators. - using iterator_category = std::bidirectional_iterator_tag; - - /// the type of the values when the iterator is dereferenced - using value_type = typename BasicJsonType::value_type; - /// a type to represent differences between iterators - using difference_type = typename BasicJsonType::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional<std::is_const<BasicJsonType>::value, - typename BasicJsonType::const_pointer, - typename BasicJsonType::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = - typename std::conditional<std::is_const<BasicJsonType>::value, - typename BasicJsonType::const_reference, - typename BasicJsonType::reference>::type; - - iter_impl() = default; - ~iter_impl() = default; - iter_impl(iter_impl&&) noexcept = default; - iter_impl& operator=(iter_impl&&) noexcept = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept : m_object(object) - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /*! - @note The conventional copy constructor and copy assignment are implicitly - defined. Combined with the following converting constructor and - assignment, they support: (1) copy from iterator to iterator, (2) - copy from const iterator to const iterator, and (3) conversion from - iterator to const iterator. However conversion from const iterator - to iterator is not defined. - */ - - /*! - @brief const copy constructor - @param[in] other const iterator to copy from - @note This copy constructor had to be defined explicitly to circumvent a bug - occurring on msvc v19.0 compiler (VS 2015) debug build. For more - information refer to: https://github.com/nlohmann/json/issues/1608 - */ - iter_impl(const iter_impl<const BasicJsonType>& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief converting assignment - @param[in] other const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept - { - if (&other != this) - { - m_object = other.m_object; - m_it = other.m_it; - } - return *this; - } - - /*! - @brief converting constructor - @param[in] other non-const iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief converting assignment - @param[in] other non-const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp) - { - m_object = other.m_object; - m_it = other.m_it; - return *this; - } - - JSON_PRIVATE_UNLESS_TESTED: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_data.m_value.object->begin(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_data.m_value.array->begin(); - break; - } - - case value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_data.m_value.object->end(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_data.m_value.array->end(); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); - return m_it.object_iterator->second; - } - - case value_t::array: - { - JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); - return *m_it.array_iterator; - } - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case value_t::array: - { - JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); - return &*m_it.array_iterator; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) - { - return m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr > - bool operator==(const IterImpl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); - } - - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - return (m_it.object_iterator == other.m_it.object_iterator); - - case value_t::array: - return (m_it.array_iterator == other.m_it.array_iterator); - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr > - bool operator!=(const IterImpl& other) const - { - return !operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); - } - - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); - - case value_t::array: - return (m_it.array_iterator < other.m_it.array_iterator); - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return !other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return !operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return !operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); - - case value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief addition of distance and iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - friend iter_impl operator+(difference_type i, const iter_impl& it) - { - auto result = it; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); - - case value_t::array: - return m_it.array_iterator - other.m_it.array_iterator; - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_data.m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); - - case value_t::array: - return *std::next(m_it.array_iterator, n); - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - const typename object_t::key_type& key() const - { - JSON_ASSERT(m_object != nullptr); - - if (JSON_HEDLEY_LIKELY(m_object->is_object())) - { - return m_it.object_iterator->first; - } - - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - JSON_PRIVATE_UNLESS_TESTED: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {}; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/iterators/iteration_proxy.hpp> - -// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <cstddef> // ptrdiff_t -#include <iterator> // reverse_iterator -#include <utility> // declval - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -////////////////////// -// reverse_iterator // -////////////////////// - -/*! -@brief a template for a reverse iterator class - -@tparam Base the base iterator type to reverse. Valid types are @ref -iterator (to create @ref reverse_iterator) and @ref const_iterator (to -create @ref const_reverse_iterator). - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - -@since version 1.0.0 -*/ -template<typename Base> -class json_reverse_iterator : public std::reverse_iterator<Base> -{ - public: - using difference_type = std::ptrdiff_t; - /// shortcut to the reverse iterator adapter - using base_iterator = std::reverse_iterator<Base>; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) {} - - /// create reverse iterator from base class - explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} - - /// post-increment (it++) - json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) - { - return static_cast<json_reverse_iterator>(base_iterator::operator++(1)); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - return static_cast<json_reverse_iterator&>(base_iterator::operator++()); - } - - /// post-decrement (it--) - json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) - { - return static_cast<json_reverse_iterator>(base_iterator::operator--(1)); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - return static_cast<json_reverse_iterator&>(base_iterator::operator--()); - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i)); - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - return static_cast<json_reverse_iterator>(base_iterator::operator+(i)); - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - return static_cast<json_reverse_iterator>(base_iterator::operator-(i)); - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return base_iterator(*this) - base_iterator(other); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - auto key() const -> decltype(std::declval<Base>().key()) - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/iterators/primitive_iterator.hpp> - -// #include <nlohmann/detail/json_custom_base_class.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <type_traits> // conditional, is_same - -// #include <nlohmann/detail/abi_macros.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/*! -@brief Default base class of the @ref basic_json class. - -So that the correct implementations of the copy / move ctors / assign operators -of @ref basic_json do not require complex case distinctions -(no base class / custom base class used as customization point), -@ref basic_json always has a base class. -By default, this class is used because it is empty and thus has no effect -on the behavior of @ref basic_json. -*/ -struct json_default_base {}; - -template<class T> -using json_base_class = typename std::conditional < - std::is_same<T, void>::value, - json_default_base, - T - >::type; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/json_pointer.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // all_of -#include <cctype> // isdigit -#include <cerrno> // errno, ERANGE -#include <cstdlib> // strtoull -#ifndef JSON_NO_IO - #include <iosfwd> // ostream -#endif // JSON_NO_IO -#include <limits> // max -#include <numeric> // accumulate -#include <string> // string -#include <utility> // move -#include <vector> // vector - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - -// #include <nlohmann/detail/string_escape.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document -/// @sa https://json.nlohmann.me/api/json_pointer/ -template<typename RefStringType> -class json_pointer -{ - // allow basic_json to access private members - NLOHMANN_BASIC_JSON_TPL_DECLARATION - friend class basic_json; - - template<typename> - friend class json_pointer; - - template<typename T> - struct string_t_helper - { - using type = T; - }; - - NLOHMANN_BASIC_JSON_TPL_DECLARATION - struct string_t_helper<NLOHMANN_BASIC_JSON_TPL> - { - using type = StringType; - }; - - public: - // for backwards compatibility accept BasicJsonType - using string_t = typename string_t_helper<RefStringType>::type; - - /// @brief create JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ - explicit json_pointer(const string_t& s = "") - : reference_tokens(split(s)) - {} - - /// @brief return a string representation of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ - string_t to_string() const - { - return std::accumulate(reference_tokens.begin(), reference_tokens.end(), - string_t{}, - [](const string_t& a, const string_t& b) - { - return detail::concat(a, '/', detail::escape(b)); - }); - } - - /// @brief return a string representation of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string()) - operator string_t() const - { - return to_string(); - } - -#ifndef JSON_NO_IO - /// @brief write string representation of the JSON pointer to stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ - friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr) - { - o << ptr.to_string(); - return o; - } -#endif - - /// @brief append another JSON pointer at the end of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ - json_pointer& operator/=(const json_pointer& ptr) - { - reference_tokens.insert(reference_tokens.end(), - ptr.reference_tokens.begin(), - ptr.reference_tokens.end()); - return *this; - } - - /// @brief append an unescaped reference token at the end of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ - json_pointer& operator/=(string_t token) - { - push_back(std::move(token)); - return *this; - } - - /// @brief append an array index at the end of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ - json_pointer& operator/=(std::size_t array_idx) - { - return *this /= std::to_string(array_idx); - } - - /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ - friend json_pointer operator/(const json_pointer& lhs, - const json_pointer& rhs) - { - return json_pointer(lhs) /= rhs; - } - - /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ - friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) - { - return json_pointer(lhs) /= std::move(token); - } - - /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ - friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) - { - return json_pointer(lhs) /= array_idx; - } - - /// @brief returns the parent of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ - json_pointer parent_pointer() const - { - if (empty()) - { - return *this; - } - - json_pointer res = *this; - res.pop_back(); - return res; - } - - /// @brief remove last reference token - /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ - void pop_back() - { - if (JSON_HEDLEY_UNLIKELY(empty())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); - } - - reference_tokens.pop_back(); - } - - /// @brief return last reference token - /// @sa https://json.nlohmann.me/api/json_pointer/back/ - const string_t& back() const - { - if (JSON_HEDLEY_UNLIKELY(empty())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); - } - - return reference_tokens.back(); - } - - /// @brief append an unescaped token at the end of the reference pointer - /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ - void push_back(const string_t& token) - { - reference_tokens.push_back(token); - } - - /// @brief append an unescaped token at the end of the reference pointer - /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ - void push_back(string_t&& token) - { - reference_tokens.push_back(std::move(token)); - } - - /// @brief return whether pointer points to the root document - /// @sa https://json.nlohmann.me/api/json_pointer/empty/ - bool empty() const noexcept - { - return reference_tokens.empty(); - } - - private: - /*! - @param[in] s reference token to be converted into an array index - - @return integer representation of @a s - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index begins not with a digit - @throw out_of_range.404 if string @a s could not be converted to an integer - @throw out_of_range.410 if an array index exceeds size_type - */ - template<typename BasicJsonType> - static typename BasicJsonType::size_type array_index(const string_t& s) - { - using size_type = typename BasicJsonType::size_type; - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) - { - JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); - } - - const char* p = s.c_str(); - char* p_end = nullptr; - errno = 0; // strtoull doesn't reset errno - const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) - if (p == p_end // invalid input or empty string - || errno == ERANGE // out of range - || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read - { - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); - } - - // only triggered on special platforms (like 32bit), see also - // https://github.com/nlohmann/json/pull/2203 - if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int) - { - JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE - } - - return static_cast<size_type>(res); - } - - JSON_PRIVATE_UNLESS_TESTED: - json_pointer top() const - { - if (JSON_HEDLEY_UNLIKELY(empty())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); - } - - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } - - private: - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. - - @throw parse_error.109 if array index is not a number - @throw type_error.313 if value cannot be unflattened - */ - template<typename BasicJsonType> - BasicJsonType& get_and_create(BasicJsonType& j) const - { - auto* result = &j; - - // in case no reference tokens exist, return a reference to the JSON value - // j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) - { - switch (result->type()) - { - case detail::value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case detail::value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - // create an entry in the array - result = &result->operator[](array_index<BasicJsonType>(reference_token)); - break; - } - - /* - The following code is only reached if there exists a reference - token _and_ the current value is primitive. In this case, we have - an error situation, because primitive values may only occur as - single value; that is, with an empty list of reference tokens. - */ - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); - } - } - - return *result; - } - - /*! - @brief return a reference to the pointed to value - - @note This version does not throw if a value is not present, but tries to - create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. - - @param[in] ptr a JSON value - - @return reference to the JSON value pointed to by the JSON pointer - - @complexity Linear in the length of the JSON pointer. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - template<typename BasicJsonType> - BasicJsonType& get_unchecked(BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->is_null()) - { - // check if reference token is a number - const bool nums = - std::all_of(reference_token.begin(), reference_token.end(), - [](const unsigned char x) - { - return std::isdigit(x); - }); - - // change value to array for numbers or "-" or to object otherwise - *ptr = (nums || reference_token == "-") - ? detail::value_t::array - : detail::value_t::object; - } - - switch (ptr->type()) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (reference_token == "-") - { - // explicitly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_data.m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token)); - } - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - template<typename BasicJsonType> - BasicJsonType& get_checked(BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, detail::concat( - "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), - ") is out of range"), ptr)); - } - - // note: at performs range check - ptr = &ptr->at(array_index<BasicJsonType>(reference_token)); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); - } - } - - return *ptr; - } - - /*! - @brief return a const reference to the pointed to value - - @param[in] ptr a JSON value - - @return const reference to the JSON value pointed to by the JSON - pointer - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - template<typename BasicJsonType> - const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); - } - - // use unchecked array access - ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token)); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - template<typename BasicJsonType> - const BasicJsonType& get_checked(const BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, detail::concat( - "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), - ") is out of range"), ptr)); - } - - // note: at performs range check - ptr = &ptr->at(array_index<BasicJsonType>(reference_token)); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr)); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - */ - template<typename BasicJsonType> - bool contains(const BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - if (!ptr->contains(reference_token)) - { - // we did not find the key in the object - return false; - } - - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - return false; - } - if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) - { - // invalid char - return false; - } - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) - { - if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) - { - // first char should be between '1' and '9' - return false; - } - for (std::size_t i = 1; i < reference_token.size(); i++) - { - if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) - { - // other char should be between '0' and '9' - return false; - } - } - } - - const auto idx = array_index<BasicJsonType>(reference_token); - if (idx >= ptr->size()) - { - // index out of range - return false; - } - - ptr = &ptr->operator[](idx); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - { - // we do not expect primitive values if there is still a - // reference token to process - return false; - } - } - } - - // no reference token left means we found a primitive value - return true; - } - - /*! - @brief split the string input to reference tokens - - @note This function is only called by the json_pointer constructor. - All exceptions below are documented there. - - @throw parse_error.107 if the pointer is not empty or begins with '/' - @throw parse_error.108 if character '~' is not followed by '0' or '1' - */ - static std::vector<string_t> split(const string_t& reference_string) - { - std::vector<string_t> result; - - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } - - // check if nonempty reference string begins with slash - if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) - { - JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); - } - - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - std::size_t slash = reference_string.find_first_of('/', 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == 0 (if slash == string_t::npos) - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == string_t::npos) - start = (slash == string_t::npos) ? 0 : slash + 1, - // find next slash - slash = reference_string.find_first_of('/', start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (std::size_t pos = reference_token.find_first_of('~'); - pos != string_t::npos; - pos = reference_token.find_first_of('~', pos + 1)) - { - JSON_ASSERT(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || - (reference_token[pos + 1] != '0' && - reference_token[pos + 1] != '1'))) - { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); - } - } - - // finally, store the reference token - detail::unescape(reference_token); - result.push_back(reference_token); - } - - return result; - } - - private: - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - template<typename BasicJsonType> - static void flatten(const string_t& reference_string, - const BasicJsonType& value, - BasicJsonType& result) - { - switch (value.type()) - { - case detail::value_t::array: - { - if (value.m_data.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) - { - flatten(detail::concat(reference_string, '/', std::to_string(i)), - value.m_data.m_value.array->operator[](i), result); - } - } - break; - } - - case detail::value_t::object: - { - if (value.m_data.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_data.m_value.object) - { - flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result); - } - } - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } - } - - /*! - @param[in] value flattened JSON - - @return unflattened JSON - - @throw parse_error.109 if array index is not a number - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - @throw type_error.313 if value cannot be unflattened - */ - template<typename BasicJsonType> - static BasicJsonType - unflatten(const BasicJsonType& value) - { - if (JSON_HEDLEY_UNLIKELY(!value.is_object())) - { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); - } - - BasicJsonType result; - - // iterate the JSON object values - for (const auto& element : *value.m_data.m_value.object) - { - if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) - { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); - } - - // assign value to reference pointed to by JSON pointer; Note that if - // the JSON pointer is "" (i.e., points to the whole value), function - // get_and_create returns a reference to result itself. An assignment - // will then create a primitive value. - json_pointer(element.first).get_and_create(result) = element.second; - } - - return result; - } - - // can't use conversion operator because of ambiguity - json_pointer<string_t> convert() const& - { - json_pointer<string_t> result; - result.reference_tokens = reference_tokens; - return result; - } - - json_pointer<string_t> convert()&& - { - json_pointer<string_t> result; - result.reference_tokens = std::move(reference_tokens); - return result; - } - - public: -#if JSON_HAS_THREE_WAY_COMPARISON - /// @brief compares two JSON pointers for equality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ - template<typename RefStringTypeRhs> - bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept - { - return reference_tokens == rhs.reference_tokens; - } - - /// @brief compares JSON pointer and string for equality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ - JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer)) - bool operator==(const string_t& rhs) const - { - return *this == json_pointer(rhs); - } - - /// @brief 3-way compares two JSON pointers - template<typename RefStringTypeRhs> - std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD* - { - return reference_tokens <=> rhs.reference_tokens; // *NOPAD* - } -#else - /// @brief compares two JSON pointers for equality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ - template<typename RefStringTypeLhs, typename RefStringTypeRhs> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs, - const json_pointer<RefStringTypeRhs>& rhs) noexcept; - - /// @brief compares JSON pointer and string for equality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ - template<typename RefStringTypeLhs, typename StringType> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs, - const StringType& rhs); - - /// @brief compares string and JSON pointer for equality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/ - template<typename RefStringTypeRhs, typename StringType> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator==(const StringType& lhs, - const json_pointer<RefStringTypeRhs>& rhs); - - /// @brief compares two JSON pointers for inequality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ - template<typename RefStringTypeLhs, typename RefStringTypeRhs> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, - const json_pointer<RefStringTypeRhs>& rhs) noexcept; - - /// @brief compares JSON pointer and string for inequality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ - template<typename RefStringTypeLhs, typename StringType> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, - const StringType& rhs); - - /// @brief compares string and JSON pointer for inequality - /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/ - template<typename RefStringTypeRhs, typename StringType> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator!=(const StringType& lhs, - const json_pointer<RefStringTypeRhs>& rhs); - - /// @brief compares two JSON pointer for less-than - template<typename RefStringTypeLhs, typename RefStringTypeRhs> - // NOLINTNEXTLINE(readability-redundant-declaration) - friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs, - const json_pointer<RefStringTypeRhs>& rhs) noexcept; -#endif - - private: - /// the reference tokens - std::vector<string_t> reference_tokens; -}; - -#if !JSON_HAS_THREE_WAY_COMPARISON -// functions cannot be defined inside class due to ODR violations -template<typename RefStringTypeLhs, typename RefStringTypeRhs> -inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, - const json_pointer<RefStringTypeRhs>& rhs) noexcept -{ - return lhs.reference_tokens == rhs.reference_tokens; -} - -template<typename RefStringTypeLhs, - typename StringType = typename json_pointer<RefStringTypeLhs>::string_t> -JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) -inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs, - const StringType& rhs) -{ - return lhs == json_pointer<RefStringTypeLhs>(rhs); -} - -template<typename RefStringTypeRhs, - typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> -JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer)) -inline bool operator==(const StringType& lhs, - const json_pointer<RefStringTypeRhs>& rhs) -{ - return json_pointer<RefStringTypeRhs>(lhs) == rhs; -} - -template<typename RefStringTypeLhs, typename RefStringTypeRhs> -inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, - const json_pointer<RefStringTypeRhs>& rhs) noexcept -{ - return !(lhs == rhs); -} - -template<typename RefStringTypeLhs, - typename StringType = typename json_pointer<RefStringTypeLhs>::string_t> -JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) -inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs, - const StringType& rhs) -{ - return !(lhs == rhs); -} - -template<typename RefStringTypeRhs, - typename StringType = typename json_pointer<RefStringTypeRhs>::string_t> -JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer)) -inline bool operator!=(const StringType& lhs, - const json_pointer<RefStringTypeRhs>& rhs) -{ - return !(lhs == rhs); -} - -template<typename RefStringTypeLhs, typename RefStringTypeRhs> -inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs, - const json_pointer<RefStringTypeRhs>& rhs) noexcept -{ - return lhs.reference_tokens < rhs.reference_tokens; -} -#endif - -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/json_ref.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <initializer_list> -#include <utility> - -// #include <nlohmann/detail/abi_macros.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -template<typename BasicJsonType> -class json_ref -{ - public: - using value_type = BasicJsonType; - - json_ref(value_type&& value) - : owned_value(std::move(value)) - {} - - json_ref(const value_type& value) - : value_ref(&value) - {} - - json_ref(std::initializer_list<json_ref> init) - : owned_value(init) - {} - - template < - class... Args, - enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 > - json_ref(Args && ... args) - : owned_value(std::forward<Args>(args)...) - {} - - // class should be movable only - json_ref(json_ref&&) noexcept = default; - json_ref(const json_ref&) = delete; - json_ref& operator=(const json_ref&) = delete; - json_ref& operator=(json_ref&&) = delete; - ~json_ref() = default; - - value_type moved_or_copied() const - { - if (value_ref == nullptr) - { - return std::move(owned_value); - } - return *value_ref; - } - - value_type const& operator*() const - { - return value_ref ? *value_ref : owned_value; - } - - value_type const* operator->() const - { - return &** this; - } - - private: - mutable value_type owned_value = nullptr; - value_type const* value_ref = nullptr; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - -// #include <nlohmann/detail/string_escape.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - -// #include <nlohmann/detail/output/binary_writer.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // reverse -#include <array> // array -#include <map> // map -#include <cmath> // isnan, isinf -#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t -#include <cstring> // memcpy -#include <limits> // numeric_limits -#include <string> // string -#include <utility> // move -#include <vector> // vector - -// #include <nlohmann/detail/input/binary_reader.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/output/output_adapters.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // copy -#include <cstddef> // size_t -#include <iterator> // back_inserter -#include <memory> // shared_ptr, make_shared -#include <string> // basic_string -#include <vector> // vector - -#ifndef JSON_NO_IO - #include <ios> // streamsize - #include <ostream> // basic_ostream -#endif // JSON_NO_IO - -// #include <nlohmann/detail/macro_scope.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/// abstract output adapter interface -template<typename CharType> struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; - - output_adapter_protocol() = default; - output_adapter_protocol(const output_adapter_protocol&) = default; - output_adapter_protocol(output_adapter_protocol&&) noexcept = default; - output_adapter_protocol& operator=(const output_adapter_protocol&) = default; - output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; -}; - -/// a type to simplify interfaces -template<typename CharType> -using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>; - -/// output adapter for byte vectors -template<typename CharType, typename AllocatorType = std::allocator<CharType>> -class output_vector_adapter : public output_adapter_protocol<CharType> -{ - public: - explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept - : v(vec) - {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - JSON_HEDLEY_NON_NULL(2) - void write_characters(const CharType* s, std::size_t length) override - { - v.insert(v.end(), s, s + length); - } - - private: - std::vector<CharType, AllocatorType>& v; -}; - -#ifndef JSON_NO_IO -/// output adapter for output streams -template<typename CharType> -class output_stream_adapter : public output_adapter_protocol<CharType> -{ - public: - explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept - : stream(s) - {} - - void write_character(CharType c) override - { - stream.put(c); - } - - JSON_HEDLEY_NON_NULL(2) - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast<std::streamsize>(length)); - } - - private: - std::basic_ostream<CharType>& stream; -}; -#endif // JSON_NO_IO - -/// output adapter for basic_string -template<typename CharType, typename StringType = std::basic_string<CharType>> -class output_string_adapter : public output_adapter_protocol<CharType> -{ - public: - explicit output_string_adapter(StringType& s) noexcept - : str(s) - {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - JSON_HEDLEY_NON_NULL(2) - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - StringType& str; -}; - -template<typename CharType, typename StringType = std::basic_string<CharType>> -class output_adapter -{ - public: - template<typename AllocatorType = std::allocator<CharType>> - output_adapter(std::vector<CharType, AllocatorType>& vec) - : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {} - -#ifndef JSON_NO_IO - output_adapter(std::basic_ostream<CharType>& s) - : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {} -#endif // JSON_NO_IO - - output_adapter(StringType& s) - : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {} - - operator output_adapter_t<CharType>() - { - return oa; - } - - private: - output_adapter_t<CharType> oa = nullptr; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/string_concat.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/////////////////// -// binary writer // -/////////////////// - -/*! -@brief serialization to CBOR and MessagePack values -*/ -template<typename BasicJsonType, typename CharType> -class binary_writer -{ - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using number_float_t = typename BasicJsonType::number_float_t; - - public: - /*! - @brief create a binary writer - - @param[in] adapter output adapter to write to - */ - explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter)) - { - JSON_ASSERT(oa); - } - - /*! - @param[in] j JSON value to serialize - @pre j.type() == value_t::object - */ - void write_bson(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::object: - { - write_bson_object(*j.m_data.m_value.object); - break; - } - - case value_t::null: - case value_t::array: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); - } - } - } - - /*! - @param[in] j JSON value to serialize - */ - void write_cbor(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: - { - oa->write_character(to_char_type(0xF6)); - break; - } - - case value_t::boolean: - { - oa->write_character(j.m_data.m_value.boolean - ? to_char_type(0xF5) - : to_char_type(0xF4)); - break; - } - - case value_t::number_integer: - { - if (j.m_data.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_data.m_value.number_integer <= 0x17) - { - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0x18)); - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0x19)); - write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0x1A)); - write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer)); - } - else - { - oa->write_character(to_char_type(0x1B)); - write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer)); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_data.m_value.number_integer; - if (j.m_data.m_value.number_integer >= -24) - { - write_number(static_cast<std::uint8_t>(0x20 + positive_number)); - } - else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0x38)); - write_number(static_cast<std::uint8_t>(positive_number)); - } - else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0x39)); - write_number(static_cast<std::uint16_t>(positive_number)); - } - else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0x3A)); - write_number(static_cast<std::uint32_t>(positive_number)); - } - else - { - oa->write_character(to_char_type(0x3B)); - write_number(static_cast<std::uint64_t>(positive_number)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_data.m_value.number_unsigned <= 0x17) - { - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0x18)); - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0x19)); - write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0x1A)); - write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned)); - } - else - { - oa->write_character(to_char_type(0x1B)); - write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned)); - } - break; - } - - case value_t::number_float: - { - if (std::isnan(j.m_data.m_value.number_float)) - { - // NaN is 0xf97e00 in CBOR - oa->write_character(to_char_type(0xF9)); - oa->write_character(to_char_type(0x7E)); - oa->write_character(to_char_type(0x00)); - } - else if (std::isinf(j.m_data.m_value.number_float)) - { - // Infinity is 0xf97c00, -Infinity is 0xf9fc00 - oa->write_character(to_char_type(0xf9)); - oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); - oa->write_character(to_char_type(0x00)); - } - else - { - write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor); - } - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_data.m_value.string->size(); - if (N <= 0x17) - { - write_number(static_cast<std::uint8_t>(0x60 + N)); - } - else if (N <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0x78)); - write_number(static_cast<std::uint8_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0x79)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0x7A)); - write_number(static_cast<std::uint32_t>(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits<std::uint64_t>::max)()) - { - oa->write_character(to_char_type(0x7B)); - write_number(static_cast<std::uint64_t>(N)); - } - // LCOV_EXCL_STOP - - // step 2: write the string - oa->write_characters( - reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()), - j.m_data.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_data.m_value.array->size(); - if (N <= 0x17) - { - write_number(static_cast<std::uint8_t>(0x80 + N)); - } - else if (N <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0x98)); - write_number(static_cast<std::uint8_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0x99)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0x9A)); - write_number(static_cast<std::uint32_t>(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits<std::uint64_t>::max)()) - { - oa->write_character(to_char_type(0x9B)); - write_number(static_cast<std::uint64_t>(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_data.m_value.array) - { - write_cbor(el); - } - break; - } - - case value_t::binary: - { - if (j.m_data.m_value.binary->has_subtype()) - { - if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)()) - { - write_number(static_cast<std::uint8_t>(0xd8)); - write_number(static_cast<std::uint8_t>(j.m_data.m_value.binary->subtype())); - } - else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)()) - { - write_number(static_cast<std::uint8_t>(0xd9)); - write_number(static_cast<std::uint16_t>(j.m_data.m_value.binary->subtype())); - } - else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)()) - { - write_number(static_cast<std::uint8_t>(0xda)); - write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype())); - } - else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)()) - { - write_number(static_cast<std::uint8_t>(0xdb)); - write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype())); - } - } - - // step 1: write control byte and the binary array size - const auto N = j.m_data.m_value.binary->size(); - if (N <= 0x17) - { - write_number(static_cast<std::uint8_t>(0x40 + N)); - } - else if (N <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0x58)); - write_number(static_cast<std::uint8_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0x59)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0x5A)); - write_number(static_cast<std::uint32_t>(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits<std::uint64_t>::max)()) - { - oa->write_character(to_char_type(0x5B)); - write_number(static_cast<std::uint64_t>(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - oa->write_characters( - reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()), - N); - - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_data.m_value.object->size(); - if (N <= 0x17) - { - write_number(static_cast<std::uint8_t>(0xA0 + N)); - } - else if (N <= (std::numeric_limits<std::uint8_t>::max)()) - { - oa->write_character(to_char_type(0xB8)); - write_number(static_cast<std::uint8_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - oa->write_character(to_char_type(0xB9)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - oa->write_character(to_char_type(0xBA)); - write_number(static_cast<std::uint32_t>(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits<std::uint64_t>::max)()) - { - oa->write_character(to_char_type(0xBB)); - write_number(static_cast<std::uint64_t>(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_data.m_value.object) - { - write_cbor(el.first); - write_cbor(el.second); - } - break; - } - - case value_t::discarded: - default: - break; - } - } - - /*! - @param[in] j JSON value to serialize - */ - void write_msgpack(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: // nil - { - oa->write_character(to_char_type(0xC0)); - break; - } - - case value_t::boolean: // true and false - { - oa->write_character(j.m_data.m_value.boolean - ? to_char_type(0xC3) - : to_char_type(0xC2)); - break; - } - - case value_t::number_integer: - { - if (j.m_data.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we used - // the code from the value_t::number_unsigned case here. - if (j.m_data.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) - { - // uint 8 - oa->write_character(to_char_type(0xCC)); - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) - { - // uint 16 - oa->write_character(to_char_type(0xCD)); - write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) - { - // uint 32 - oa->write_character(to_char_type(0xCE)); - write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) - { - // uint 64 - oa->write_character(to_char_type(0xCF)); - write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer)); - } - } - else - { - if (j.m_data.m_value.number_integer >= -32) - { - // negative fixnum - write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() && - j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) - { - // int 8 - oa->write_character(to_char_type(0xD0)); - write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() && - j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) - { - // int 16 - oa->write_character(to_char_type(0xD1)); - write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() && - j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) - { - // int 32 - oa->write_character(to_char_type(0xD2)); - write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() && - j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) - { - // int 64 - oa->write_character(to_char_type(0xD3)); - write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_data.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)()) - { - // uint 8 - oa->write_character(to_char_type(0xCC)); - write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)()) - { - // uint 16 - oa->write_character(to_char_type(0xCD)); - write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)()) - { - // uint 32 - oa->write_character(to_char_type(0xCE)); - write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer)); - } - else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) - { - // uint 64 - oa->write_character(to_char_type(0xCF)); - write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer)); - } - break; - } - - case value_t::number_float: - { - write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_data.m_value.string->size(); - if (N <= 31) - { - // fixstr - write_number(static_cast<std::uint8_t>(0xA0 | N)); - } - else if (N <= (std::numeric_limits<std::uint8_t>::max)()) - { - // str 8 - oa->write_character(to_char_type(0xD9)); - write_number(static_cast<std::uint8_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - // str 16 - oa->write_character(to_char_type(0xDA)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - // str 32 - oa->write_character(to_char_type(0xDB)); - write_number(static_cast<std::uint32_t>(N)); - } - - // step 2: write the string - oa->write_characters( - reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()), - j.m_data.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_data.m_value.array->size(); - if (N <= 15) - { - // fixarray - write_number(static_cast<std::uint8_t>(0x90 | N)); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - // array 16 - oa->write_character(to_char_type(0xDC)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - // array 32 - oa->write_character(to_char_type(0xDD)); - write_number(static_cast<std::uint32_t>(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_data.m_value.array) - { - write_msgpack(el); - } - break; - } - - case value_t::binary: - { - // step 0: determine if the binary type has a set subtype to - // determine whether or not to use the ext or fixext types - const bool use_ext = j.m_data.m_value.binary->has_subtype(); - - // step 1: write control byte and the byte string length - const auto N = j.m_data.m_value.binary->size(); - if (N <= (std::numeric_limits<std::uint8_t>::max)()) - { - std::uint8_t output_type{}; - bool fixed = true; - if (use_ext) - { - switch (N) - { - case 1: - output_type = 0xD4; // fixext 1 - break; - case 2: - output_type = 0xD5; // fixext 2 - break; - case 4: - output_type = 0xD6; // fixext 4 - break; - case 8: - output_type = 0xD7; // fixext 8 - break; - case 16: - output_type = 0xD8; // fixext 16 - break; - default: - output_type = 0xC7; // ext 8 - fixed = false; - break; - } - - } - else - { - output_type = 0xC4; // bin 8 - fixed = false; - } - - oa->write_character(to_char_type(output_type)); - if (!fixed) - { - write_number(static_cast<std::uint8_t>(N)); - } - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - const std::uint8_t output_type = use_ext - ? 0xC8 // ext 16 - : 0xC5; // bin 16 - - oa->write_character(to_char_type(output_type)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - const std::uint8_t output_type = use_ext - ? 0xC9 // ext 32 - : 0xC6; // bin 32 - - oa->write_character(to_char_type(output_type)); - write_number(static_cast<std::uint32_t>(N)); - } - - // step 1.5: if this is an ext type, write the subtype - if (use_ext) - { - write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype())); - } - - // step 2: write the byte string - oa->write_characters( - reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()), - N); - - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_data.m_value.object->size(); - if (N <= 15) - { - // fixmap - write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF))); - } - else if (N <= (std::numeric_limits<std::uint16_t>::max)()) - { - // map 16 - oa->write_character(to_char_type(0xDE)); - write_number(static_cast<std::uint16_t>(N)); - } - else if (N <= (std::numeric_limits<std::uint32_t>::max)()) - { - // map 32 - oa->write_character(to_char_type(0xDF)); - write_number(static_cast<std::uint32_t>(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_data.m_value.object) - { - write_msgpack(el.first); - write_msgpack(el.second); - } - break; - } - - case value_t::discarded: - default: - break; - } - } - - /*! - @param[in] j JSON value to serialize - @param[in] use_count whether to use '#' prefixes (optimized format) - @param[in] use_type whether to use '$' prefixes (optimized format) - @param[in] add_prefix whether prefixes need to be used for this value - @param[in] use_bjdata whether write in BJData format, default is false - */ - void write_ubjson(const BasicJsonType& j, const bool use_count, - const bool use_type, const bool add_prefix = true, - const bool use_bjdata = false) - { - switch (j.type()) - { - case value_t::null: - { - if (add_prefix) - { - oa->write_character(to_char_type('Z')); - } - break; - } - - case value_t::boolean: - { - if (add_prefix) - { - oa->write_character(j.m_data.m_value.boolean - ? to_char_type('T') - : to_char_type('F')); - } - break; - } - - case value_t::number_integer: - { - write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata); - break; - } - - case value_t::number_unsigned: - { - write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata); - break; - } - - case value_t::number_float: - { - write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata); - break; - } - - case value_t::string: - { - if (add_prefix) - { - oa->write_character(to_char_type('S')); - } - write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata); - oa->write_characters( - reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()), - j.m_data.m_value.string->size()); - break; - } - - case value_t::array: - { - if (add_prefix) - { - oa->write_character(to_char_type('[')); - } - - bool prefix_required = true; - if (use_type && !j.m_data.m_value.array->empty()) - { - JSON_ASSERT(use_count); - const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); - const bool same_prefix = std::all_of(j.begin() + 1, j.end(), - [this, first_prefix, use_bjdata](const BasicJsonType & v) - { - return ubjson_prefix(v, use_bjdata) == first_prefix; - }); - - std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type - - if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) - { - prefix_required = false; - oa->write_character(to_char_type('$')); - oa->write_character(first_prefix); - } - } - - if (use_count) - { - oa->write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata); - } - - for (const auto& el : *j.m_data.m_value.array) - { - write_ubjson(el, use_count, use_type, prefix_required, use_bjdata); - } - - if (!use_count) - { - oa->write_character(to_char_type(']')); - } - - break; - } - - case value_t::binary: - { - if (add_prefix) - { - oa->write_character(to_char_type('[')); - } - - if (use_type && !j.m_data.m_value.binary->empty()) - { - JSON_ASSERT(use_count); - oa->write_character(to_char_type('$')); - oa->write_character('U'); - } - - if (use_count) - { - oa->write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata); - } - - if (use_type) - { - oa->write_characters( - reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()), - j.m_data.m_value.binary->size()); - } - else - { - for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i) - { - oa->write_character(to_char_type('U')); - oa->write_character(j.m_data.m_value.binary->data()[i]); - } - } - - if (!use_count) - { - oa->write_character(to_char_type(']')); - } - - break; - } - - case value_t::object: - { - if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end()) - { - if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata) - { - break; - } - } - - if (add_prefix) - { - oa->write_character(to_char_type('{')); - } - - bool prefix_required = true; - if (use_type && !j.m_data.m_value.object->empty()) - { - JSON_ASSERT(use_count); - const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); - const bool same_prefix = std::all_of(j.begin(), j.end(), - [this, first_prefix, use_bjdata](const BasicJsonType & v) - { - return ubjson_prefix(v, use_bjdata) == first_prefix; - }); - - std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type - - if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) - { - prefix_required = false; - oa->write_character(to_char_type('$')); - oa->write_character(first_prefix); - } - } - - if (use_count) - { - oa->write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata); - } - - for (const auto& el : *j.m_data.m_value.object) - { - write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata); - oa->write_characters( - reinterpret_cast<const CharType*>(el.first.c_str()), - el.first.size()); - write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata); - } - - if (!use_count) - { - oa->write_character(to_char_type('}')); - } - - break; - } - - case value_t::discarded: - default: - break; - } - } - - private: - ////////// - // BSON // - ////////// - - /*! - @return The size of a BSON document entry header, including the id marker - and the entry name size (and its null-terminator). - */ - static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) - { - const auto it = name.find(static_cast<typename string_t::value_type>(0)); - if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) - { - JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); - static_cast<void>(j); - } - - return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; - } - - /*! - @brief Writes the given @a element_type and @a name to the output adapter - */ - void write_bson_entry_header(const string_t& name, - const std::uint8_t element_type) - { - oa->write_character(to_char_type(element_type)); // boolean - oa->write_characters( - reinterpret_cast<const CharType*>(name.c_str()), - name.size() + 1u); - } - - /*! - @brief Writes a BSON element with key @a name and boolean value @a value - */ - void write_bson_boolean(const string_t& name, - const bool value) - { - write_bson_entry_header(name, 0x08); - oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); - } - - /*! - @brief Writes a BSON element with key @a name and double value @a value - */ - void write_bson_double(const string_t& name, - const double value) - { - write_bson_entry_header(name, 0x01); - write_number<double>(value, true); - } - - /*! - @return The size of the BSON-encoded string in @a value - */ - static std::size_t calc_bson_string_size(const string_t& value) - { - return sizeof(std::int32_t) + value.size() + 1ul; - } - - /*! - @brief Writes a BSON element with key @a name and string value @a value - */ - void write_bson_string(const string_t& name, - const string_t& value) - { - write_bson_entry_header(name, 0x02); - - write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true); - oa->write_characters( - reinterpret_cast<const CharType*>(value.c_str()), - value.size() + 1); - } - - /*! - @brief Writes a BSON element with key @a name and null value - */ - void write_bson_null(const string_t& name) - { - write_bson_entry_header(name, 0x0A); - } - - /*! - @return The size of the BSON-encoded integer @a value - */ - static std::size_t calc_bson_integer_size(const std::int64_t value) - { - return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)() - ? sizeof(std::int32_t) - : sizeof(std::int64_t); - } - - /*! - @brief Writes a BSON element with key @a name and integer @a value - */ - void write_bson_integer(const string_t& name, - const std::int64_t value) - { - if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()) - { - write_bson_entry_header(name, 0x10); // int32 - write_number<std::int32_t>(static_cast<std::int32_t>(value), true); - } - else - { - write_bson_entry_header(name, 0x12); // int64 - write_number<std::int64_t>(static_cast<std::int64_t>(value), true); - } - } - - /*! - @return The size of the BSON-encoded unsigned integer in @a j - */ - static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept - { - return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) - ? sizeof(std::int32_t) - : sizeof(std::int64_t); - } - - /*! - @brief Writes a BSON element with key @a name and unsigned @a value - */ - void write_bson_unsigned(const string_t& name, - const BasicJsonType& j) - { - if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) - { - write_bson_entry_header(name, 0x10 /* int32 */); - write_number<std::int32_t>(static_cast<std::int32_t>(j.m_data.m_value.number_unsigned), true); - } - else if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)())) - { - write_bson_entry_header(name, 0x12 /* int64 */); - write_number<std::int64_t>(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned), true); - } - else - { - JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j)); - } - } - - /*! - @brief Writes a BSON element with key @a name and object @a value - */ - void write_bson_object_entry(const string_t& name, - const typename BasicJsonType::object_t& value) - { - write_bson_entry_header(name, 0x03); // object - write_bson_object(value); - } - - /*! - @return The size of the BSON-encoded array @a value - */ - static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) - { - std::size_t array_index = 0ul; - - const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) - { - return result + calc_bson_element_size(std::to_string(array_index++), el); - }); - - return sizeof(std::int32_t) + embedded_document_size + 1ul; - } - - /*! - @return The size of the BSON-encoded binary array @a value - */ - static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) - { - return sizeof(std::int32_t) + value.size() + 1ul; - } - - /*! - @brief Writes a BSON element with key @a name and array @a value - */ - void write_bson_array(const string_t& name, - const typename BasicJsonType::array_t& value) - { - write_bson_entry_header(name, 0x04); // array - write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true); - - std::size_t array_index = 0ul; - - for (const auto& el : value) - { - write_bson_element(std::to_string(array_index++), el); - } - - oa->write_character(to_char_type(0x00)); - } - - /*! - @brief Writes a BSON element with key @a name and binary value @a value - */ - void write_bson_binary(const string_t& name, - const binary_t& value) - { - write_bson_entry_header(name, 0x05); - - write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true); - write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00)); - - oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size()); - } - - /*! - @brief Calculates the size necessary to serialize the JSON value @a j with its @a name - @return The calculated size for the BSON document entry for @a j with the given @a name. - */ - static std::size_t calc_bson_element_size(const string_t& name, - const BasicJsonType& j) - { - const auto header_size = calc_bson_entry_header_size(name, j); - switch (j.type()) - { - case value_t::object: - return header_size + calc_bson_object_size(*j.m_data.m_value.object); - - case value_t::array: - return header_size + calc_bson_array_size(*j.m_data.m_value.array); - - case value_t::binary: - return header_size + calc_bson_binary_size(*j.m_data.m_value.binary); - - case value_t::boolean: - return header_size + 1ul; - - case value_t::number_float: - return header_size + 8ul; - - case value_t::number_integer: - return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer); - - case value_t::number_unsigned: - return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned); - - case value_t::string: - return header_size + calc_bson_string_size(*j.m_data.m_value.string); - - case value_t::null: - return header_size + 0ul; - - // LCOV_EXCL_START - case value_t::discarded: - default: - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) - return 0ul; - // LCOV_EXCL_STOP - } - } - - /*! - @brief Serializes the JSON value @a j to BSON and associates it with the - key @a name. - @param name The name to associate with the JSON entity @a j within the - current BSON document - */ - void write_bson_element(const string_t& name, - const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::object: - return write_bson_object_entry(name, *j.m_data.m_value.object); - - case value_t::array: - return write_bson_array(name, *j.m_data.m_value.array); - - case value_t::binary: - return write_bson_binary(name, *j.m_data.m_value.binary); - - case value_t::boolean: - return write_bson_boolean(name, j.m_data.m_value.boolean); - - case value_t::number_float: - return write_bson_double(name, j.m_data.m_value.number_float); - - case value_t::number_integer: - return write_bson_integer(name, j.m_data.m_value.number_integer); - - case value_t::number_unsigned: - return write_bson_unsigned(name, j); - - case value_t::string: - return write_bson_string(name, *j.m_data.m_value.string); - - case value_t::null: - return write_bson_null(name); - - // LCOV_EXCL_START - case value_t::discarded: - default: - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) - return; - // LCOV_EXCL_STOP - } - } - - /*! - @brief Calculates the size of the BSON serialization of the given - JSON-object @a j. - @param[in] value JSON value to serialize - @pre value.type() == value_t::object - */ - static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) - { - const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0), - [](size_t result, const typename BasicJsonType::object_t::value_type & el) - { - return result += calc_bson_element_size(el.first, el.second); - }); - - return sizeof(std::int32_t) + document_size + 1ul; - } - - /*! - @param[in] value JSON value to serialize - @pre value.type() == value_t::object - */ - void write_bson_object(const typename BasicJsonType::object_t& value) - { - write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true); - - for (const auto& el : value) - { - write_bson_element(el.first, el.second); - } - - oa->write_character(to_char_type(0x00)); - } - - ////////// - // CBOR // - ////////// - - static constexpr CharType get_cbor_float_prefix(float /*unused*/) - { - return to_char_type(0xFA); // Single-Precision Float - } - - static constexpr CharType get_cbor_float_prefix(double /*unused*/) - { - return to_char_type(0xFB); // Double-Precision Float - } - - ///////////// - // MsgPack // - ///////////// - - static constexpr CharType get_msgpack_float_prefix(float /*unused*/) - { - return to_char_type(0xCA); // float 32 - } - - static constexpr CharType get_msgpack_float_prefix(double /*unused*/) - { - return to_char_type(0xCB); // float 64 - } - - //////////// - // UBJSON // - //////////// - - // UBJSON: write number (floating point) - template<typename NumberType, typename std::enable_if< - std::is_floating_point<NumberType>::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix, - const bool use_bjdata) - { - if (add_prefix) - { - oa->write_character(get_ubjson_float_prefix(n)); - } - write_number(n, use_bjdata); - } - - // UBJSON: write number (unsigned integer) - template<typename NumberType, typename std::enable_if< - std::is_unsigned<NumberType>::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix, - const bool use_bjdata) - { - if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('i')); // int8 - } - write_number(static_cast<std::uint8_t>(n), use_bjdata); - } - else if (n <= (std::numeric_limits<std::uint8_t>::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('U')); // uint8 - } - write_number(static_cast<std::uint8_t>(n), use_bjdata); - } - else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('I')); // int16 - } - write_number(static_cast<std::int16_t>(n), use_bjdata); - } - else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('u')); // uint16 - bjdata only - } - write_number(static_cast<std::uint16_t>(n), use_bjdata); - } - else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('l')); // int32 - } - write_number(static_cast<std::int32_t>(n), use_bjdata); - } - else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('m')); // uint32 - bjdata only - } - write_number(static_cast<std::uint32_t>(n), use_bjdata); - } - else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('L')); // int64 - } - write_number(static_cast<std::int64_t>(n), use_bjdata); - } - else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('M')); // uint64 - bjdata only - } - write_number(static_cast<std::uint64_t>(n), use_bjdata); - } - else - { - if (add_prefix) - { - oa->write_character(to_char_type('H')); // high-precision number - } - - const auto number = BasicJsonType(n).dump(); - write_number_with_ubjson_prefix(number.size(), true, use_bjdata); - for (std::size_t i = 0; i < number.size(); ++i) - { - oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i]))); - } - } - } - - // UBJSON: write number (signed integer) - template < typename NumberType, typename std::enable_if < - std::is_signed<NumberType>::value&& - !std::is_floating_point<NumberType>::value, int >::type = 0 > - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix, - const bool use_bjdata) - { - if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('i')); // int8 - } - write_number(static_cast<std::int8_t>(n), use_bjdata); - } - else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('U')); // uint8 - } - write_number(static_cast<std::uint8_t>(n), use_bjdata); - } - else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('I')); // int16 - } - write_number(static_cast<std::int16_t>(n), use_bjdata); - } - else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)()))) - { - if (add_prefix) - { - oa->write_character(to_char_type('u')); // uint16 - bjdata only - } - write_number(static_cast<uint16_t>(n), use_bjdata); - } - else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('l')); // int32 - } - write_number(static_cast<std::int32_t>(n), use_bjdata); - } - else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)()))) - { - if (add_prefix) - { - oa->write_character(to_char_type('m')); // uint32 - bjdata only - } - write_number(static_cast<uint32_t>(n), use_bjdata); - } - else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('L')); // int64 - } - write_number(static_cast<std::int64_t>(n), use_bjdata); - } - // LCOV_EXCL_START - else - { - if (add_prefix) - { - oa->write_character(to_char_type('H')); // high-precision number - } - - const auto number = BasicJsonType(n).dump(); - write_number_with_ubjson_prefix(number.size(), true, use_bjdata); - for (std::size_t i = 0; i < number.size(); ++i) - { - oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i]))); - } - } - // LCOV_EXCL_STOP - } - - /*! - @brief determine the type prefix of container values - */ - CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept - { - switch (j.type()) - { - case value_t::null: - return 'Z'; - - case value_t::boolean: - return j.m_data.m_value.boolean ? 'T' : 'F'; - - case value_t::number_integer: - { - if ((std::numeric_limits<std::int8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) - { - return 'i'; - } - if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) - { - return 'U'; - } - if ((std::numeric_limits<std::int16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) - { - return 'I'; - } - if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())) - { - return 'u'; - } - if ((std::numeric_limits<std::int32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) - { - return 'l'; - } - if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())) - { - return 'm'; - } - if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) - { - return 'L'; - } - // anything else is treated as high-precision number - return 'H'; // LCOV_EXCL_LINE - } - - case value_t::number_unsigned: - { - if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)())) - { - return 'i'; - } - if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)())) - { - return 'U'; - } - if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)())) - { - return 'I'; - } - if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)())) - { - return 'u'; - } - if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) - { - return 'l'; - } - if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)())) - { - return 'm'; - } - if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)())) - { - return 'L'; - } - if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)()) - { - return 'M'; - } - // anything else is treated as high-precision number - return 'H'; // LCOV_EXCL_LINE - } - - case value_t::number_float: - return get_ubjson_float_prefix(j.m_data.m_value.number_float); - - case value_t::string: - return 'S'; - - case value_t::array: // fallthrough - case value_t::binary: - return '['; - - case value_t::object: - return '{'; - - case value_t::discarded: - default: // discarded values - return 'N'; - } - } - - static constexpr CharType get_ubjson_float_prefix(float /*unused*/) - { - return 'd'; // float 32 - } - - static constexpr CharType get_ubjson_float_prefix(double /*unused*/) - { - return 'D'; // float 64 - } - - /*! - @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid - */ - bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type) - { - std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, - {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'} - }; - - string_t key = "_ArrayType_"; - auto it = bjdtype.find(static_cast<string_t>(value.at(key))); - if (it == bjdtype.end()) - { - return true; - } - CharType dtype = it->second; - - key = "_ArraySize_"; - std::size_t len = (value.at(key).empty() ? 0 : 1); - for (const auto& el : value.at(key)) - { - len *= static_cast<std::size_t>(el.m_data.m_value.number_unsigned); - } - - key = "_ArrayData_"; - if (value.at(key).size() != len) - { - return true; - } - - oa->write_character('['); - oa->write_character('$'); - oa->write_character(dtype); - oa->write_character('#'); - - key = "_ArraySize_"; - write_ubjson(value.at(key), use_count, use_type, true, true); - - key = "_ArrayData_"; - if (dtype == 'U' || dtype == 'C') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::uint8_t>(el.m_data.m_value.number_unsigned), true); - } - } - else if (dtype == 'i') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::int8_t>(el.m_data.m_value.number_integer), true); - } - } - else if (dtype == 'u') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::uint16_t>(el.m_data.m_value.number_unsigned), true); - } - } - else if (dtype == 'I') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::int16_t>(el.m_data.m_value.number_integer), true); - } - } - else if (dtype == 'm') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::uint32_t>(el.m_data.m_value.number_unsigned), true); - } - } - else if (dtype == 'l') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::int32_t>(el.m_data.m_value.number_integer), true); - } - } - else if (dtype == 'M') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::uint64_t>(el.m_data.m_value.number_unsigned), true); - } - } - else if (dtype == 'L') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<std::int64_t>(el.m_data.m_value.number_integer), true); - } - } - else if (dtype == 'd') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<float>(el.m_data.m_value.number_float), true); - } - } - else if (dtype == 'D') - { - for (const auto& el : value.at(key)) - { - write_number(static_cast<double>(el.m_data.m_value.number_float), true); - } - } - return false; - } - - /////////////////////// - // Utility functions // - /////////////////////// - - /* - @brief write a number to output input - @param[in] n number of type @a NumberType - @param[in] OutputIsLittleEndian Set to true if output data is - required to be little endian - @tparam NumberType the type of the number - - @note This function needs to respect the system's endianness, because bytes - in CBOR, MessagePack, and UBJSON are stored in network order (big - endian) and therefore need reordering on little endian systems. - On the other hand, BSON and BJData use little endian and should reorder - on big endian systems. - */ - template<typename NumberType> - void write_number(const NumberType n, const bool OutputIsLittleEndian = false) - { - // step 1: write number to array of length NumberType - std::array<CharType, sizeof(NumberType)> vec{}; - std::memcpy(vec.data(), &n, sizeof(NumberType)); - - // step 2: write array to output (with possible reordering) - if (is_little_endian != OutputIsLittleEndian) - { - // reverse byte order prior to conversion if necessary - std::reverse(vec.begin(), vec.end()); - } - - oa->write_characters(vec.data(), sizeof(NumberType)); - } - - void write_compact_float(const number_float_t n, detail::input_format_t format) - { -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) && - static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) && - static_cast<double>(static_cast<float>(n)) == static_cast<double>(n)) - { - oa->write_character(format == detail::input_format_t::cbor - ? get_cbor_float_prefix(static_cast<float>(n)) - : get_msgpack_float_prefix(static_cast<float>(n))); - write_number(static_cast<float>(n)); - } - else - { - oa->write_character(format == detail::input_format_t::cbor - ? get_cbor_float_prefix(n) - : get_msgpack_float_prefix(n)); - write_number(n); - } -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - } - - public: - // The following to_char_type functions are implement the conversion - // between uint8_t and CharType. In case CharType is not unsigned, - // such a conversion is required to allow values greater than 128. - // See <https://github.com/nlohmann/json/issues/1286> for a discussion. - template < typename C = CharType, - enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr > - static constexpr CharType to_char_type(std::uint8_t x) noexcept - { - return *reinterpret_cast<char*>(&x); - } - - template < typename C = CharType, - enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr > - static CharType to_char_type(std::uint8_t x) noexcept - { - static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); - static_assert(std::is_trivial<CharType>::value, "CharType must be trivial"); - CharType result; - std::memcpy(&result, &x, sizeof(x)); - return result; - } - - template<typename C = CharType, - enable_if_t<std::is_unsigned<C>::value>* = nullptr> - static constexpr CharType to_char_type(std::uint8_t x) noexcept - { - return x; - } - - template < typename InputCharType, typename C = CharType, - enable_if_t < - std::is_signed<C>::value && - std::is_signed<char>::value && - std::is_same<char, typename std::remove_cv<InputCharType>::type>::value - > * = nullptr > - static constexpr CharType to_char_type(InputCharType x) noexcept - { - return x; - } - - private: - /// whether we can assume little endianness - const bool is_little_endian = little_endianness(); - - /// the output - output_adapter_t<CharType> oa = nullptr; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/output/output_adapters.hpp> - -// #include <nlohmann/detail/output/serializer.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de> -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <algorithm> // reverse, remove, fill, find, none_of -#include <array> // array -#include <clocale> // localeconv, lconv -#include <cmath> // labs, isfinite, isnan, signbit -#include <cstddef> // size_t, ptrdiff_t -#include <cstdint> // uint8_t -#include <cstdio> // snprintf -#include <limits> // numeric_limits -#include <string> // string, char_traits -#include <iomanip> // setfill, setw -#include <type_traits> // is_same -#include <utility> // move - -// #include <nlohmann/detail/conversions/to_chars.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/> -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <array> // array -#include <cmath> // signbit, isfinite -#include <cstdint> // intN_t, uintN_t -#include <cstring> // memcpy, memmove -#include <limits> // numeric_limits -#include <type_traits> // conditional - -// #include <nlohmann/detail/macro_scope.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/*! -@brief implements the Grisu2 algorithm for binary to decimal floating-point -conversion. - -This implementation is a slightly modified version of the reference -implementation which may be obtained from -http://florian.loitsch.com/publications (bench.tar.gz). - -The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. - -For a detailed description of the algorithm see: - -[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with - Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming - Language Design and Implementation, PLDI 2010 -[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", - Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language - Design and Implementation, PLDI 1996 -*/ -namespace dtoa_impl -{ - -template<typename Target, typename Source> -Target reinterpret_bits(const Source source) -{ - static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); - - Target target; - std::memcpy(&target, &source, sizeof(Source)); - return target; -} - -struct diyfp // f * 2^e -{ - static constexpr int kPrecision = 64; // = q - - std::uint64_t f = 0; - int e = 0; - - constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} - - /*! - @brief returns x - y - @pre x.e == y.e and x.f >= y.f - */ - static diyfp sub(const diyfp& x, const diyfp& y) noexcept - { - JSON_ASSERT(x.e == y.e); - JSON_ASSERT(x.f >= y.f); - - return {x.f - y.f, x.e}; - } - - /*! - @brief returns x * y - @note The result is rounded. (Only the upper q bits are returned.) - */ - static diyfp mul(const diyfp& x, const diyfp& y) noexcept - { - static_assert(kPrecision == 64, "internal error"); - - // Computes: - // f = round((x.f * y.f) / 2^q) - // e = x.e + y.e + q - - // Emulate the 64-bit * 64-bit multiplication: - // - // p = u * v - // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) - // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) - // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) - // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) - // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) - // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) - // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) - // - // (Since Q might be larger than 2^32 - 1) - // - // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) - // - // (Q_hi + H does not overflow a 64-bit int) - // - // = p_lo + 2^64 p_hi - - const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; - const std::uint64_t u_hi = x.f >> 32u; - const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; - const std::uint64_t v_hi = y.f >> 32u; - - const std::uint64_t p0 = u_lo * v_lo; - const std::uint64_t p1 = u_lo * v_hi; - const std::uint64_t p2 = u_hi * v_lo; - const std::uint64_t p3 = u_hi * v_hi; - - const std::uint64_t p0_hi = p0 >> 32u; - const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; - const std::uint64_t p1_hi = p1 >> 32u; - const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; - const std::uint64_t p2_hi = p2 >> 32u; - - std::uint64_t Q = p0_hi + p1_lo + p2_lo; - - // The full product might now be computed as - // - // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) - // p_lo = p0_lo + (Q << 32) - // - // But in this particular case here, the full p_lo is not required. - // Effectively we only need to add the highest bit in p_lo to p_hi (and - // Q_hi + 1 does not overflow). - - Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up - - const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); - - return {h, x.e + y.e + 64}; - } - - /*! - @brief normalize x such that the significand is >= 2^(q-1) - @pre x.f != 0 - */ - static diyfp normalize(diyfp x) noexcept - { - JSON_ASSERT(x.f != 0); - - while ((x.f >> 63u) == 0) - { - x.f <<= 1u; - x.e--; - } - - return x; - } - - /*! - @brief normalize x such that the result has the exponent E - @pre e >= x.e and the upper e - x.e bits of x.f must be zero. - */ - static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept - { - const int delta = x.e - target_exponent; - - JSON_ASSERT(delta >= 0); - JSON_ASSERT(((x.f << delta) >> delta) == x.f); - - return {x.f << delta, target_exponent}; - } -}; - -struct boundaries -{ - diyfp w; - diyfp minus; - diyfp plus; -}; - -/*! -Compute the (normalized) diyfp representing the input number 'value' and its -boundaries. - -@pre value must be finite and positive -*/ -template<typename FloatType> -boundaries compute_boundaries(FloatType value) -{ - JSON_ASSERT(std::isfinite(value)); - JSON_ASSERT(value > 0); - - // Convert the IEEE representation into a diyfp. - // - // If v is denormal: - // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) - // If v is normalized: - // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) - - static_assert(std::numeric_limits<FloatType>::is_iec559, - "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); - - constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit) - constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1); - constexpr int kMinExp = 1 - kBias; - constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) - - using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type; - - const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value)); - const std::uint64_t E = bits >> (kPrecision - 1); - const std::uint64_t F = bits & (kHiddenBit - 1); - - const bool is_denormal = E == 0; - const diyfp v = is_denormal - ? diyfp(F, kMinExp) - : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias); - - // Compute the boundaries m- and m+ of the floating-point value - // v = f * 2^e. - // - // Determine v- and v+, the floating-point predecessor and successor if v, - // respectively. - // - // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) - // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) - // - // v+ = v + 2^e - // - // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ - // between m- and m+ round to v, regardless of how the input rounding - // algorithm breaks ties. - // - // ---+-------------+-------------+-------------+-------------+--- (A) - // v- m- v m+ v+ - // - // -----------------+------+------+-------------+-------------+--- (B) - // v- m- v m+ v+ - - const bool lower_boundary_is_closer = F == 0 && E > 1; - const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); - const diyfp m_minus = lower_boundary_is_closer - ? diyfp(4 * v.f - 1, v.e - 2) // (B) - : diyfp(2 * v.f - 1, v.e - 1); // (A) - - // Determine the normalized w+ = m+. - const diyfp w_plus = diyfp::normalize(m_plus); - - // Determine w- = m- such that e_(w-) = e_(w+). - const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); - - return {diyfp::normalize(v), w_minus, w_plus}; -} - -// Given normalized diyfp w, Grisu needs to find a (normalized) cached -// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies -// within a certain range [alpha, gamma] (Definition 3.2 from [1]) -// -// alpha <= e = e_c + e_w + q <= gamma -// -// or -// -// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q -// <= f_c * f_w * 2^gamma -// -// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies -// -// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma -// -// or -// -// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) -// -// The choice of (alpha,gamma) determines the size of the table and the form of -// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well -// in practice: -// -// The idea is to cut the number c * w = f * 2^e into two parts, which can be -// processed independently: An integral part p1, and a fractional part p2: -// -// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e -// = (f div 2^-e) + (f mod 2^-e) * 2^e -// = p1 + p2 * 2^e -// -// The conversion of p1 into decimal form requires a series of divisions and -// modulos by (a power of) 10. These operations are faster for 32-bit than for -// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be -// achieved by choosing -// -// -e >= 32 or e <= -32 := gamma -// -// In order to convert the fractional part -// -// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... -// -// into decimal form, the fraction is repeatedly multiplied by 10 and the digits -// d[-i] are extracted in order: -// -// (10 * p2) div 2^-e = d[-1] -// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... -// -// The multiplication by 10 must not overflow. It is sufficient to choose -// -// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. -// -// Since p2 = f mod 2^-e < 2^-e, -// -// -e <= 60 or e >= -60 := alpha - -constexpr int kAlpha = -60; -constexpr int kGamma = -32; - -struct cached_power // c = f * 2^e ~= 10^k -{ - std::uint64_t f; - int e; - int k; -}; - -/*! -For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached -power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c -satisfies (Definition 3.2 from [1]) - - alpha <= e_c + e + q <= gamma. -*/ -inline cached_power get_cached_power_for_binary_exponent(int e) -{ - // Now - // - // alpha <= e_c + e + q <= gamma (1) - // ==> f_c * 2^alpha <= c * 2^e * 2^q - // - // and since the c's are normalized, 2^(q-1) <= f_c, - // - // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) - // ==> 2^(alpha - e - 1) <= c - // - // If c were an exact power of ten, i.e. c = 10^k, one may determine k as - // - // k = ceil( log_10( 2^(alpha - e - 1) ) ) - // = ceil( (alpha - e - 1) * log_10(2) ) - // - // From the paper: - // "In theory the result of the procedure could be wrong since c is rounded, - // and the computation itself is approximated [...]. In practice, however, - // this simple function is sufficient." - // - // For IEEE double precision floating-point numbers converted into - // normalized diyfp's w = f * 2^e, with q = 64, - // - // e >= -1022 (min IEEE exponent) - // -52 (p - 1) - // -52 (p - 1, possibly normalize denormal IEEE numbers) - // -11 (normalize the diyfp) - // = -1137 - // - // and - // - // e <= +1023 (max IEEE exponent) - // -52 (p - 1) - // -11 (normalize the diyfp) - // = 960 - // - // This binary exponent range [-1137,960] results in a decimal exponent - // range [-307,324]. One does not need to store a cached power for each - // k in this range. For each such k it suffices to find a cached power - // such that the exponent of the product lies in [alpha,gamma]. - // This implies that the difference of the decimal exponents of adjacent - // table entries must be less than or equal to - // - // floor( (gamma - alpha) * log_10(2) ) = 8. - // - // (A smaller distance gamma-alpha would require a larger table.) - - // NB: - // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. - - constexpr int kCachedPowersMinDecExp = -300; - constexpr int kCachedPowersDecStep = 8; - - static constexpr std::array<cached_power, 79> kCachedPowers = - { - { - { 0xAB70FE17C79AC6CA, -1060, -300 }, - { 0xFF77B1FCBEBCDC4F, -1034, -292 }, - { 0xBE5691EF416BD60C, -1007, -284 }, - { 0x8DD01FAD907FFC3C, -980, -276 }, - { 0xD3515C2831559A83, -954, -268 }, - { 0x9D71AC8FADA6C9B5, -927, -260 }, - { 0xEA9C227723EE8BCB, -901, -252 }, - { 0xAECC49914078536D, -874, -244 }, - { 0x823C12795DB6CE57, -847, -236 }, - { 0xC21094364DFB5637, -821, -228 }, - { 0x9096EA6F3848984F, -794, -220 }, - { 0xD77485CB25823AC7, -768, -212 }, - { 0xA086CFCD97BF97F4, -741, -204 }, - { 0xEF340A98172AACE5, -715, -196 }, - { 0xB23867FB2A35B28E, -688, -188 }, - { 0x84C8D4DFD2C63F3B, -661, -180 }, - { 0xC5DD44271AD3CDBA, -635, -172 }, - { 0x936B9FCEBB25C996, -608, -164 }, - { 0xDBAC6C247D62A584, -582, -156 }, - { 0xA3AB66580D5FDAF6, -555, -148 }, - { 0xF3E2F893DEC3F126, -529, -140 }, - { 0xB5B5ADA8AAFF80B8, -502, -132 }, - { 0x87625F056C7C4A8B, -475, -124 }, - { 0xC9BCFF6034C13053, -449, -116 }, - { 0x964E858C91BA2655, -422, -108 }, - { 0xDFF9772470297EBD, -396, -100 }, - { 0xA6DFBD9FB8E5B88F, -369, -92 }, - { 0xF8A95FCF88747D94, -343, -84 }, - { 0xB94470938FA89BCF, -316, -76 }, - { 0x8A08F0F8BF0F156B, -289, -68 }, - { 0xCDB02555653131B6, -263, -60 }, - { 0x993FE2C6D07B7FAC, -236, -52 }, - { 0xE45C10C42A2B3B06, -210, -44 }, - { 0xAA242499697392D3, -183, -36 }, - { 0xFD87B5F28300CA0E, -157, -28 }, - { 0xBCE5086492111AEB, -130, -20 }, - { 0x8CBCCC096F5088CC, -103, -12 }, - { 0xD1B71758E219652C, -77, -4 }, - { 0x9C40000000000000, -50, 4 }, - { 0xE8D4A51000000000, -24, 12 }, - { 0xAD78EBC5AC620000, 3, 20 }, - { 0x813F3978F8940984, 30, 28 }, - { 0xC097CE7BC90715B3, 56, 36 }, - { 0x8F7E32CE7BEA5C70, 83, 44 }, - { 0xD5D238A4ABE98068, 109, 52 }, - { 0x9F4F2726179A2245, 136, 60 }, - { 0xED63A231D4C4FB27, 162, 68 }, - { 0xB0DE65388CC8ADA8, 189, 76 }, - { 0x83C7088E1AAB65DB, 216, 84 }, - { 0xC45D1DF942711D9A, 242, 92 }, - { 0x924D692CA61BE758, 269, 100 }, - { 0xDA01EE641A708DEA, 295, 108 }, - { 0xA26DA3999AEF774A, 322, 116 }, - { 0xF209787BB47D6B85, 348, 124 }, - { 0xB454E4A179DD1877, 375, 132 }, - { 0x865B86925B9BC5C2, 402, 140 }, - { 0xC83553C5C8965D3D, 428, 148 }, - { 0x952AB45CFA97A0B3, 455, 156 }, - { 0xDE469FBD99A05FE3, 481, 164 }, - { 0xA59BC234DB398C25, 508, 172 }, - { 0xF6C69A72A3989F5C, 534, 180 }, - { 0xB7DCBF5354E9BECE, 561, 188 }, - { 0x88FCF317F22241E2, 588, 196 }, - { 0xCC20CE9BD35C78A5, 614, 204 }, - { 0x98165AF37B2153DF, 641, 212 }, - { 0xE2A0B5DC971F303A, 667, 220 }, - { 0xA8D9D1535CE3B396, 694, 228 }, - { 0xFB9B7CD9A4A7443C, 720, 236 }, - { 0xBB764C4CA7A44410, 747, 244 }, - { 0x8BAB8EEFB6409C1A, 774, 252 }, - { 0xD01FEF10A657842C, 800, 260 }, - { 0x9B10A4E5E9913129, 827, 268 }, - { 0xE7109BFBA19C0C9D, 853, 276 }, - { 0xAC2820D9623BF429, 880, 284 }, - { 0x80444B5E7AA7CF85, 907, 292 }, - { 0xBF21E44003ACDD2D, 933, 300 }, - { 0x8E679C2F5E44FF8F, 960, 308 }, - { 0xD433179D9C8CB841, 986, 316 }, - { 0x9E19DB92B4E31BA9, 1013, 324 }, - } - }; - - // This computation gives exactly the same results for k as - // k = ceil((kAlpha - e - 1) * 0.30102999566398114) - // for |e| <= 1500, but doesn't require floating-point operations. - // NB: log_10(2) ~= 78913 / 2^18 - JSON_ASSERT(e >= -1500); - JSON_ASSERT(e <= 1500); - const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0); - - const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; - JSON_ASSERT(index >= 0); - JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size()); - - const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)]; - JSON_ASSERT(kAlpha <= cached.e + e + 64); - JSON_ASSERT(kGamma >= cached.e + e + 64); - - return cached; -} - -/*! -For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. -For n == 0, returns 1 and sets pow10 := 1. -*/ -inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) -{ - // LCOV_EXCL_START - if (n >= 1000000000) - { - pow10 = 1000000000; - return 10; - } - // LCOV_EXCL_STOP - if (n >= 100000000) - { - pow10 = 100000000; - return 9; - } - if (n >= 10000000) - { - pow10 = 10000000; - return 8; - } - if (n >= 1000000) - { - pow10 = 1000000; - return 7; - } - if (n >= 100000) - { - pow10 = 100000; - return 6; - } - if (n >= 10000) - { - pow10 = 10000; - return 5; - } - if (n >= 1000) - { - pow10 = 1000; - return 4; - } - if (n >= 100) - { - pow10 = 100; - return 3; - } - if (n >= 10) - { - pow10 = 10; - return 2; - } - - pow10 = 1; - return 1; -} - -inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, - std::uint64_t rest, std::uint64_t ten_k) -{ - JSON_ASSERT(len >= 1); - JSON_ASSERT(dist <= delta); - JSON_ASSERT(rest <= delta); - JSON_ASSERT(ten_k > 0); - - // <--------------------------- delta ----> - // <---- dist ---------> - // --------------[------------------+-------------------]-------------- - // M- w M+ - // - // ten_k - // <------> - // <---- rest ----> - // --------------[------------------+----+--------------]-------------- - // w V - // = buf * 10^k - // - // ten_k represents a unit-in-the-last-place in the decimal representation - // stored in buf. - // Decrement buf by ten_k while this takes buf closer to w. - - // The tests are written in this order to avoid overflow in unsigned - // integer arithmetic. - - while (rest < dist - && delta - rest >= ten_k - && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) - { - JSON_ASSERT(buf[len - 1] != '0'); - buf[len - 1]--; - rest += ten_k; - } -} - -/*! -Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. -M- and M+ must be normalized and share the same exponent -60 <= e <= -32. -*/ -inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, - diyfp M_minus, diyfp w, diyfp M_plus) -{ - static_assert(kAlpha >= -60, "internal error"); - static_assert(kGamma <= -32, "internal error"); - - // Generates the digits (and the exponent) of a decimal floating-point - // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's - // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. - // - // <--------------------------- delta ----> - // <---- dist ---------> - // --------------[------------------+-------------------]-------------- - // M- w M+ - // - // Grisu2 generates the digits of M+ from left to right and stops as soon as - // V is in [M-,M+]. - - JSON_ASSERT(M_plus.e >= kAlpha); - JSON_ASSERT(M_plus.e <= kGamma); - - std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) - std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) - - // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): - // - // M+ = f * 2^e - // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e - // = ((p1 ) * 2^-e + (p2 )) * 2^e - // = p1 + p2 * 2^e - - const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); - - auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) - std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e - - // 1) - // - // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] - - JSON_ASSERT(p1 > 0); - - std::uint32_t pow10{}; - const int k = find_largest_pow10(p1, pow10); - - // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) - // - // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) - // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) - // - // M+ = p1 + p2 * 2^e - // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e - // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e - // = d[k-1] * 10^(k-1) + ( rest) * 2^e - // - // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) - // - // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] - // - // but stop as soon as - // - // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e - - int n = k; - while (n > 0) - { - // Invariants: - // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) - // pow10 = 10^(n-1) <= p1 < 10^n - // - const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) - const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) - // - // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e - // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) - // - JSON_ASSERT(d <= 9); - buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d - // - // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) - // - p1 = r; - n--; - // - // M+ = buffer * 10^n + (p1 + p2 * 2^e) - // pow10 = 10^n - // - - // Now check if enough digits have been generated. - // Compute - // - // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e - // - // Note: - // Since rest and delta share the same exponent e, it suffices to - // compare the significands. - const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; - if (rest <= delta) - { - // V = buffer * 10^n, with M- <= V <= M+. - - decimal_exponent += n; - - // We may now just stop. But instead look if the buffer could be - // decremented to bring V closer to w. - // - // pow10 = 10^n is now 1 ulp in the decimal representation V. - // The rounding procedure works with diyfp's with an implicit - // exponent of e. - // - // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e - // - const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; - grisu2_round(buffer, length, dist, delta, rest, ten_n); - - return; - } - - pow10 /= 10; - // - // pow10 = 10^(n-1) <= p1 < 10^n - // Invariants restored. - } - - // 2) - // - // The digits of the integral part have been generated: - // - // M+ = d[k-1]...d[1]d[0] + p2 * 2^e - // = buffer + p2 * 2^e - // - // Now generate the digits of the fractional part p2 * 2^e. - // - // Note: - // No decimal point is generated: the exponent is adjusted instead. - // - // p2 actually represents the fraction - // - // p2 * 2^e - // = p2 / 2^-e - // = d[-1] / 10^1 + d[-2] / 10^2 + ... - // - // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) - // - // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m - // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) - // - // using - // - // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) - // = ( d) * 2^-e + ( r) - // - // or - // 10^m * p2 * 2^e = d + r * 2^e - // - // i.e. - // - // M+ = buffer + p2 * 2^e - // = buffer + 10^-m * (d + r * 2^e) - // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e - // - // and stop as soon as 10^-m * r * 2^e <= delta * 2^e - - JSON_ASSERT(p2 > delta); - - int m = 0; - for (;;) - { - // Invariant: - // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e - // = buffer * 10^-m + 10^-m * (p2 ) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e - // - JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10); - p2 *= 10; - const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e - const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e - // - // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) - // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e - // - JSON_ASSERT(d <= 9); - buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d - // - // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e - // - p2 = r; - m++; - // - // M+ = buffer * 10^-m + 10^-m * p2 * 2^e - // Invariant restored. - - // Check if enough digits have been generated. - // - // 10^-m * p2 * 2^e <= delta * 2^e - // p2 * 2^e <= 10^m * delta * 2^e - // p2 <= 10^m * delta - delta *= 10; - dist *= 10; - if (p2 <= delta) - { - break; - } - } - - // V = buffer * 10^-m, with M- <= V <= M+. - - decimal_exponent -= m; - - // 1 ulp in the decimal representation is now 10^-m. - // Since delta and dist are now scaled by 10^m, we need to do the - // same with ulp in order to keep the units in sync. - // - // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e - // - const std::uint64_t ten_m = one.f; - grisu2_round(buffer, length, dist, delta, p2, ten_m); - - // By construction this algorithm generates the shortest possible decimal - // number (Loitsch, Theorem 6.2) which rounds back to w. - // For an input number of precision p, at least - // - // N = 1 + ceil(p * log_10(2)) - // - // decimal digits are sufficient to identify all binary floating-point - // numbers (Matula, "In-and-Out conversions"). - // This implies that the algorithm does not produce more than N decimal - // digits. - // - // N = 17 for p = 53 (IEEE double precision) - // N = 9 for p = 24 (IEEE single precision) -} - -/*! -v = buf * 10^decimal_exponent -len is the length of the buffer (number of decimal digits) -The buffer must be large enough, i.e. >= max_digits10. -*/ -JSON_HEDLEY_NON_NULL(1) -inline void grisu2(char* buf, int& len, int& decimal_exponent, - diyfp m_minus, diyfp v, diyfp m_plus) -{ - JSON_ASSERT(m_plus.e == m_minus.e); - JSON_ASSERT(m_plus.e == v.e); - - // --------(-----------------------+-----------------------)-------- (A) - // m- v m+ - // - // --------------------(-----------+-----------------------)-------- (B) - // m- v m+ - // - // First scale v (and m- and m+) such that the exponent is in the range - // [alpha, gamma]. - - const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); - - const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k - - // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] - const diyfp w = diyfp::mul(v, c_minus_k); - const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); - const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); - - // ----(---+---)---------------(---+---)---------------(---+---)---- - // w- w w+ - // = c*m- = c*v = c*m+ - // - // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and - // w+ are now off by a small amount. - // In fact: - // - // w - v * 10^k < 1 ulp - // - // To account for this inaccuracy, add resp. subtract 1 ulp. - // - // --------+---[---------------(---+---)---------------]---+-------- - // w- M- w M+ w+ - // - // Now any number in [M-, M+] (bounds included) will round to w when input, - // regardless of how the input rounding algorithm breaks ties. - // - // And digit_gen generates the shortest possible such number in [M-, M+]. - // Note that this does not mean that Grisu2 always generates the shortest - // possible number in the interval (m-, m+). - const diyfp M_minus(w_minus.f + 1, w_minus.e); - const diyfp M_plus (w_plus.f - 1, w_plus.e ); - - decimal_exponent = -cached.k; // = -(-k) = k - - grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); -} - -/*! -v = buf * 10^decimal_exponent -len is the length of the buffer (number of decimal digits) -The buffer must be large enough, i.e. >= max_digits10. -*/ -template<typename FloatType> -JSON_HEDLEY_NON_NULL(1) -void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) -{ - static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3, - "internal error: not enough precision"); - - JSON_ASSERT(std::isfinite(value)); - JSON_ASSERT(value > 0); - - // If the neighbors (and boundaries) of 'value' are always computed for double-precision - // numbers, all float's can be recovered using strtod (and strtof). However, the resulting - // decimal representations are not exactly "short". - // - // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) - // says "value is converted to a string as if by std::sprintf in the default ("C") locale" - // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars' - // does. - // On the other hand, the documentation for 'std::to_chars' requires that "parsing the - // representation using the corresponding std::from_chars function recovers value exactly". That - // indicates that single precision floating-point numbers should be recovered using - // 'std::strtof'. - // - // NB: If the neighbors are computed for single-precision numbers, there is a single float - // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision - // value is off by 1 ulp. -#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) - const boundaries w = compute_boundaries(static_cast<double>(value)); -#else - const boundaries w = compute_boundaries(value); -#endif - - grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); -} - -/*! -@brief appends a decimal representation of e to buf -@return a pointer to the element following the exponent. -@pre -1000 < e < 1000 -*/ -JSON_HEDLEY_NON_NULL(1) -JSON_HEDLEY_RETURNS_NON_NULL -inline char* append_exponent(char* buf, int e) -{ - JSON_ASSERT(e > -1000); - JSON_ASSERT(e < 1000); - - if (e < 0) - { - e = -e; - *buf++ = '-'; - } - else - { - *buf++ = '+'; - } - - auto k = static_cast<std::uint32_t>(e); - if (k < 10) - { - // Always print at least two digits in the exponent. - // This is for compatibility with printf("%g"). - *buf++ = '0'; - *buf++ = static_cast<char>('0' + k); - } - else if (k < 100) - { - *buf++ = static_cast<char>('0' + k / 10); - k %= 10; - *buf++ = static_cast<char>('0' + k); - } - else - { - *buf++ = static_cast<char>('0' + k / 100); - k %= 100; - *buf++ = static_cast<char>('0' + k / 10); - k %= 10; - *buf++ = static_cast<char>('0' + k); - } - - return buf; -} - -/*! -@brief prettify v = buf * 10^decimal_exponent - -If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point -notation. Otherwise it will be printed in exponential notation. - -@pre min_exp < 0 -@pre max_exp > 0 -*/ -JSON_HEDLEY_NON_NULL(1) -JSON_HEDLEY_RETURNS_NON_NULL -inline char* format_buffer(char* buf, int len, int decimal_exponent, - int min_exp, int max_exp) -{ - JSON_ASSERT(min_exp < 0); - JSON_ASSERT(max_exp > 0); - - const int k = len; - const int n = len + decimal_exponent; - - // v = buf * 10^(n-k) - // k is the length of the buffer (number of decimal digits) - // n is the position of the decimal point relative to the start of the buffer. - - if (k <= n && n <= max_exp) - { - // digits[000] - // len <= max_exp + 2 - - std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k)); - // Make it look like a floating-point number (#362, #378) - buf[n + 0] = '.'; - buf[n + 1] = '0'; - return buf + (static_cast<size_t>(n) + 2); - } - - if (0 < n && n <= max_exp) - { - // dig.its - // len <= max_digits10 + 1 - - JSON_ASSERT(k > n); - - std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n)); - buf[n] = '.'; - return buf + (static_cast<size_t>(k) + 1U); - } - - if (min_exp < n && n <= 0) - { - // 0.[000]digits - // len <= 2 + (-min_exp - 1) + max_digits10 - - std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k)); - buf[0] = '0'; - buf[1] = '.'; - std::memset(buf + 2, '0', static_cast<size_t>(-n)); - return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k)); - } - - if (k == 1) - { - // dE+123 - // len <= 1 + 5 - - buf += 1; - } - else - { - // d.igitsE+123 - // len <= max_digits10 + 1 + 5 - - std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1); - buf[1] = '.'; - buf += 1 + static_cast<size_t>(k); - } - - *buf++ = 'e'; - return append_exponent(buf, n - 1); -} - -} // namespace dtoa_impl - -/*! -@brief generates a decimal representation of the floating-point number value in [first, last). - -The format of the resulting decimal representation is similar to printf's %g -format. Returns an iterator pointing past-the-end of the decimal representation. - -@note The input number must be finite, i.e. NaN's and Inf's are not supported. -@note The buffer must be large enough. -@note The result is NOT null-terminated. -*/ -template<typename FloatType> -JSON_HEDLEY_NON_NULL(1, 2) -JSON_HEDLEY_RETURNS_NON_NULL -char* to_chars(char* first, const char* last, FloatType value) -{ - static_cast<void>(last); // maybe unused - fix warning - JSON_ASSERT(std::isfinite(value)); - - // Use signbit(value) instead of (value < 0) since signbit works for -0. - if (std::signbit(value)) - { - value = -value; - *first++ = '-'; - } - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - if (value == 0) // +-0 - { - *first++ = '0'; - // Make it look like a floating-point number (#362, #378) - *first++ = '.'; - *first++ = '0'; - return first; - } -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - - JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10); - - // Compute v = buffer * 10^decimal_exponent. - // The decimal digits are stored in the buffer, which needs to be interpreted - // as an unsigned decimal integer. - // len is the length of the buffer, i.e. the number of decimal digits. - int len = 0; - int decimal_exponent = 0; - dtoa_impl::grisu2(first, len, decimal_exponent, value); - - JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10); - - // Format the buffer like printf("%.*g", prec, value) - constexpr int kMinExp = -4; - // Use digits10 here to increase compatibility with version 2. - constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10; - - JSON_ASSERT(last - first >= kMaxExp + 2); - JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10); - JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6); - - return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); -} - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/exceptions.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/cpp_future.hpp> - -// #include <nlohmann/detail/output/binary_writer.hpp> - -// #include <nlohmann/detail/output/output_adapters.hpp> - -// #include <nlohmann/detail/string_concat.hpp> - -// #include <nlohmann/detail/value_t.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN -namespace detail -{ - -/////////////////// -// serialization // -/////////////////// - -/// how to treat decoding errors -enum class error_handler_t -{ - strict, ///< throw a type_error exception in case of invalid UTF-8 - replace, ///< replace invalid UTF-8 sequences with U+FFFD - ignore ///< ignore invalid UTF-8 sequences -}; - -template<typename BasicJsonType> -class serializer -{ - using string_t = typename BasicJsonType::string_t; - using number_float_t = typename BasicJsonType::number_float_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using binary_char_t = typename BasicJsonType::binary_t::value_type; - static constexpr std::uint8_t UTF8_ACCEPT = 0; - static constexpr std::uint8_t UTF8_REJECT = 1; - - public: - /*! - @param[in] s output stream to serialize to - @param[in] ichar indentation character to use - @param[in] error_handler_ how to react on decoding errors - */ - serializer(output_adapter_t<char> s, const char ichar, - error_handler_t error_handler_ = error_handler_t::strict) - : o(std::move(s)) - , loc(std::localeconv()) - , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep))) - , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point))) - , indent_char(ichar) - , indent_string(512, indent_char) - , error_handler(error_handler_) - {} - - // delete because of pointer members - serializer(const serializer&) = delete; - serializer& operator=(const serializer&) = delete; - serializer(serializer&&) = delete; - serializer& operator=(serializer&&) = delete; - ~serializer() = default; - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - binary values are serialized as objects containing the subtype and the - byte array - - @param[in] val value to serialize - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters - in the output are escaped with `\uXXXX` sequences, and the result consists - of ASCII characters only. - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(const BasicJsonType& val, - const bool pretty_print, - const bool ensure_ascii, - const unsigned int indent_step, - const unsigned int current_indent = 0) - { - switch (val.m_data.m_type) - { - case value_t::object: - { - if (val.m_data.m_value.object->empty()) - { - o->write_characters("{}", 2); - return; - } - - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - auto i = val.m_data.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - JSON_ASSERT(i != val.m_data.m_value.object->cend()); - JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend()); - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_character('{'); - - // first n-1 elements - auto i = val.m_data.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - JSON_ASSERT(i != val.m_data.m_value.object->cend()); - JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend()); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - - o->write_character('}'); - } - - return; - } - - case value_t::array: - { - if (val.m_data.m_value.array->empty()) - { - o->write_characters("[]", 2); - return; - } - - if (pretty_print) - { - o->write_characters("[\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - for (auto i = val.m_data.m_value.array->cbegin(); - i != val.m_data.m_value.array->cend() - 1; ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - JSON_ASSERT(!val.m_data.m_value.array->empty()); - o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character(']'); - } - else - { - o->write_character('['); - - // first n-1 elements - for (auto i = val.m_data.m_value.array->cbegin(); - i != val.m_data.m_value.array->cend() - 1; ++i) - { - dump(*i, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - JSON_ASSERT(!val.m_data.m_value.array->empty()); - dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); - - o->write_character(']'); - } - - return; - } - - case value_t::string: - { - o->write_character('\"'); - dump_escaped(*val.m_data.m_value.string, ensure_ascii); - o->write_character('\"'); - return; - } - - case value_t::binary: - { - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - o->write_characters(indent_string.c_str(), new_indent); - - o->write_characters("\"bytes\": [", 10); - - if (!val.m_data.m_value.binary->empty()) - { - for (auto i = val.m_data.m_value.binary->cbegin(); - i != val.m_data.m_value.binary->cend() - 1; ++i) - { - dump_integer(*i); - o->write_characters(", ", 2); - } - dump_integer(val.m_data.m_value.binary->back()); - } - - o->write_characters("],\n", 3); - o->write_characters(indent_string.c_str(), new_indent); - - o->write_characters("\"subtype\": ", 11); - if (val.m_data.m_value.binary->has_subtype()) - { - dump_integer(val.m_data.m_value.binary->subtype()); - } - else - { - o->write_characters("null", 4); - } - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_characters("{\"bytes\":[", 10); - - if (!val.m_data.m_value.binary->empty()) - { - for (auto i = val.m_data.m_value.binary->cbegin(); - i != val.m_data.m_value.binary->cend() - 1; ++i) - { - dump_integer(*i); - o->write_character(','); - } - dump_integer(val.m_data.m_value.binary->back()); - } - - o->write_characters("],\"subtype\":", 12); - if (val.m_data.m_value.binary->has_subtype()) - { - dump_integer(val.m_data.m_value.binary->subtype()); - o->write_character('}'); - } - else - { - o->write_characters("null}", 5); - } - } - return; - } - - case value_t::boolean: - { - if (val.m_data.m_value.boolean) - { - o->write_characters("true", 4); - } - else - { - o->write_characters("false", 5); - } - return; - } - - case value_t::number_integer: - { - dump_integer(val.m_data.m_value.number_integer); - return; - } - - case value_t::number_unsigned: - { - dump_integer(val.m_data.m_value.number_unsigned); - return; - } - - case value_t::number_float: - { - dump_float(val.m_data.m_value.number_float); - return; - } - - case value_t::discarded: - { - o->write_characters("<discarded>", 11); - return; - } - - case value_t::null: - { - o->write_characters("null", 4); - return; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - } - - JSON_PRIVATE_UNLESS_TESTED: - /*! - @brief dump escaped string - - Escape a string by replacing certain special characters by a sequence of an - escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. The escaped string is written to output stream @a o. - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - - @complexity Linear in the length of string @a s. - */ - void dump_escaped(const string_t& s, const bool ensure_ascii) - { - std::uint32_t codepoint{}; - std::uint8_t state = UTF8_ACCEPT; - std::size_t bytes = 0; // number of bytes written to string_buffer - - // number of bytes written at the point of the last valid byte - std::size_t bytes_after_last_accept = 0; - std::size_t undumped_chars = 0; - - for (std::size_t i = 0; i < s.size(); ++i) - { - const auto byte = static_cast<std::uint8_t>(s[i]); - - switch (decode(state, codepoint, byte)) - { - case UTF8_ACCEPT: // decode found a new code point - { - switch (codepoint) - { - case 0x08: // backspace - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'b'; - break; - } - - case 0x09: // horizontal tab - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 't'; - break; - } - - case 0x0A: // newline - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'n'; - break; - } - - case 0x0C: // formfeed - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'f'; - break; - } - - case 0x0D: // carriage return - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'r'; - break; - } - - case 0x22: // quotation mark - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = '\"'; - break; - } - - case 0x5C: // reverse solidus - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = '\\'; - break; - } - - default: - { - // escape control characters (0x00..0x1F) or, if - // ensure_ascii parameter is used, non-ASCII characters - if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) - { - if (codepoint <= 0xFFFF) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", - static_cast<std::uint16_t>(codepoint))); - bytes += 6; - } - else - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", - static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)), - static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)))); - bytes += 12; - } - } - else - { - // copy byte to buffer (all previous bytes - // been copied have in default case above) - string_buffer[bytes++] = s[i]; - } - break; - } - } - - // write buffer and reset index; there must be 13 bytes - // left, as this is the maximal number of bytes to be - // written ("\uxxxx\uxxxx\0") for one code point - if (string_buffer.size() - bytes < 13) - { - o->write_characters(string_buffer.data(), bytes); - bytes = 0; - } - - // remember the byte position of this accept - bytes_after_last_accept = bytes; - undumped_chars = 0; - break; - } - - case UTF8_REJECT: // decode found invalid UTF-8 byte - { - switch (error_handler) - { - case error_handler_t::strict: - { - JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr)); - } - - case error_handler_t::ignore: - case error_handler_t::replace: - { - // in case we saw this character the first time, we - // would like to read it again, because the byte - // may be OK for itself, but just not OK for the - // previous sequence - if (undumped_chars > 0) - { - --i; - } - - // reset length buffer to the last accepted index; - // thus removing/ignoring the invalid characters - bytes = bytes_after_last_accept; - - if (error_handler == error_handler_t::replace) - { - // add a replacement character - if (ensure_ascii) - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'u'; - string_buffer[bytes++] = 'f'; - string_buffer[bytes++] = 'f'; - string_buffer[bytes++] = 'f'; - string_buffer[bytes++] = 'd'; - } - else - { - string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF'); - string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF'); - string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD'); - } - - // write buffer and reset index; there must be 13 bytes - // left, as this is the maximal number of bytes to be - // written ("\uxxxx\uxxxx\0") for one code point - if (string_buffer.size() - bytes < 13) - { - o->write_characters(string_buffer.data(), bytes); - bytes = 0; - } - - bytes_after_last_accept = bytes; - } - - undumped_chars = 0; - - // continue processing the string - state = UTF8_ACCEPT; - break; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - break; - } - - default: // decode found yet incomplete multi-byte code point - { - if (!ensure_ascii) - { - // code point will not be escaped - copy byte to buffer - string_buffer[bytes++] = s[i]; - } - ++undumped_chars; - break; - } - } - } - - // we finished processing the string - if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) - { - // write buffer - if (bytes > 0) - { - o->write_characters(string_buffer.data(), bytes); - } - } - else - { - // we finish reading, but do not accept: string was incomplete - switch (error_handler) - { - case error_handler_t::strict: - { - JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr)); - } - - case error_handler_t::ignore: - { - // write all accepted bytes - o->write_characters(string_buffer.data(), bytes_after_last_accept); - break; - } - - case error_handler_t::replace: - { - // write all accepted bytes - o->write_characters(string_buffer.data(), bytes_after_last_accept); - // add a replacement character - if (ensure_ascii) - { - o->write_characters("\\ufffd", 6); - } - else - { - o->write_characters("\xEF\xBF\xBD", 3); - } - break; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - } - } - - private: - /*! - @brief count digits - - Count the number of decimal (base 10) digits for an input unsigned integer. - - @param[in] x unsigned integer number to count its digits - @return number of decimal digits - */ - inline unsigned int count_digits(number_unsigned_t x) noexcept - { - unsigned int n_digits = 1; - for (;;) - { - if (x < 10) - { - return n_digits; - } - if (x < 100) - { - return n_digits + 1; - } - if (x < 1000) - { - return n_digits + 2; - } - if (x < 10000) - { - return n_digits + 3; - } - x = x / 10000u; - n_digits += 4; - } - } - - /*! - * @brief convert a byte to a uppercase hex representation - * @param[in] byte byte to represent - * @return representation ("00".."FF") - */ - static std::string hex_bytes(std::uint8_t byte) - { - std::string result = "FF"; - constexpr const char* nibble_to_hex = "0123456789ABCDEF"; - result[0] = nibble_to_hex[byte / 16]; - result[1] = nibble_to_hex[byte % 16]; - return result; - } - - // templates to avoid warnings about useless casts - template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0> - bool is_negative_number(NumberType x) - { - return x < 0; - } - - template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 > - bool is_negative_number(NumberType /*unused*/) - { - return false; - } - - /*! - @brief dump an integer - - Dump a given integer to output stream @a o. Works internally with - @a number_buffer. - - @param[in] x integer number (signed or unsigned) to dump - @tparam NumberType either @a number_integer_t or @a number_unsigned_t - */ - template < typename NumberType, detail::enable_if_t < - std::is_integral<NumberType>::value || - std::is_same<NumberType, number_unsigned_t>::value || - std::is_same<NumberType, number_integer_t>::value || - std::is_same<NumberType, binary_char_t>::value, - int > = 0 > - void dump_integer(NumberType x) - { - static constexpr std::array<std::array<char, 2>, 100> digits_to_99 - { - { - {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, - {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, - {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, - {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, - {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, - {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, - {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, - {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, - {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, - {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, - } - }; - - // special case for "0" - if (x == 0) - { - o->write_character('0'); - return; - } - - // use a pointer to fill the buffer - auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) - - number_unsigned_t abs_value; - - unsigned int n_chars{}; - - if (is_negative_number(x)) - { - *buffer_ptr = '-'; - abs_value = remove_sign(static_cast<number_integer_t>(x)); - - // account one more byte for the minus sign - n_chars = 1 + count_digits(abs_value); - } - else - { - abs_value = static_cast<number_unsigned_t>(x); - n_chars = count_digits(abs_value); - } - - // spare 1 byte for '\0' - JSON_ASSERT(n_chars < number_buffer.size() - 1); - - // jump to the end to generate the string from backward, - // so we later avoid reversing the result - buffer_ptr += n_chars; - - // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu - // See: https://www.youtube.com/watch?v=o4-CwDo2zpg - while (abs_value >= 100) - { - const auto digits_index = static_cast<unsigned>((abs_value % 100)); - abs_value /= 100; - *(--buffer_ptr) = digits_to_99[digits_index][1]; - *(--buffer_ptr) = digits_to_99[digits_index][0]; - } - - if (abs_value >= 10) - { - const auto digits_index = static_cast<unsigned>(abs_value); - *(--buffer_ptr) = digits_to_99[digits_index][1]; - *(--buffer_ptr) = digits_to_99[digits_index][0]; - } - else - { - *(--buffer_ptr) = static_cast<char>('0' + abs_value); - } - - o->write_characters(number_buffer.data(), n_chars); - } - - /*! - @brief dump a floating-point number - - Dump a given floating-point number to output stream @a o. Works internally - with @a number_buffer. - - @param[in] x floating-point number to dump - */ - void dump_float(number_float_t x) - { - // NaN / inf - if (!std::isfinite(x)) - { - o->write_characters("null", 4); - return; - } - - // If number_float_t is an IEEE-754 single or double precision number, - // use the Grisu2 algorithm to produce short numbers which are - // guaranteed to round-trip, using strtof and strtod, resp. - // - // NB: The test below works if <long double> == <double>. - static constexpr bool is_ieee_single_or_double - = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) || - (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024); - - dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>()); - } - - void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) - { - auto* begin = number_buffer.data(); - auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); - - o->write_characters(begin, static_cast<size_t>(end - begin)); - } - - void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) - { - // get number of digits for a float -> text -> float round-trip - static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10; - - // the actual conversion - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); - - // negative value indicates an error - JSON_ASSERT(len > 0); - // check if buffer was large enough - JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size()); - - // erase thousands separator - if (thousands_sep != '\0') - { - // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 - const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); - std::fill(end, number_buffer.end(), '\0'); - JSON_ASSERT((end - number_buffer.begin()) <= len); - len = (end - number_buffer.begin()); - } - - // convert decimal point to '.' - if (decimal_point != '\0' && decimal_point != '.') - { - // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 - const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); - if (dec_pos != number_buffer.end()) - { - *dec_pos = '.'; - } - } - - o->write_characters(number_buffer.data(), static_cast<std::size_t>(len)); - - // determine if we need to append ".0" - const bool value_is_int_like = - std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, - [](char c) - { - return c == '.' || c == 'e'; - }); - - if (value_is_int_like) - { - o->write_characters(".0", 2); - } - } - - /*! - @brief check whether a string is UTF-8 encoded - - The function checks each byte of a string whether it is UTF-8 encoded. The - result of the check is stored in the @a state parameter. The function must - be called initially with state 0 (accept). State 1 means the string must - be rejected, because the current byte is not allowed. If the string is - completely processed, but the state is non-zero, the string ended - prematurely; that is, the last byte indicated more bytes should have - followed. - - @param[in,out] state the state of the decoding - @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) - @param[in] byte next byte to decode - @return new state - - @note The function has been edited: a std::array is used. - - @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> - @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - */ - static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept - { - static const std::array<std::uint8_t, 400> utf8d = - { - { - 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, // 00..1F - 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, // 20..3F - 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, // 40..5F - 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, // 60..7F - 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, // 80..9F - 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, // A0..BF - 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, // C0..DF - 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF - 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 - } - }; - - JSON_ASSERT(byte < utf8d.size()); - const std::uint8_t type = utf8d[byte]; - - codep = (state != UTF8_ACCEPT) - ? (byte & 0x3fu) | (codep << 6u) - : (0xFFu >> type) & (byte); - - const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type); - JSON_ASSERT(index < utf8d.size()); - state = utf8d[index]; - return state; - } - - /* - * Overload to make the compiler happy while it is instantiating - * dump_integer for number_unsigned_t. - * Must never be called. - */ - number_unsigned_t remove_sign(number_unsigned_t x) - { - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return x; // LCOV_EXCL_LINE - } - - /* - * Helper function for dump_integer - * - * This function takes a negative signed integer and returns its absolute - * value as unsigned integer. The plus/minus shuffling is necessary as we can - * not directly remove the sign of an arbitrary signed integer as the - * absolute values of INT_MIN and INT_MAX are usually not the same. See - * #1708 for details. - */ - inline number_unsigned_t remove_sign(number_integer_t x) noexcept - { - JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression) - return static_cast<number_unsigned_t>(-(x + 1)) + 1; - } - - private: - /// the output of the serializer - output_adapter_t<char> o = nullptr; - - /// a (hopefully) large enough character buffer - std::array<char, 64> number_buffer{{}}; - - /// the locale - const std::lconv* loc = nullptr; - /// the locale's thousand separator character - const char thousands_sep = '\0'; - /// the locale's decimal point character - const char decimal_point = '\0'; - - /// string buffer - std::array<char, 512> string_buffer{{}}; - - /// the indentation character - const char indent_char; - /// the indentation string - string_t indent_string; - - /// error_handler how to react on decoding errors - const error_handler_t error_handler; -}; - -} // namespace detail -NLOHMANN_JSON_NAMESPACE_END - -// #include <nlohmann/detail/value_t.hpp> - -// #include <nlohmann/json_fwd.hpp> - -// #include <nlohmann/ordered_map.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#include <functional> // equal_to, less -#include <initializer_list> // initializer_list -#include <iterator> // input_iterator_tag, iterator_traits -#include <memory> // allocator -#include <stdexcept> // for out_of_range -#include <type_traits> // enable_if, is_convertible -#include <utility> // pair -#include <vector> // vector - -// #include <nlohmann/detail/macro_scope.hpp> - -// #include <nlohmann/detail/meta/type_traits.hpp> - - -NLOHMANN_JSON_NAMESPACE_BEGIN - -/// ordered_map: a minimal map-like container that preserves insertion order -/// for use within nlohmann::basic_json<ordered_map> -template <class Key, class T, class IgnoredLess = std::less<Key>, - class Allocator = std::allocator<std::pair<const Key, T>>> - struct ordered_map : std::vector<std::pair<const Key, T>, Allocator> -{ - using key_type = Key; - using mapped_type = T; - using Container = std::vector<std::pair<const Key, T>, Allocator>; - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using size_type = typename Container::size_type; - using value_type = typename Container::value_type; -#ifdef JSON_HAS_CPP_14 - using key_compare = std::equal_to<>; -#else - using key_compare = std::equal_to<Key>; -#endif - - // Explicit constructors instead of `using Container::Container` - // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) - ordered_map() noexcept(noexcept(Container())) : Container{} {} - explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} - template <class It> - ordered_map(It first, It last, const Allocator& alloc = Allocator()) - : Container{first, last, alloc} {} - ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() ) - : Container{init, alloc} {} - - std::pair<iterator, bool> emplace(const key_type& key, T&& t) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return {it, false}; - } - } - Container::emplace_back(key, std::forward<T>(t)); - return {std::prev(this->end()), true}; - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - std::pair<iterator, bool> emplace(KeyType && key, T && t) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return {it, false}; - } - } - Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t)); - return {std::prev(this->end()), true}; - } - - T& operator[](const key_type& key) - { - return emplace(key, T{}).first->second; - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - T & operator[](KeyType && key) - { - return emplace(std::forward<KeyType>(key), T{}).first->second; - } - - const T& operator[](const key_type& key) const - { - return at(key); - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - const T & operator[](KeyType && key) const - { - return at(std::forward<KeyType>(key)); - } - - T& at(const key_type& key) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it->second; - } - } - - JSON_THROW(std::out_of_range("key not found")); - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it->second; - } - } - - JSON_THROW(std::out_of_range("key not found")); - } - - const T& at(const key_type& key) const - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it->second; - } - } - - JSON_THROW(std::out_of_range("key not found")); - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it->second; - } - } - - JSON_THROW(std::out_of_range("key not found")); - } - - size_type erase(const key_type& key) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - // Since we cannot move const Keys, re-construct them in place - for (auto next = it; ++next != this->end(); ++it) - { - it->~value_type(); // Destroy but keep allocation - new (&*it) value_type{std::move(*next)}; - } - Container::pop_back(); - return 1; - } - } - return 0; - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - // Since we cannot move const Keys, re-construct them in place - for (auto next = it; ++next != this->end(); ++it) - { - it->~value_type(); // Destroy but keep allocation - new (&*it) value_type{std::move(*next)}; - } - Container::pop_back(); - return 1; - } - } - return 0; - } - - iterator erase(iterator pos) - { - return erase(pos, std::next(pos)); - } - - iterator erase(iterator first, iterator last) - { - if (first == last) - { - return first; - } - - const auto elements_affected = std::distance(first, last); - const auto offset = std::distance(Container::begin(), first); - - // This is the start situation. We need to delete elements_affected - // elements (3 in this example: e, f, g), and need to return an - // iterator past the last deleted element (h in this example). - // Note that offset is the distance from the start of the vector - // to first. We will need this later. - - // [ a, b, c, d, e, f, g, h, i, j ] - // ^ ^ - // first last - - // Since we cannot move const Keys, we re-construct them in place. - // We start at first and re-construct (viz. copy) the elements from - // the back of the vector. Example for first iteration: - - // ,--------. - // v | destroy e and re-construct with h - // [ a, b, c, d, e, f, g, h, i, j ] - // ^ ^ - // it it + elements_affected - - for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) - { - it->~value_type(); // destroy but keep allocation - new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it - } - - // [ a, b, c, d, h, i, j, h, i, j ] - // ^ ^ - // first last - - // remove the unneeded elements at the end of the vector - Container::resize(this->size() - static_cast<size_type>(elements_affected)); - - // [ a, b, c, d, h, i, j ] - // ^ ^ - // first last - - // first is now pointing past the last deleted element, but we cannot - // use this iterator, because it may have been invalidated by the - // resize call. Instead, we can return begin() + offset. - return Container::begin() + offset; - } - - size_type count(const key_type& key) const - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return 1; - } - } - return 0; - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return 1; - } - } - return 0; - } - - iterator find(const key_type& key) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it; - } - } - return Container::end(); - } - - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> - iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it; - } - } - return Container::end(); - } - - const_iterator find(const key_type& key) const - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, key)) - { - return it; - } - } - return Container::end(); - } - - std::pair<iterator, bool> insert( value_type&& value ) - { - return emplace(value.first, std::move(value.second)); - } - - std::pair<iterator, bool> insert( const value_type& value ) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (m_compare(it->first, value.first)) - { - return {it, false}; - } - } - Container::push_back(value); - return {--this->end(), true}; - } - - template<typename InputIt> - using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, - std::input_iterator_tag>::value>::type; - - template<typename InputIt, typename = require_input_iter<InputIt>> - void insert(InputIt first, InputIt last) - { - for (auto it = first; it != last; ++it) - { - insert(*it); - } - } - -private: - JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare(); -}; - -NLOHMANN_JSON_NAMESPACE_END - - -#if defined(JSON_HAS_CPP_17) - #if JSON_HAS_STATIC_RTTI - #include <any> - #endif - #include <string_view> -#endif - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -NLOHMANN_JSON_NAMESPACE_BEGIN - -/*! -@brief a class to store JSON values - -@internal -@invariant The member variables @a m_value and @a m_type have the following -relationship: -- If `m_type == value_t::object`, then `m_value.object != nullptr`. -- If `m_type == value_t::array`, then `m_value.array != nullptr`. -- If `m_type == value_t::string`, then `m_value.string != nullptr`. -The invariants are checked by member function assert_invariant(). - -@note ObjectType trick from https://stackoverflow.com/a/9860911 -@endinternal - -@since version 1.0.0 - -@nosubgrouping -*/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) - : public ::nlohmann::detail::json_base_class<CustomBaseClass> -{ - private: - template<detail::value_t> friend struct detail::external_constructor; - - template<typename> - friend class ::nlohmann::json_pointer; - // can be restored when json_pointer backwards compatibility is removed - // friend ::nlohmann::json_pointer<StringType>; - - template<typename BasicJsonType, typename InputType> - friend class ::nlohmann::detail::parser; - friend ::nlohmann::detail::serializer<basic_json>; - template<typename BasicJsonType> - friend class ::nlohmann::detail::iter_impl; - template<typename BasicJsonType, typename CharType> - friend class ::nlohmann::detail::binary_writer; - template<typename BasicJsonType, typename InputType, typename SAX> - friend class ::nlohmann::detail::binary_reader; - template<typename BasicJsonType> - friend class ::nlohmann::detail::json_sax_dom_parser; - template<typename BasicJsonType> - friend class ::nlohmann::detail::json_sax_dom_callback_parser; - friend class ::nlohmann::detail::exception; - - /// workaround type for MSVC - using basic_json_t = NLOHMANN_BASIC_JSON_TPL; - using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>; - - JSON_PRIVATE_UNLESS_TESTED: - // convenience aliases for types residing in namespace detail; - using lexer = ::nlohmann::detail::lexer_base<basic_json>; - - template<typename InputAdapterType> - static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser( - InputAdapterType adapter, - detail::parser_callback_t<basic_json>cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false - ) - { - return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter), - std::move(cb), allow_exceptions, ignore_comments); - } - - private: - using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; - template<typename BasicJsonType> - using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>; - template<typename BasicJsonType> - using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>; - template<typename Iterator> - using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>; - template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>; - - template<typename CharType> - using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>; - - template<typename InputType> - using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>; - template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>; - - JSON_PRIVATE_UNLESS_TESTED: - using serializer = ::nlohmann::detail::serializer<basic_json>; - - public: - using value_t = detail::value_t; - /// JSON Pointer, see @ref nlohmann::json_pointer - using json_pointer = ::nlohmann::json_pointer<StringType>; - template<typename T, typename SFINAE> - using json_serializer = JSONSerializer<T, SFINAE>; - /// how to treat decoding errors - using error_handler_t = detail::error_handler_t; - /// how to treat CBOR tags - using cbor_tag_handler_t = detail::cbor_tag_handler_t; - /// helper type for initializer lists of basic_json values - using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>; - - using input_format_t = detail::input_format_t; - /// SAX interface type, see @ref nlohmann::json_sax - using json_sax_t = json_sax<basic_json>; - - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - using exception = detail::exception; - using parse_error = detail::parse_error; - using invalid_iterator = detail::invalid_iterator; - using type_error = detail::type_error; - using out_of_range = detail::out_of_range; - using other_error = detail::other_error; - - /// @} - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType<basic_json>; - - /// the type of an element pointer - using pointer = typename std::allocator_traits<allocator_type>::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; - - /// an iterator for a basic_json container - using iterator = iter_impl<basic_json>; - /// a const iterator for a basic_json container - using const_iterator = iter_impl<const basic_json>; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>; - - /// @} - - /// @brief returns the allocator associated with the container - /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/ - static allocator_type get_allocator() - { - return allocator_type(); - } - - /// @brief returns version information on the library - /// @sa https://json.nlohmann.me/api/basic_json/meta/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json meta() - { - basic_json result; - - result["copyright"] = "(C) 2013-2023 Niels Lohmann"; - result["name"] = "JSON for Modern C++"; - result["url"] = "https://github.com/nlohmann/json"; - result["version"]["string"] = - detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.', - std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.', - std::to_string(NLOHMANN_JSON_VERSION_PATCH)); - result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; - result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; - result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; - -#ifdef _WIN32 - result["platform"] = "win32"; -#elif defined __linux__ - result["platform"] = "linux"; -#elif defined __APPLE__ - result["platform"] = "apple"; -#elif defined __unix__ - result["platform"] = "unix"; -#else - result["platform"] = "unknown"; -#endif - -#if defined(__ICC) || defined(__INTEL_COMPILER) - result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; -#elif defined(__clang__) - result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; -#elif defined(__GNUC__) || defined(__GNUG__) - result["compiler"] = {{"family", "gcc"}, {"version", detail::concat( - std::to_string(__GNUC__), '.', - std::to_string(__GNUC_MINOR__), '.', - std::to_string(__GNUC_PATCHLEVEL__)) - } - }; -#elif defined(__HP_cc) || defined(__HP_aCC) - result["compiler"] = "hp" -#elif defined(__IBMCPP__) - result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; -#elif defined(_MSC_VER) - result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; -#elif defined(__PGI) - result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; -#elif defined(__SUNPRO_CC) - result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; -#else - result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; -#endif - -#if defined(_MSVC_LANG) - result["compiler"]["c++"] = std::to_string(_MSVC_LANG); -#elif defined(__cplusplus) - result["compiler"]["c++"] = std::to_string(__cplusplus); -#else - result["compiler"]["c++"] = "unknown"; -#endif - return result; - } - - /////////////////////////// - // JSON value data types // - /////////////////////////// - - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ - - /// @brief default object key comparator type - /// The actual object key comparator type (@ref object_comparator_t) may be - /// different. - /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/ -#if defined(JSON_HAS_CPP_14) - // use of transparent comparator avoids unnecessary repeated construction of temporaries - // in functions involving lookup by key with types other than object_t::key_type (aka. StringType) - using default_object_comparator_t = std::less<>; -#else - using default_object_comparator_t = std::less<StringType>; -#endif - - /// @brief a type for an object - /// @sa https://json.nlohmann.me/api/basic_json/object_t/ - using object_t = ObjectType<StringType, - basic_json, - default_object_comparator_t, - AllocatorType<std::pair<const StringType, - basic_json>>>; - - /// @brief a type for an array - /// @sa https://json.nlohmann.me/api/basic_json/array_t/ - using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; - - /// @brief a type for a string - /// @sa https://json.nlohmann.me/api/basic_json/string_t/ - using string_t = StringType; - - /// @brief a type for a boolean - /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/ - using boolean_t = BooleanType; - - /// @brief a type for a number (integer) - /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/ - using number_integer_t = NumberIntegerType; - - /// @brief a type for a number (unsigned) - /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/ - using number_unsigned_t = NumberUnsignedType; - - /// @brief a type for a number (floating-point) - /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/ - using number_float_t = NumberFloatType; - - /// @brief a type for a packed binary type - /// @sa https://json.nlohmann.me/api/basic_json/binary_t/ - using binary_t = nlohmann::byte_container_with_subtype<BinaryType>; - - /// @brief object key comparator type - /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/ - using object_comparator_t = detail::actual_object_comparator_t<basic_json>; - - /// @} - - private: - - /// helper for exception-safe object creation - template<typename T, typename... Args> - JSON_HEDLEY_RETURNS_NON_NULL - static T* create(Args&& ... args) - { - AllocatorType<T> alloc; - using AllocatorTraits = std::allocator_traits<AllocatorType<T>>; - - auto deleter = [&](T * obj) - { - AllocatorTraits::deallocate(alloc, obj, 1); - }; - std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter); - AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...); - JSON_ASSERT(obj != nullptr); - return obj.release(); - } - - //////////////////////// - // JSON value storage // - //////////////////////// - - JSON_PRIVATE_UNLESS_TESTED: - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - binary | binary | pointer to @ref binary_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// binary (stored with pointer to save storage) - binary_t* binary; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create<object_t>(); - break; - } - - case value_t::array: - { - array = create<array_t>(); - break; - } - - case value_t::string: - { - string = create<string_t>(""); - break; - } - - case value_t::binary: - { - binary = create<binary_t>(); - break; - } - - case value_t::boolean: - { - boolean = static_cast<boolean_t>(false); - break; - } - - case value_t::number_integer: - { - number_integer = static_cast<number_integer_t>(0); - break; - } - - case value_t::number_unsigned: - { - number_unsigned = static_cast<number_unsigned_t>(0); - break; - } - - case value_t::number_float: - { - number_float = static_cast<number_float_t>(0.0); - break; - } - - case value_t::null: - { - object = nullptr; // silence warning, see #821 - break; - } - - case value_t::discarded: - default: - { - object = nullptr; // silence warning, see #821 - if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) - { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE - } - break; - } - } - } - - /// constructor for strings - json_value(const string_t& value) : string(create<string_t>(value)) {} - - /// constructor for rvalue strings - json_value(string_t&& value) : string(create<string_t>(std::move(value))) {} - - /// constructor for objects - json_value(const object_t& value) : object(create<object_t>(value)) {} - - /// constructor for rvalue objects - json_value(object_t&& value) : object(create<object_t>(std::move(value))) {} - - /// constructor for arrays - json_value(const array_t& value) : array(create<array_t>(value)) {} - - /// constructor for rvalue arrays - json_value(array_t&& value) : array(create<array_t>(std::move(value))) {} - - /// constructor for binary arrays - json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {} - - /// constructor for rvalue binary arrays - json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {} - - /// constructor for binary arrays (internal type) - json_value(const binary_t& value) : binary(create<binary_t>(value)) {} - - /// constructor for rvalue binary arrays (internal type) - json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {} - - void destroy(value_t t) - { - if ( - (t == value_t::object && object == nullptr) || - (t == value_t::array && array == nullptr) || - (t == value_t::string && string == nullptr) || - (t == value_t::binary && binary == nullptr) - ) - { - //not initialized (e.g. due to exception in the ctor) - return; - } - if (t == value_t::array || t == value_t::object) - { - // flatten the current json_value to a heap-allocated stack - std::vector<basic_json> stack; - - // move the top-level items to stack - if (t == value_t::array) - { - stack.reserve(array->size()); - std::move(array->begin(), array->end(), std::back_inserter(stack)); - } - else - { - stack.reserve(object->size()); - for (auto&& it : *object) - { - stack.push_back(std::move(it.second)); - } - } - - while (!stack.empty()) - { - // move the last item to local variable to be processed - basic_json current_item(std::move(stack.back())); - stack.pop_back(); - - // if current_item is array/object, move - // its children to the stack to be processed later - if (current_item.is_array()) - { - std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack)); - - current_item.m_data.m_value.array->clear(); - } - else if (current_item.is_object()) - { - for (auto&& it : *current_item.m_data.m_value.object) - { - stack.push_back(std::move(it.second)); - } - - current_item.m_data.m_value.object->clear(); - } - - // it's now safe that current_item get destructed - // since it doesn't have any children - } - } - - switch (t) - { - case value_t::object: - { - AllocatorType<object_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, object); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1); - break; - } - - case value_t::array: - { - AllocatorType<array_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, array); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1); - break; - } - - case value_t::string: - { - AllocatorType<string_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, string); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1); - break; - } - - case value_t::binary: - { - AllocatorType<binary_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, binary); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1); - break; - } - - case value_t::null: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::discarded: - default: - { - break; - } - } - } - }; - - private: - /*! - @brief checks the class invariants - - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - - Furthermore, the parent relation is checked for arrays and objects: If - @a check_parents true and the value is an array or object, then the - container's elements must have the current value as parent. - - @param[in] check_parents whether the parent relation should be checked. - The value is true by default and should only be set to false - during destruction of objects when the invariant does not - need to hold. - */ - void assert_invariant(bool check_parents = true) const noexcept - { - JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr); - JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr); - JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr); - JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr); - -#if JSON_DIAGNOSTICS - JSON_TRY - { - // cppcheck-suppress assertWithSideEffect - JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) - { - return j.m_parent == this; - })); - } - JSON_CATCH(...) {} // LCOV_EXCL_LINE -#endif - static_cast<void>(check_parents); - } - - void set_parents() - { -#if JSON_DIAGNOSTICS - switch (m_data.m_type) - { - case value_t::array: - { - for (auto& element : *m_data.m_value.array) - { - element.m_parent = this; - } - break; - } - - case value_t::object: - { - for (auto& element : *m_data.m_value.object) - { - element.second.m_parent = this; - } - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - break; - } -#endif - } - - iterator set_parents(iterator it, typename iterator::difference_type count_set_parents) - { -#if JSON_DIAGNOSTICS - for (typename iterator::difference_type i = 0; i < count_set_parents; ++i) - { - (it + i)->m_parent = this; - } -#else - static_cast<void>(count_set_parents); -#endif - return it; - } - - reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1)) - { -#if JSON_DIAGNOSTICS - if (old_capacity != static_cast<std::size_t>(-1)) - { - // see https://github.com/nlohmann/json/issues/2838 - JSON_ASSERT(type() == value_t::array); - if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity)) - { - // capacity has changed: update all parents - set_parents(); - return j; - } - } - - // ordered_json uses a vector internally, so pointers could have - // been invalidated; see https://github.com/nlohmann/json/issues/2962 -#ifdef JSON_HEDLEY_MSVC_VERSION -#pragma warning(push ) -#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr -#endif - if (detail::is_ordered_map<object_t>::value) - { - set_parents(); - return j; - } -#ifdef JSON_HEDLEY_MSVC_VERSION -#pragma warning( pop ) -#endif - - j.m_parent = this; -#else - static_cast<void>(j); - static_cast<void>(old_capacity); -#endif - return j; - } - - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /// @brief parser event types - /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/ - using parse_event_t = detail::parse_event_t; - - /// @brief per-element parser callback type - /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/ - using parser_callback_t = detail::parser_callback_t<basic_json>; - - ////////////////// - // constructors // - ////////////////// - - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ - - /// @brief create an empty value with a given type - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(const value_t v) - : m_data(v) - { - assert_invariant(); - } - - /// @brief create a null object - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape) - : basic_json(value_t::null) - { - assert_invariant(); - } - - /// @brief create a JSON value from compatible types - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - template < typename CompatibleType, - typename U = detail::uncvref_t<CompatibleType>, - detail::enable_if_t < - !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 > - basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) - JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), - std::forward<CompatibleType>(val)))) - { - JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val)); - set_parents(); - assert_invariant(); - } - - /// @brief create a JSON value from an existing one - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - template < typename BasicJsonType, - detail::enable_if_t < - detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 > - basic_json(const BasicJsonType& val) - { - using other_boolean_t = typename BasicJsonType::boolean_t; - using other_number_float_t = typename BasicJsonType::number_float_t; - using other_number_integer_t = typename BasicJsonType::number_integer_t; - using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using other_string_t = typename BasicJsonType::string_t; - using other_object_t = typename BasicJsonType::object_t; - using other_array_t = typename BasicJsonType::array_t; - using other_binary_t = typename BasicJsonType::binary_t; - - switch (val.type()) - { - case value_t::boolean: - JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>()); - break; - case value_t::number_float: - JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>()); - break; - case value_t::number_integer: - JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>()); - break; - case value_t::number_unsigned: - JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>()); - break; - case value_t::string: - JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>()); - break; - case value_t::object: - JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>()); - break; - case value_t::array: - JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>()); - break; - case value_t::binary: - JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>()); - break; - case value_t::null: - *this = nullptr; - break; - case value_t::discarded: - m_data.m_type = value_t::discarded; - break; - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - JSON_ASSERT(m_data.m_type == val.type()); - set_parents(); - assert_invariant(); - } - - /// @brief create a container (array or object) from an initializer list - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(initializer_list_t init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const detail::json_ref<basic_json>& element_ref) - { - // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int; - // (many string types can be constructed from 0 via its null-pointer guise, so we get a - // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows) - return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string(); - }); - - // adjust type if type deduction is not wanted - if (!type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } - - // if object is wanted but impossible, throw an exception - if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) - { - JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr)); - } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_data.m_type = value_t::object; - m_data.m_value = value_t::object; - - for (auto& element_ref : init) - { - auto element = element_ref.moved_or_copied(); - m_data.m_value.object->emplace( - std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)), - std::move((*element.m_data.m_value.array)[1])); - } - } - else - { - // the initializer list describes an array -> create array - m_data.m_type = value_t::array; - m_data.m_value.array = create<array_t>(init.begin(), init.end()); - } - - set_parents(); - assert_invariant(); - } - - /// @brief explicitly create a binary array (without subtype) - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init) - { - auto res = basic_json(); - res.m_data.m_type = value_t::binary; - res.m_data.m_value = init; - return res; - } - - /// @brief explicitly create a binary array (with subtype) - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) - { - auto res = basic_json(); - res.m_data.m_type = value_t::binary; - res.m_data.m_value = binary_t(init, subtype); - return res; - } - - /// @brief explicitly create a binary array - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init) - { - auto res = basic_json(); - res.m_data.m_type = value_t::binary; - res.m_data.m_value = std::move(init); - return res; - } - - /// @brief explicitly create a binary array (with subtype) - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) - { - auto res = basic_json(); - res.m_data.m_type = value_t::binary; - res.m_data.m_value = binary_t(std::move(init), subtype); - return res; - } - - /// @brief explicitly create an array from an initializer list - /// @sa https://json.nlohmann.me/api/basic_json/array/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json array(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::array); - } - - /// @brief explicitly create an object from an initializer list - /// @sa https://json.nlohmann.me/api/basic_json/object/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json object(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::object); - } - - /// @brief construct an array with count copies of given value - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(size_type cnt, const basic_json& val): - m_data{cnt, val} - { - set_parents(); - assert_invariant(); - } - - /// @brief construct a JSON container given an iterator range - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - template < class InputIT, typename std::enable_if < - std::is_same<InputIT, typename basic_json_t::iterator>::value || - std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 > - basic_json(InputIT first, InputIT last) - { - JSON_ASSERT(first.m_object != nullptr); - JSON_ASSERT(last.m_object != nullptr); - - // make sure iterator fits the current value - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr)); - } - - // copy type from first iterator - m_data.m_type = first.m_object->m_data.m_type; - - // check if iterator range is complete for primitive values - switch (m_data.m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() - || !last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object)); - } - break; - } - - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::binary: - case value_t::discarded: - default: - break; - } - - switch (m_data.m_type) - { - case value_t::number_integer: - { - m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_data.m_value.number_float = first.m_object->m_data.m_value.number_float; - break; - } - - case value_t::boolean: - { - m_data.m_value.boolean = first.m_object->m_data.m_value.boolean; - break; - } - - case value_t::string: - { - m_data.m_value = *first.m_object->m_data.m_value.string; - break; - } - - case value_t::object: - { - m_data.m_value.object = create<object_t>(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - m_data.m_value.array = create<array_t>(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - case value_t::binary: - { - m_data.m_value = *first.m_object->m_data.m_value.binary; - break; - } - - case value_t::null: - case value_t::discarded: - default: - JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); - } - - set_parents(); - assert_invariant(); - } - - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// - - template<typename JsonRef, - detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>, - std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 > - basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} - - /// @brief copy constructor - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(const basic_json& other) - : json_base_class_t(other) - { - m_data.m_type = other.m_data.m_type; - // check of passed value is valid - other.assert_invariant(); - - switch (m_data.m_type) - { - case value_t::object: - { - m_data.m_value = *other.m_data.m_value.object; - break; - } - - case value_t::array: - { - m_data.m_value = *other.m_data.m_value.array; - break; - } - - case value_t::string: - { - m_data.m_value = *other.m_data.m_value.string; - break; - } - - case value_t::boolean: - { - m_data.m_value = other.m_data.m_value.boolean; - break; - } - - case value_t::number_integer: - { - m_data.m_value = other.m_data.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_data.m_value = other.m_data.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_data.m_value = other.m_data.m_value.number_float; - break; - } - - case value_t::binary: - { - m_data.m_value = *other.m_data.m_value.binary; - break; - } - - case value_t::null: - case value_t::discarded: - default: - break; - } - - set_parents(); - assert_invariant(); - } - - /// @brief move constructor - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(basic_json&& other) noexcept - : json_base_class_t(std::forward<json_base_class_t>(other)), - m_data(std::move(other.m_data)) - { - // check that passed value is valid - other.assert_invariant(false); - - // invalidate payload - other.m_data.m_type = value_t::null; - other.m_data.m_value = {}; - - set_parents(); - assert_invariant(); - } - - /// @brief copy assignment - /// @sa https://json.nlohmann.me/api/basic_json/operator=/ - basic_json& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible<value_t>::value&& - std::is_nothrow_move_assignable<value_t>::value&& - std::is_nothrow_move_constructible<json_value>::value&& - std::is_nothrow_move_assignable<json_value>::value&& - std::is_nothrow_move_assignable<json_base_class_t>::value - ) - { - // check that passed value is valid - other.assert_invariant(); - - using std::swap; - swap(m_data.m_type, other.m_data.m_type); - swap(m_data.m_value, other.m_data.m_value); - json_base_class_t::operator=(std::move(other)); - - set_parents(); - assert_invariant(); - return *this; - } - - /// @brief destructor - /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/ - ~basic_json() noexcept - { - assert_invariant(false); - } - - /// @} - - public: - /////////////////////// - // object inspection // - /////////////////////// - - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ - - /// @brief serialization - /// @sa https://json.nlohmann.me/api/basic_json/dump/ - string_t dump(const int indent = -1, - const char indent_char = ' ', - const bool ensure_ascii = false, - const error_handler_t error_handler = error_handler_t::strict) const - { - string_t result; - serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler); - - if (indent >= 0) - { - s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent)); - } - else - { - s.dump(*this, false, ensure_ascii, 0); - } - - return result; - } - - /// @brief return the type of the JSON value (explicit) - /// @sa https://json.nlohmann.me/api/basic_json/type/ - constexpr value_t type() const noexcept - { - return m_data.m_type; - } - - /// @brief return whether type is primitive - /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ - constexpr bool is_primitive() const noexcept - { - return is_null() || is_string() || is_boolean() || is_number() || is_binary(); - } - - /// @brief return whether type is structured - /// @sa https://json.nlohmann.me/api/basic_json/is_structured/ - constexpr bool is_structured() const noexcept - { - return is_array() || is_object(); - } - - /// @brief return whether value is null - /// @sa https://json.nlohmann.me/api/basic_json/is_null/ - constexpr bool is_null() const noexcept - { - return m_data.m_type == value_t::null; - } - - /// @brief return whether value is a boolean - /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ - constexpr bool is_boolean() const noexcept - { - return m_data.m_type == value_t::boolean; - } - - /// @brief return whether value is a number - /// @sa https://json.nlohmann.me/api/basic_json/is_number/ - constexpr bool is_number() const noexcept - { - return is_number_integer() || is_number_float(); - } - - /// @brief return whether value is an integer number - /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ - constexpr bool is_number_integer() const noexcept - { - return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned; - } - - /// @brief return whether value is an unsigned integer number - /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ - constexpr bool is_number_unsigned() const noexcept - { - return m_data.m_type == value_t::number_unsigned; - } - - /// @brief return whether value is a floating-point number - /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ - constexpr bool is_number_float() const noexcept - { - return m_data.m_type == value_t::number_float; - } - - /// @brief return whether value is an object - /// @sa https://json.nlohmann.me/api/basic_json/is_object/ - constexpr bool is_object() const noexcept - { - return m_data.m_type == value_t::object; - } - - /// @brief return whether value is an array - /// @sa https://json.nlohmann.me/api/basic_json/is_array/ - constexpr bool is_array() const noexcept - { - return m_data.m_type == value_t::array; - } - - /// @brief return whether value is a string - /// @sa https://json.nlohmann.me/api/basic_json/is_string/ - constexpr bool is_string() const noexcept - { - return m_data.m_type == value_t::string; - } - - /// @brief return whether value is a binary array - /// @sa https://json.nlohmann.me/api/basic_json/is_binary/ - constexpr bool is_binary() const noexcept - { - return m_data.m_type == value_t::binary; - } - - /// @brief return whether value is discarded - /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ - constexpr bool is_discarded() const noexcept - { - return m_data.m_type == value_t::discarded; - } - - /// @brief return the type of the JSON value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/ - constexpr operator value_t() const noexcept - { - return m_data.m_type; - } - - /// @} - - private: - ////////////////// - // value access // - ////////////////// - - /// get a boolean (explicit) - boolean_t get_impl(boolean_t* /*unused*/) const - { - if (JSON_HEDLEY_LIKELY(is_boolean())) - { - return m_data.m_value.boolean; - } - - JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this)); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t* /*unused*/) noexcept - { - return is_object() ? m_data.m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept - { - return is_object() ? m_data.m_value.object : nullptr; - } - - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t* /*unused*/) noexcept - { - return is_array() ? m_data.m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept - { - return is_array() ? m_data.m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t* /*unused*/) noexcept - { - return is_string() ? m_data.m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept - { - return is_string() ? m_data.m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept - { - return is_boolean() ? &m_data.m_value.boolean : nullptr; - } - - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept - { - return is_boolean() ? &m_data.m_value.boolean : nullptr; - } - - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept - { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; - } - - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept - { - return is_number_integer() ? &m_data.m_value.number_integer : nullptr; - } - - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept - { - return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept - { - return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept - { - return is_number_float() ? &m_data.m_value.number_float : nullptr; - } - - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept - { - return is_number_float() ? &m_data.m_value.number_float : nullptr; - } - - /// get a pointer to the value (binary) - binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept - { - return is_binary() ? m_data.m_value.binary : nullptr; - } - - /// get a pointer to the value (binary) - constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept - { - return is_binary() ? m_data.m_value.binary : nullptr; - } - - /*! - @brief helper function to implement get_ref() - - This function helps to implement get_ref() without code duplication for - const and non-const overloads - - @tparam ThisType will be deduced as `basic_json` or `const basic_json` - - @throw type_error.303 if ReferenceType does not match underlying value - type of the current JSON - */ - template<typename ReferenceType, typename ThisType> - static ReferenceType get_ref_impl(ThisType& obj) - { - // delegate the call to get_ptr<>() - auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>(); - - if (JSON_HEDLEY_LIKELY(ptr != nullptr)) - { - return *ptr; - } - - JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); - } - - public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /// @brief get a pointer value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) - { - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast<PointerType>(nullptr)); - } - - /// @brief get a pointer value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ - template < typename PointerType, typename std::enable_if < - std::is_pointer<PointerType>::value&& - std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 > - constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) - { - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast<PointerType>(nullptr)); - } - - private: - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value - which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) - and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). - The value is converted by calling the @ref json_serializer<ValueType> - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - ValueType ret; - JSONSerializer<ValueType>::from_json(*this, ret); - return ret; - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json, - - @ref json_serializer<ValueType> has a `from_json()` method of the form - `void from_json(const basic_json&, ValueType&)`, and - - @ref json_serializer<ValueType> does not have a `from_json()` method of - the form `ValueType from_json(const basic_json&)` - - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer<ValueType> `from_json()` method throws - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector<short>`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map<std::string\, - json>`.,get__ValueType_const} - - @since version 2.1.0 - */ - template < typename ValueType, - detail::enable_if_t < - detail::is_default_constructible<ValueType>::value&& - detail::has_from_json<basic_json_t, ValueType>::value, - int > = 0 > - ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( - JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>()))) - { - auto ret = ValueType(); - JSONSerializer<ValueType>::from_json(*this, ret); - return ret; - } - - /*! - @brief get a value (explicit); special case - - Explicit type conversion between the JSON value and a compatible value - which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) - and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). - The value is converted by calling the @ref json_serializer<ValueType> - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - return JSONSerializer<ValueType>::from_json(*this); - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json and - - @ref json_serializer<ValueType> has a `from_json()` method of the form - `ValueType from_json(const basic_json&)` - - @note If @ref json_serializer<ValueType> has both overloads of - `from_json()`, this one is chosen. - - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer<ValueType> `from_json()` method throws - - @since version 2.1.0 - */ - template < typename ValueType, - detail::enable_if_t < - detail::has_non_default_from_json<basic_json_t, ValueType>::value, - int > = 0 > - ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( - JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>()))) - { - return JSONSerializer<ValueType>::from_json(*this); - } - - /*! - @brief get special-case overload - - This overloads converts the current @ref basic_json in a different - @ref basic_json type - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this, converted into @a BasicJsonType - - @complexity Depending on the implementation of the called `from_json()` - method. - - @since version 3.2.0 - */ - template < typename BasicJsonType, - detail::enable_if_t < - detail::is_basic_json<BasicJsonType>::value, - int > = 0 > - BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const - { - return *this; - } - - /*! - @brief get special-case overload - - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this - - @complexity Constant. - - @since version 2.1.0 - */ - template<typename BasicJsonType, - detail::enable_if_t< - std::is_same<BasicJsonType, basic_json_t>::value, - int> = 0> - basic_json get_impl(detail::priority_tag<3> /*unused*/) const - { - return *this; - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template<typename PointerType, - detail::enable_if_t< - std::is_pointer<PointerType>::value, - int> = 0> - constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept - -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>()) - { - // delegate the call to get_ptr - return get_ptr<PointerType>(); - } - - public: - /*! - @brief get a (pointer) value (explicit) - - Performs explicit type conversion between the JSON value and a compatible value if required. - - - If the requested type is a pointer to the internally stored JSON value that pointer is returned. - No copies are made. - - - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible - from the current @ref basic_json. - - - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()` - method. - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @tparam ValueType if necessary - - @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required - - @since version 2.1.0 - */ - template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>> -#if defined(JSON_HAS_CPP_14) - constexpr -#endif - auto get() const noexcept( - noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))) - -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})) - { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get<const basic_json_t>(), which is why we - // still need the uncvref - static_assert(!std::is_reference<ValueTypeCV>::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - return get_impl<ValueType>(detail::priority_tag<4> {}); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa see @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>()) - { - // delegate the call to get_ptr - return get_ptr<PointerType>(); - } - - /// @brief get a value (explicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_to/ - template < typename ValueType, - detail::enable_if_t < - !detail::is_basic_json<ValueType>::value&& - detail::has_from_json<basic_json_t, ValueType>::value, - int > = 0 > - ValueType & get_to(ValueType& v) const noexcept(noexcept( - JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v))) - { - JSONSerializer<ValueType>::from_json(*this, v); - return v; - } - - // specialization to allow calling get_to with a basic_json value - // see https://github.com/nlohmann/json/issues/2175 - template<typename ValueType, - detail::enable_if_t < - detail::is_basic_json<ValueType>::value, - int> = 0> - ValueType & get_to(ValueType& v) const - { - v = *this; - return v; - } - - template < - typename T, std::size_t N, - typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - detail::enable_if_t < - detail::has_from_json<basic_json_t, Array>::value, int > = 0 > - Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - noexcept(noexcept(JSONSerializer<Array>::from_json( - std::declval<const basic_json_t&>(), v))) - { - JSONSerializer<Array>::from_json(*this, v); - return v; - } - - /// @brief get a reference value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ - template<typename ReferenceType, typename std::enable_if< - std::is_reference<ReferenceType>::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl<ReferenceType>(*this); - } - - /// @brief get a reference value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ - template < typename ReferenceType, typename std::enable_if < - std::is_reference<ReferenceType>::value&& - std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 > - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl<ReferenceType>(*this); - } - - /*! - @brief get a value (implicit) - - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. - - @return copy of the JSON value, converted to type @a ValueType - - @throw type_error.302 in case passed type @a ValueType is incompatible - to the JSON value type (e.g., the JSON value is of type boolean, but a - string is requested); see example below - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector<short>`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map<std::string\, - json>`.,operator__ValueType} - - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - detail::conjunction < - detail::negation<std::is_pointer<ValueType>>, - detail::negation<std::is_same<ValueType, std::nullptr_t>>, - detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>, - detail::negation<std::is_same<ValueType, typename string_t::value_type>>, - detail::negation<detail::is_basic_json<ValueType>>, - detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>, -#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) - detail::negation<std::is_same<ValueType, std::string_view>>, -#endif -#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI - detail::negation<std::is_same<ValueType, std::any>>, -#endif - detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType> - >::value, int >::type = 0 > - JSON_EXPLICIT operator ValueType() const - { - // delegate the call to get<>() const - return get<ValueType>(); - } - - /// @brief get a binary value - /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ - binary_t& get_binary() - { - if (!is_binary()) - { - JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this)); - } - - return *get_ptr<binary_t*>(); - } - - /// @brief get a binary value - /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ - const binary_t& get_binary() const - { - if (!is_binary()) - { - JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this)); - } - - return *get_ptr<const binary_t*>(); - } - - /// @} - - //////////////////// - // element access // - //////////////////// - - /// @name element access - /// Access to the JSON value. - /// @{ - - /// @brief access specified array element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - reference at(size_type idx) - { - // at only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - JSON_TRY - { - return set_parent(m_data.m_value.array->at(idx)); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } - } - else - { - JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); - } - } - - /// @brief access specified array element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - const_reference at(size_type idx) const - { - // at only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - JSON_TRY - { - return m_data.m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } - } - else - { - JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); - } - } - - /// @brief access specified object element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); - } - - auto it = m_data.m_value.object->find(key); - if (it == m_data.m_value.object->end()) - { - JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this)); - } - return set_parent(it->second); - } - - /// @brief access specified object element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - reference at(KeyType && key) - { - // at only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); - } - - auto it = m_data.m_value.object->find(std::forward<KeyType>(key)); - if (it == m_data.m_value.object->end()) - { - JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this)); - } - return set_parent(it->second); - } - - /// @brief access specified object element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); - } - - auto it = m_data.m_value.object->find(key); - if (it == m_data.m_value.object->end()) - { - JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this)); - } - return it->second; - } - - /// @brief access specified object element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - const_reference at(KeyType && key) const - { - // at only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this)); - } - - auto it = m_data.m_value.object->find(std::forward<KeyType>(key)); - if (it == m_data.m_value.object->end()) - { - JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this)); - } - return it->second; - } - - /// @brief access specified array element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_data.m_type = value_t::array; - m_data.m_value.array = create<array_t>(); - assert_invariant(); - } - - // operator[] only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - // fill up array with null values if given idx is outside range - if (idx >= m_data.m_value.array->size()) - { -#if JSON_DIAGNOSTICS - // remember array size & capacity before resizing - const auto old_size = m_data.m_value.array->size(); - const auto old_capacity = m_data.m_value.array->capacity(); -#endif - m_data.m_value.array->resize(idx + 1); - -#if JSON_DIAGNOSTICS - if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity)) - { - // capacity has changed: update all parents - set_parents(); - } - else - { - // set parent for values added above - set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size)); - } -#endif - assert_invariant(); - } - - return m_data.m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this)); - } - - /// @brief access specified array element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - return m_data.m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](typename object_t::key_type key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_data.m_type = value_t::object; - m_data.m_value.object = create<object_t>(); - assert_invariant(); - } - - // operator[] only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - auto result = m_data.m_value.object->emplace(std::move(key), nullptr); - return set_parent(result.first->second); - } - - JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - auto it = m_data.m_value.object->find(key); - JSON_ASSERT(it != m_data.m_value.object->end()); - return it->second; - } - - JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); - } - - // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC - // (they seemingly cannot be constrained to resolve the ambiguity) - template<typename T> - reference operator[](T* key) - { - return operator[](typename object_t::key_type(key)); - } - - template<typename T> - const_reference operator[](T* key) const - { - return operator[](typename object_t::key_type(key)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 > - reference operator[](KeyType && key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_data.m_type = value_t::object; - m_data.m_value.object = create<object_t>(); - assert_invariant(); - } - - // operator[] only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr); - return set_parent(result.first->second); - } - - JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 > - const_reference operator[](KeyType && key) const - { - // const operator[] only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - auto it = m_data.m_value.object->find(std::forward<KeyType>(key)); - JSON_ASSERT(it != m_data.m_value.object->end()); - return it->second; - } - - JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this)); - } - - private: - template<typename KeyType> - using is_comparable_with_object_key = detail::is_comparable < - object_comparator_t, const typename object_t::key_type&, KeyType >; - - template<typename ValueType> - using value_return_type = std::conditional < - detail::is_c_string_uncvref<ValueType>::value, - string_t, typename std::decay<ValueType>::type >; - - public: - /// @brief access specified object element with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template < class ValueType, detail::enable_if_t < - !detail::is_transparent<object_comparator_t>::value - && detail::is_getable<basic_json_t, ValueType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const - { - // value only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return it->template get<ValueType>(); - } - - return default_value; - } - - JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); - } - - /// @brief access specified object element with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type, - detail::enable_if_t < - !detail::is_transparent<object_comparator_t>::value - && detail::is_getable<basic_json_t, ReturnType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const - { - // value only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return it->template get<ReturnType>(); - } - - return std::forward<ValueType>(default_value); - } - - JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); - } - - /// @brief access specified object element with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template < class ValueType, class KeyType, detail::enable_if_t < - detail::is_transparent<object_comparator_t>::value - && !detail::is_json_pointer<KeyType>::value - && is_comparable_with_object_key<KeyType>::value - && detail::is_getable<basic_json_t, ValueType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - ValueType value(KeyType && key, const ValueType& default_value) const - { - // value only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(std::forward<KeyType>(key)); - if (it != end()) - { - return it->template get<ValueType>(); - } - - return default_value; - } - - JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); - } - - /// @brief access specified object element via JSON Pointer with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type, - detail::enable_if_t < - detail::is_transparent<object_comparator_t>::value - && !detail::is_json_pointer<KeyType>::value - && is_comparable_with_object_key<KeyType>::value - && detail::is_getable<basic_json_t, ReturnType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - ReturnType value(KeyType && key, ValueType && default_value) const - { - // value only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(std::forward<KeyType>(key)); - if (it != end()) - { - return it->template get<ReturnType>(); - } - - return std::forward<ValueType>(default_value); - } - - JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); - } - - /// @brief access specified object element via JSON Pointer with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template < class ValueType, detail::enable_if_t < - detail::is_getable<basic_json_t, ValueType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - ValueType value(const json_pointer& ptr, const ValueType& default_value) const - { - // value only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this).template get<ValueType>(); - } - JSON_INTERNAL_CATCH (out_of_range&) - { - return default_value; - } - } - - JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); - } - - /// @brief access specified object element via JSON Pointer with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type, - detail::enable_if_t < - detail::is_getable<basic_json_t, ReturnType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - ReturnType value(const json_pointer& ptr, ValueType && default_value) const - { - // value only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this).template get<ReturnType>(); - } - JSON_INTERNAL_CATCH (out_of_range&) - { - return std::forward<ValueType>(default_value); - } - } - - JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this)); - } - - template < class ValueType, class BasicJsonType, detail::enable_if_t < - detail::is_basic_json<BasicJsonType>::value - && detail::is_getable<basic_json_t, ValueType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const - { - return value(ptr.convert(), default_value); - } - - template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type, - detail::enable_if_t < - detail::is_basic_json<BasicJsonType>::value - && detail::is_getable<basic_json_t, ReturnType>::value - && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 > - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const - { - return value(ptr.convert(), std::forward<ValueType>(default_value)); - } - - /// @brief access the first element - /// @sa https://json.nlohmann.me/api/basic_json/front/ - reference front() - { - return *begin(); - } - - /// @brief access the first element - /// @sa https://json.nlohmann.me/api/basic_json/front/ - const_reference front() const - { - return *cbegin(); - } - - /// @brief access the last element - /// @sa https://json.nlohmann.me/api/basic_json/back/ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } - - /// @brief access the last element - /// @sa https://json.nlohmann.me/api/basic_json/back/ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } - - /// @brief remove element given an iterator - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - template < class IteratorType, detail::enable_if_t < - std::is_same<IteratorType, typename basic_json_t::iterator>::value || - std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 > - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); - } - - IteratorType result = end(); - - switch (m_data.m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - case value_t::binary: - { - if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) - { - JSON_THROW(invalid_iterator::create(205, "iterator out of range", this)); - } - - if (is_string()) - { - AllocatorType<string_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1); - m_data.m_value.string = nullptr; - } - else if (is_binary()) - { - AllocatorType<binary_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1); - m_data.m_value.binary = nullptr; - } - - m_data.m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator); - break; - } - - case value_t::null: - case value_t::discarded: - default: - JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); - } - - return result; - } - - /// @brief remove elements given an iterator range - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - template < class IteratorType, detail::enable_if_t < - std::is_same<IteratorType, typename basic_json_t::iterator>::value || - std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 > - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) - { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this)); - } - - IteratorType result = end(); - - switch (m_data.m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - case value_t::binary: - { - if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() - || !last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", this)); - } - - if (is_string()) - { - AllocatorType<string_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1); - m_data.m_value.string = nullptr; - } - else if (is_binary()) - { - AllocatorType<binary_t> alloc; - std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary); - std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1); - m_data.m_value.binary = nullptr; - } - - m_data.m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - case value_t::null: - case value_t::discarded: - default: - JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); - } - - return result; - } - - private: - template < typename KeyType, detail::enable_if_t < - detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 > - size_type erase_internal(KeyType && key) - { - // this erase only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); - } - - return m_data.m_value.object->erase(std::forward<KeyType>(key)); - } - - template < typename KeyType, detail::enable_if_t < - !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 > - size_type erase_internal(KeyType && key) - { - // this erase only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); - } - - const auto it = m_data.m_value.object->find(std::forward<KeyType>(key)); - if (it != m_data.m_value.object->end()) - { - m_data.m_value.object->erase(it); - return 1; - } - return 0; - } - - public: - - /// @brief remove element from a JSON object given a key - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - size_type erase(const typename object_t::key_type& key) - { - // the indirection via erase_internal() is added to avoid making this - // function a template and thus de-rank it during overload resolution - return erase_internal(key); - } - - /// @brief remove element from a JSON object given a key - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - size_type erase(KeyType && key) - { - return erase_internal(std::forward<KeyType>(key)); - } - - /// @brief remove element from a JSON array given an index - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - void erase(const size_type idx) - { - // this erase only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - if (JSON_HEDLEY_UNLIKELY(idx >= size())) - { - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); - } - - m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx)); - } - else - { - JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this)); - } - } - - /// @} - - //////////// - // lookup // - //////////// - - /// @name lookup - /// @{ - - /// @brief find an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/find/ - iterator find(const typename object_t::key_type& key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_data.m_value.object->find(key); - } - - return result; - } - - /// @brief find an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/find/ - const_iterator find(const typename object_t::key_type& key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_data.m_value.object->find(key); - } - - return result; - } - - /// @brief find an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/find/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - iterator find(KeyType && key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key)); - } - - return result; - } - - /// @brief find an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/find/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - const_iterator find(KeyType && key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key)); - } - - return result; - } - - /// @brief returns the number of occurrences of a key in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/count/ - size_type count(const typename object_t::key_type& key) const - { - // return 0 for all nonobject types - return is_object() ? m_data.m_value.object->count(key) : 0; - } - - /// @brief returns the number of occurrences of a key in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/count/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - size_type count(KeyType && key) const - { - // return 0 for all nonobject types - return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0; - } - - /// @brief check the existence of an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/contains/ - bool contains(const typename object_t::key_type& key) const - { - return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end(); - } - - /// @brief check the existence of an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/contains/ - template<class KeyType, detail::enable_if_t< - detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0> - bool contains(KeyType && key) const - { - return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end(); - } - - /// @brief check the existence of an element in a JSON object given a JSON pointer - /// @sa https://json.nlohmann.me/api/basic_json/contains/ - bool contains(const json_pointer& ptr) const - { - return ptr.contains(this); - } - - template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const - { - return ptr.contains(this); - } - - /// @} - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ - - /// @brief returns an iterator to the first element - /// @sa https://json.nlohmann.me/api/basic_json/begin/ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } - - /// @brief returns an iterator to the first element - /// @sa https://json.nlohmann.me/api/basic_json/begin/ - const_iterator begin() const noexcept - { - return cbegin(); - } - - /// @brief returns a const iterator to the first element - /// @sa https://json.nlohmann.me/api/basic_json/cbegin/ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } - - /// @brief returns an iterator to one past the last element - /// @sa https://json.nlohmann.me/api/basic_json/end/ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } - - /// @brief returns an iterator to one past the last element - /// @sa https://json.nlohmann.me/api/basic_json/end/ - const_iterator end() const noexcept - { - return cend(); - } - - /// @brief returns an iterator to one past the last element - /// @sa https://json.nlohmann.me/api/basic_json/cend/ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } - - /// @brief returns an iterator to the reverse-beginning - /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - - /// @brief returns an iterator to the reverse-beginning - /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } - - /// @brief returns an iterator to the reverse-end - /// @sa https://json.nlohmann.me/api/basic_json/rend/ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - - /// @brief returns an iterator to the reverse-end - /// @sa https://json.nlohmann.me/api/basic_json/rend/ - const_reverse_iterator rend() const noexcept - { - return crend(); - } - - /// @brief returns a const reverse iterator to the last element - /// @sa https://json.nlohmann.me/api/basic_json/crbegin/ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } - - /// @brief returns a const reverse iterator to one before the first - /// @sa https://json.nlohmann.me/api/basic_json/crend/ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } - - public: - /// @brief wrapper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - /// @deprecated This function is deprecated since 3.1.0 and will be removed in - /// version 4.0.0 of the library. Please use @ref items() instead; - /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. - JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) - static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept - { - return ref.items(); - } - - /// @brief wrapper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - /// @deprecated This function is deprecated since 3.1.0 and will be removed in - /// version 4.0.0 of the library. Please use @ref items() instead; - /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. - JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) - static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept - { - return ref.items(); - } - - /// @brief helper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - iteration_proxy<iterator> items() noexcept - { - return iteration_proxy<iterator>(*this); - } - - /// @brief helper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - iteration_proxy<const_iterator> items() const noexcept - { - return iteration_proxy<const_iterator>(*this); - } - - /// @} - - ////////////// - // capacity // - ////////////// - - /// @name capacity - /// @{ - - /// @brief checks whether the container is empty. - /// @sa https://json.nlohmann.me/api/basic_json/empty/ - bool empty() const noexcept - { - switch (m_data.m_type) - { - case value_t::null: - { - // null values are empty - return true; - } - - case value_t::array: - { - // delegate call to array_t::empty() - return m_data.m_value.array->empty(); - } - - case value_t::object: - { - // delegate call to object_t::empty() - return m_data.m_value.object->empty(); - } - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // all other types are nonempty - return false; - } - } - } - - /// @brief returns the number of elements - /// @sa https://json.nlohmann.me/api/basic_json/size/ - size_type size() const noexcept - { - switch (m_data.m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } - - case value_t::array: - { - // delegate call to array_t::size() - return m_data.m_value.array->size(); - } - - case value_t::object: - { - // delegate call to object_t::size() - return m_data.m_value.object->size(); - } - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // all other types have size 1 - return 1; - } - } - } - - /// @brief returns the maximum possible number of elements - /// @sa https://json.nlohmann.me/api/basic_json/max_size/ - size_type max_size() const noexcept - { - switch (m_data.m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_data.m_value.array->max_size(); - } - - case value_t::object: - { - // delegate call to object_t::max_size() - return m_data.m_value.object->max_size(); - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // all other types have max_size() == size() - return size(); - } - } - } - - /// @} - - /////////////// - // modifiers // - /////////////// - - /// @name modifiers - /// @{ - - /// @brief clears the contents - /// @sa https://json.nlohmann.me/api/basic_json/clear/ - void clear() noexcept - { - switch (m_data.m_type) - { - case value_t::number_integer: - { - m_data.m_value.number_integer = 0; - break; - } - - case value_t::number_unsigned: - { - m_data.m_value.number_unsigned = 0; - break; - } - - case value_t::number_float: - { - m_data.m_value.number_float = 0.0; - break; - } - - case value_t::boolean: - { - m_data.m_value.boolean = false; - break; - } - - case value_t::string: - { - m_data.m_value.string->clear(); - break; - } - - case value_t::binary: - { - m_data.m_value.binary->clear(); - break; - } - - case value_t::array: - { - m_data.m_value.array->clear(); - break; - } - - case value_t::object: - { - m_data.m_value.object->clear(); - break; - } - - case value_t::null: - case value_t::discarded: - default: - break; - } - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) - { - JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); - } - - // transform null object into an array - if (is_null()) - { - m_data.m_type = value_t::array; - m_data.m_value = value_t::array; - assert_invariant(); - } - - // add element to array (move semantics) - const auto old_capacity = m_data.m_value.array->capacity(); - m_data.m_value.array->push_back(std::move(val)); - set_parent(m_data.m_value.array->back(), old_capacity); - // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) - { - JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); - } - - // transform null object into an array - if (is_null()) - { - m_data.m_type = value_t::array; - m_data.m_value = value_t::array; - assert_invariant(); - } - - // add element to array - const auto old_capacity = m_data.m_value.array->capacity(); - m_data.m_value.array->push_back(val); - set_parent(m_data.m_value.array->back(), old_capacity); - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) - { - JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this)); - } - - // transform null object into an object - if (is_null()) - { - m_data.m_type = value_t::object; - m_data.m_value = value_t::object; - assert_invariant(); - } - - // add element to object - auto res = m_data.m_value.object->insert(val); - set_parent(res.first->second); - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(initializer_list_t init) - { - if (is_object() && init.size() == 2 && (*init.begin())->is_string()) - { - basic_json&& key = init.begin()->moved_or_copied(); - push_back(typename object_t::value_type( - std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied())); - } - else - { - push_back(basic_json(init)); - } - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(initializer_list_t init) - { - push_back(init); - return *this; - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/ - template<class... Args> - reference emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) - { - JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this)); - } - - // transform null object into an array - if (is_null()) - { - m_data.m_type = value_t::array; - m_data.m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - const auto old_capacity = m_data.m_value.array->capacity(); - m_data.m_value.array->emplace_back(std::forward<Args>(args)...); - return set_parent(m_data.m_value.array->back(), old_capacity); - } - - /// @brief add an object to an object if key does not exist - /// @sa https://json.nlohmann.me/api/basic_json/emplace/ - template<class... Args> - std::pair<iterator, bool> emplace(Args&& ... args) - { - // emplace only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) - { - JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this)); - } - - // transform null object into an object - if (is_null()) - { - m_data.m_type = value_t::object; - m_data.m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...); - set_parent(res.first->second); - - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; - } - - /// Helper for insertion of an iterator - /// @note: This uses std::distance to support GCC 4.8, - /// see https://github.com/nlohmann/json/pull/1257 - template<typename... Args> - iterator insert_iterator(const_iterator pos, Args&& ... args) - { - iterator result(this); - JSON_ASSERT(m_data.m_value.array != nullptr); - - auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator); - m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...); - result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos; - - // This could have been written as: - // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val); - // but the return value of insert is missing in GCC 4.8, so it is written this way instead. - - set_parents(); - return result; - } - - /// @brief inserts element into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); - } - - // insert to array and return iterator - return insert_iterator(pos, val); - } - - JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); - } - - /// @brief inserts element into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } - - /// @brief inserts copies of element into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); - } - - // insert to array and return iterator - return insert_iterator(pos, cnt, val); - } - - JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); - } - - /// @brief inserts range of elements into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (JSON_HEDLEY_UNLIKELY(!is_array())) - { - JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); - } - - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); - } - - // check if range iterators belong to the same JSON object - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); - } - - if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) - { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this)); - } - - // insert to array and return iterator - return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); - } - - /// @brief inserts elements from initializer list into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, initializer_list_t ilist) - { - // insert only works for arrays - if (JSON_HEDLEY_UNLIKELY(!is_array())) - { - JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); - } - - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); - } - - // insert to array and return iterator - return insert_iterator(pos, ilist.begin(), ilist.end()); - } - - /// @brief inserts range of elements into object - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - void insert(const_iterator first, const_iterator last) - { - // insert only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this)); - } - - // check if range iterators belong to the same JSON object - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); - } - - // passed iterators must belong to objects - if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this)); - } - - m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); - } - - /// @brief updates a JSON object from another object, overwriting existing keys - /// @sa https://json.nlohmann.me/api/basic_json/update/ - void update(const_reference j, bool merge_objects = false) - { - update(j.begin(), j.end(), merge_objects); - } - - /// @brief updates a JSON object from another object, overwriting existing keys - /// @sa https://json.nlohmann.me/api/basic_json/update/ - void update(const_iterator first, const_iterator last, bool merge_objects = false) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_data.m_type = value_t::object; - m_data.m_value.object = create<object_t>(); - assert_invariant(); - } - - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this)); - } - - // check if range iterators belong to the same JSON object - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); - } - - // passed iterators must belong to objects - if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) - { - JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object)); - } - - for (auto it = first; it != last; ++it) - { - if (merge_objects && it.value().is_object()) - { - auto it2 = m_data.m_value.object->find(it.key()); - if (it2 != m_data.m_value.object->end()) - { - it2->second.update(it.value(), true); - continue; - } - } - m_data.m_value.object->operator[](it.key()) = it.value(); -#if JSON_DIAGNOSTICS - m_data.m_value.object->operator[](it.key()).m_parent = this; -#endif - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible<value_t>::value&& - std::is_nothrow_move_assignable<value_t>::value&& - std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - std::is_nothrow_move_assignable<json_value>::value - ) - { - std::swap(m_data.m_type, other.m_data.m_type); - std::swap(m_data.m_value, other.m_data.m_value); - - set_parents(); - other.set_parents(); - assert_invariant(); - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - friend void swap(reference left, reference right) noexcept ( - std::is_nothrow_move_constructible<value_t>::value&& - std::is_nothrow_move_assignable<value_t>::value&& - std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - std::is_nothrow_move_assignable<json_value>::value - ) - { - left.swap(right); - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - { - // swap only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - using std::swap; - swap(*(m_data.m_value.array), other); - } - else - { - JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - { - // swap only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - using std::swap; - swap(*(m_data.m_value.object), other); - } - else - { - JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - { - // swap only works for strings - if (JSON_HEDLEY_LIKELY(is_string())) - { - using std::swap; - swap(*(m_data.m_value.string), other); - } - else - { - JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - { - // swap only works for strings - if (JSON_HEDLEY_LIKELY(is_binary())) - { - using std::swap; - swap(*(m_data.m_value.binary), other); - } - else - { - JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape) - { - // swap only works for strings - if (JSON_HEDLEY_LIKELY(is_binary())) - { - using std::swap; - swap(*(m_data.m_value.binary), other); - } - else - { - JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this)); - } - } - - /// @} - - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// - - /// @name lexicographical comparison operators - /// @{ - - // note parentheses around operands are necessary; see - // https://github.com/nlohmann/json/issues/1530 -#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \ - const auto lhs_type = lhs.type(); \ - const auto rhs_type = rhs.type(); \ - \ - if (lhs_type == rhs_type) /* NOLINT(readability/braces) */ \ - { \ - switch (lhs_type) \ - { \ - case value_t::array: \ - return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array); \ - \ - case value_t::object: \ - return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \ - \ - case value_t::null: \ - return (null_result); \ - \ - case value_t::string: \ - return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \ - \ - case value_t::boolean: \ - return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean); \ - \ - case value_t::number_integer: \ - return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer); \ - \ - case value_t::number_unsigned: \ - return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned); \ - \ - case value_t::number_float: \ - return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float); \ - \ - case value_t::binary: \ - return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary); \ - \ - case value_t::discarded: \ - default: \ - return (unordered_result); \ - } \ - } \ - else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \ - { \ - return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \ - } \ - else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \ - { \ - return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \ - } \ - else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \ - { \ - return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \ - } \ - else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \ - { \ - return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \ - } \ - else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \ - { \ - return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \ - } \ - else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \ - { \ - return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \ - } \ - else if(compares_unordered(lhs, rhs))\ - {\ - return (unordered_result);\ - }\ - \ - return (default_result); - - JSON_PRIVATE_UNLESS_TESTED: - // returns true if: - // - any operand is NaN and the other operand is of number type - // - any operand is discarded - // in legacy mode, discarded values are considered ordered if - // an operation is computed as an odd number of inverses of others - static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept - { - if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number()) - || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number())) - { - return true; - } -#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON - return (lhs.is_discarded() || rhs.is_discarded()) && !inverse; -#else - static_cast<void>(inverse); - return lhs.is_discarded() || rhs.is_discarded(); -#endif - } - - private: - bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept - { - return compares_unordered(*this, rhs, inverse); - } - - public: -#if JSON_HAS_THREE_WAY_COMPARISON - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - bool operator==(const_reference rhs) const noexcept - { -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - const_reference lhs = *this; - JSON_IMPLEMENT_OPERATOR( ==, true, false, false) -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - } - - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - template<typename ScalarType> - requires std::is_scalar_v<ScalarType> - bool operator==(ScalarType rhs) const noexcept - { - return *this == basic_json(rhs); - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - bool operator!=(const_reference rhs) const noexcept - { - if (compares_unordered(rhs, true)) - { - return false; - } - return !operator==(rhs); - } - - /// @brief comparison: 3-way - /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ - std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD* - { - const_reference lhs = *this; - // default_result is used if we cannot compare values. In that case, - // we compare types. - JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD* - std::partial_ordering::equivalent, - std::partial_ordering::unordered, - lhs_type <=> rhs_type) // *NOPAD* - } - - /// @brief comparison: 3-way - /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ - template<typename ScalarType> - requires std::is_scalar_v<ScalarType> - std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD* - { - return *this <=> basic_json(rhs); // *NOPAD* - } - -#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON - // all operators that are computed as an odd number of inverses of others - // need to be overloaded to emulate the legacy comparison behavior - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) - bool operator<=(const_reference rhs) const noexcept - { - if (compares_unordered(rhs, true)) - { - return false; - } - return !(rhs < *this); - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - template<typename ScalarType> - requires std::is_scalar_v<ScalarType> - bool operator<=(ScalarType rhs) const noexcept - { - return *this <= basic_json(rhs); - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) - bool operator>=(const_reference rhs) const noexcept - { - if (compares_unordered(rhs, true)) - { - return false; - } - return !(*this < rhs); - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - template<typename ScalarType> - requires std::is_scalar_v<ScalarType> - bool operator>=(ScalarType rhs) const noexcept - { - return *this >= basic_json(rhs); - } -#endif -#else - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - JSON_IMPLEMENT_OPERATOR( ==, true, false, false) -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - } - - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator==(const_reference lhs, ScalarType rhs) noexcept - { - return lhs == basic_json(rhs); - } - - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator==(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) == rhs; - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - if (compares_unordered(lhs, rhs, true)) - { - return false; - } - return !(lhs == rhs); - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept - { - return lhs != basic_json(rhs); - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) != rhs; - } - - /// @brief comparison: less than - /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - // default_result is used if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type)) - } - - /// @brief comparison: less than - /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator<(const_reference lhs, ScalarType rhs) noexcept - { - return lhs < basic_json(rhs); - } - - /// @brief comparison: less than - /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator<(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) < rhs; - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - if (compares_unordered(lhs, rhs, true)) - { - return false; - } - return !(rhs < lhs); - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept - { - return lhs <= basic_json(rhs); - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) <= rhs; - } - - /// @brief comparison: greater than - /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - // double inverse - if (compares_unordered(lhs, rhs)) - { - return false; - } - return !(lhs <= rhs); - } - - /// @brief comparison: greater than - /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator>(const_reference lhs, ScalarType rhs) noexcept - { - return lhs > basic_json(rhs); - } - - /// @brief comparison: greater than - /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator>(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) > rhs; - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - if (compares_unordered(lhs, rhs, true)) - { - return false; - } - return !(lhs < rhs); - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept - { - return lhs >= basic_json(rhs); - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - template<typename ScalarType, typename std::enable_if< - std::is_scalar<ScalarType>::value, int>::type = 0> - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) >= rhs; - } -#endif - -#undef JSON_IMPLEMENT_OPERATOR - - /// @} - - /////////////////// - // serialization // - /////////////////// - - /// @name serialization - /// @{ -#ifndef JSON_NO_IO - /// @brief serialize to stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = o.width() > 0; - const auto indentation = pretty_print ? o.width() : 0; - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // do the actual serialization - serializer s(detail::output_adapter<char>(o), o.fill()); - s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation)); - return o; - } - - /// @brief serialize to stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ - /// @deprecated This function is deprecated since 3.0.0 and will be removed in - /// version 4.0.0 of the library. Please use - /// operator<<(std::ostream&, const basic_json&) instead; that is, - /// replace calls like `j >> o;` with `o << j;`. - JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } -#endif // JSON_NO_IO - /// @} - - ///////////////////// - // deserialization // - ///////////////////// - - /// @name deserialization - /// @{ - - /// @brief deserialize from a compatible input - /// @sa https://json.nlohmann.me/api/basic_json/parse/ - template<typename InputType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json parse(InputType&& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false) - { - basic_json result; - parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result); - return result; - } - - /// @brief deserialize from a pair of character iterators - /// @sa https://json.nlohmann.me/api/basic_json/parse/ - template<typename IteratorType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json parse(IteratorType first, - IteratorType last, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false) - { - basic_json result; - parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); - return result; - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) - static basic_json parse(detail::span_input_adapter&& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false) - { - basic_json result; - parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); - return result; - } - - /// @brief check if the input is valid JSON - /// @sa https://json.nlohmann.me/api/basic_json/accept/ - template<typename InputType> - static bool accept(InputType&& i, - const bool ignore_comments = false) - { - return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true); - } - - /// @brief check if the input is valid JSON - /// @sa https://json.nlohmann.me/api/basic_json/accept/ - template<typename IteratorType> - static bool accept(IteratorType first, IteratorType last, - const bool ignore_comments = false) - { - return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) - static bool accept(detail::span_input_adapter&& i, - const bool ignore_comments = false) - { - return parser(i.get(), nullptr, false, ignore_comments).accept(true); - } - - /// @brief generate SAX events - /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ - template <typename InputType, typename SAX> - JSON_HEDLEY_NON_NULL(2) - static bool sax_parse(InputType&& i, SAX* sax, - input_format_t format = input_format_t::json, - const bool strict = true, - const bool ignore_comments = false) - { - auto ia = detail::input_adapter(std::forward<InputType>(i)); - return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) - : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); - } - - /// @brief generate SAX events - /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ - template<class IteratorType, class SAX> - JSON_HEDLEY_NON_NULL(3) - static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, - input_format_t format = input_format_t::json, - const bool strict = true, - const bool ignore_comments = false) - { - auto ia = detail::input_adapter(std::move(first), std::move(last)); - return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) - : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); - } - - /// @brief generate SAX events - /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ - /// @deprecated This function is deprecated since 3.8.0 and will be removed in - /// version 4.0.0 of the library. Please use - /// sax_parse(ptr, ptr + len) instead. - template <typename SAX> - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) - JSON_HEDLEY_NON_NULL(2) - static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, - input_format_t format = input_format_t::json, - const bool strict = true, - const bool ignore_comments = false) - { - auto ia = i.get(); - return format == input_format_t::json - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict); - } -#ifndef JSON_NO_IO - /// @brief deserialize from stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ - /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in - /// version 4.0.0 of the library. Please use - /// operator>>(std::istream&, basic_json&) instead; that is, - /// replace calls like `j << i;` with `i >> j;`. - JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - return operator>>(i, j); - } - - /// @brief deserialize from stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - parser(detail::input_adapter(i)).parse(false, j); - return i; - } -#endif // JSON_NO_IO - /// @} - - /////////////////////////// - // convenience functions // - /////////////////////////// - - /// @brief return the type as string - /// @sa https://json.nlohmann.me/api/basic_json/type_name/ - JSON_HEDLEY_RETURNS_NON_NULL - const char* type_name() const noexcept - { - switch (m_data.m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::binary: - return "binary"; - case value_t::discarded: - return "discarded"; - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - default: - return "number"; - } - } - - JSON_PRIVATE_UNLESS_TESTED: - ////////////////////// - // member variables // - ////////////////////// - - struct data - { - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - - data(const value_t v) - : m_type(v), m_value(v) - { - } - - data(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create<array_t>(cnt, val); - } - - data() noexcept = default; - data(data&&) noexcept = default; - data(const data&) noexcept = delete; - data& operator=(data&&) noexcept = delete; - data& operator=(const data&) noexcept = delete; - - ~data() noexcept - { - m_value.destroy(m_type); - } - }; - - data m_data = {}; - -#if JSON_DIAGNOSTICS - /// a pointer to a parent value (for debugging purposes) - basic_json* m_parent = nullptr; -#endif - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - public: - /// @brief create a CBOR serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ - static std::vector<std::uint8_t> to_cbor(const basic_json& j) - { - std::vector<std::uint8_t> result; - to_cbor(j, result); - return result; - } - - /// @brief create a CBOR serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ - static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o) - { - binary_writer<std::uint8_t>(o).write_cbor(j); - } - - /// @brief create a CBOR serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ - static void to_cbor(const basic_json& j, detail::output_adapter<char> o) - { - binary_writer<char>(o).write_cbor(j); - } - - /// @brief create a MessagePack serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ - static std::vector<std::uint8_t> to_msgpack(const basic_json& j) - { - std::vector<std::uint8_t> result; - to_msgpack(j, result); - return result; - } - - /// @brief create a MessagePack serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ - static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o) - { - binary_writer<std::uint8_t>(o).write_msgpack(j); - } - - /// @brief create a MessagePack serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ - static void to_msgpack(const basic_json& j, detail::output_adapter<char> o) - { - binary_writer<char>(o).write_msgpack(j); - } - - /// @brief create a UBJSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ - static std::vector<std::uint8_t> to_ubjson(const basic_json& j, - const bool use_size = false, - const bool use_type = false) - { - std::vector<std::uint8_t> result; - to_ubjson(j, result, use_size, use_type); - return result; - } - - /// @brief create a UBJSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ - static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o, - const bool use_size = false, const bool use_type = false) - { - binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type); - } - - /// @brief create a UBJSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ - static void to_ubjson(const basic_json& j, detail::output_adapter<char> o, - const bool use_size = false, const bool use_type = false) - { - binary_writer<char>(o).write_ubjson(j, use_size, use_type); - } - - /// @brief create a BJData serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ - static std::vector<std::uint8_t> to_bjdata(const basic_json& j, - const bool use_size = false, - const bool use_type = false) - { - std::vector<std::uint8_t> result; - to_bjdata(j, result, use_size, use_type); - return result; - } - - /// @brief create a BJData serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ - static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o, - const bool use_size = false, const bool use_type = false) - { - binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true); - } - - /// @brief create a BJData serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/ - static void to_bjdata(const basic_json& j, detail::output_adapter<char> o, - const bool use_size = false, const bool use_type = false) - { - binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true); - } - - /// @brief create a BSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ - static std::vector<std::uint8_t> to_bson(const basic_json& j) - { - std::vector<std::uint8_t> result; - to_bson(j, result); - return result; - } - - /// @brief create a BSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ - static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o) - { - binary_writer<std::uint8_t>(o).write_bson(j); - } - - /// @brief create a BSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ - static void to_bson(const basic_json& j, detail::output_adapter<char> o) - { - binary_writer<char>(o).write_bson(j); - } - - /// @brief create a JSON value from an input in CBOR format - /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ - template<typename InputType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_cbor(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward<InputType>(i)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in CBOR format - /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ - template<typename IteratorType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_cbor(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); - return res ? result : basic_json(value_t::discarded); - } - - template<typename T> - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) - static basic_json from_cbor(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) - static basic_json from_cbor(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in MessagePack format - /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ - template<typename InputType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_msgpack(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward<InputType>(i)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in MessagePack format - /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ - template<typename IteratorType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_msgpack(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - template<typename T> - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) - static basic_json from_msgpack(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_msgpack(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) - static basic_json from_msgpack(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in UBJSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ - template<typename InputType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_ubjson(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward<InputType>(i)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in UBJSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ - template<typename IteratorType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_ubjson(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - template<typename T> - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) - static basic_json from_ubjson(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_ubjson(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) - static basic_json from_ubjson(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BJData format - /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ - template<typename InputType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bjdata(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward<InputType>(i)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BJData format - /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/ - template<typename IteratorType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bjdata(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ - template<typename InputType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bson(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward<InputType>(i)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ - template<typename IteratorType> - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bson(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - template<typename T> - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) - static basic_json from_bson(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_bson(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) - static basic_json from_bson(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - /// @} - - ////////////////////////// - // JSON Pointer support // - ////////////////////////// - - /// @name JSON Pointer functions - /// @{ - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } - - template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) - { - return ptr.get_unchecked(this); - } - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } - - template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const - { - return ptr.get_unchecked(this); - } - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/at/ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } - - template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) - { - return ptr.get_checked(this); - } - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/at/ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } - - template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0> - JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens) - const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const - { - return ptr.get_checked(this); - } - - /// @brief return flattened JSON value - /// @sa https://json.nlohmann.me/api/basic_json/flatten/ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } - - /// @brief unflatten a previously flattened JSON value - /// @sa https://json.nlohmann.me/api/basic_json/unflatten/ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } - - /// @} - - ////////////////////////// - // JSON Patch functions // - ////////////////////////// - - /// @name JSON Patch functions - /// @{ - - /// @brief applies a JSON patch in-place without copying the object - /// @sa https://json.nlohmann.me/api/basic_json/patch/ - void patch_inplace(const basic_json& json_patch) - { - basic_json& result = *this; - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string & op) - { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } - - return patch_operations::invalid; - }; - - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.empty()) - { - result = val; - return; - } - - // make sure the top element of the pointer exists - json_pointer const top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.back(); - ptr.pop_back(); - // parent must exist when performing patch add per RFC6902 specs - basic_json& parent = result.at(ptr); - - switch (parent.m_data.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = json_pointer::template array_index<basic_json_t>(last_path); - if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) - { - // avoid undefined behavior - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); - } - - // default case: insert add offset - parent.insert(parent.begin() + static_cast<difference_type>(idx), val); - } - break; - } - - // if there exists a parent it cannot be primitive - case value_t::string: // LCOV_EXCL_LINE - case value_t::boolean: // LCOV_EXCL_LINE - case value_t::number_integer: // LCOV_EXCL_LINE - case value_t::number_unsigned: // LCOV_EXCL_LINE - case value_t::number_float: // LCOV_EXCL_LINE - case value_t::binary: // LCOV_EXCL_LINE - case value_t::discarded: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [this, & result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.back(); - ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (JSON_HEDLEY_LIKELY(it != parent.end())) - { - parent.erase(it); - } - else - { - JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this)); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(json_pointer::template array_index<basic_json_t>(last_path)); - } - }; - - // type check: top level value must be an array - if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch)); - } - - // iterate and apply the operations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json & - { - // find value - auto it = val.m_data.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable) - - // check if desired value is present - if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) - { - // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); - } - - // check if result is of type string - if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) - { - // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); - } - - // no error: return value - return it->second; - }; - - // type check: every element of the array must be an object - if (JSON_HEDLEY_UNLIKELY(!val.is_object())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val)); - } - - // collect mandatory members - const auto op = get_value("op", "op", true).template get<std::string>(); - const auto path = get_value(op, "path", true).template get<std::string>(); - json_pointer ptr(path); - - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } - - case patch_operations::remove: - { - operation_remove(ptr); - break; - } - - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } - - case patch_operations::move: - { - const auto from_path = get_value("move", "from", true).template get<std::string>(); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json const v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } - - case patch_operations::copy: - { - const auto from_path = get_value("copy", "from", true).template get<std::string>(); - const json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json const v = result.at(from_ptr); - - // The copy is functionally identical to an "add" - // operation at the target location using the value - // specified in the "from" member. - operation_add(ptr, v); - break; - } - - case patch_operations::test: - { - bool success = false; - JSON_TRY - { - // check if "value" matches the one at "path" - // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); - } - JSON_INTERNAL_CATCH (out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (JSON_HEDLEY_UNLIKELY(!success)) - { - JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); - } - - break; - } - - case patch_operations::invalid: - default: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val)); - } - } - } - } - - /// @brief applies a JSON patch to a copy of the current object - /// @sa https://json.nlohmann.me/api/basic_json/patch/ - basic_json patch(const basic_json& json_patch) const - { - basic_json result = *this; - result.patch_inplace(json_patch); - return result; - } - - /// @brief creates a diff as a JSON patch - /// @sa https://json.nlohmann.me/api/basic_json/diff/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json diff(const basic_json& source, const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) - { - return result; - } - - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - return result; - } - - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - std::size_t i = 0; - while (i < source.size() && i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i))); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // We now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast<difference_type>(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", detail::concat(path, '/', std::to_string(i))} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", detail::concat(path, "/-")}, - {"value", target[i]} - }); - ++i; - } - - break; - } - - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.cbegin(); it != source.cend(); ++it) - { - // escape the key name to be used in a JSON patch - const auto path_key = detail::concat(path, '/', detail::escape(it.key())); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path_key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, {"path", path_key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.cbegin(); it != target.cend(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto path_key = detail::concat(path, '/', detail::escape(it.key())); - result.push_back( - { - {"op", "add"}, {"path", path_key}, - {"value", it.value()} - }); - } - } - - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - break; - } - } - - return result; - } - /// @} - - //////////////////////////////// - // JSON Merge Patch functions // - //////////////////////////////// - - /// @name JSON Merge Patch functions - /// @{ - - /// @brief applies a JSON Merge Patch - /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/ - void merge_patch(const basic_json& apply_patch) - { - if (apply_patch.is_object()) - { - if (!is_object()) - { - *this = object(); - } - for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) - { - if (it.value().is_null()) - { - erase(it.key()); - } - else - { - operator[](it.key()).merge_patch(it.value()); - } - } - } - else - { - *this = apply_patch; - } - } - - /// @} -}; - -/// @brief user-defined to_string function for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/to_string/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) -{ - return j.dump(); -} - -inline namespace literals -{ -inline namespace json_literals -{ - -/// @brief user-defined string literal for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ -JSON_HEDLEY_NON_NULL(1) -#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - inline nlohmann::json operator ""_json(const char* s, std::size_t n) -#else - inline nlohmann::json operator "" _json(const char* s, std::size_t n) -#endif -{ - return nlohmann::json::parse(s, s + n); -} - -/// @brief user-defined string literal for JSON pointer -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ -JSON_HEDLEY_NON_NULL(1) -#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n) -#else - inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) -#endif -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -} // namespace json_literals -} // namespace literals -NLOHMANN_JSON_NAMESPACE_END - -/////////////////////// -// nonmember support // -/////////////////////// - -namespace std // NOLINT(cert-dcl58-cpp) -{ - -/// @brief hash value for JSON objects -/// @sa https://json.nlohmann.me/api/basic_json/std_hash/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp) -{ - std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const - { - return nlohmann::detail::hash(j); - } -}; - -// specialization for std::less<value_t> -template<> -struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679 -{ - /*! - @brief compare two value_t enum values - @since version 3.0.0 - */ - bool operator()(::nlohmann::detail::value_t lhs, - ::nlohmann::detail::value_t rhs) const noexcept - { -#if JSON_HAS_THREE_WAY_COMPARISON - return std::is_lt(lhs <=> rhs); // *NOPAD* -#else - return ::nlohmann::detail::operator<(lhs, rhs); -#endif - } -}; - -// C++20 prohibit function specialization in the std namespace. -#ifndef JSON_HAS_CPP_20 - -/// @brief exchanges the values of two JSON objects -/// @sa https://json.nlohmann.me/api/basic_json/std_swap/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) - is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value) -{ - j1.swap(j2); -} - -#endif - -} // namespace std - -#if JSON_USE_GLOBAL_UDLS - #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) - using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) - #else - using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers) - using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers) - #endif -#endif - -// #include <nlohmann/detail/macro_unscope.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// restore clang diagnostic settings -#if defined(__clang__) - #pragma clang diagnostic pop -#endif - -// clean up -#undef JSON_ASSERT -#undef JSON_INTERNAL_CATCH -#undef JSON_THROW -#undef JSON_PRIVATE_UNLESS_TESTED -#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION -#undef NLOHMANN_BASIC_JSON_TPL -#undef JSON_EXPLICIT -#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL -#undef JSON_INLINE_VARIABLE -#undef JSON_NO_UNIQUE_ADDRESS -#undef JSON_DISABLE_ENUM_SERIALIZATION -#undef JSON_USE_GLOBAL_UDLS - -#ifndef JSON_TEST_KEEP_MACROS - #undef JSON_CATCH - #undef JSON_TRY - #undef JSON_HAS_CPP_11 - #undef JSON_HAS_CPP_14 - #undef JSON_HAS_CPP_17 - #undef JSON_HAS_CPP_20 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #undef JSON_HAS_THREE_WAY_COMPARISON - #undef JSON_HAS_RANGES - #undef JSON_HAS_STATIC_RTTI - #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON -#endif - -// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -#undef JSON_HEDLEY_ALWAYS_INLINE -#undef JSON_HEDLEY_ARM_VERSION -#undef JSON_HEDLEY_ARM_VERSION_CHECK -#undef JSON_HEDLEY_ARRAY_PARAM -#undef JSON_HEDLEY_ASSUME -#undef JSON_HEDLEY_BEGIN_C_DECLS -#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE -#undef JSON_HEDLEY_CLANG_HAS_BUILTIN -#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_CLANG_HAS_EXTENSION -#undef JSON_HEDLEY_CLANG_HAS_FEATURE -#undef JSON_HEDLEY_CLANG_HAS_WARNING -#undef JSON_HEDLEY_COMPCERT_VERSION -#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK -#undef JSON_HEDLEY_CONCAT -#undef JSON_HEDLEY_CONCAT3 -#undef JSON_HEDLEY_CONCAT3_EX -#undef JSON_HEDLEY_CONCAT_EX -#undef JSON_HEDLEY_CONST -#undef JSON_HEDLEY_CONSTEXPR -#undef JSON_HEDLEY_CONST_CAST -#undef JSON_HEDLEY_CPP_CAST -#undef JSON_HEDLEY_CRAY_VERSION -#undef JSON_HEDLEY_CRAY_VERSION_CHECK -#undef JSON_HEDLEY_C_DECL -#undef JSON_HEDLEY_DEPRECATED -#undef JSON_HEDLEY_DEPRECATED_FOR -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#undef JSON_HEDLEY_DIAGNOSTIC_POP -#undef JSON_HEDLEY_DIAGNOSTIC_PUSH -#undef JSON_HEDLEY_DMC_VERSION -#undef JSON_HEDLEY_DMC_VERSION_CHECK -#undef JSON_HEDLEY_EMPTY_BASES -#undef JSON_HEDLEY_EMSCRIPTEN_VERSION -#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK -#undef JSON_HEDLEY_END_C_DECLS -#undef JSON_HEDLEY_FLAGS -#undef JSON_HEDLEY_FLAGS_CAST -#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE -#undef JSON_HEDLEY_GCC_HAS_BUILTIN -#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_GCC_HAS_EXTENSION -#undef JSON_HEDLEY_GCC_HAS_FEATURE -#undef JSON_HEDLEY_GCC_HAS_WARNING -#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK -#undef JSON_HEDLEY_GCC_VERSION -#undef JSON_HEDLEY_GCC_VERSION_CHECK -#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE -#undef JSON_HEDLEY_GNUC_HAS_BUILTIN -#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_GNUC_HAS_EXTENSION -#undef JSON_HEDLEY_GNUC_HAS_FEATURE -#undef JSON_HEDLEY_GNUC_HAS_WARNING -#undef JSON_HEDLEY_GNUC_VERSION -#undef JSON_HEDLEY_GNUC_VERSION_CHECK -#undef JSON_HEDLEY_HAS_ATTRIBUTE -#undef JSON_HEDLEY_HAS_BUILTIN -#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS -#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_HAS_EXTENSION -#undef JSON_HEDLEY_HAS_FEATURE -#undef JSON_HEDLEY_HAS_WARNING -#undef JSON_HEDLEY_IAR_VERSION -#undef JSON_HEDLEY_IAR_VERSION_CHECK -#undef JSON_HEDLEY_IBM_VERSION -#undef JSON_HEDLEY_IBM_VERSION_CHECK -#undef JSON_HEDLEY_IMPORT -#undef JSON_HEDLEY_INLINE -#undef JSON_HEDLEY_INTEL_CL_VERSION -#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK -#undef JSON_HEDLEY_INTEL_VERSION -#undef JSON_HEDLEY_INTEL_VERSION_CHECK -#undef JSON_HEDLEY_IS_CONSTANT -#undef JSON_HEDLEY_IS_CONSTEXPR_ -#undef JSON_HEDLEY_LIKELY -#undef JSON_HEDLEY_MALLOC -#undef JSON_HEDLEY_MCST_LCC_VERSION -#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK -#undef JSON_HEDLEY_MESSAGE -#undef JSON_HEDLEY_MSVC_VERSION -#undef JSON_HEDLEY_MSVC_VERSION_CHECK -#undef JSON_HEDLEY_NEVER_INLINE -#undef JSON_HEDLEY_NON_NULL -#undef JSON_HEDLEY_NO_ESCAPE -#undef JSON_HEDLEY_NO_RETURN -#undef JSON_HEDLEY_NO_THROW -#undef JSON_HEDLEY_NULL -#undef JSON_HEDLEY_PELLES_VERSION -#undef JSON_HEDLEY_PELLES_VERSION_CHECK -#undef JSON_HEDLEY_PGI_VERSION -#undef JSON_HEDLEY_PGI_VERSION_CHECK -#undef JSON_HEDLEY_PREDICT -#undef JSON_HEDLEY_PRINTF_FORMAT -#undef JSON_HEDLEY_PRIVATE -#undef JSON_HEDLEY_PUBLIC -#undef JSON_HEDLEY_PURE -#undef JSON_HEDLEY_REINTERPRET_CAST -#undef JSON_HEDLEY_REQUIRE -#undef JSON_HEDLEY_REQUIRE_CONSTEXPR -#undef JSON_HEDLEY_REQUIRE_MSG -#undef JSON_HEDLEY_RESTRICT -#undef JSON_HEDLEY_RETURNS_NON_NULL -#undef JSON_HEDLEY_SENTINEL -#undef JSON_HEDLEY_STATIC_ASSERT -#undef JSON_HEDLEY_STATIC_CAST -#undef JSON_HEDLEY_STRINGIFY -#undef JSON_HEDLEY_STRINGIFY_EX -#undef JSON_HEDLEY_SUNPRO_VERSION -#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK -#undef JSON_HEDLEY_TINYC_VERSION -#undef JSON_HEDLEY_TINYC_VERSION_CHECK -#undef JSON_HEDLEY_TI_ARMCL_VERSION -#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL2000_VERSION -#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL430_VERSION -#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL6X_VERSION -#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL7X_VERSION -#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK -#undef JSON_HEDLEY_TI_CLPRU_VERSION -#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK -#undef JSON_HEDLEY_TI_VERSION -#undef JSON_HEDLEY_TI_VERSION_CHECK -#undef JSON_HEDLEY_UNAVAILABLE -#undef JSON_HEDLEY_UNLIKELY -#undef JSON_HEDLEY_UNPREDICTABLE -#undef JSON_HEDLEY_UNREACHABLE -#undef JSON_HEDLEY_UNREACHABLE_RETURN -#undef JSON_HEDLEY_VERSION -#undef JSON_HEDLEY_VERSION_DECODE_MAJOR -#undef JSON_HEDLEY_VERSION_DECODE_MINOR -#undef JSON_HEDLEY_VERSION_DECODE_REVISION -#undef JSON_HEDLEY_VERSION_ENCODE -#undef JSON_HEDLEY_WARNING -#undef JSON_HEDLEY_WARN_UNUSED_RESULT -#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG -#undef JSON_HEDLEY_FALL_THROUGH - - - -#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/inc/json_fwd.hxx b/inc/json_fwd.hxx deleted file mode 100644 index 29a6036..0000000 --- a/inc/json_fwd.hxx +++ /dev/null @@ -1,176 +0,0 @@ -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - -#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ -#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ - -#include <cstdint> // int64_t, uint64_t -#include <map> // map -#include <memory> // allocator -#include <string> // string -#include <vector> // vector - -// #include <nlohmann/detail/abi_macros.hpp> -// __ _____ _____ _____ -// __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 -// |_____|_____|_____|_|___| https://github.com/nlohmann/json -// -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> -// SPDX-License-Identifier: MIT - - - -// This file contains all macro definitions affecting or depending on the ABI - -#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK - #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) - #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 - #warning "Already included a different version of the library!" - #endif - #endif -#endif - -#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) - -#ifndef JSON_DIAGNOSTICS - #define JSON_DIAGNOSTICS 0 -#endif - -#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON - #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 -#endif - -#if JSON_DIAGNOSTICS - #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag -#else - #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS -#endif - -#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON - #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp -#else - #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON -#endif - -#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION - #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 -#endif - -// Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) - -#define NLOHMANN_JSON_ABI_TAGS \ - NLOHMANN_JSON_ABI_TAGS_CONCAT( \ - NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ - NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) - -// Construct the namespace version component -#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ - _v ## major ## _ ## minor ## _ ## patch -#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ - NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) - -#if NLOHMANN_JSON_NAMESPACE_NO_VERSION -#define NLOHMANN_JSON_NAMESPACE_VERSION -#else -#define NLOHMANN_JSON_NAMESPACE_VERSION \ - NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ - NLOHMANN_JSON_VERSION_MINOR, \ - NLOHMANN_JSON_VERSION_PATCH) -#endif - -// Combine namespace components -#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b -#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ - NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) - -#ifndef NLOHMANN_JSON_NAMESPACE -#define NLOHMANN_JSON_NAMESPACE \ - nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ - NLOHMANN_JSON_ABI_TAGS, \ - NLOHMANN_JSON_NAMESPACE_VERSION) -#endif - -#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN -#define NLOHMANN_JSON_NAMESPACE_BEGIN \ - namespace nlohmann \ - { \ - inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ - NLOHMANN_JSON_ABI_TAGS, \ - NLOHMANN_JSON_NAMESPACE_VERSION) \ - { -#endif - -#ifndef NLOHMANN_JSON_NAMESPACE_END -#define NLOHMANN_JSON_NAMESPACE_END \ - } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ - } // namespace nlohmann -#endif - - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -NLOHMANN_JSON_NAMESPACE_BEGIN - -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template<typename T = void, typename SFINAE = void> -struct adl_serializer; - -/// a class to store JSON values -/// @sa https://json.nlohmann.me/api/basic_json/ -template<template<typename U, typename V, typename... Args> class ObjectType = - std::map, - template<typename U, typename... Args> class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template<typename U> class AllocatorType = std::allocator, - template<typename T, typename SFINAE = void> class JSONSerializer = - adl_serializer, - class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError - class CustomBaseClass = void> -class basic_json; - -/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document -/// @sa https://json.nlohmann.me/api/json_pointer/ -template<typename RefStringType> -class json_pointer; - -/*! -@brief default specialization -@sa https://json.nlohmann.me/api/json/ -*/ -using json = basic_json<>; - -/// @brief a minimal map-like container that preserves insertion order -/// @sa https://json.nlohmann.me/api/ordered_map/ -template<class Key, class T, class IgnoredLess, class Allocator> -struct ordered_map; - -/// @brief specialization that maintains the insertion order of object keys -/// @sa https://json.nlohmann.me/api/ordered_json/ -using ordered_json = basic_json<nlohmann::ordered_map>; - -NLOHMANN_JSON_NAMESPACE_END - -#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ diff --git a/inc/toml.hxx b/inc/toml.hxx deleted file mode 100644 index 1bb9d66..0000000 --- a/inc/toml.hxx +++ /dev/null @@ -1,17788 +0,0 @@ -//---------------------------------------------------------------------------------------------------------------------- -// -// 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_NVCC -#ifdef __NVCOMPILER_MAJOR__ -#define TOML_NVCC __NVCOMPILER_MAJOR__ -#else -#define TOML_NVCC 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 -#ifndef 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 -#endif - -// TOML_NEVER_INLINE -#ifndef 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 -#endif - -// MSVC attributes -#ifndef TOML_ABSTRACT_INTERFACE -#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable) -#endif -#ifndef TOML_EMPTY_BASES -#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases) -#endif - -// TOML_TRIVIAL_ABI -#ifndef 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 -#endif - -// TOML_NODISCARD -#ifndef 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 -#endif - -// TOML_NODISCARD_CTOR -#ifndef TOML_NODISCARD_CTOR -#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907 -#define TOML_NODISCARD_CTOR [[nodiscard]] -#else -#define TOML_NODISCARD_CTOR -#endif -#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 -#ifndef 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 -#endif - -// TOML_UNREACHABLE -#ifndef 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 -#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_view> -#include <string> -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; -} - -#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 <cstdint> -#include <cstddef> -#include <cstring> -#include <cfloat> -#include <climits> -#include <cmath> -#include <limits> -#include <memory> -#include <iosfwd> -#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::size_t; - using ::std::intptr_t; - using ::std::uintptr_t; - using ::std::ptrdiff_t; - using ::std::nullptr_t; - using ::std::int8_t; - using ::std::int16_t; - using ::std::int32_t; - using ::std::int64_t; - using ::std::uint8_t; - using ::std::uint16_t; - using ::std::uint32_t; - using ::std::uint64_t; - using ::std::uint_least32_t; - using ::std::uint_least64_t; -} - -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 <vector> -#include <iterator> -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 }); - } - } - - 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 - -// workaround for this: https://github.com/marzer/tomlplusplus/issues/220 -#if TOML_NVCC -#define TOML_NVCC_WORKAROUND \ - { \ - return {}; \ - } -#else -#define TOML_NVCC_WORKAROUND = 0 -#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_NODISCARD - virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0; - - TOML_NODISCARD - 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 TOML_NVCC_WORKAROUND; - - TOML_PURE_GETTER - virtual bool is_table() const noexcept TOML_NVCC_WORKAROUND; - - TOML_PURE_GETTER - virtual bool is_array() const noexcept = 0; - - TOML_PURE_GETTER - virtual bool is_array_of_tables() const noexcept TOML_NVCC_WORKAROUND; - - 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_UNREACHABLE; - } - - 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(); - - TOML_UNREACHABLE; - } - - 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(); - - TOML_UNREACHABLE; - } - - 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; - -#undef TOML_NVCC_WORKAROUND - -#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_PURE_GETTER - 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_NODISCARD - 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_NODISCARD - 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_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; - - TOML_NODISCARD - 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 <map> -#include <iterator> -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_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final; - - TOML_NODISCARD - 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_UNREACHABLE; - } - - 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 - } -} -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, ¤t, 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_NODISCARD - 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_NODISCARD - 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_NODISCARD - 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_NODISCARD - 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 <istream> -#include <fstream> -#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 as a signed 64-bit integer"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 as a signed 64-bit integer"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; - } - - 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_NVCC -#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 |
