diff --git a/.gitattributes b/.gitattributes index 30085cf..71a3e24 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,6 +17,9 @@ *.runsettings text encoding=UTF-8 eol=crlf *.md text encoding=UTF-8 eol=lf *.css text encoding=UTF-8 eol=lf +.gitignore text encoding=UTF-8 eol=lf +.gitattributes text encoding=UTF-8 eol=lf +.editorconfig text encoding=UTF-8 eol=lf meson.build text encoding=UTF-8 eol=lf meson_options.txt text encoding=UTF-8 eol=lf Doxyfile text encoding=UTF-8 eol=lf diff --git a/docs/tomlplusplus.css b/docs/tomlplusplus.css index 88230d3..75264fc 100644 --- a/docs/tomlplusplus.css +++ b/docs/tomlplusplus.css @@ -8,6 +8,14 @@ body margin-top: 3rem; } +@media screen and (min-width: 768px) and (max-width: 991px) +{ + body + { + margin-top: 6rem; + } +} + a { text-decoration: none !important; @@ -22,6 +30,11 @@ header z-index: 100; } +header, header * +{ + white-space: nowrap; +} + article, article > header, article div > section { margin-bottom: 5rem; @@ -65,13 +78,10 @@ pre a.tpp-injected .tpp-enable-if > a { white-space: nowrap; - font-size: 0.8rem; + font-size: 0.7rem; font-weight: bold; background-color: #858585; color: #050505; - padding-bottom: 0px; - margin: 0px 1px; - margin-bottom: 2px; } .tpp-enable-if > a:hover @@ -135,7 +145,7 @@ pre.m-code + pre.m-console span } /* comments */ -.m-code .c1 +pre.m-code .c1 { color: rgb(87,166,74); } @@ -149,25 +159,31 @@ pre.m-code .mh } /* keywords */ -.m-code .k +pre.m-code .k { color: rgb(86,156,214); } +pre.m-code .kt, +pre.m-code .k, +pre.m-code .nc +{ + font-weight: normal; +} /* identifier names */ -.m-code .n +pre.m-code .n { color: rgb(220,220,220); } /* punctuators (brackets etc) */ -.m-code .p +pre.m-code .p { color: rgb(120,120,120); } /* preprocessor directives */ -.m-code .cp +pre.m-code .cp { color: rgb(120,120,120); } @@ -209,7 +225,6 @@ pre.m-code .mh margin-right: -0.9rem; margin-top: -0.5rem; } - @media screen and (min-width: 992px) { .gh-badges @@ -255,6 +270,27 @@ main > article > .m-container.m-container-inflatable > .m-row > div.m-col-l-10.m max-width: calc(100% + 2rem); } +/* include */ +.m-doc-details div h3 +{ + overflow: auto; +} +h1 .m-doc-include, +h3 .m-doc-include +{ + float: right; +} +h1 .m-doc-include *, +h3 .m-doc-include * +{ + opacity: 1.0 !important; +} +h1 .m-doc-include .cp, +h3 .m-doc-include .cp +{ + color: #747474; +} + /* "Try this code on Compiler Explorer" */ .godbolt { diff --git a/examples/utf8_console.h b/examples/utf8_console.h index f519760..602d724 100644 --- a/examples/utf8_console.h +++ b/examples/utf8_console.h @@ -5,47 +5,6 @@ #ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #define VC_EXTRALEAN - #define NOATOM // - Atom Manager routines - #define NOBITMAP - #define NOCLIPBOARD // - Clipboard routines - #define NOCOLOR // - Screen colors - #define NOCOMM // - COMM driver routines - #define NOCTLMGR // - Control and Dialog routines - #define NODEFERWINDOWPOS // - DeferWindowPos routines - #define NODRAWTEXT // - DrawText() and DT_* - #define NOGDI // - All GDI defines and routines - #define NOGDICAPMASKS // - CC_*, LC_*, PC_*, CP_*, TC_*, RC_ - #define NOHELP // - Help engine interface. - #define NOICONS // - IDI_* - #define NOKANJI // - Kanji support stuff. - #define NOKEYSTATES // - MK_* - #define NOKERNEL // - All KERNEL defines and routines - #define NOMB // - MB_* and MessageBox() - #define NOMCX // - Modem Configuration Extensions - #define NOMENUS // - MF_* - #define NOMEMMGR // - GMEM_*, LMEM_*, GHND, LHND, associated routines - #define NOMETAFILE // - typedef METAFILEPICT - #define NOMINMAX // - Macros min(a,b) and max(a,b) - #define NOMSG // - typedef MSG and associated routines - //#define NONLS // - All NLS defines and routines - #define NOOPENFILE // - OpenFile(), OemToAnsi, AnsiToOem, and OF_* - #define NOPROFILER // - Profiler interface. - #define NORASTEROPS // - Binary and Tertiary raster ops - #define NOSCROLL // - SB_* and scrolling routines - #define NOSERVICE // - All Service Controller routines, SERVICE_ equates, etc. - #define NOSHOWWINDOW // - SW_* - #define NOSOUND // - Sound driver routines - #define NOSYSCOMMANDS // - SC_* - #define NOSYSMETRICS // - SM_* - #define NOTEXTMETRIC // - typedef TEXTMETRIC and associated routines - #define NOUSER // - All USER defines and routines - #define NOVIRTUALKEYCODES // - VK_* - #define NOWH // - SetWindowsHook and WH_* - #define NOWINOFFSETS // - GWL_*, GCL_*, associated routines - #define NOWINMESSAGES // - WM_*, EM_*, LB_*, CB_* - #define NOWINSTYLES // - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* #include inline void init_utf8_console() noexcept diff --git a/include/toml++/toml.h b/include/toml++/toml.h index af39ec9..409a994 100644 --- a/include/toml++/toml.h +++ b/include/toml++/toml.h @@ -103,6 +103,10 @@ #undef TOML_EVAL_BOOL_1 #undef TOML_EVAL_BOOL_0 #undef TOML_HAS_CUSTOM_OPTIONAL_TYPE + #undef TOML_UNWRAPPED_NODE_TYPE_LIST + #undef TOML_NATIVE_VALUE_TYPE_LIST + #undef TOML_NATIVE_STRING_TYPE_NAME + #undef TOML_NODE_TYPE_LIST #endif //# {{ diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h index c3f1d38..2d8c7a6 100644 --- a/include/toml++/toml_array.h +++ b/include/toml++/toml_array.h @@ -174,7 +174,7 @@ namespace toml::impl TOML_ALWAYS_INLINE auto* make_node(T&& val) noexcept { - using type = unwrapped>; + using type = unwrap_node>; if constexpr (is_one_of) { static_assert( @@ -190,14 +190,18 @@ namespace toml::impl "Instantiating values from wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled." ); static_assert( - is_value_or_promotable, + is_native || is_losslessly_convertible_to_native, "Value initializers must be (or be promotable to) one of the TOML value types" ); - #if TOML_WINDOWS_COMPAT if constexpr (is_wide_string) + { + #if TOML_WINDOWS_COMPAT return new value{ narrow(std::forward(val)) }; + #else + static_assert(dependent_false, "Evaluated unreachable branch!"); + #endif + } else - #endif return new value{ std::forward(val) }; } } @@ -613,13 +617,14 @@ namespace toml template iterator emplace(const_iterator pos, V&&... args) noexcept { - using type = impl::unwrapped; + using type = impl::unwrap_node; static_assert( - impl::is_value_or_node, - "Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array" + impl::is_native || impl::is_one_of, + "Emplacement type parameter must be one of the following:" + TOML_UNWRAPPED_NODE_TYPE_LIST ); - return { values.emplace(pos.raw_, new impl::node_of{ std::forward(args)...} ) }; + return { values.emplace(pos.raw_, new impl::wrap_node{ std::forward(args)...} ) }; } /// \brief Removes the specified node from the array. @@ -774,13 +779,14 @@ namespace toml template decltype(auto) emplace_back(V&&... args) noexcept { - using type = impl::unwrapped; + using type = impl::unwrap_node; static_assert( - impl::is_value_or_node, - "Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array" + impl::is_native || impl::is_one_of, + "Emplacement type parameter must be one of the following:" + TOML_UNWRAPPED_NODE_TYPE_LIST ); - auto nde = new impl::node_of{ std::forward(args)... }; + auto nde = new impl::wrap_node{ std::forward(args)... }; values.emplace_back(nde); return *nde; } @@ -837,7 +843,7 @@ namespace toml /// /// \returns A pointer to the selected node if it existed and was of the specified type, or nullptr. template - [[nodiscard]] impl::node_of* get_as(size_t index) noexcept + [[nodiscard]] impl::wrap_node* get_as(size_t index) noexcept { if (auto val = get(index)) return val->as(); @@ -851,7 +857,7 @@ namespace toml /// /// \returns A pointer to the selected node if it existed and was of the specified type, or nullptr. template - [[nodiscard]] const impl::node_of* get_as(size_t index) const noexcept + [[nodiscard]] const impl::wrap_node* get_as(size_t index) const noexcept { if (auto val = get(index)) return val->as(); @@ -879,9 +885,9 @@ namespace toml template [[nodiscard]] static bool container_equality(const array& lhs, const T& rhs) noexcept { - using elem_t = std::remove_const_t; + using element_type = std::remove_const_t; static_assert( - impl::is_value_or_promotable, + impl::is_native || impl::is_losslessly_convertible_to_native, "Container element type must be (or be promotable to) one of the TOML value types" ); @@ -893,7 +899,7 @@ namespace toml size_t i{}; for (auto& list_elem : rhs) { - const auto elem = lhs.get_as>(i++); + const auto elem = lhs.get_as>(i++); if (!elem || *elem != list_elem) return false; } diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index ecf466d..25f4463 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -16,6 +16,9 @@ TOML_DISABLE_ALL_WARNINGS #endif #include #include //memcpy, memset +#include +#include +#include #include #include #include @@ -38,6 +41,17 @@ TOML_POP_WARNINGS #define TOML_LAUNDER(x) x #endif +////////// ENVIRONMENT GROUND-TRUTHS + +static_assert(CHAR_BIT == 8); +static_assert(FLT_RADIX == 2); +static_assert('A' == 65); +static_assert(sizeof(double) == 8); +static_assert(std::numeric_limits::is_iec559); +static_assert(std::numeric_limits::digits == 53); +static_assert(std::numeric_limits::digits10 == 15); +static_assert(std::numeric_limits::max_digits10 == 17); + ////////// FORWARD DECLARATIONS & TYPEDEFS TOML_PUSH_WARNINGS @@ -287,9 +301,9 @@ namespace toml /// \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(). + /// \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; #if TOML_WINDOWS_COMPAT @@ -338,6 +352,27 @@ namespace toml::impl return static_cast>(val); } + // Q: "why not use the built-in fpclassify?" + // A: Because it gets broken by -ffast-math and friends + + enum class fp_class : unsigned { ok, neg_inf, pos_inf, nan }; + + [[nodiscard]] + inline fp_class fpclassify(const double& val) noexcept + { + constexpr uint64_t sign = 0b1000000000000000000000000000000000000000000000000000000000000000ull; + constexpr uint64_t exponent = 0b0111111111110000000000000000000000000000000000000000000000000000ull; + constexpr uint64_t mantissa = 0b0000000000001111111111111111111111111111111111111111111111111111ull; + + uint64_t val_bits; + memcpy(&val_bits, &val, sizeof(val)); + if ((val_bits & exponent) != exponent) + return fp_class::ok; + if ((val_bits & mantissa)) + return fp_class::nan; + return (val_bits & sign) ? fp_class::neg_inf : fp_class::pos_inf; + } + // Q: "why not use std::find??" // A: Because is _huge_ and std::find would be the only thing I used from it. // I don't want to impose such a heavy compile-time burden on users. @@ -368,16 +403,217 @@ namespace toml::impl TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS - 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; + // general value traits + // (as they relate to their equivalent native TOML type) + template + struct value_traits + { + using native_type = void; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = false; + static constexpr bool can_represent_native = false; + static constexpr bool can_partially_represent_native = false; + static constexpr auto node_type = ::toml::node_type::none; + }; + template struct value_traits : value_traits {}; + template struct value_traits : value_traits {}; + template struct value_traits : value_traits{}; + template struct value_traits : value_traits{}; + template struct value_traits : value_traits{}; + + // integer value traits + + template + struct unsigned_integer_value_traits + { + using native_type = int64_t; + static constexpr bool is_native = false; + static constexpr bool is_signed = false; + static constexpr auto min = (std::numeric_limits::min)(); + static constexpr auto max = (std::numeric_limits::max)(); + static constexpr bool is_losslessly_convertible_to_native + = (std::numeric_limits::max)() <= 9223372036854775807ULL; + static constexpr bool can_represent_native = false; + static constexpr bool can_partially_represent_native = true; + static constexpr auto node_type = ::toml::node_type::integer; + }; + template + struct signed_integer_value_traits + { + using native_type = int64_t; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_signed = true; + static constexpr auto min = (std::numeric_limits::min)(); + static constexpr auto max = (std::numeric_limits::max)(); + static constexpr bool is_losslessly_convertible_to_native + = (std::numeric_limits::min)() >= (-9223372036854775807LL - 1LL) + && (std::numeric_limits::max)() <= 9223372036854775807LL; + static constexpr bool can_represent_native + = (std::numeric_limits::min)() <= (-9223372036854775807LL - 1LL) + && (std::numeric_limits::max)() >= 9223372036854775807LL; + static constexpr bool can_partially_represent_native = true; + static constexpr auto node_type = ::toml::node_type::integer; + }; + + template > + struct integer_value_traits : signed_integer_value_traits {}; + template + struct integer_value_traits : unsigned_integer_value_traits {}; + + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + template <> struct value_traits : integer_value_traits {}; + #ifdef __SIZEOF_INT128__ + template + struct big_integer_value_traits + { + using native_type = int64_t; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = false; + static constexpr bool is_signed = static_cast(-1) < T{}; // for impls not properly specializing + static constexpr bool can_represent_native = is_signed; + static constexpr bool can_partially_represent_native = true; + static constexpr auto node_type = ::toml::node_type::integer; + }; + template <> + struct value_traits<__int128_t> : big_integer_value_traits<__int128_t> + { + static constexpr auto max = static_cast<__int128_t>(( __uint128_t{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1); + static constexpr auto min = -max - __int128_t{ 1 }; + }; + template <> + struct value_traits<__uint128_t> : big_integer_value_traits<__uint128_t> + { + static constexpr auto min = __uint128_t{}; + static constexpr auto max = (2u * static_cast<__uint128_t>(value_traits<__int128_t>::max)) + 1u; + }; + #endif + #ifdef TOML_SMALL_INT_TYPE + template <> struct value_traits : signed_integer_value_traits {}; + #endif + static_assert(value_traits::is_native); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // float value traits + + template + struct float_value_traits + { + using native_type = double; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_signed = true; + static constexpr bool is_losslessly_convertible_to_native + = std::numeric_limits::is_iec559 + && std::numeric_limits::digits <= 53 + && std::numeric_limits::digits10 <= 15 + && std::numeric_limits::max_digits10 <= 17; + static constexpr bool can_represent_native + = std::numeric_limits::is_iec559 + && std::numeric_limits::digits >= 53 + && std::numeric_limits::digits10 >= 15 + && std::numeric_limits::max_digits10 >= 17; + static constexpr bool can_partially_represent_native //32-bit float values + = std::numeric_limits::is_iec559 + && std::numeric_limits::digits >= 24 + && std::numeric_limits::digits10 >= 6 + && std::numeric_limits::max_digits10 >= 9; + static constexpr auto node_type = ::toml::node_type::floating_point; + }; + template <> struct value_traits : float_value_traits {}; + template <> struct value_traits : float_value_traits {}; + template <> struct value_traits : float_value_traits {}; + #if defined(FLT16_MANT_DIG) && defined(FLT16_DIG) && defined(FLT16_DECIMAL_DIG) + template <> struct value_traits<_Float16> : float_value_traits<_Float16> {}; + #endif + //#ifdef __SIZEOF_FLOAT80__ + //template <> struct value_traits<__float80> : float_value_traits<__float80> {}; + //#endif + #ifdef __SIZEOF_FLOAT128__ + template <> struct value_traits<__float128> : float_value_traits<__float128> {}; + #endif + #ifdef TOML_SMALL_FLOAT_TYPE + template <> struct value_traits : float_value_traits {}; + #endif + static_assert(value_traits::is_native); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // string value traits + + template + struct string_value_traits + { + using native_type = ::toml::string; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native + = !std::is_array_v + && (!std::is_pointer_v || std::is_const_v>); + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto node_type = ::toml::node_type::string; + }; + template <> struct value_traits : string_value_traits {}; + template <> struct value_traits : string_value_traits {}; + template <> struct value_traits : string_value_traits {}; + template struct value_traits : string_value_traits {}; + template <> struct value_traits : string_value_traits {}; + template struct value_traits : string_value_traits {}; + #ifdef __cpp_lib_char8_t + template <> struct value_traits : string_value_traits {}; + template <> struct value_traits : string_value_traits {}; + template <> struct value_traits : string_value_traits {}; + template struct value_traits : string_value_traits {}; + template <> struct value_traits : string_value_traits {}; + template struct value_traits : string_value_traits {}; + #endif + #if TOML_WINDOWS_COMPAT + template + struct wstring_value_traits + { + using native_type = ::toml::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; //widen + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto node_type = ::toml::node_type::string; + }; + template <> struct value_traits : wstring_value_traits {}; + template <> struct value_traits : wstring_value_traits {}; + template <> struct value_traits : wstring_value_traits {}; + template struct value_traits : wstring_value_traits {}; + template <> struct value_traits : wstring_value_traits {}; + template struct value_traits : wstring_value_traits {}; + #endif + + // other native value traits + + template + 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 node_type = NodeType; + }; + template <> struct value_traits : native_value_traits {}; + template <> struct value_traits : native_value_traits {}; + template <> struct value_traits