#pragma once ////////// CONFIGURATION // clang-format off #ifdef TOML_CONFIG_HEADER #include TOML_CONFIG_HEADER #undef TOML_CONFIG_HEADER #endif #ifndef TOML_CHAR_8_STRINGS #define TOML_CHAR_8_STRINGS 0 #endif #ifndef TOML_UNRELEASED_FEATURES #define TOML_UNRELEASED_FEATURES 1 #endif #ifndef TOML_LARGE_FILES #define TOML_LARGE_FILES 0 #endif #ifndef TOML_ASSERT #ifdef assert #define TOML_ASSERT(expr) assert(expr) #else #define TOML_ASSERT(expr) (void)0 #endif #endif #ifndef TOML_UNDEF_MACROS #define TOML_UNDEF_MACROS 1 #endif ////////// COMPILER & ENVIRONMENT STUFF #ifndef __cplusplus #error toml++ is a C++ library. #endif #if defined(__clang__) || defined(__GNUC__) #define TOML_GCC_ATTR(attr) __attribute__((attr)) #else #define TOML_GCC_ATTR(attr) #endif #ifdef __clang__ #ifndef __cpp_exceptions #define TOML_EXCEPTIONS 0 #endif #define TOML_PUSH_WARNINGS _Pragma("clang diagnostic push") #define TOML_DISABLE_SWITCH_WARNINGS _Pragma("clang diagnostic ignored \"-Wswitch\"") #define TOML_DISABLE_INIT_WARNINGS _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") #define TOML_DISABLE_ALL_WARNINGS _Pragma("clang diagnostic ignored \"-Weverything\"") #define TOML_POP_WARNINGS _Pragma("clang diagnostic pop") #define TOML_ALWAYS_INLINE TOML_GCC_ATTR(__always_inline__) inline #define TOML_ASSUME(cond) __builtin_assume(cond) #define TOML_UNREACHABLE __builtin_unreachable() #if __has_declspec_attribute(novtable) #define TOML_INTERFACE __declspec(novtable) #endif #if __has_declspec_attribute(empty_bases) #define TOML_EMPTY_BASES __declspec(empty_bases) #endif //floating-point from_chars and to_chars are not implemented in any version of clang as of 1/1/2020 #ifndef TOML_USE_STREAMS_FOR_FLOATS #define TOML_USE_STREAMS_FOR_FLOATS 1 #endif #elif defined(_MSC_VER) #ifndef _CPPUNWIND #define TOML_EXCEPTIONS 0 #endif #define TOML_CPP_VERSION _MSVC_LANG #define TOML_PUSH_WARNINGS __pragma(warning(push)) #define TOML_DISABLE_SWITCH_WARNINGS __pragma(warning(disable: 4063)) #define TOML_DISABLE_ALL_WARNINGS __pragma(warning(pop)) \ __pragma(warning(push, 0)) #define TOML_POP_WARNINGS __pragma(warning(pop)) #define TOML_ALWAYS_INLINE __forceinline #define TOML_ASSUME(cond) __assume(cond) #define TOML_UNREACHABLE __assume(0) #define TOML_INTERFACE __declspec(novtable) #define TOML_EMPTY_BASES __declspec(empty_bases) #elif defined(__GNUC__) #ifndef __cpp_exceptions #define TOML_EXCEPTIONS 0 #endif #define TOML_PUSH_WARNINGS _Pragma("GCC diagnostic push") #define TOML_DISABLE_SWITCH_WARNINGS _Pragma("GCC diagnostic ignored \"-Wswitch\"") #define TOML_DISABLE_INIT_WARNINGS _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \ _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \ _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") #define TOML_DISABLE_ALL_WARNINGS _Pragma("GCC diagnostic ignored \"-Wall\"") \ _Pragma("GCC diagnostic ignored \"-Wextra\"") \ _Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") #define TOML_POP_WARNINGS _Pragma("GCC diagnostic pop") #define TOML_ALWAYS_INLINE TOML_GCC_ATTR(__always_inline__) inline #define TOML_UNREACHABLE __builtin_unreachable() //floating-point from_chars and to_chars are not implemented in any version of gcc as of 1/1/2020 #ifndef TOML_USE_STREAMS_FOR_FLOATS #define TOML_USE_STREAMS_FOR_FLOATS 1 #endif #endif #ifndef TOML_CPP_VERSION #define TOML_CPP_VERSION __cplusplus #endif #if TOML_CPP_VERSION < 201103L #error toml++ requires C++17 or higher. For a TOML parser supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml #elif TOML_CPP_VERSION < 201703L #error toml++ requires C++17 or higher. For a TOML parser supporting C++11 see https://github.com/skystrife/cpptoml #elif TOML_CPP_VERSION >= 202600L #define TOML_CPP 26 #elif TOML_CPP_VERSION >= 202300L #define TOML_CPP 23 #elif TOML_CPP_VERSION >= 202000L #define TOML_CPP 20 #elif TOML_CPP_VERSION >= 201703L #define TOML_CPP 17 #endif #ifndef TOML_EXCEPTIONS #define TOML_EXCEPTIONS 1 #endif #ifndef TOML_DOXYGEN #define TOML_DOXYGEN 0 #endif #if TOML_EXCEPTIONS #define TOML_MAY_THROW #define TOML_MAY_THROW_UNLESS(...) noexcept(__VA_ARGS__) #else #define TOML_MAY_THROW noexcept #define TOML_MAY_THROW_UNLESS(...) noexcept #endif #ifndef TOML_DISABLE_INIT_WARNINGS #define TOML_DISABLE_INIT_WARNINGS #endif #ifndef TOML_USE_STREAMS_FOR_FLOATS #define TOML_USE_STREAMS_FOR_FLOATS 0 #endif #ifndef TOML_PUSH_WARNINGS #define TOML_PUSH_WARNINGS #endif #ifndef TOML_DISABLE_ALL_WARNINGS #define TOML_DISABLE_ALL_WARNINGS #endif #ifndef TOML_POP_WARNINGS #define TOML_POP_WARNINGS #endif #ifndef TOML_INTERFACE #define TOML_INTERFACE #endif #ifndef TOML_EMPTY_BASES #define TOML_EMPTY_BASES #endif #ifndef TOML_ALWAYS_INLINE #define TOML_ALWAYS_INLINE inline #endif #ifndef TOML_ASSUME #define TOML_ASSUME(cond) (void)0 #endif #ifndef TOML_UNREACHABLE #define TOML_UNREACHABLE TOML_ASSERT(false) #endif #define TOML_NO_DEFAULT_CASE default: TOML_UNREACHABLE #ifdef __cpp_consteval #define TOML_CONSTEVAL consteval #else #define TOML_CONSTEVAL constexpr #endif #ifndef __INTELLISENSE__ #if __has_cpp_attribute(likely) #define TOML_LIKELY [[likely]] #endif #if __has_cpp_attribute(unlikely) #define TOML_UNLIKELY [[unlikely]] #endif #if __has_cpp_attribute(no_unique_address) #define TOML_NO_UNIQUE_ADDRESS [[no_unique_address]] #endif #if __has_cpp_attribute(nodiscard) >= 201907L #define TOML_NODISCARD_CTOR [[nodiscard]] #endif #endif //__INTELLISENSE__ #ifndef TOML_LIKELY #define TOML_LIKELY #endif #ifndef TOML_UNLIKELY #define TOML_UNLIKELY #endif #ifndef TOML_NO_UNIQUE_ADDRESS #define TOML_NO_UNIQUE_ADDRESS #endif #ifndef TOML_NODISCARD_CTOR #define TOML_NODISCARD_CTOR #endif #include "toml_version.h" #define TOML_MAKE_VERSION(maj, min, rev) \ ((maj) * 1000 + (min) * 25 + (rev)) #if TOML_UNRELEASED_FEATURES #define TOML_LANG_EFFECTIVE_VERSION \ TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION+1) #else #define TOML_LANG_EFFECTIVE_VERSION \ TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_REVISION) #endif #define TOML_LANG_HIGHER_THAN(maj, min, rev) \ (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(maj, min, rev)) #define TOML_LANG_AT_LEAST(maj, min, rev) \ (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(maj, min, rev)) #define TOML_LANG_EXACTLY(maj, min, rev) \ (TOML_LANG_EFFECTIVE_VERSION == TOML_MAKE_VERSION(maj, min, rev)) ////////// INCLUDES TOML_PUSH_WARNINGS TOML_DISABLE_ALL_WARNINGS #include #include //memcpy, memset #include //log10 #include #include #include #include #include #include #include #include #if TOML_USE_STREAMS_FOR_FLOATS #include #endif #if TOML_EXCEPTIONS #include #endif TOML_POP_WARNINGS #if TOML_CHAR_8_STRINGS #if !defined(__cpp_lib_char8_t) #error toml++ requires implementation support to use char8_t strings, but yours does not provide it. #endif #define TOML_STRING_PREFIX_1(S) u8##S #define TOML_STRING_PREFIX(S) TOML_STRING_PREFIX_1(S) #else #define TOML_STRING_PREFIX(S) S #endif ////////// FORWARD DECLARATIONS & TYPEDEFS // clang-format on /// \brief The root namespace for all toml++ functions and types. namespace toml { inline namespace literals { using namespace std::string_literals; using namespace std::string_view_literals; [[nodiscard]] TOML_ALWAYS_INLINE TOML_CONSTEVAL uint8_t operator"" _u8(unsigned long long n) noexcept { return static_cast(n); } [[nodiscard]] TOML_ALWAYS_INLINE TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept { return static_cast(n); } } #if TOML_CHAR_8_STRINGS using string_char = char8_t; using string = std::u8string; using string_view = std::u8string_view; #else /// \brief The base character type for keys and string values. /// \attention This will be `char8_t` if `TOML_CHAR_8_STRINGS` is `1`. using string_char = char; /// \brief The string type for keys and string values. /// \attention This will be `std::u8string` if `TOML_CHAR_8_STRINGS` is `1`. using string = std::string; /// \brief The string type for keys and string values. /// \attention This will be `std::u8string_view` if `TOML_CHAR_8_STRINGS` is `1`. using string_view = std::string_view; #endif struct date; struct time; struct time_offset; struct date_time; class node; template class node_view; template class value; class array; class table; /// \brief TOML node type identifiers. enum class node_type : uint8_t { table, ///< The node is a toml::table. array, ///< The node is a toml::array. string, ///< The node is a toml::value. integer, ///< The node is a toml::value. floating_point, ///< The node is a toml::value. boolean, ///< The node is a toml::value. date, ///< The node is a toml::value. time, ///< The node is a toml::value. date_time ///< The node is a toml::value. }; #if TOML_LARGE_FILES using source_index = uint32_t; #else /// \brief The integer type used to tally line numbers and columns. /// \attention This will be `uint32_t` if `TOML_LARGE_FILES` is `1`. using source_index = uint16_t; #endif /// \brief A source document line-and-column pair. struct source_position { /// \brief The line number. /// \remarks Valid line numbers start at 1. source_index line; /// \brief The column number. /// \remarks Valid column numbers start at 1. source_index column; /// \brief Returns true if both line and column numbers are non-zero. [[nodiscard]] explicit constexpr operator bool () const noexcept { return line > source_index{} && column > source_index{}; } [[nodiscard]] friend constexpr bool operator == (const source_position& lhs, const source_position& rhs) noexcept { return lhs.line == rhs.line && lhs.column == rhs.column; } [[nodiscard]] friend constexpr bool operator != (const source_position& lhs, const source_position& rhs) noexcept { return lhs.line != rhs.line || lhs.column != rhs.column; } [[nodiscard]] friend constexpr bool operator < (const source_position& lhs, const source_position& rhs) noexcept { return lhs.line < rhs.line || (lhs.line == rhs.line && lhs.column < rhs.column); } [[nodiscard]] friend constexpr bool operator <= (const source_position& lhs, const source_position& rhs) noexcept { return lhs.line < rhs.line || (lhs.line == rhs.line && lhs.column <= rhs.column); } template friend std::basic_ostream& operator << (std::basic_ostream& lhs, const source_position& rhs) TOML_MAY_THROW { return lhs << "line " << rhs.line << ", column " << rhs.column; } }; /// \brief A pointer to a shared string resource containing a source path. using source_path_ptr = std::shared_ptr; /// \brief A source document region. struct source_region { /// \brief The beginning of the region (inclusive). source_position begin; /// \brief The end of the region (exclusive). source_position end; /// \brief The path to the corresponding source document. /// /// \remarks This will be `nullptr` if no path was provided to toml::parse(). source_path_ptr path; }; TOML_PUSH_WARNINGS TOML_DISABLE_INIT_WARNINGS #if TOML_DOXYGEN || !TOML_EXCEPTIONS /// \brief An error thrown/returned when parsing fails. /// /// \remarks This class inherits from `std::runtime_error` when exceptions are enabled. /// The public interface is the same regardless of exception mode. class parse_error final { private: std::string description_; source_region source_; public: TOML_NODISCARD_CTOR parse_error(std::string&& desc, source_region&& src) noexcept : description_{ std::move(desc) }, source_{ std::move(src) } {} TOML_NODISCARD_CTOR parse_error(std::string&& desc, const source_region& src) noexcept : parse_error{ std::move(desc), source_region{ src } } {} TOML_NODISCARD_CTOR parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept : parse_error{ std::move(desc), source_region{ position, position, path } } {} /// \brief Returns a textual description of the error. [[nodiscard]] std::string_view description() const noexcept { return description_; } /// \brief Returns the region of the source document responsible for the error. [[nodiscard]] const source_region& source() const noexcept { return source_; } }; #else class parse_error final : public std::runtime_error { private: source_region source_; public: TOML_NODISCARD_CTOR TOML_GCC_ATTR(nonnull) parse_error(const char* desc, source_region&& src) noexcept : std::runtime_error{ desc }, source_{ std::move(src) } {} TOML_NODISCARD_CTOR TOML_GCC_ATTR(nonnull) parse_error(const char* desc, const source_region& src) noexcept : parse_error{ desc, source_region{ src } } {} TOML_NODISCARD_CTOR TOML_GCC_ATTR(nonnull) parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept : parse_error{ desc, source_region{ position, position, path } } {} [[nodiscard]] std::string_view description() const noexcept { return std::string_view{ what() }; } [[nodiscard]] const source_region& source() const noexcept { return source_; } }; #endif TOML_POP_WARNINGS } /// \brief Internal implementation details. No user-serviceable parts within. namespace toml::impl { template using string_map = std::map>; //heterogeneous lookup #if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20)) template using remove_cvref_t = std::remove_cvref_t; #else template using remove_cvref_t = std::remove_cv_t>; #endif template struct is_one_of_ : std::integral_constant) > {}; template inline constexpr bool is_one_of = is_one_of_::value; template using enable_if_one_of = std::enable_if_t>; template using enable_if_not_one_of = std::enable_if_t>; template [[nodiscard]] TOML_ALWAYS_INLINE constexpr std::underlying_type_t unwrap_enum(T val) noexcept { return static_cast>(val); } // Q: "why not use std::find??" // A: Because is _huge_ and std::find would be the only thing I used from it. // I don't want to impose such a heavy burden on users. template inline std::optional find(const std::vector& haystack, const T& needle) noexcept { const auto end = haystack.size(); for (size_t i = 0; i < end; i++) if (haystack[i] == needle) return i; return {}; } class parser; template inline constexpr bool is_value = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; template inline constexpr bool is_value_or_promotable = is_value || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v #ifdef TOML_SMALL_FLOAT_TYPE || std::is_same_v #endif ; template inline constexpr bool is_value_or_node = is_value || std::is_same_v || std::is_same_v; template struct node_wrapper { using type = T; }; template <> struct node_wrapper { using type = value; }; template <> struct node_wrapper { using type = value; }; template <> struct node_wrapper { using type = value; }; template <> struct node_wrapper { using type = value; }; template <> struct node_wrapper { using type = value; }; template <> struct node_wrapper