#ifndef TOML11_COMPAT_HPP #define TOML11_COMPAT_HPP #include "version.hpp" #include #include #include #include #include #include #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE # if __has_include() # include # endif #endif #include // ---------------------------------------------------------------------------- #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE # if __has_cpp_attribute(deprecated) # define TOML11_HAS_ATTR_DEPRECATED 1 # endif #endif #if defined(TOML11_HAS_ATTR_DEPRECATED) # define TOML11_DEPRECATED(msg) [[deprecated(msg)]] #elif defined(__GNUC__) # define TOML11_DEPRECATED(msg) __attribute__((deprecated(msg))) #elif defined(_MSC_VER) # define TOML11_DEPRECATED(msg) __declspec(deprecated(msg)) #else # define TOML11_DEPRECATED(msg) #endif // ---------------------------------------------------------------------------- #if defined(__cpp_if_constexpr) # if __cpp_if_constexpr >= 201606L # define TOML11_HAS_CONSTEXPR_IF 1 # endif #endif #if defined(TOML11_HAS_CONSTEXPR_IF) # define TOML11_CONSTEXPR_IF if constexpr #else # define TOML11_CONSTEXPR_IF if #endif // ---------------------------------------------------------------------------- #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE # if defined(__cpp_lib_make_unique) # if __cpp_lib_make_unique >= 201304L # define TOML11_HAS_STD_MAKE_UNIQUE 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_MAKE_UNIQUE) using std::make_unique; #else template std::unique_ptr make_unique(Ts&& ... args) { return std::unique_ptr(new T(std::forward(args)...)); } #endif // TOML11_HAS_STD_MAKE_UNIQUE } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE # if defined(__cpp_lib_make_reverse_iterator) # if __cpp_lib_make_reverse_iterator >= 201402L # define TOML11_HAS_STD_MAKE_REVERSE_ITERATOR 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { # if defined(TOML11_HAS_STD_MAKE_REVERSE_ITERATOR) using std::make_reverse_iterator; #else template std::reverse_iterator make_reverse_iterator(Iterator iter) { return std::reverse_iterator(iter); } #endif // TOML11_HAS_STD_MAKE_REVERSE_ITERATOR } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE # if defined(__cpp_lib_clamp) # if __cpp_lib_clamp >= 201603L # define TOML11_HAS_STD_CLAMP 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_CLAMP) using std::clamp; #else template T clamp(const T& x, const T& low, const T& high) noexcept { assert(low <= high); return (std::min)((std::max)(x, low), high); } #endif // TOML11_HAS_STD_CLAMP } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE # if defined(__cpp_lib_bit_cast) # if __cpp_lib_bit_cast >= 201806L # define TOML11_HAS_STD_BIT_CAST 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_BIT_CAST) using std::bit_cast; #else template U bit_cast(const T& x) noexcept { static_assert(sizeof(T) == sizeof(U), ""); static_assert(std::is_default_constructible::value, ""); U z; std::memcpy(reinterpret_cast(std::addressof(z)), reinterpret_cast(std::addressof(x)), sizeof(T)); return z; } #endif // TOML11_HAS_STD_BIT_CAST } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- // C++20 remove_cvref_t #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE # if defined(__cpp_lib_remove_cvref) # if __cpp_lib_remove_cvref >= 201711L # define TOML11_HAS_STD_REMOVE_CVREF 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_REMOVE_CVREF) using std::remove_cvref; using std::remove_cvref_t; #else template struct remove_cvref { using type = typename std::remove_cv< typename std::remove_reference::type>::type; }; template using remove_cvref_t = typename remove_cvref::type; #endif // TOML11_HAS_STD_REMOVE_CVREF } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- // C++17 and/or/not #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE # if defined(__cpp_lib_logical_traits) # if __cpp_lib_logical_traits >= 201510L # define TOML11_HAS_STD_CONJUNCTION 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_CONJUNCTION) using std::conjunction; using std::disjunction; using std::negation; #else template struct conjunction : std::true_type{}; template struct conjunction : T{}; template struct conjunction : std::conditional(T::value), conjunction, T>::type {}; template struct disjunction : std::false_type{}; template struct disjunction : T {}; template struct disjunction : std::conditional(T::value), T, disjunction>::type {}; template struct negation : std::integral_constant(T::value)>{}; #endif // TOML11_HAS_STD_CONJUNCTION } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- // C++14 index_sequence #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE # if defined(__cpp_lib_integer_sequence) # if __cpp_lib_integer_sequence >= 201304L # define TOML11_HAS_STD_INTEGER_SEQUENCE 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_INTEGER_SEQUENCE) using std::index_sequence; using std::make_index_sequence; #else template struct index_sequence{}; template struct double_index_sequence; template struct double_index_sequence> { using type = index_sequence; }; template struct double_index_sequence> { using type = index_sequence; }; template struct index_sequence_maker { using type = typename double_index_sequence< N % 2 == 1, N/2, typename index_sequence_maker::type >::type; }; template<> struct index_sequence_maker<0> { using type = index_sequence<>; }; template using make_index_sequence = typename index_sequence_maker::type; #endif // TOML11_HAS_STD_INTEGER_SEQUENCE } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- // C++14 enable_if_t #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE # if defined(__cpp_lib_transformation_trait_aliases) # if __cpp_lib_transformation_trait_aliases >= 201304L # define TOML11_HAS_STD_ENABLE_IF_T 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_ENABLE_IF_T) using std::enable_if_t; #else template using enable_if_t = typename std::enable_if::type; #endif // TOML11_HAS_STD_ENABLE_IF_T } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- // return_type_of_t #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE # if defined(__cpp_lib_is_invocable) # if __cpp_lib_is_invocable >= 201703 # define TOML11_HAS_STD_INVOKE_RESULT 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_INVOKE_RESULT) template using return_type_of_t = std::invoke_result_t; #else // result_of is deprecated after C++17 template using return_type_of_t = typename std::result_of::type; #endif // TOML11_HAS_STD_INVOKE_RESULT } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // --------------------------------------------------------------------------- // C++17 void_t #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE # if defined(__cpp_lib_void_t) # if __cpp_lib_void_t >= 201411L # define TOML11_HAS_STD_VOID_T 1 # endif # endif #endif namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { #if defined(TOML11_HAS_STD_VOID_T) using std::void_t; #else template using void_t = void; #endif // TOML11_HAS_STD_VOID_T } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml // ---------------------------------------------------------------------------- // (subset of) source_location #if TOML11_CPLUSPLUS_STANDARD_VERSION >= 202002L # if __has_include() # define TOML11_HAS_STD_SOURCE_LOCATION # endif // has_include #endif // c++20 #if ! defined(TOML11_HAS_STD_SOURCE_LOCATION) # if defined(__GNUC__) && ! defined(__clang__) # if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE # if __has_include() # define TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION # endif # endif # endif // GNU g++ #endif // not TOML11_HAS_STD_SOURCE_LOCATION #if ! defined(TOML11_HAS_STD_SOURCE_LOCATION) && ! defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) # if defined(__GNUC__) && ! defined(__clang__) # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) # define TOML11_HAS_BUILTIN_FILE_LINE 1 # define TOML11_BUILTIN_LINE_TYPE int # endif # elif defined(__clang__) // clang 9.0.0 implements builtin_FILE/LINE # if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) # define TOML11_HAS_BUILTIN_FILE_LINE 1 # define TOML11_BUILTIN_LINE_TYPE unsigned int # endif # elif defined(_MSVC_LANG) && defined(_MSC_VER) # if _MSC_VER > 1926 # define TOML11_HAS_BUILTIN_FILE_LINE 1 # define TOML11_BUILTIN_LINE_TYPE int # endif # endif #endif #if defined(TOML11_HAS_STD_SOURCE_LOCATION) #include namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { using source_location = std::source_location; inline std::string to_string(const source_location& loc) { const char* fname = loc.file_name(); if(fname) { return std::string(" at line ") + std::to_string(loc.line()) + std::string(" in file ") + std::string(fname); } else { return std::string(" at line ") + std::to_string(loc.line()) + std::string(" in unknown file"); } } } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml #elif defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) #include namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { using source_location = std::experimental::source_location; inline std::string to_string(const source_location& loc) { const char* fname = loc.file_name(); if(fname) { return std::string(" at line ") + std::to_string(loc.line()) + std::string(" in file ") + std::string(fname); } else { return std::string(" at line ") + std::to_string(loc.line()) + std::string(" in unknown file"); } } } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml #elif defined(TOML11_HAS_BUILTIN_FILE_LINE) namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { struct source_location { using line_type = TOML11_BUILTIN_LINE_TYPE; static source_location current(const line_type line = __builtin_LINE(), const char* file = __builtin_FILE()) { return source_location(line, file); } source_location(const line_type line, const char* file) : line_(line), file_name_(file) {} line_type line() const noexcept {return line_;} const char* file_name() const noexcept {return file_name_;} private: line_type line_; const char* file_name_; }; inline std::string to_string(const source_location& loc) { const char* fname = loc.file_name(); if(fname) { return std::string(" at line ") + std::to_string(loc.line()) + std::string(" in file ") + std::string(fname); } else { return std::string(" at line ") + std::to_string(loc.line()) + std::string(" in unknown file"); } } } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml #else // no builtin namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { struct source_location { static source_location current() { return source_location{}; } }; inline std::string to_string(const source_location&) { return std::string(""); } } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml #endif // TOML11_HAS_STD_SOURCE_LOCATION // ---------------------------------------------------------------------------- // (subset of) optional #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE # if __has_include() # include # endif // has_include(optional) #endif // C++17 #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE # if defined(__cpp_lib_optional) # if __cpp_lib_optional >= 201606L # define TOML11_HAS_STD_OPTIONAL 1 # endif # endif #endif #if defined(TOML11_HAS_STD_OPTIONAL) namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { using std::optional; inline std::nullopt_t make_nullopt() {return std::nullopt;} template std::basic_ostream& operator<<(std::basic_ostream& os, const std::nullopt_t&) { os << "nullopt"; return os; } } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml #else // TOML11_HAS_STD_OPTIONAL namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { namespace cxx { struct nullopt_t{}; inline nullopt_t make_nullopt() {return nullopt_t{};} inline bool operator==(const nullopt_t&, const nullopt_t&) noexcept {return true;} inline bool operator!=(const nullopt_t&, const nullopt_t&) noexcept {return false;} inline bool operator< (const nullopt_t&, const nullopt_t&) noexcept {return false;} inline bool operator<=(const nullopt_t&, const nullopt_t&) noexcept {return true;} inline bool operator> (const nullopt_t&, const nullopt_t&) noexcept {return false;} inline bool operator>=(const nullopt_t&, const nullopt_t&) noexcept {return true;} template std::basic_ostream& operator<<(std::basic_ostream& os, const nullopt_t&) { os << "nullopt"; return os; } template class optional { public: using value_type = T; public: optional() noexcept : has_value_(false), null_('\0') {} optional(nullopt_t) noexcept : has_value_(false), null_('\0') {} optional(const T& x): has_value_(true), value_(x) {} optional(T&& x): has_value_(true), value_(std::move(x)) {} template::value, std::nullptr_t> = nullptr> explicit optional(U&& x): has_value_(true), value_(std::forward(x)) {} optional(const optional& rhs): has_value_(rhs.has_value_) { if(rhs.has_value_) { this->assigner(rhs.value_); } } optional(optional&& rhs): has_value_(rhs.has_value_) { if(this->has_value_) { this->assigner(std::move(rhs.value_)); } } optional& operator=(const optional& rhs) { if(this == std::addressof(rhs)) {return *this;} this->cleanup(); this->has_value_ = rhs.has_value_; if(this->has_value_) { this->assigner(rhs.value_); } return *this; } optional& operator=(optional&& rhs) { if(this == std::addressof(rhs)) {return *this;} this->cleanup(); this->has_value_ = rhs.has_value_; if(this->has_value_) { this->assigner(std::move(rhs.value_)); } return *this; } template>, std::is_constructible >::value, std::nullptr_t> = nullptr> explicit optional(const optional& rhs): has_value_(rhs.has_value_), null_('\0') { if(rhs.has_value_) { this->assigner(rhs.value_); } } template>, std::is_constructible >::value, std::nullptr_t> = nullptr> explicit optional(optional&& rhs): has_value_(rhs.has_value_), null_('\0') { if(this->has_value_) { this->assigner(std::move(rhs.value_)); } } template>, std::is_constructible >::value, std::nullptr_t> = nullptr> optional& operator=(const optional& rhs) { if(this == std::addressof(rhs)) {return *this;} this->cleanup(); this->has_value_ = rhs.has_value_; if(this->has_value_) { this->assigner(rhs.value_); } return *this; } template>, std::is_constructible >::value, std::nullptr_t> = nullptr> optional& operator=(optional&& rhs) { if(this == std::addressof(rhs)) {return *this;} this->cleanup(); this->has_value_ = rhs.has_value_; if(this->has_value_) { this->assigner(std::move(rhs.value_)); } return *this; } ~optional() noexcept { this->cleanup(); } explicit operator bool() const noexcept { return has_value_; } bool has_value() const noexcept {return has_value_;} value_type const& value(source_location loc = source_location::current()) const { if( ! this->has_value_) { throw std::runtime_error("optional::value(): bad_unwrap" + to_string(loc)); } return this->value_; } value_type& value(source_location loc = source_location::current()) { if( ! this->has_value_) { throw std::runtime_error("optional::value(): bad_unwrap" + to_string(loc)); } return this->value_; } value_type const& value_or(const value_type& opt) const { if(this->has_value_) {return this->value_;} else {return opt;} } value_type& value_or(value_type& opt) { if(this->has_value_) {return this->value_;} else {return opt;} } private: void cleanup() noexcept { if(this->has_value_) { value_.~T(); } } template void assigner(U&& x) { const auto tmp = ::new(std::addressof(this->value_)) value_type(std::forward(x)); assert(tmp == std::addressof(this->value_)); (void)tmp; } private: bool has_value_; union { char null_; T value_; }; }; } // cxx } // TOML11_INLINE_VERSION_NAMESPACE } // toml #endif // TOML11_HAS_STD_OPTIONAL #endif // TOML11_COMPAT_HPP