mirror of
https://github.com/marzer/tomlplusplus.git
synced 2024-09-04 05:59:37 +00:00
expanded allowable conversion semantics of value and value_or
also: - fixed infinity and NaN-related code breaking when using -ffast-math and friends - added much more detail to many static_assert error messages - added more test permutations of various compiler flags - added many more static checks to test code
This commit is contained in:
parent
de07ba7187
commit
cb791fe0ef
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -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
|
||||
|
@ -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 <blah.h> */
|
||||
.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
|
||||
{
|
||||
|
@ -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 <Windows.h>
|
||||
|
||||
inline void init_utf8_console() noexcept
|
||||
|
@ -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
|
||||
|
||||
//# {{
|
||||
|
@ -174,7 +174,7 @@ namespace toml::impl
|
||||
TOML_ALWAYS_INLINE
|
||||
auto* make_node(T&& val) noexcept
|
||||
{
|
||||
using type = unwrapped<remove_cvref_t<T>>;
|
||||
using type = unwrap_node<remove_cvref_t<T>>;
|
||||
if constexpr (is_one_of<type, array, table>)
|
||||
{
|
||||
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<type>,
|
||||
is_native<type> || is_losslessly_convertible_to_native<type>,
|
||||
"Value initializers must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (is_wide_string<T>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return new value{ narrow(std::forward<T>(val)) };
|
||||
else
|
||||
#else
|
||||
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return new value{ std::forward<T>(val) };
|
||||
}
|
||||
}
|
||||
@ -613,13 +617,14 @@ namespace toml
|
||||
template <typename U, typename... V>
|
||||
iterator emplace(const_iterator pos, V&&... args) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
using type = impl::unwrap_node<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"Emplacement type parameter must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
return { values.emplace(pos.raw_, new impl::node_of<type>{ std::forward<V>(args)...} ) };
|
||||
return { values.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<V>(args)...} ) };
|
||||
}
|
||||
|
||||
/// \brief Removes the specified node from the array.
|
||||
@ -774,13 +779,14 @@ namespace toml
|
||||
template <typename U, typename... V>
|
||||
decltype(auto) emplace_back(V&&... args) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
using type = impl::unwrap_node<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"Emplacement type parameter must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
auto nde = new impl::node_of<type>{ std::forward<V>(args)... };
|
||||
auto nde = new impl::wrap_node<type>{ std::forward<V>(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 <typename T>
|
||||
[[nodiscard]] impl::node_of<T>* get_as(size_t index) noexcept
|
||||
[[nodiscard]] impl::wrap_node<T>* get_as(size_t index) noexcept
|
||||
{
|
||||
if (auto val = get(index))
|
||||
return val->as<T>();
|
||||
@ -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 <typename T>
|
||||
[[nodiscard]] const impl::node_of<T>* get_as(size_t index) const noexcept
|
||||
[[nodiscard]] const impl::wrap_node<T>* get_as(size_t index) const noexcept
|
||||
{
|
||||
if (auto val = get(index))
|
||||
return val->as<T>();
|
||||
@ -879,9 +885,9 @@ namespace toml
|
||||
template <typename T>
|
||||
[[nodiscard]] static bool container_equality(const array& lhs, const T& rhs) noexcept
|
||||
{
|
||||
using elem_t = std::remove_const_t<typename T::value_type>;
|
||||
using element_type = std::remove_const_t<typename T::value_type>;
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<elem_t>,
|
||||
impl::is_native<element_type> || impl::is_losslessly_convertible_to_native<element_type>,
|
||||
"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<impl::promoted<elem_t>>(i++);
|
||||
const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
|
||||
if (!elem || *elem != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ TOML_DISABLE_ALL_WARNINGS
|
||||
#endif
|
||||
#include <cstdint>
|
||||
#include <cstring> //memcpy, memset
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
@ -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<double>::is_iec559);
|
||||
static_assert(std::numeric_limits<double>::digits == 53);
|
||||
static_assert(std::numeric_limits<double>::digits10 == 15);
|
||||
static_assert(std::numeric_limits<double>::max_digits10 == 17);
|
||||
|
||||
////////// FORWARD DECLARATIONS & TYPEDEFS
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
@ -338,6 +352,27 @@ namespace toml::impl
|
||||
return static_cast<std::underlying_type_t<T>>(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 <algorithm> 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,15 +403,216 @@ namespace toml::impl
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
|
||||
// general value traits
|
||||
// (as they relate to their equivalent native TOML type)
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_value =
|
||||
std::is_same_v<T, string>
|
||||
|| std::is_same_v<T, int64_t>
|
||||
|| std::is_same_v<T, double>
|
||||
|| std::is_same_v<T, bool>
|
||||
|| std::is_same_v<T, date>
|
||||
|| std::is_same_v<T, time>
|
||||
|| std::is_same_v<T, date_time>;
|
||||
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 <typename T> struct value_traits<T&> : value_traits<T> {};
|
||||
template <typename T> struct value_traits<T&&> : value_traits<T> {};
|
||||
template <typename T> struct value_traits<T*const> : value_traits<T*>{};
|
||||
template <typename T> struct value_traits<T*volatile> : value_traits<T*>{};
|
||||
template <typename T> struct value_traits<T*const volatile> : value_traits<T*>{};
|
||||
|
||||
// integer value traits
|
||||
|
||||
template <typename T>
|
||||
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<T>::min)();
|
||||
static constexpr auto max = (std::numeric_limits<T>::max)();
|
||||
static constexpr bool is_losslessly_convertible_to_native
|
||||
= (std::numeric_limits<T>::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 <typename T>
|
||||
struct signed_integer_value_traits
|
||||
{
|
||||
using native_type = int64_t;
|
||||
static constexpr bool is_native = std::is_same_v<T, native_type>;
|
||||
static constexpr bool is_signed = true;
|
||||
static constexpr auto min = (std::numeric_limits<T>::min)();
|
||||
static constexpr auto max = (std::numeric_limits<T>::max)();
|
||||
static constexpr bool is_losslessly_convertible_to_native
|
||||
= (std::numeric_limits<T>::min)() >= (-9223372036854775807LL - 1LL)
|
||||
&& (std::numeric_limits<T>::max)() <= 9223372036854775807LL;
|
||||
static constexpr bool can_represent_native
|
||||
= (std::numeric_limits<T>::min)() <= (-9223372036854775807LL - 1LL)
|
||||
&& (std::numeric_limits<T>::max)() >= 9223372036854775807LL;
|
||||
static constexpr bool can_partially_represent_native = true;
|
||||
static constexpr auto node_type = ::toml::node_type::integer;
|
||||
};
|
||||
|
||||
template <typename T, bool U = std::is_unsigned_v<T>>
|
||||
struct integer_value_traits : signed_integer_value_traits<T> {};
|
||||
template <typename T>
|
||||
struct integer_value_traits<T, true> : unsigned_integer_value_traits<T> {};
|
||||
|
||||
template <> struct value_traits<char> : integer_value_traits<char> {};
|
||||
template <> struct value_traits<signed char> : integer_value_traits<signed char> {};
|
||||
template <> struct value_traits<unsigned char> : integer_value_traits<unsigned char> {};
|
||||
template <> struct value_traits<signed short> : integer_value_traits<signed short> {};
|
||||
template <> struct value_traits<unsigned short> : integer_value_traits<unsigned short> {};
|
||||
template <> struct value_traits<signed int> : integer_value_traits<signed int> {};
|
||||
template <> struct value_traits<unsigned int> : integer_value_traits<unsigned int> {};
|
||||
template <> struct value_traits<signed long> : integer_value_traits<signed long> {};
|
||||
template <> struct value_traits<unsigned long> : integer_value_traits<unsigned long> {};
|
||||
template <> struct value_traits<signed long long> : integer_value_traits<signed long long> {};
|
||||
template <> struct value_traits<unsigned long long> : integer_value_traits<unsigned long long> {};
|
||||
#ifdef __SIZEOF_INT128__
|
||||
template <typename T>
|
||||
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<T>(-1) < T{}; // for impls not properly specializing <type_traits>
|
||||
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<TOML_SMALL_INT_TYPE> : signed_integer_value_traits<TOML_SMALL_INT_TYPE> {};
|
||||
#endif
|
||||
static_assert(value_traits<int64_t>::is_native);
|
||||
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);
|
||||
|
||||
// float value traits
|
||||
|
||||
template <typename T>
|
||||
struct float_value_traits
|
||||
{
|
||||
using native_type = double;
|
||||
static constexpr bool is_native = std::is_same_v<T, native_type>;
|
||||
static constexpr bool is_signed = true;
|
||||
static constexpr bool is_losslessly_convertible_to_native
|
||||
= std::numeric_limits<T>::is_iec559
|
||||
&& std::numeric_limits<T>::digits <= 53
|
||||
&& std::numeric_limits<T>::digits10 <= 15
|
||||
&& std::numeric_limits<T>::max_digits10 <= 17;
|
||||
static constexpr bool can_represent_native
|
||||
= std::numeric_limits<T>::is_iec559
|
||||
&& std::numeric_limits<T>::digits >= 53
|
||||
&& std::numeric_limits<T>::digits10 >= 15
|
||||
&& std::numeric_limits<T>::max_digits10 >= 17;
|
||||
static constexpr bool can_partially_represent_native //32-bit float values
|
||||
= std::numeric_limits<T>::is_iec559
|
||||
&& std::numeric_limits<T>::digits >= 24
|
||||
&& std::numeric_limits<T>::digits10 >= 6
|
||||
&& std::numeric_limits<T>::max_digits10 >= 9;
|
||||
static constexpr auto node_type = ::toml::node_type::floating_point;
|
||||
};
|
||||
template <> struct value_traits<float> : float_value_traits<float> {};
|
||||
template <> struct value_traits<double> : float_value_traits<double> {};
|
||||
template <> struct value_traits<long double> : float_value_traits<long double> {};
|
||||
#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<TOML_SMALL_FLOAT_TYPE> : float_value_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
|
||||
|
||||
template <typename T>
|
||||
struct string_value_traits
|
||||
{
|
||||
using native_type = ::toml::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 node_type = ::toml::node_type::string;
|
||||
};
|
||||
template <> struct value_traits<std::string> : string_value_traits<std::string> {};
|
||||
template <> struct value_traits<std::string_view> : string_value_traits<std::string_view> {};
|
||||
template <> struct value_traits<const char*> : string_value_traits<const char *> {};
|
||||
template <size_t N> struct value_traits<const char[N]> : string_value_traits<const char[N]> {};
|
||||
template <> struct value_traits<char*> : string_value_traits<char*> {};
|
||||
template <size_t N> struct value_traits<char[N]> : string_value_traits<char[N]> {};
|
||||
#ifdef __cpp_lib_char8_t
|
||||
template <> struct value_traits<std::u8string> : string_value_traits<std::u8string> {};
|
||||
template <> struct value_traits<std::u8string_view> : string_value_traits<std::u8string_view> {};
|
||||
template <> struct value_traits<const char8_t*> : string_value_traits<const char8_t*> {};
|
||||
template <size_t N> struct value_traits<const char8_t[N]> : string_value_traits<const char8_t[N]> {};
|
||||
template <> struct value_traits<char8_t*> : string_value_traits<char8_t*> {};
|
||||
template <size_t N> struct value_traits<char8_t[N]> : string_value_traits<char8_t[N]> {};
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
template <typename T>
|
||||
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<T, std::wstring>; //widen
|
||||
static constexpr bool can_partially_represent_native = can_represent_native;
|
||||
static constexpr auto node_type = ::toml::node_type::string;
|
||||
};
|
||||
template <> struct value_traits<std::wstring> : wstring_value_traits<std::wstring> {};
|
||||
template <> struct value_traits<std::wstring_view> : wstring_value_traits<std::wstring_view> {};
|
||||
template <> struct value_traits<const wchar_t*> : wstring_value_traits<const wchar_t*> {};
|
||||
template <size_t N> struct value_traits<const wchar_t[N]> : wstring_value_traits<const wchar_t[N]> {};
|
||||
template <> struct value_traits<wchar_t*> : wstring_value_traits<wchar_t*> {};
|
||||
template <size_t N> struct value_traits<wchar_t[N]> : wstring_value_traits<wchar_t[N]> {};
|
||||
#endif
|
||||
|
||||
// other native value traits
|
||||
|
||||
template <typename T, ::toml::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 node_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> {};
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_wide_string = is_one_of<
|
||||
@ -387,34 +623,20 @@ namespace toml::impl
|
||||
std::wstring
|
||||
>;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_value_or_promotable =
|
||||
is_value<T>
|
||||
|| std::is_same_v<std::decay_t<T>, string_char*>
|
||||
|| std::is_same_v<T, string_view>
|
||||
|| std::is_same_v<T, int32_t>
|
||||
|| std::is_same_v<T, int16_t>
|
||||
|| std::is_same_v<T, int8_t>
|
||||
|| std::is_same_v<T, uint32_t>
|
||||
|| std::is_same_v<T, uint16_t>
|
||||
|| std::is_same_v<T, uint8_t>
|
||||
|| std::is_same_v<T, float>
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|| is_wide_string<T>
|
||||
#endif
|
||||
#ifdef TOML_SMALL_FLOAT_TYPE
|
||||
|| std::is_same_v<T, TOML_SMALL_FLOAT_TYPE>
|
||||
#endif
|
||||
#ifdef TOML_SMALL_INT_TYPE
|
||||
|| std::is_same_v<T, TOML_SMALL_INT_TYPE>
|
||||
#endif
|
||||
;
|
||||
// native value category queries
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_value_or_node =
|
||||
is_value<T>
|
||||
|| std::is_same_v<T, array>
|
||||
|| std::is_same_v<T, table>;
|
||||
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...>;
|
||||
|
||||
template <typename T> struct node_wrapper { using type = T; };
|
||||
template <> struct node_wrapper<string> { using type = value<string>; };
|
||||
@ -424,65 +646,16 @@ namespace toml::impl
|
||||
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 node_of = typename impl::node_wrapper<T>::type;
|
||||
template <typename T> using wrap_node = typename node_wrapper<T>::type;
|
||||
|
||||
template <typename T> struct node_unwrapper { using type = T; };
|
||||
template <typename T> struct node_unwrapper<value<T>> { using type = T; };
|
||||
template <typename T> using unwrap_node = typename node_unwrapper<T>::type;
|
||||
|
||||
template <typename T> using unwrapped = typename impl::node_unwrapper<T>::type;
|
||||
|
||||
template <typename T> struct value_promoter { using type = T; };
|
||||
template <size_t N> struct value_promoter<const string_char[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<const string_char(&)[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<const string_char(&&)[N]> { using type = string; };
|
||||
template <> struct value_promoter<const string_char*> { using type = string; };
|
||||
template <size_t N> struct value_promoter<string_char[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<string_char(&)[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<string_char(&&)[N]> { using type = string; };
|
||||
template <> struct value_promoter<string_char*> { using type = string; };
|
||||
template <> struct value_promoter<string_view> { using type = string; };
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
template <size_t N> struct value_promoter<const wchar_t[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<const wchar_t(&)[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<const wchar_t(&&)[N]> { using type = string; };
|
||||
template <> struct value_promoter<const wchar_t*> { using type = string; };
|
||||
template <size_t N> struct value_promoter<wchar_t[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<wchar_t(&)[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<wchar_t(&&)[N]> { using type = string; };
|
||||
template <> struct value_promoter<wchar_t*> { using type = string; };
|
||||
template <> struct value_promoter<std::wstring_view> { using type = string; };
|
||||
template <> struct value_promoter<std::wstring> { using type = string; };
|
||||
#endif
|
||||
template <> struct value_promoter<int32_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<int16_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<int8_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint32_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint16_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint8_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<float> { using type = double; };
|
||||
#ifdef TOML_SMALL_FLOAT_TYPE
|
||||
template <> struct value_promoter<TOML_SMALL_FLOAT_TYPE> { using type = double; };
|
||||
#endif
|
||||
#ifdef TOML_SMALL_INT_TYPE
|
||||
template <> struct value_promoter<TOML_SMALL_INT_TYPE> { using type = int64_t; };
|
||||
#endif
|
||||
template <typename T> using promoted = typename impl::value_promoter<T>::type;
|
||||
|
||||
template <typename T> struct node_type_of_;
|
||||
template <> struct node_type_of_<table> { static constexpr auto value = node_type::table; };
|
||||
template <> struct node_type_of_<array> { static constexpr auto value = node_type::array; };
|
||||
template <> struct node_type_of_<string> { static constexpr auto value = node_type::string; };
|
||||
template <> struct node_type_of_<int64_t> { static constexpr auto value = node_type::integer; };
|
||||
template <> struct node_type_of_<double> { static constexpr auto value = node_type::floating_point; };
|
||||
template <> struct node_type_of_<bool> { static constexpr auto value = node_type::boolean; };
|
||||
template <> struct node_type_of_<date> { static constexpr auto value = node_type::date; };
|
||||
template <> struct node_type_of_<time> { static constexpr auto value = node_type::time; };
|
||||
template <> struct node_type_of_<date_time> { static constexpr auto value = node_type::date_time; };
|
||||
|
||||
template <typename T>
|
||||
inline constexpr auto node_type_of = node_type_of_<promoted<typename node_unwrapper<remove_cvref_t<T>>::type>>::value;
|
||||
template <typename T> struct node_type_getter { static constexpr auto value = value_traits<T>::node_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 <typename T> inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value;
|
||||
|
||||
inline constexpr std::string_view low_character_escape_table[] =
|
||||
{
|
||||
@ -534,26 +707,28 @@ namespace toml::impl
|
||||
"date-time"sv
|
||||
};
|
||||
|
||||
#define TOML_P2S_DECL(Linkage, Type) \
|
||||
#define TOML_P2S_DECL(Type) \
|
||||
template <typename Char> \
|
||||
Linkage void print_to_stream(Type, std::basic_ostream<Char>&)
|
||||
inline void print_to_stream(Type, std::basic_ostream<Char>&)
|
||||
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int8_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int16_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int32_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int64_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint8_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint16_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint32_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint64_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, float);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, double);
|
||||
TOML_P2S_DECL(inline, const date&);
|
||||
TOML_P2S_DECL(inline, const time&);
|
||||
TOML_P2S_DECL(inline, time_offset);
|
||||
TOML_P2S_DECL(inline, const date_time&);
|
||||
TOML_P2S_DECL(int8_t);
|
||||
TOML_P2S_DECL(int16_t);
|
||||
TOML_P2S_DECL(int32_t);
|
||||
TOML_P2S_DECL(int64_t);
|
||||
TOML_P2S_DECL(uint8_t);
|
||||
TOML_P2S_DECL(uint16_t);
|
||||
TOML_P2S_DECL(uint32_t);
|
||||
TOML_P2S_DECL(uint64_t);
|
||||
TOML_P2S_DECL(float);
|
||||
TOML_P2S_DECL(const date&);
|
||||
TOML_P2S_DECL(const time&);
|
||||
TOML_P2S_DECL(time_offset);
|
||||
TOML_P2S_DECL(const date_time&);
|
||||
|
||||
#undef TOML_P2S_DECL
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool dependent_false = false;
|
||||
}
|
||||
|
||||
namespace toml
|
||||
@ -566,28 +741,28 @@ namespace toml
|
||||
inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>;
|
||||
/// \brief Metafunction for determining if a type is a toml::string or toml::value<toml::string>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_string = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<string>>;
|
||||
inline constexpr bool is_string = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<string>>;
|
||||
/// \brief Metafunction for determining if a type is an int64_t or toml::value<int64_t>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_integer = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<int64_t>>;
|
||||
inline constexpr bool is_integer = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<int64_t>>;
|
||||
/// \brief Metafunction for determining if a type is a double or toml::value<double>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_floating_point = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<double>>;
|
||||
inline constexpr bool is_floating_point = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<double>>;
|
||||
/// \brief Metafunction for determining if a type satisfies `toml::is_integer || toml::is_floating_point`.
|
||||
template <typename T>
|
||||
inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
|
||||
/// \brief Metafunction for determining if a type is a bool toml::value<bool>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_boolean = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<bool>>;
|
||||
inline constexpr bool is_boolean = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<bool>>;
|
||||
/// \brief Metafunction for determining if a type is a toml::date or toml::value<date>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_date = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<date>>;
|
||||
inline constexpr bool is_date = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date>>;
|
||||
/// \brief Metafunction for determining if a type is a toml::time or toml::value<time>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_time = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<time>>;
|
||||
inline constexpr bool is_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<time>>;
|
||||
/// \brief Metafunction for determining if a type is a toml::date_time or toml::value<date_time>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_date_time = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<date_time>>;
|
||||
inline constexpr bool is_date_time = std::is_same_v<impl::wrap_node<impl::remove_cvref_t<T>>, value<date_time>>;
|
||||
|
||||
/// \brief Pretty-prints the value of a node_type to a stream.
|
||||
///
|
||||
|
@ -12,6 +12,10 @@
|
||||
//# }}
|
||||
|
||||
#include "toml_default_formatter.h"
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
#include <cmath>
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
|
@ -29,16 +29,18 @@ namespace toml
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
TOML_ATTR(const)
|
||||
TOML_ATTR(flatten)
|
||||
constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
|
||||
{
|
||||
return static_cast<format_flags>(impl::unbox_enum(lhs) & impl::unbox_enum(rhs));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
TOML_ATTR(const)
|
||||
TOML_ATTR(flatten)
|
||||
constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
|
||||
{
|
||||
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
|
||||
|
@ -75,7 +75,6 @@ namespace toml
|
||||
// print_to_stream() machinery
|
||||
namespace impl
|
||||
{
|
||||
template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
|
||||
template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,41 @@
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
#define TOML_NATIVE_STRING_TYPE_NAME "std::u8string"
|
||||
#else
|
||||
#define TOML_NATIVE_STRING_TYPE_NAME "std::string"
|
||||
#endif
|
||||
|
||||
#define TOML_NATIVE_VALUE_TYPE_LIST \
|
||||
"\n| - " TOML_NATIVE_STRING_TYPE_NAME \
|
||||
"\n| - int64_t" \
|
||||
"\n| - double" \
|
||||
"\n| - bool" \
|
||||
"\n| - toml::date" \
|
||||
"\n| - toml::time" \
|
||||
"\n| - toml::date_time"
|
||||
|
||||
|
||||
#define TOML_NODE_TYPE_LIST \
|
||||
"\n| - toml::table" \
|
||||
"\n| - toml::array" \
|
||||
"\n| - toml::value<" TOML_NATIVE_STRING_TYPE_NAME ">" \
|
||||
"\n| - toml::value<int64_t>" \
|
||||
"\n| - toml::value<double>" \
|
||||
"\n| - toml::value<bool>" \
|
||||
"\n| - toml::value<toml::date>" \
|
||||
"\n| - toml::value<toml::time>" \
|
||||
"\n| - toml::value<toml::date_time>"
|
||||
|
||||
#define TOML_UNWRAPPED_NODE_TYPE_LIST \
|
||||
"\n|" \
|
||||
"\n| A native TOML value type" \
|
||||
TOML_NATIVE_VALUE_TYPE_LIST \
|
||||
"\n|" \
|
||||
"\n| A TOML node type" \
|
||||
TOML_NODE_TYPE_LIST
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief A TOML node.
|
||||
@ -27,24 +62,27 @@ namespace toml
|
||||
node& operator= (node&& rhs) noexcept;
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
impl::node_of<T>& ref_cast() & noexcept
|
||||
[[nodiscard]]
|
||||
TOML_ALWAYS_INLINE
|
||||
impl::wrap_node<T>& ref_cast() & noexcept
|
||||
{
|
||||
return *reinterpret_cast<impl::node_of<T>*>(this);
|
||||
return *reinterpret_cast<impl::wrap_node<T>*>(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
impl::node_of<T>&& ref_cast() && noexcept
|
||||
[[nodiscard]]
|
||||
TOML_ALWAYS_INLINE
|
||||
impl::wrap_node<T>&& ref_cast() && noexcept
|
||||
{
|
||||
return std::move(*reinterpret_cast<impl::node_of<T>*>(this));
|
||||
return std::move(*reinterpret_cast<impl::wrap_node<T>*>(this));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
const impl::node_of<T>& ref_cast() const & noexcept
|
||||
[[nodiscard]]
|
||||
TOML_ALWAYS_INLINE
|
||||
const impl::wrap_node<T>& ref_cast() const & noexcept
|
||||
{
|
||||
return *reinterpret_cast<const impl::node_of<T>*>(this);
|
||||
return *reinterpret_cast<const impl::wrap_node<T>*>(this);
|
||||
}
|
||||
|
||||
template <typename N, typename T>
|
||||
@ -93,13 +131,14 @@ namespace toml
|
||||
///
|
||||
/// \returns Returns true if this node is an instance of the specified type.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
[[nodiscard]]
|
||||
bool is() const noexcept
|
||||
{
|
||||
using type = impl::unwrapped<impl::remove_cvref_t<T>>;
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"The template type argument of node::is() must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>) return is_table();
|
||||
@ -142,6 +181,19 @@ namespace toml
|
||||
[[nodiscard]] virtual const toml::value<time>* as_time() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<date_time>* as_date_time() const noexcept;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
decltype(auto) get_value_exact() const noexcept;
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
optional<T> value_exact() const noexcept;
|
||||
|
||||
/// \brief Gets the raw value contained by this node.
|
||||
///
|
||||
/// \detail The optional returned by this function will only contain a value if the node was an instance of
|
||||
@ -189,7 +241,8 @@ namespace toml
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching type (or convertible to it), or an empty optional.
|
||||
template <typename T>
|
||||
[[nodiscard]] optional<T> value() const noexcept;
|
||||
[[nodiscard]]
|
||||
optional<T> value() const noexcept;
|
||||
|
||||
/// \brief Gets the raw value contained by this node, or a default.
|
||||
///
|
||||
@ -202,7 +255,8 @@ namespace toml
|
||||
///
|
||||
/// \see node::value()
|
||||
template <typename T>
|
||||
[[nodiscard]] auto value_or(T&& default_value) const noexcept;
|
||||
[[nodiscard]]
|
||||
auto value_or(T&& default_value) const noexcept;
|
||||
|
||||
/// \brief Gets a pointer to the node as a more specific node type.
|
||||
///
|
||||
@ -226,13 +280,14 @@ namespace toml
|
||||
///
|
||||
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
impl::node_of<T>* as() noexcept
|
||||
[[nodiscard]]
|
||||
impl::wrap_node<T>* as() noexcept
|
||||
{
|
||||
using type = impl::unwrapped<T>;
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"The template type argument of node::as() must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>) return as_table();
|
||||
@ -248,13 +303,14 @@ namespace toml
|
||||
|
||||
/// \brief Gets a pointer to the node as a more specific node type (const overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
const impl::node_of<T>* as() const noexcept
|
||||
[[nodiscard]]
|
||||
const impl::wrap_node<T>* as() const noexcept
|
||||
{
|
||||
using type = impl::unwrapped<T>;
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"The template type argument of node::as() must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>) return as_table();
|
||||
@ -424,18 +480,20 @@ namespace toml
|
||||
|
||||
|
||||
template <typename T, typename N>
|
||||
[[nodiscard]] static decltype(auto) do_ref(N&& n) noexcept
|
||||
[[nodiscard]]
|
||||
static decltype(auto) do_ref(N&& n) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<T>;
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"The template type argument of node::ref() must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
TOML_ASSERT(
|
||||
n.template is<T>()
|
||||
&& "template type argument T provided to toml::node::ref() didn't match the node's actual type"
|
||||
);
|
||||
if constexpr (impl::is_value<type>)
|
||||
if constexpr (impl::is_native<type>)
|
||||
return std::forward<N>(n).template ref_cast<type>().get();
|
||||
else
|
||||
return std::forward<N>(n).template ref_cast<type>();
|
||||
@ -511,21 +569,24 @@ namespace toml
|
||||
///
|
||||
/// \returns A reference to the underlying data.
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::unwrapped<T>& ref() & noexcept
|
||||
[[nodiscard]]
|
||||
impl::unwrap_node<T>& ref() & noexcept
|
||||
{
|
||||
return do_ref<T>(*this);
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data (rvalue overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::unwrapped<T>&& ref() && noexcept
|
||||
[[nodiscard]]
|
||||
impl::unwrap_node<T>&& ref() && noexcept
|
||||
{
|
||||
return do_ref<T>(std::move(*this));
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data (const lvalue overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] const impl::unwrapped<T>& ref() const& noexcept
|
||||
[[nodiscard]]
|
||||
const impl::unwrap_node<T>& ref() const& noexcept
|
||||
{
|
||||
return do_ref<T>(*this);
|
||||
}
|
||||
|
@ -147,12 +147,14 @@ namespace toml
|
||||
[[nodiscard]]
|
||||
auto as() const noexcept
|
||||
{
|
||||
using type = impl::unwrap_node<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<impl::unwrapped<U>>,
|
||||
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"Template type parameter must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
return node_ ? node_->template as<U>() : nullptr;
|
||||
return node_ ? node_->template as<type>() : nullptr;
|
||||
}
|
||||
|
||||
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
|
||||
@ -174,6 +176,15 @@ namespace toml
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
|
||||
[[nodiscard]] auto as_date_time() const noexcept { return as<date_time>(); }
|
||||
|
||||
template <typename U>
|
||||
[[nodiscard]]
|
||||
optional<U> value_exact() const noexcept
|
||||
{
|
||||
if (node_)
|
||||
return node_->template value_exact<U>();
|
||||
return {};
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_INIT_WARNINGS
|
||||
|
||||
@ -185,7 +196,8 @@ namespace toml
|
||||
///
|
||||
/// \see node::value()
|
||||
template <typename U>
|
||||
[[nodiscard]] optional<U> value() const noexcept
|
||||
[[nodiscard]]
|
||||
optional<U> value() const noexcept
|
||||
{
|
||||
if (node_)
|
||||
return node_->template value<U>();
|
||||
@ -205,12 +217,45 @@ namespace toml
|
||||
///
|
||||
/// \see node::value_or()
|
||||
template <typename U>
|
||||
[[nodiscard]] auto value_or(U&& default_value) const noexcept
|
||||
[[nodiscard]]
|
||||
auto value_or(U&& default_value) const noexcept
|
||||
{
|
||||
using return_type = decltype(node_->value_or(std::forward<U>(default_value)));
|
||||
using namespace ::toml::impl;
|
||||
|
||||
static_assert(
|
||||
!is_wide_string<U> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
if constexpr (is_wide_string<U>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
if (node_)
|
||||
return node_->value_or(std::forward<U>(default_value));
|
||||
return return_type{ std::forward<U>(default_value) };
|
||||
return std::wstring{ std::forward<U>(default_value) };
|
||||
|
||||
#else
|
||||
|
||||
static_assert(impl::dependent_false<U>, "Evaluated unreachable branch!");
|
||||
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
using value_type = std::conditional_t<
|
||||
std::is_pointer_v<std::decay_t<U>>,
|
||||
std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<U>>>>,
|
||||
std::decay_t<U>
|
||||
>;
|
||||
|
||||
if (node_)
|
||||
return node_->value_or(std::forward<U>(default_value));
|
||||
if constexpr (std::is_pointer_v<value_type>)
|
||||
return value_type{ default_value };
|
||||
else
|
||||
return std::forward<U>(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the viewed node based on its concrete type.
|
||||
@ -252,10 +297,11 @@ namespace toml
|
||||
template <typename U>
|
||||
[[nodiscard]] decltype(auto) ref() const noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
using type = impl::unwrap_node<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"Template type parameter must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
TOML_ASSERT(
|
||||
node_
|
||||
@ -296,7 +342,10 @@ namespace toml
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
template <typename U, typename = std::enable_if_t<
|
||||
impl::is_native<U>
|
||||
|| impl::is_losslessly_convertible_to_native<U>
|
||||
>>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
static_assert(
|
||||
@ -304,20 +353,27 @@ namespace toml
|
||||
"Comparison with wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (impl::is_wide_string<U>)
|
||||
return lhs == impl::narrow(rhs);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return lhs == impl::narrow(rhs);
|
||||
#else
|
||||
static_assert(impl::dependent_false<U>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto val = lhs.as<impl::native_type_of<U>>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(
|
||||
const node_view&,
|
||||
const U&,
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
template <typename U, typename = std::enable_if_t<
|
||||
impl::is_native<U>
|
||||
|| impl::is_losslessly_convertible_to_native<U>
|
||||
>>
|
||||
)
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
|
||||
|
@ -1023,8 +1023,8 @@ namespace toml::impl
|
||||
push_parse_scope("floating-point"sv);
|
||||
|
||||
start_recording(true);
|
||||
const int sign = *cp == U'-' ? -1 : 1;
|
||||
if (is_match(*cp, U'+', U'-'))
|
||||
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');
|
||||
@ -1037,9 +1037,14 @@ namespace toml::impl
|
||||
if (cp && !is_value_terminator(*cp))
|
||||
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
|
||||
|
||||
return inf
|
||||
? sign * std::numeric_limits<double>::infinity()
|
||||
: std::numeric_limits<double>::quiet_NaN();
|
||||
// control for implementations that don't properly implement std::numeric_limits<double>::quiet_NaN()
|
||||
// and/or std::numeric_limits<double>::infinity() (e.g. due to -ffast-math and friends)
|
||||
constexpr uint64_t neg_inf = 0b1111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t pos_inf = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t qnan = 0b0111111111111000000000000000000000000000000000000000000000000000ull;
|
||||
double rval;
|
||||
std::memcpy(&rval, inf ? (negative ? &neg_inf : &pos_inf) : &qnan, sizeof(double));
|
||||
return rval;
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
|
@ -34,8 +34,7 @@ namespace toml::impl
|
||||
// - Strings in C++. Honestly.
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(std::basic_string_view<Char1> str, std::basic_ostream<Char2>& stream)
|
||||
inline void print_to_stream(std::basic_string_view<Char1> str, std::basic_ostream<Char2>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char1) == 1);
|
||||
static_assert(sizeof(Char2) == 1);
|
||||
@ -43,8 +42,7 @@ namespace toml::impl
|
||||
}
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(const std::basic_string<Char1>& str, std::basic_ostream<Char2>& stream)
|
||||
inline void print_to_stream(const std::basic_string<Char1>& str, std::basic_ostream<Char2>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char1) == 1);
|
||||
static_assert(sizeof(Char2) == 1);
|
||||
@ -52,8 +50,7 @@ namespace toml::impl
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(char character, std::basic_ostream<Char>& stream)
|
||||
inline void print_to_stream(char character, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.put(static_cast<Char>(character));
|
||||
@ -61,8 +58,7 @@ namespace toml::impl
|
||||
|
||||
template <typename Char>
|
||||
TOML_ATTR(nonnull)
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(const char* str, size_t len, std::basic_ostream<Char>& stream)
|
||||
inline void print_to_stream(const char* str, size_t len, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
|
||||
@ -71,8 +67,7 @@ namespace toml::impl
|
||||
#ifdef __cpp_lib_char8_t
|
||||
|
||||
template <typename Char>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(char8_t character, std::basic_ostream<Char>& stream)
|
||||
inline void print_to_stream(char8_t character, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.put(static_cast<Char>(character));
|
||||
@ -80,8 +75,7 @@ namespace toml::impl
|
||||
|
||||
template <typename Char>
|
||||
TOML_ATTR(nonnull)
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(const char8_t* str, size_t len, std::basic_ostream<Char>& stream)
|
||||
inline void print_to_stream(const char8_t* str, size_t len, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
|
||||
@ -130,8 +124,7 @@ namespace toml::impl
|
||||
|
||||
#define TOML_P2S_OVERLOAD(Type) \
|
||||
template <typename Char> \
|
||||
TOML_ALWAYS_INLINE \
|
||||
void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
|
||||
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
|
||||
{ \
|
||||
static_assert(sizeof(Char) == 1); \
|
||||
print_integer_to_stream(val, stream); \
|
||||
@ -157,19 +150,21 @@ namespace toml::impl
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
switch (std::fpclassify(val))
|
||||
switch (impl::fpclassify(val))
|
||||
{
|
||||
case FP_INFINITE:
|
||||
if (val < T{})
|
||||
print_to_stream('-', stream);
|
||||
case fp_class::neg_inf:
|
||||
print_to_stream("-inf"sv, stream);
|
||||
break;
|
||||
|
||||
case fp_class::pos_inf:
|
||||
print_to_stream("inf"sv, stream);
|
||||
return;
|
||||
break;
|
||||
|
||||
case FP_NAN:
|
||||
case fp_class::nan:
|
||||
print_to_stream("nan"sv, stream);
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
case fp_class::ok:
|
||||
{
|
||||
static constexpr auto needs_decimal_point = [](auto&& s) noexcept
|
||||
{
|
||||
@ -204,32 +199,32 @@ namespace toml::impl
|
||||
print_to_stream(".0"sv, stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
|
||||
extern template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
|
||||
#endif
|
||||
|
||||
#define TOML_P2S_OVERLOAD(Type) \
|
||||
template <typename Char> \
|
||||
TOML_ALWAYS_INLINE \
|
||||
void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
|
||||
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
|
||||
{ \
|
||||
static_assert(sizeof(Char) == 1); \
|
||||
print_floating_point_to_stream(val, stream); \
|
||||
}
|
||||
|
||||
TOML_P2S_OVERLOAD(float)
|
||||
TOML_P2S_OVERLOAD(double)
|
||||
|
||||
#undef TOML_P2S_OVERLOAD
|
||||
|
||||
template <typename Char>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(bool val, std::basic_ostream<Char>& stream)
|
||||
inline void print_to_stream(bool val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val ? "true"sv : "false"sv, stream);
|
||||
|
@ -453,11 +453,15 @@ namespace toml
|
||||
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (impl::is_wide_string<K>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return insert(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
|
||||
else
|
||||
#else
|
||||
static_assert(impl::dependent_false<K>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ipos = values.lower_bound(key);
|
||||
if (ipos == values.end() || ipos->first != key)
|
||||
@ -560,11 +564,15 @@ namespace toml
|
||||
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (impl::is_wide_string<K>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return insert_or_assign(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
|
||||
else
|
||||
#else
|
||||
static_assert(impl::dependent_false<K>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ipos = values.lower_bound(key);
|
||||
if (ipos == values.end() || ipos->first != key)
|
||||
@ -626,17 +634,22 @@ namespace toml
|
||||
"Emplacement using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (impl::is_wide_string<K>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return emplace<U>(impl::narrow(std::forward<K>(key)), std::forward<V>(args)...);
|
||||
else
|
||||
#else
|
||||
static_assert(impl::dependent_false<U>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
using type = impl::unwrapped<U>;
|
||||
using type = impl::unwrap_node<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
impl::is_native<type> || impl::is_one_of<type, table, array>,
|
||||
"The emplacement type argument of table::emplace() must be one of the following:"
|
||||
TOML_UNWRAPPED_NODE_TYPE_LIST
|
||||
);
|
||||
|
||||
auto ipos = values.lower_bound(key);
|
||||
@ -645,7 +658,7 @@ namespace toml
|
||||
ipos = values.emplace_hint(
|
||||
ipos,
|
||||
std::forward<K>(key),
|
||||
new impl::node_of<type>{ std::forward<V>(args)... }
|
||||
new impl::wrap_node<type>{ std::forward<V>(args)... }
|
||||
);
|
||||
return { ipos, true };
|
||||
}
|
||||
@ -782,11 +795,15 @@ namespace toml
|
||||
"Retrieval using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (impl::is_wide_string<Key>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return do_get(vals, impl::narrow(key));
|
||||
else
|
||||
#else
|
||||
static_assert(impl::dependent_false<Key>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto it = vals.find(key); it != vals.end())
|
||||
return { it->second.get() };
|
||||
@ -927,7 +944,7 @@ namespace toml
|
||||
///
|
||||
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::node_of<T>* get_as(string_view key) noexcept
|
||||
[[nodiscard]] impl::wrap_node<T>* get_as(string_view key) noexcept
|
||||
{
|
||||
return do_get_as<T>(values, key);
|
||||
}
|
||||
@ -939,7 +956,7 @@ namespace toml
|
||||
///
|
||||
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
|
||||
template <typename T>
|
||||
[[nodiscard]] const impl::node_of<T>* get_as(string_view key) const noexcept
|
||||
[[nodiscard]] const impl::wrap_node<T>* get_as(string_view key) const noexcept
|
||||
{
|
||||
return do_get_as<T>(values, key);
|
||||
}
|
||||
@ -955,7 +972,7 @@ namespace toml
|
||||
///
|
||||
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::node_of<T>* get_as(std::wstring_view key) noexcept
|
||||
[[nodiscard]] impl::wrap_node<T>* get_as(std::wstring_view key) noexcept
|
||||
{
|
||||
return get_as<T>(impl::narrow(key));
|
||||
}
|
||||
@ -969,7 +986,7 @@ namespace toml
|
||||
///
|
||||
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
|
||||
template <typename T>
|
||||
[[nodiscard]] const impl::node_of<T>* get_as(std::wstring_view key) const noexcept
|
||||
[[nodiscard]] const impl::wrap_node<T>* get_as(std::wstring_view key) const noexcept
|
||||
{
|
||||
return get_as<T>(impl::narrow(key));
|
||||
}
|
||||
|
@ -20,25 +20,27 @@ namespace toml
|
||||
///
|
||||
/// \tparam T The value's data type. Can be one of:
|
||||
/// - toml::string
|
||||
/// - int64_t
|
||||
/// - double
|
||||
/// - bool
|
||||
/// - toml::date
|
||||
/// - toml::time
|
||||
/// - toml::date_time
|
||||
/// - int64_t
|
||||
/// - double
|
||||
/// - bool
|
||||
template <typename T>
|
||||
class TOML_API value final : public node
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value<T>,
|
||||
"Template type parameter must be one of the TOML value types"
|
||||
impl::is_native<T>,
|
||||
"A toml::value<> must model one of the native TOML value types:"
|
||||
TOML_NATIVE_VALUE_TYPE_LIST
|
||||
);
|
||||
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
|
||||
template <typename U, typename V>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
[[nodiscard]]
|
||||
TOML_ALWAYS_INLINE
|
||||
static auto as_value([[maybe_unused]] V* ptr) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
@ -194,21 +196,40 @@ namespace toml
|
||||
}
|
||||
|
||||
/// \brief Value equality operator.
|
||||
[[nodiscard]] friend bool operator == (const value& lhs, value_arg rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator == (const value& lhs, value_arg rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<value_type, double>)
|
||||
{
|
||||
using namespace ::toml::impl;
|
||||
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
|
||||
{
|
||||
return ((static_cast<uint64_t>(l) << 32) | static_cast<uint64_t>(r));
|
||||
return (static_cast<uint64_t>(unbox_enum(l)) << 32)
|
||||
| static_cast<uint64_t>(unbox_enum(r));
|
||||
};
|
||||
|
||||
switch (pack(std::fpclassify(lhs.val_), std::fpclassify(rhs)))
|
||||
switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
|
||||
{
|
||||
case pack(FP_INFINITE, FP_INFINITE): return (lhs.val_ < 0.0) == (rhs < 0.0);
|
||||
case pack(FP_NAN, FP_NAN): return true;
|
||||
default: return lhs.val_ == rhs;
|
||||
case pack(fp_class::pos_inf, fp_class::neg_inf): [[fallthrough]];
|
||||
case pack(fp_class::pos_inf, fp_class::nan): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::nan): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::neg_inf):
|
||||
return false;
|
||||
|
||||
case pack(fp_class::pos_inf, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::neg_inf): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::nan):
|
||||
return true;
|
||||
|
||||
case pack(fp_class::ok, fp_class::ok):
|
||||
return lhs.val_ == rhs;
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
else
|
||||
return lhs.val_ == rhs;
|
||||
@ -241,7 +262,8 @@ namespace toml
|
||||
///
|
||||
/// \returns True if the values were of the same type and contained the same value.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const value& lhs, const value<U>& rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator == (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs == rhs.val_; //calls asymmetrical value-equality operator defined above
|
||||
@ -256,7 +278,8 @@ namespace toml
|
||||
///
|
||||
/// \returns True if the values were not of the same type, or did not contain the same value.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator != (const value& lhs, const value<U>& rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator != (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
@ -269,7 +292,8 @@ namespace toml
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() < rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() < rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator < (const value& lhs, const value<U>& rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator < (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ < rhs.val_;
|
||||
@ -285,7 +309,8 @@ namespace toml
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() <= rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() <= rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator <= (const value& lhs, const value<U>& rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator <= (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ <= rhs.val_;
|
||||
@ -301,7 +326,8 @@ namespace toml
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() > rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() > rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator > (const value& lhs, const value<U>& rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator > (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ > rhs.val_;
|
||||
@ -317,7 +343,8 @@ namespace toml
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() >= rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() >= rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator >= (const value& lhs, const value<U>& rhs) noexcept
|
||||
[[nodiscard]]
|
||||
friend bool operator >= (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ >= rhs.val_;
|
||||
@ -339,128 +366,265 @@ namespace toml
|
||||
TOML_POP_WARNINGS
|
||||
#endif
|
||||
|
||||
template <size_t N> value(const string_char(&)[N]) -> value<string>;
|
||||
template <size_t N> value(const string_char(&&)[N]) -> value<string>;
|
||||
value(const string_char*) -> value<string>;
|
||||
template <size_t N> value(string_char(&)[N]) -> value<string>;
|
||||
template <size_t N> value(string_char(&&)[N]) -> value<string>;
|
||||
value(string_char*) -> value<string>;
|
||||
value(string_view) -> value<string>;
|
||||
value(string) -> value<string>;
|
||||
value(bool) -> value<bool>;
|
||||
value(float) -> value<double>;
|
||||
value(double) -> value<double>;
|
||||
value(int8_t) -> value<int64_t>;
|
||||
value(int16_t) -> value<int64_t>;
|
||||
value(int32_t) -> value<int64_t>;
|
||||
value(int64_t) -> value<int64_t>;
|
||||
value(uint8_t) -> value<int64_t>;
|
||||
value(uint16_t) -> value<int64_t>;
|
||||
value(uint32_t) -> value<int64_t>;
|
||||
value(date) -> value<date>;
|
||||
value(time) -> value<time>;
|
||||
value(date_time) -> value<date_time>;
|
||||
#ifdef TOML_SMALL_FLOAT_TYPE
|
||||
value(TOML_SMALL_FLOAT_TYPE) -> value<double>;
|
||||
#endif
|
||||
#ifdef TOML_SMALL_INT_TYPE
|
||||
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
|
||||
#endif
|
||||
template <typename T>
|
||||
value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_INIT_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
inline decltype(auto) node::get_value_exact() const noexcept
|
||||
{
|
||||
using namespace ::toml::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>);
|
||||
TOML_ASSERT(this->type() == node_type_of<T>);
|
||||
|
||||
if constexpr (node_type_of<T> == node_type::string)
|
||||
{
|
||||
const auto& str = *ref_cast<string>();
|
||||
if constexpr (std::is_same_v<T, string>)
|
||||
return str;
|
||||
else if constexpr (std::is_same_v<T, string_view>)
|
||||
return T{ str };
|
||||
else if constexpr (std::is_same_v<T, const string_char*>)
|
||||
return str.c_str();
|
||||
|
||||
else if constexpr (std::is_same_v<T, std::wstring>)
|
||||
{
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return widen(str);
|
||||
#else
|
||||
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
|
||||
// char8_t -> char (safe)
|
||||
else if constexpr (is_one_of<T, std::string, std::string_view>)
|
||||
return T(reinterpret_cast<const char*>(str.c_str()), str.length());
|
||||
else if constexpr (std::is_same_v<T, const char*>)
|
||||
return reinterpret_cast<const char*>(str.c_str());
|
||||
|
||||
#ifdef __cpp_lib_char8_t
|
||||
// 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(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return static_cast<T>(*ref_cast<native_type_of<T>>());
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline optional<T> node::value_exact() const noexcept
|
||||
{
|
||||
using namespace ::toml::impl;
|
||||
|
||||
static_assert(
|
||||
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings with node::value_exact() is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
static_assert(
|
||||
is_native<T> || can_represent_native<T>,
|
||||
"The return type of node::value_exact() must be one of the following:"
|
||||
"\n|"
|
||||
"\n| A native TOML value type"
|
||||
TOML_NATIVE_VALUE_TYPE_LIST
|
||||
"\n|"
|
||||
"\n| A non-view type capable of losslessly representing a native TOML value type"
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
"\n| - std::string"
|
||||
#elif defined __cpp_lib_char8_t
|
||||
"\n| - std::u8string"
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
"\n| - std::wstring"
|
||||
#endif
|
||||
"\n| - any signed integer type >= 64 bits"
|
||||
"\n| - any floating-point type >= 64 bits of precision"
|
||||
"\n|"
|
||||
"\n| An immutable view type not requiring additional temporary storage"
|
||||
"\n| - std::string_view"
|
||||
"\n| - const char*"
|
||||
#ifdef __cpp_lib_char8_t
|
||||
"\n| - std::u8string_view"
|
||||
"\n| - const char8_t*"
|
||||
#endif
|
||||
);
|
||||
|
||||
if (type() == node_type_of<T>)
|
||||
return { this->get_value_exact<T>() };
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline optional<T> node::value() const noexcept
|
||||
{
|
||||
using namespace ::toml::impl;
|
||||
|
||||
static_assert(
|
||||
!impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings with node::value() is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
static_assert(
|
||||
impl::is_value<T>
|
||||
|| std::is_same_v<T, string_view>
|
||||
|| (TOML_WINDOWS_COMPAT && std::is_same_v<T, std::wstring>),
|
||||
"Value type must be one of the TOML value types (or string_view)"
|
||||
is_native<T> || can_represent_native<T> || can_partially_represent_native<T>,
|
||||
"The return type of node::value() must be one of the following:"
|
||||
"\n|"
|
||||
"\n| A native TOML value type"
|
||||
TOML_NATIVE_VALUE_TYPE_LIST
|
||||
"\n|"
|
||||
"\n| A non-view type capable of losslessly representing a native TOML value type"
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
"\n| - std::string"
|
||||
#elif defined __cpp_lib_char8_t
|
||||
"\n| - std::u8string"
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
"\n| - std::wstring"
|
||||
#endif
|
||||
"\n| - any signed integer type >= 64 bits"
|
||||
"\n| - any floating-point type >= 64 bits of precision"
|
||||
"\n|"
|
||||
"\n| A non-view type capable of (reasonably) representing a native TOML value type"
|
||||
"\n| - any other integer type"
|
||||
"\n| - any floating-point type >= 32 bits of precision"
|
||||
"\n|"
|
||||
"\n| An immutable view type not requiring additional temporary storage"
|
||||
"\n| - std::string_view"
|
||||
"\n| - const char*"
|
||||
#ifdef __cpp_lib_char8_t
|
||||
"\n| - std::u8string_view"
|
||||
"\n| - const char8_t*"
|
||||
#endif
|
||||
);
|
||||
|
||||
// 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, 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())
|
||||
{
|
||||
case node_type::none: [[fallthrough]];
|
||||
case node_type::table: [[fallthrough]];
|
||||
case node_type::array:
|
||||
return {};
|
||||
|
||||
case node_type::string:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, string> || std::is_same_v<T, string_view>)
|
||||
return { T{ ref_cast<string>().get() } };
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
else if constexpr (std::is_same_v<T, std::wstring>)
|
||||
return { impl::widen(ref_cast<string>().get()) };
|
||||
#endif
|
||||
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
// int -> *
|
||||
case node_type::integer:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, int64_t>)
|
||||
return ref_cast<int64_t>().get();
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return static_cast<double>(ref_cast<int64_t>().get());
|
||||
// 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
|
||||
{
|
||||
using traits = value_traits<T>;
|
||||
const int64_t val = *ref_cast<int64_t>();
|
||||
if constexpr (!traits::is_signed)
|
||||
{
|
||||
if constexpr ((sizeof(T) * CHAR_BIT) <= 53) // 53 bits < int64_max < 54 bits
|
||||
{
|
||||
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) };
|
||||
}
|
||||
}
|
||||
|
||||
// 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:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, double>)
|
||||
return ref_cast<double>().get();
|
||||
else if constexpr (std::is_same_v<T, int64_t>)
|
||||
return static_cast<int64_t>(ref_cast<double>().get());
|
||||
// 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 (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)())
|
||||
return {};
|
||||
return { static_cast<T>(val) };
|
||||
}
|
||||
}
|
||||
|
||||
// float -> anything else
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
// bool -> *
|
||||
case node_type::boolean:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, bool>)
|
||||
return ref_cast<bool>().get();
|
||||
// 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 {};
|
||||
}
|
||||
}
|
||||
|
||||
case node_type::date:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, date>)
|
||||
return ref_cast<date>().get();
|
||||
else
|
||||
// non-values, or 'exact' types covered above
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::time:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, time>)
|
||||
return ref_cast<time>().get();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::date_time:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, date_time>)
|
||||
return ref_cast<date_time>().get();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
@ -468,35 +632,95 @@ namespace toml
|
||||
template <typename T>
|
||||
inline auto node::value_or(T&& default_value) const noexcept
|
||||
{
|
||||
using namespace ::toml::impl;
|
||||
|
||||
static_assert(
|
||||
!impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<impl::remove_cvref_t<T>>,
|
||||
"Default value type must be (or be promotable to) one of the TOML value types"
|
||||
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings with node::value_or() is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
||||
);
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (impl::is_wide_string<T>)
|
||||
|
||||
if constexpr (is_wide_string<T>)
|
||||
{
|
||||
if (this->type() == node_type::string)
|
||||
return impl::widen(ref_cast<string>().get());
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
if (type() == node_type::string)
|
||||
return widen(*ref_cast<string>());
|
||||
return std::wstring{ std::forward<T>(default_value) };
|
||||
|
||||
#else
|
||||
|
||||
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
using value_type = impl::promoted<impl::remove_cvref_t<T>>;
|
||||
using return_type = std::conditional_t<
|
||||
std::is_same_v<value_type, string>,
|
||||
std::conditional_t<std::is_same_v<impl::remove_cvref_t<T>, string>, string, string_view>,
|
||||
value_type
|
||||
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>;
|
||||
|
||||
if (auto val = this->value<return_type>())
|
||||
static_assert(
|
||||
traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
|
||||
"The default return value type of node::value_or() must be one of the following:"
|
||||
"\n|"
|
||||
"\n| A native TOML value type"
|
||||
TOML_NATIVE_VALUE_TYPE_LIST
|
||||
"\n| "
|
||||
"\n| A non-view type capable of losslessly representing a native TOML value type"
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
"\n| - std::string"
|
||||
#elif defined __cpp_lib_char8_t
|
||||
"\n| - std::u8string"
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
"\n| - std::wstring"
|
||||
#endif
|
||||
"\n| - any signed integer type >= 64 bits"
|
||||
"\n| - any floating-point type >= 64 bits of precision"
|
||||
"\n|"
|
||||
"\n| A non-view type capable of (reasonably) representing a native TOML value type"
|
||||
"\n| - any other integer type"
|
||||
"\n| - any floating-point type >= 32 bits of precision"
|
||||
"\n|"
|
||||
"\n| A compatible view type"
|
||||
"\n| - std::string_view"
|
||||
"\n| - const char*"
|
||||
"\n| - const char[] (deduced as const char*)"
|
||||
"\n| - char* (deduced as const char*)"
|
||||
#ifdef __cpp_lib_char8_t
|
||||
"\n| - std::u8string_view"
|
||||
"\n| - const char8_t*"
|
||||
"\n| - const char8_t[] (deduced as const char8_t*)"
|
||||
"\n| - char8_t* (deduced as const char8_t*)"
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
"\n| - std::wstring_view (promoted to std::wstring)"
|
||||
"\n| - const wchar_t* (promoted to std::wstring)"
|
||||
"\n| - const wchar_t[] (promoted to std::wstring)"
|
||||
"\n| - wchar_t* (promoted to std::wstring)"
|
||||
#endif
|
||||
);
|
||||
|
||||
if constexpr (traits::is_native)
|
||||
{
|
||||
if (type() == node_type_of<value_type>)
|
||||
return *ref_cast<typename traits::native_type>();
|
||||
return std::forward<T>(default_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto val = this->value<value_type>())
|
||||
return *val;
|
||||
return return_type{ std::forward<T>(default_value) };
|
||||
if constexpr (std::is_pointer_v<value_type>)
|
||||
return value_type{ default_value };
|
||||
else
|
||||
return std::forward<T>(default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
#pragma once
|
||||
|
||||
#define TOML_LIB_MAJOR 1
|
||||
#define TOML_LIB_MINOR 3
|
||||
#define TOML_LIB_PATCH 4
|
||||
#define TOML_LIB_MINOR 4
|
||||
#define TOML_LIB_PATCH 0
|
||||
|
||||
#define TOML_LANG_MAJOR 1
|
||||
#define TOML_LANG_MINOR 0
|
||||
|
@ -1,7 +1,7 @@
|
||||
project(
|
||||
'tomlplusplus',
|
||||
'cpp',
|
||||
version : '1.3.4',
|
||||
version : '1.4.0',
|
||||
license : 'MIT',
|
||||
default_options : [
|
||||
'cpp_std=c++17',
|
||||
@ -104,7 +104,6 @@ if build_tests or build_examples
|
||||
endif
|
||||
add_project_arguments([
|
||||
'-ferror-limit=5',
|
||||
'-fchar8_t',
|
||||
'-Wno-unused-command-line-argument',
|
||||
|
||||
# flags from here down are disabling stupidly pedantic warnings that only appear with -Weverything
|
||||
|
@ -35,9 +35,9 @@ def python_value_to_tomlpp(val):
|
||||
return 'true' if val else 'false'
|
||||
elif isinstance(val, float):
|
||||
if math.isinf(val):
|
||||
return ('-' if val < 0.0 else '') + 'std::numeric_limits<double>::infinity()'
|
||||
return 'make_infinity({})'.format('' if val >= 0.0 else '-1')
|
||||
elif math.isnan(val):
|
||||
return 'std::numeric_limits<double>::quiet_NaN()'
|
||||
return 'make_nan()'
|
||||
else:
|
||||
return str(val)
|
||||
elif isinstance(val, int):
|
||||
|
@ -155,7 +155,6 @@ class HTMLDocument(object):
|
||||
|
||||
|
||||
|
||||
|
||||
def html_find_parent(tag, names, cutoff=None):
|
||||
if not utils.is_collection(names):
|
||||
names = [ names ]
|
||||
@ -861,13 +860,10 @@ class ExtDocLinksFix(object):
|
||||
def __call__(self, file, doc):
|
||||
changed = False
|
||||
root = doc.body.main.article.div.div
|
||||
|
||||
tags = tags = html_shallow_search(root, self.__allowedNames, lambda t: html_find_parent(t, 'a', root) is None)
|
||||
|
||||
strings = []
|
||||
for tag in tags:
|
||||
strings = strings + html_string_descendants(tag, lambda t: html_find_parent(t, 'a', tag) is None)
|
||||
|
||||
for expr, uri in self.__expressions:
|
||||
for string in strings:
|
||||
if string.parent is None:
|
||||
@ -880,7 +876,6 @@ class ExtDocLinksFix(object):
|
||||
if (begins_with_ws and new_tag.string is not None and not new_tag.string[:1].isspace()):
|
||||
new_tag.insert_before(' ')
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
@ -1009,11 +1004,6 @@ def postprocess_file(dir, file, fixes):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def preprocess_xml(xml_dir):
|
||||
pass
|
||||
|
||||
|
@ -79,6 +79,22 @@ def is_collection(val):
|
||||
|
||||
|
||||
|
||||
def is_pow2(v):
|
||||
return v & (v-1) == 0
|
||||
|
||||
|
||||
|
||||
def next_power_of_2(n):
|
||||
if n == 0:
|
||||
return 1
|
||||
if n & (n - 1) == 0:
|
||||
return n
|
||||
while n & (n - 1) > 0:
|
||||
n &= (n - 1)
|
||||
return n << 1
|
||||
|
||||
|
||||
|
||||
def get_all_files(dir, all=None, any=None):
|
||||
files = [f for f in [path.join(dir, f) for f in os.listdir(dir)] if path.isfile(f)]
|
||||
if (files and all is not None):
|
||||
|
@ -6,8 +6,17 @@
|
||||
#pragma once
|
||||
#include "settings.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#endif
|
||||
|
||||
#if __has_include(<Catch2/single_include/catch2/catch.hpp>)
|
||||
#include <Catch2/single_include/catch2/catch.hpp>
|
||||
#else
|
||||
#error Catch2 is missing! You probably need to fetch submodules ("git submodule update --init extern/Catch2")
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
@ -744,7 +744,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_10, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ S(R"(sf1)"sv), std::numeric_limits<double>::infinity() },
|
||||
{ S(R"(sf1)"sv), make_infinity() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -752,7 +752,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_11, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ S(R"(sf2)"sv), std::numeric_limits<double>::infinity() },
|
||||
{ S(R"(sf2)"sv), make_infinity() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -760,7 +760,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_12, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ S(R"(sf2)"sv), -std::numeric_limits<double>::infinity() },
|
||||
{ S(R"(sf2)"sv), make_infinity(-1) },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -768,7 +768,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_13, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ S(R"(sf4)"sv), std::numeric_limits<double>::quiet_NaN() },
|
||||
{ S(R"(sf4)"sv), make_nan() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -776,7 +776,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_14, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ S(R"(sf5)"sv), std::numeric_limits<double>::quiet_NaN() },
|
||||
{ S(R"(sf5)"sv), make_nan() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -784,7 +784,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_15, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ S(R"(sf6)"sv), std::numeric_limits<double>::quiet_NaN() },
|
||||
{ S(R"(sf6)"sv), make_nan() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
|
27
tests/evil_macros.h
Normal file
27
tests/evil_macros.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
// simulate some 'evil' macros to ensure the library is robust against them if they appear in the wild.
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef min
|
||||
#define min(...) THIS_IS_AN_EVIL_MACRO
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(...) THIS_IS_AN_EVIL_MACRO
|
||||
#endif
|
||||
|
||||
#ifndef near
|
||||
#define near THIS_IS_AN_EVIL_MACRO
|
||||
#endif
|
||||
|
||||
#ifndef far
|
||||
#define far THIS_IS_AN_EVIL_MACRO
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
// ...
|
||||
|
||||
#endif
|
@ -9,11 +9,7 @@
|
||||
#endif
|
||||
|
||||
#if USE_TARTANLLAMA_OPTIONAL
|
||||
#if __has_include(<tloptional/include/tl/optional.hpp>)
|
||||
#include <tloptional/include/tl/optional.hpp>
|
||||
#else
|
||||
#error TartanLlama/optional is missing! You probably need to fetch submodules ("git submodule update --init extern/tloptional")
|
||||
#endif
|
||||
#include "tloptional.h"
|
||||
#endif
|
||||
|
||||
#if USE_SINGLE_HEADER
|
||||
@ -30,11 +26,234 @@
|
||||
#error TOML_WINDOWS_COMPAT does not match _WIN32 (default behaviour should be to match)
|
||||
#endif
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
#define int128 __int128_t
|
||||
#define uint128 __uint128_t
|
||||
#endif
|
||||
#if defined(FLT16_MANT_DIG) && defined(FLT16_DIG) && defined(FLT16_DECIMAL_DIG)
|
||||
#define float16 _Float16
|
||||
#endif
|
||||
|
||||
namespace toml
|
||||
{
|
||||
using std::declval;
|
||||
using std::is_same_v;
|
||||
|
||||
#define CHECK_CAN_REPRESENT_NATIVE(T, expected) \
|
||||
static_assert((impl::value_traits<T>::is_native || impl::value_traits<T>::can_represent_native) == expected)
|
||||
|
||||
CHECK_CAN_REPRESENT_NATIVE(time, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(date, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(date_time, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(bool, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(int8_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(int16_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(int32_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(int64_t, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(uint8_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(uint16_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(uint32_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(uint64_t, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(float, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(double, true);
|
||||
#ifdef int128
|
||||
CHECK_CAN_REPRESENT_NATIVE(int128, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(uint128, false);
|
||||
#endif
|
||||
#ifdef float16
|
||||
CHECK_CAN_REPRESENT_NATIVE(float16, false);
|
||||
#endif
|
||||
|
||||
CHECK_CAN_REPRESENT_NATIVE(char*, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char*const, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char(&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char(&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char(&&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char(&&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char*, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char*const, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(std::string, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(std::string_view, true);
|
||||
#ifdef __cpp_lib_char8_t
|
||||
CHECK_CAN_REPRESENT_NATIVE(char8_t*, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char8_t*const, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char8_t[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char8_t[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char8_t(&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char8_t(&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(char(&&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char8_t(&&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char8_t*, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const char8_t*const, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(std::u8string, true);
|
||||
CHECK_CAN_REPRESENT_NATIVE(std::u8string_view, true);
|
||||
#endif
|
||||
CHECK_CAN_REPRESENT_NATIVE(wchar_t*, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(wchar_t*const, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(wchar_t[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const wchar_t[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(wchar_t(&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const wchar_t(&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(wchar_t(&&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const wchar_t(&&)[2], false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const wchar_t*, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(const wchar_t*const, false);
|
||||
CHECK_CAN_REPRESENT_NATIVE(std::wstring, !!TOML_WINDOWS_COMPAT);
|
||||
CHECK_CAN_REPRESENT_NATIVE(std::wstring_view, false);
|
||||
|
||||
#define CHECK_VALUE_EXACT(T, expected) \
|
||||
static_assert(is_same_v<decltype(declval<node>().value_exact<T>()), optional<expected>>); \
|
||||
static_assert(is_same_v<decltype(declval<node_view<node>>().value_exact<T>()), optional<expected>>); \
|
||||
static_assert(is_same_v<decltype(declval<node_view<const node>>().value_exact<T>()), optional<expected>>)
|
||||
|
||||
#define CHECK_VALUE_OR(T, expected) \
|
||||
static_assert(is_same_v<decltype(declval<node>().value_or(declval<T>())), expected>); \
|
||||
static_assert(is_same_v<decltype(declval<node_view<node>>().value_or(declval<T>())), expected>); \
|
||||
static_assert(is_same_v<decltype(declval<node_view<const node>>().value_or(declval<T>())), expected>)
|
||||
|
||||
CHECK_VALUE_EXACT( time, time);
|
||||
CHECK_VALUE_EXACT( date, date);
|
||||
CHECK_VALUE_EXACT( date_time, date_time);
|
||||
CHECK_VALUE_EXACT( bool, bool);
|
||||
CHECK_VALUE_EXACT( double, double);
|
||||
CHECK_VALUE_EXACT( int64_t, int64_t);
|
||||
CHECK_VALUE_EXACT( const char*, const char*);
|
||||
CHECK_VALUE_EXACT( std::string_view, std::string_view);
|
||||
CHECK_VALUE_EXACT( std::string, std::string);
|
||||
#ifdef __cpp_lib_char8_t
|
||||
CHECK_VALUE_EXACT( const char8_t*, const char8_t*);
|
||||
CHECK_VALUE_EXACT( std::u8string_view, std::u8string_view);
|
||||
CHECK_VALUE_EXACT( std::u8string, std::u8string);
|
||||
#endif
|
||||
|
||||
CHECK_VALUE_OR( time, time);
|
||||
CHECK_VALUE_OR( time&, time);
|
||||
CHECK_VALUE_OR( time&&, time);
|
||||
CHECK_VALUE_OR( time const, time);
|
||||
CHECK_VALUE_OR( date, date);
|
||||
CHECK_VALUE_OR( date&, date);
|
||||
CHECK_VALUE_OR( date&&, date);
|
||||
CHECK_VALUE_OR( date const, date);
|
||||
CHECK_VALUE_OR( date_time, date_time);
|
||||
CHECK_VALUE_OR( date_time&, date_time);
|
||||
CHECK_VALUE_OR( date_time&&, date_time);
|
||||
CHECK_VALUE_OR( date_time const, date_time);
|
||||
CHECK_VALUE_OR( bool, bool);
|
||||
CHECK_VALUE_OR( bool&, bool);
|
||||
CHECK_VALUE_OR( bool&&, bool);
|
||||
CHECK_VALUE_OR( bool const, bool);
|
||||
CHECK_VALUE_OR( int32_t, int32_t);
|
||||
CHECK_VALUE_OR( int32_t&, int32_t);
|
||||
CHECK_VALUE_OR( int32_t&&, int32_t);
|
||||
CHECK_VALUE_OR( int32_t const, int32_t);
|
||||
CHECK_VALUE_OR( int64_t, int64_t);
|
||||
CHECK_VALUE_OR( int64_t&, int64_t);
|
||||
CHECK_VALUE_OR( int64_t&&, int64_t);
|
||||
CHECK_VALUE_OR( int64_t const, int64_t);
|
||||
#ifdef int128
|
||||
CHECK_VALUE_OR( int128, int128);
|
||||
CHECK_VALUE_OR( int128&, int128);
|
||||
CHECK_VALUE_OR( int128&&, int128);
|
||||
CHECK_VALUE_OR( int128 const, int128);
|
||||
CHECK_VALUE_OR( uint128, uint128);
|
||||
CHECK_VALUE_OR( uint128&, uint128);
|
||||
CHECK_VALUE_OR( uint128&&, uint128);
|
||||
CHECK_VALUE_OR( uint128 const, uint128);
|
||||
#endif
|
||||
CHECK_VALUE_OR( float, float);
|
||||
CHECK_VALUE_OR( float&, float);
|
||||
CHECK_VALUE_OR( float&&, float);
|
||||
CHECK_VALUE_OR( float const, float);
|
||||
CHECK_VALUE_OR( double, double);
|
||||
CHECK_VALUE_OR( double&, double);
|
||||
CHECK_VALUE_OR( double&&, double);
|
||||
CHECK_VALUE_OR( double const, double);
|
||||
CHECK_VALUE_OR( char*, const char*);
|
||||
CHECK_VALUE_OR( char*&, const char*);
|
||||
CHECK_VALUE_OR( char*&&, const char*);
|
||||
CHECK_VALUE_OR( char*const, const char*);
|
||||
CHECK_VALUE_OR( char[2], const char*);
|
||||
CHECK_VALUE_OR( char(&)[2], const char*);
|
||||
CHECK_VALUE_OR( char(&&)[2], const char*);
|
||||
CHECK_VALUE_OR( const char*, const char*);
|
||||
CHECK_VALUE_OR( const char*&, const char*);
|
||||
CHECK_VALUE_OR( const char*&&, const char*);
|
||||
CHECK_VALUE_OR( const char*const, const char*);
|
||||
CHECK_VALUE_OR( const char[2], const char*);
|
||||
CHECK_VALUE_OR( const char(&)[2], const char*);
|
||||
CHECK_VALUE_OR( const char(&&)[2], const char*);
|
||||
CHECK_VALUE_OR( std::string_view, std::string_view);
|
||||
CHECK_VALUE_OR( std::string_view&, std::string_view);
|
||||
CHECK_VALUE_OR( std::string_view&&, std::string_view);
|
||||
CHECK_VALUE_OR( const std::string_view, std::string_view);
|
||||
CHECK_VALUE_OR( const std::string_view&, std::string_view);
|
||||
CHECK_VALUE_OR( const std::string_view&&, std::string_view);
|
||||
CHECK_VALUE_OR( std::string, std::string);
|
||||
CHECK_VALUE_OR( std::string&, std::string);
|
||||
CHECK_VALUE_OR( std::string&&, std::string);
|
||||
CHECK_VALUE_OR( const std::string, std::string);
|
||||
CHECK_VALUE_OR( const std::string&, std::string);
|
||||
CHECK_VALUE_OR( const std::string&&, std::string);
|
||||
#ifdef __cpp_lib_char8_t
|
||||
CHECK_VALUE_OR( char8_t*, const char8_t*);
|
||||
CHECK_VALUE_OR( char8_t*&, const char8_t*);
|
||||
CHECK_VALUE_OR( char8_t*&&, const char8_t*);
|
||||
CHECK_VALUE_OR( char8_t*const, const char8_t*);
|
||||
CHECK_VALUE_OR( char8_t[2], const char8_t*);
|
||||
CHECK_VALUE_OR( char8_t(&)[2], const char8_t*);
|
||||
CHECK_VALUE_OR( char8_t(&&)[2], const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t*, const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t*&, const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t*&&, const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t*const, const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t[2], const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t(&)[2], const char8_t*);
|
||||
CHECK_VALUE_OR( const char8_t(&&)[2], const char8_t*);
|
||||
CHECK_VALUE_OR( std::u8string_view, std::u8string_view);
|
||||
CHECK_VALUE_OR( std::u8string_view&, std::u8string_view);
|
||||
CHECK_VALUE_OR( std::u8string_view&&, std::u8string_view);
|
||||
CHECK_VALUE_OR( const std::u8string_view, std::u8string_view);
|
||||
CHECK_VALUE_OR( const std::u8string_view&, std::u8string_view);
|
||||
CHECK_VALUE_OR( const std::u8string_view&&, std::u8string_view);
|
||||
CHECK_VALUE_OR( std::u8string, std::u8string);
|
||||
CHECK_VALUE_OR( std::u8string&, std::u8string);
|
||||
CHECK_VALUE_OR( std::u8string&&, std::u8string);
|
||||
CHECK_VALUE_OR( const std::u8string, std::u8string);
|
||||
CHECK_VALUE_OR( const std::u8string&, std::u8string);
|
||||
CHECK_VALUE_OR( const std::u8string&&, std::u8string);
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
CHECK_VALUE_OR( wchar_t*, std::wstring);
|
||||
CHECK_VALUE_OR( wchar_t*&, std::wstring);
|
||||
CHECK_VALUE_OR( wchar_t*&&, std::wstring);
|
||||
CHECK_VALUE_OR( wchar_t*const, std::wstring);
|
||||
CHECK_VALUE_OR( wchar_t[2], std::wstring);
|
||||
CHECK_VALUE_OR( wchar_t(&)[2], std::wstring);
|
||||
CHECK_VALUE_OR( wchar_t(&&)[2], std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t*, std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t*&, std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t*&&, std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t*const, std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t[2], std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t(&)[2], std::wstring);
|
||||
CHECK_VALUE_OR( const wchar_t(&&)[2], std::wstring);
|
||||
CHECK_VALUE_OR( std::wstring_view, std::wstring);
|
||||
CHECK_VALUE_OR( std::wstring_view&, std::wstring);
|
||||
CHECK_VALUE_OR( std::wstring_view&&, std::wstring);
|
||||
CHECK_VALUE_OR( const std::wstring_view, std::wstring);
|
||||
CHECK_VALUE_OR( const std::wstring_view&, std::wstring);
|
||||
CHECK_VALUE_OR( const std::wstring_view&&, std::wstring);
|
||||
CHECK_VALUE_OR( std::wstring, std::wstring);
|
||||
CHECK_VALUE_OR( std::wstring&, std::wstring);
|
||||
CHECK_VALUE_OR( std::wstring&&, std::wstring);
|
||||
CHECK_VALUE_OR( const std::wstring, std::wstring);
|
||||
CHECK_VALUE_OR( const std::wstring&, std::wstring);
|
||||
CHECK_VALUE_OR( const std::wstring&&, std::wstring);
|
||||
#endif
|
||||
|
||||
|
||||
static_assert(is_same_v<decltype(declval<node&>().ref<double>()), double&>);
|
||||
static_assert(is_same_v<decltype(declval<node&&>().ref<double>()), double&&>);
|
||||
static_assert(is_same_v<decltype(declval<const node&>().ref<double>()), const double&>);
|
||||
|
@ -48,9 +48,3 @@ TEST_CASE("values - printing")
|
||||
CHECK(print_value(10000000000) == "10000000000");
|
||||
CHECK(print_value(100000000000000) == "100000000000000");
|
||||
}
|
||||
|
||||
static_assert(std::is_same_v<string, decltype(std::declval<node>().value_or(S(""s)))>);
|
||||
static_assert(std::is_same_v<string_view, decltype(std::declval<node>().value_or(S(""sv)))>);
|
||||
static_assert(std::is_same_v<string_view, decltype(std::declval<node>().value_or(S("")))>);
|
||||
|
||||
|
||||
|
@ -24,65 +24,153 @@ test_sources = [
|
||||
'windows_compat.cpp'
|
||||
]
|
||||
|
||||
compiler_supports_char8_strings = compiler.compiles('''
|
||||
compiler_supports_cpp20 = compiler.links('''
|
||||
#include <version>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string s = "kek";
|
||||
std::cout << s << std::endl;
|
||||
return 0;
|
||||
}
|
||||
''',
|
||||
name : 'supports C++20',
|
||||
args : [ '-std=c++2a' ]
|
||||
)
|
||||
|
||||
compiler_supports_char8 = compiler_supports_cpp20 and compiler.links('''
|
||||
#include <version>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
#ifndef __cpp_lib_char8_t
|
||||
#error oh noes
|
||||
#endif
|
||||
|
||||
static_assert(!std::is_same_v<char, char8_t>);
|
||||
static_assert(!std::is_same_v<std::string, std::u8string>);
|
||||
|
||||
std::u8string func()
|
||||
{
|
||||
return std::u8string{ u8"this is a test."sv };
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
''',
|
||||
name : 'char8 string check',
|
||||
args : [ '-std=c++2a' ]
|
||||
name : 'supports char8_t',
|
||||
args : [ '-std=c++2a', '-fchar8_t' ]
|
||||
)
|
||||
|
||||
character_types = ['char', 'char8']
|
||||
compiler_supports_float16 = compiler.links('''
|
||||
int main()
|
||||
{
|
||||
static_assert(sizeof(_Float16) = 2);
|
||||
_Float16 f = static_cast<_Float16>(1);
|
||||
return 0;
|
||||
}
|
||||
''',
|
||||
name : 'supports float16',
|
||||
args : [ '-mfp16-format=ieee' ]
|
||||
)
|
||||
|
||||
compiler_supports_fast_math = compiler.links('''
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
int main()
|
||||
{
|
||||
std::cout << std::exp2(2.0) << std::pow(2.0, 3.0) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
''',
|
||||
name : 'supports fast-math',
|
||||
args : [ '-ffast-math', '-ffp-contract=fast' ]
|
||||
)
|
||||
|
||||
fast_math_modes = [ false, true ]
|
||||
char8_modes = [ false, true ]
|
||||
exception_modes = [ true, false ]
|
||||
unreleased_feature_modes = [ true, false ]
|
||||
tloptional_modes = [ true, false ]
|
||||
strict_modes = [ false, true ]
|
||||
cpp20_modes = [ false, true ]
|
||||
executables = []
|
||||
counter = 0
|
||||
foreach character_type : character_types
|
||||
if character_type == 'char8' and not compiler_supports_char8_strings
|
||||
foreach cpp20 : cpp20_modes
|
||||
foreach strict : strict_modes
|
||||
if cpp20 and not compiler_supports_cpp20
|
||||
continue
|
||||
endif
|
||||
foreach char8 : char8_modes
|
||||
if char8 and (not cpp20 or not compiler_supports_char8 or strict)
|
||||
continue
|
||||
endif
|
||||
foreach fast_math : fast_math_modes
|
||||
if fast_math and not compiler_supports_fast_math
|
||||
continue
|
||||
endif
|
||||
foreach exceptions : exception_modes
|
||||
foreach unreleased_features : unreleased_feature_modes
|
||||
foreach tloptional : tloptional_modes
|
||||
|
||||
if tloptional and not (character_type =='char' and unreleased_features and exceptions)
|
||||
continue
|
||||
endif
|
||||
|
||||
name = character_type
|
||||
name = ''
|
||||
overrides = []
|
||||
args = []
|
||||
|
||||
if character_type =='char8'
|
||||
overrides += 'cpp_std=none'
|
||||
args += '-DTOML_CHAR_8_STRINGS=1'
|
||||
args += '-std=c++2a'
|
||||
if compiler_supports_float16
|
||||
args += '-mfp16-format=ieee'
|
||||
endif
|
||||
|
||||
if unreleased_features
|
||||
args += '-DTOML_UNRELEASED_FEATURES=1'
|
||||
if cpp20
|
||||
name = 'cpp20'
|
||||
overrides += 'cpp_std=none'
|
||||
args += '-std=c++2a'
|
||||
|
||||
if compiler_supports_char8
|
||||
args += '-fchar8_t'
|
||||
endif
|
||||
else
|
||||
name = 'cpp17'
|
||||
endif
|
||||
|
||||
if strict
|
||||
name = name + '_strict'
|
||||
args += '-DTOML_UNRELEASED_FEATURES=0'
|
||||
else
|
||||
args += '-DTOML_UNRELEASED_FEATURES=1'
|
||||
endif
|
||||
|
||||
if char8
|
||||
name = name + '_char8'
|
||||
args += '-DTOML_CHAR_8_STRINGS=1'
|
||||
endif
|
||||
|
||||
|
||||
if not exceptions
|
||||
name = name + '_noexcept'
|
||||
overrides += 'cpp_eh=none'
|
||||
endif
|
||||
|
||||
if tloptional
|
||||
name = name + '_tlopt'
|
||||
args += '-DUSE_TARTANLLAMA_OPTIONAL=1'
|
||||
if fast_math
|
||||
name = name + '_fastmath'
|
||||
if compiler.get_id() == 'gcc' or compiler.get_id() == 'clang'
|
||||
args += '-ffast-math'
|
||||
args += '-ffp-contract=fast'
|
||||
endif
|
||||
endif
|
||||
|
||||
args += '-DTEST_BUILD_ID=@0@'.format(counter)
|
||||
if counter % 6 == 3
|
||||
args += '-DTOML_ALL_INLINE=1'
|
||||
endif
|
||||
if counter % 2 == 1
|
||||
args += '-DUSE_SINGLE_HEADER=1'
|
||||
endif
|
||||
if counter % 4 == 2 and exceptions
|
||||
args += '-DUSE_TARTANLLAMA_OPTIONAL=1'
|
||||
name = name + '_tlopt'
|
||||
endif
|
||||
|
||||
if compiler.get_id() == 'gcc'
|
||||
args += '-Wno-padded'
|
||||
@ -108,10 +196,11 @@ foreach character_type : character_types
|
||||
|
||||
counter = counter + 1
|
||||
|
||||
endforeach # tloptional_modes
|
||||
endforeach # unreleased_feature_modes
|
||||
endforeach # exception_modes
|
||||
endforeach # character_type
|
||||
endforeach # exceptions
|
||||
endforeach # fast_math
|
||||
endforeach # char8
|
||||
endforeach # strict
|
||||
endforeach # cpp20
|
||||
|
||||
locales = [
|
||||
'C',
|
||||
@ -125,8 +214,8 @@ locales = [
|
||||
'de_DE.utf8'
|
||||
]
|
||||
|
||||
foreach locale : locales
|
||||
foreach executable : executables
|
||||
test(locale + '_' + executable[0], executable[1], env : ['LC_ALL=' + locale])
|
||||
foreach executable : executables
|
||||
foreach locale : locales
|
||||
test(executable[0] + ' (' + locale + ')', executable[1], env : ['LC_ALL=' + locale])
|
||||
endforeach
|
||||
endforeach
|
||||
|
@ -200,12 +200,12 @@ TEST_CASE("parsing - inf and nan")
|
||||
)"sv,
|
||||
[](table&& tbl)
|
||||
{
|
||||
CHECK(tbl[S("sf1")] == std::numeric_limits<double>::infinity());
|
||||
CHECK(tbl[S("sf2")] == std::numeric_limits<double>::infinity());
|
||||
CHECK(tbl[S("sf3")] == -std::numeric_limits<double>::infinity());
|
||||
CHECK(std::isnan(tbl[S("sf4")].as<double>()->get()));
|
||||
CHECK(std::isnan(tbl[S("sf5")].as<double>()->get()));
|
||||
CHECK(std::isnan(tbl[S("sf6")].as<double>()->get()));
|
||||
CHECK(impl::fpclassify(**tbl[S("sf1")].as<double>()) == impl::fp_class::pos_inf);
|
||||
CHECK(impl::fpclassify(**tbl[S("sf2")].as<double>()) == impl::fp_class::pos_inf);
|
||||
CHECK(impl::fpclassify(**tbl[S("sf3")].as<double>()) == impl::fp_class::neg_inf);
|
||||
CHECK(impl::fpclassify(**tbl[S("sf4")].as<double>()) == impl::fp_class::nan);
|
||||
CHECK(impl::fpclassify(**tbl[S("sf5")].as<double>()) == impl::fp_class::nan);
|
||||
CHECK(impl::fpclassify(**tbl[S("sf6")].as<double>()) == impl::fp_class::nan);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -7,14 +7,6 @@
|
||||
|
||||
// toml++ config
|
||||
#define TOML_UNDEF_MACROS 0
|
||||
#ifdef TEST_BUILD_ID
|
||||
#if (TEST_BUILD_ID % 3 == 0) && !defined(TOML_ALL_INLINE)
|
||||
#define TOML_ALL_INLINE 1
|
||||
#endif
|
||||
#if (TEST_BUILD_ID % 2 == 0) && !defined(USE_SINGLE_HEADER)
|
||||
#define USE_SINGLE_HEADER 1
|
||||
#endif
|
||||
#endif
|
||||
#ifndef TOML_ALL_INLINE
|
||||
#define TOML_ALL_INLINE 0
|
||||
#endif
|
||||
@ -38,6 +30,7 @@
|
||||
#define CATCH_CONFIG_CONSOLE_WIDTH 120
|
||||
#define CATCH_CONFIG_CPP11_TO_STRING
|
||||
#define CATCH_CONFIG_DISABLE_MATCHERS
|
||||
#define CATCH_CONFIG_NO_NOMINMAX
|
||||
|
||||
//windows.h config (included transitively by catch2 on windows)
|
||||
#ifdef _WIN32
|
||||
@ -63,7 +56,7 @@
|
||||
#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 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_*
|
||||
|
@ -2,13 +2,11 @@
|
||||
#include "settings.h"
|
||||
|
||||
#if USE_TARTANLLAMA_OPTIONAL
|
||||
#if __has_include(<tloptional/include/tl/optional.hpp>)
|
||||
#include <tloptional/include/tl/optional.hpp>
|
||||
#else
|
||||
#error TartanLlama/optional is missing! You probably need to fetch submodules ("git submodule update --init extern/tloptional")
|
||||
#endif
|
||||
#include "tloptional.h"
|
||||
#endif
|
||||
|
||||
#include "evil_macros.h"
|
||||
|
||||
#if USE_SINGLE_HEADER
|
||||
#include "../toml.hpp"
|
||||
#else
|
||||
@ -43,6 +41,27 @@ TOML_POP_WARNINGS
|
||||
while (false)
|
||||
#endif
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
inline double make_infinity(int sign = 1) noexcept
|
||||
{
|
||||
constexpr uint64_t pos_inf = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t neg_inf = 0b1111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
double val;
|
||||
std::memcpy(&val, sign >= 0 ? &pos_inf : &neg_inf, sizeof(double));
|
||||
return val;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
inline double make_nan() noexcept
|
||||
{
|
||||
constexpr uint64_t qnan = 0b0111111111111000000000000000000000000000000000000000000000000000ull;
|
||||
double val;
|
||||
std::memcpy(&val, &qnan, sizeof(double));
|
||||
return val;
|
||||
}
|
||||
|
||||
// function_view - adapted from here: https://vittorioromeo.info/index/blog/passing_functions_to_functions.html
|
||||
template <typename Func>
|
||||
class function_view;
|
||||
@ -112,7 +131,7 @@ inline bool parse_expected_value(
|
||||
|
||||
static constexpr auto is_val = [](char32_t codepoint)
|
||||
{
|
||||
if constexpr (std::is_same_v<string, impl::promoted<T>>)
|
||||
if constexpr (impl::node_type_of<T> == node_type::string)
|
||||
return codepoint == U'"' || codepoint == U'\'';
|
||||
else
|
||||
return !impl::is_whitespace(codepoint);
|
||||
@ -152,7 +171,7 @@ inline bool parse_expected_value(
|
||||
end.column++;
|
||||
}
|
||||
|
||||
using value_type = impl::promoted<impl::remove_cvref_t<T>>;
|
||||
using value_type = impl::native_type_of<impl::remove_cvref_t<T>>;
|
||||
value<value_type> val_parsed;
|
||||
{
|
||||
INFO("["sv << test_file << ", line "sv << test_line << "] "sv << "parse_expected_value: Checking initial parse"sv)
|
||||
|
22
tests/tloptional.h
Normal file
22
tests/tloptional.h
Normal file
@ -0,0 +1,22 @@
|
||||
// This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
// Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#endif
|
||||
|
||||
#if __has_include(<tloptional/include/tl/optional.hpp>)
|
||||
#include <tloptional/include/tl/optional.hpp>
|
||||
#else
|
||||
#error TartanLlama/optional is missing! You probably need to fetch submodules ("git submodule update --init extern/tloptional")
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
@ -70,8 +70,4 @@ TEST_CASE("windows compat")
|
||||
REQUIRE(!tbl.contains(L"foo"));
|
||||
}
|
||||
|
||||
static_assert(std::is_same_v<std::wstring, decltype(std::declval<toml::node>().value_or(L""s))>);
|
||||
static_assert(std::is_same_v<std::wstring, decltype(std::declval<toml::node>().value_or(L""sv))>);
|
||||
static_assert(std::is_same_v<std::wstring, decltype(std::declval<toml::node>().value_or(L""))>);
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
@ -97,8 +97,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -96,8 +96,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -98,8 +98,11 @@
|
||||
<Natvis Include="toml++.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\tests\catch2.h" />
|
||||
<ClInclude Include="..\tests\evil_macros.h" />
|
||||
<ClInclude Include="..\tests\settings.h" />
|
||||
<ClInclude Include="..\tests\tests.h" />
|
||||
<ClInclude Include="..\tests\tloptional.h" />
|
||||
<ClInclude Include="..\tests\unicode.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user