improved support for using enums with value_or()
This commit is contained in:
parent
42a428f8ea
commit
941341fce6
@ -33,6 +33,10 @@ template:
|
||||
- fixed `for_each()` compilation error on GCC <= 7 (#197) (@sagi-ottopia, @damirbarr)
|
||||
- fixed `FLT_RADIX` check getting broken by Intel MKL headers (#202) (@iago-lito)
|
||||
|
||||
#### Additions
|
||||
|
||||
- improved support for using enums with `value_or()`
|
||||
|
||||
#### Changes:
|
||||
|
||||
- renamed header files to have `.hpp` extension (`toml.h` is still present for backwards-compatibility)
|
||||
|
@ -476,10 +476,22 @@ TOML_IMPL_NAMESPACE_START
|
||||
template <typename T, typename... U>
|
||||
inline constexpr bool first_is_same<T, T, U...> = true;
|
||||
|
||||
template <typename T, bool = std::is_enum_v<T>>
|
||||
struct underlying_type_
|
||||
{
|
||||
using type = std::underlying_type_t<T>;
|
||||
};
|
||||
template <typename T>
|
||||
struct underlying_type_<T, false>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
using underlying_type = typename underlying_type_<T>::type;
|
||||
|
||||
// general value traits
|
||||
// (as they relate to their equivalent native TOML type)
|
||||
template <typename T>
|
||||
struct value_traits
|
||||
struct default_value_traits
|
||||
{
|
||||
using native_type = void;
|
||||
static constexpr bool is_native = false;
|
||||
@ -489,6 +501,27 @@ TOML_IMPL_NAMESPACE_START
|
||||
static constexpr auto type = node_type::none;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_traits;
|
||||
|
||||
template <typename T, bool = std::is_enum_v<T>>
|
||||
struct value_traits_base_selector
|
||||
{
|
||||
static_assert(!is_cvref<T>);
|
||||
|
||||
using type = default_value_traits;
|
||||
};
|
||||
template <typename T>
|
||||
struct value_traits_base_selector<T, true>
|
||||
{
|
||||
static_assert(!is_cvref<T>);
|
||||
|
||||
using type = value_traits<underlying_type<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_traits : value_traits_base_selector<T>::type
|
||||
{};
|
||||
template <typename T>
|
||||
struct value_traits<const T> : value_traits<T>
|
||||
{};
|
||||
@ -509,32 +542,35 @@ TOML_IMPL_NAMESPACE_START
|
||||
template <typename T>
|
||||
struct integer_limits
|
||||
{
|
||||
static constexpr auto min = (std::numeric_limits<T>::min)();
|
||||
static constexpr auto max = (std::numeric_limits<T>::max)();
|
||||
static constexpr T min = T{ (std::numeric_limits<underlying_type<T>>::min)() };
|
||||
static constexpr T max = T{ (std::numeric_limits<underlying_type<T>>::max)() };
|
||||
};
|
||||
template <typename T>
|
||||
struct integer_traits_base : integer_limits<T>
|
||||
{
|
||||
using native_type = int64_t;
|
||||
static constexpr bool is_native = std::is_same_v<T, native_type>;
|
||||
static constexpr bool is_signed = static_cast<T>(-1) < T{}; // for impls not specializing std::is_signed<T>
|
||||
static constexpr bool is_native = std::is_same_v<underlying_type<T>, native_type>;
|
||||
static constexpr bool is_signed = static_cast<underlying_type<T>>(-1) < underlying_type<T>{};
|
||||
static constexpr auto type = node_type::integer;
|
||||
static constexpr bool can_partially_represent_native = true;
|
||||
};
|
||||
template <typename T>
|
||||
struct unsigned_integer_traits : integer_traits_base<T>
|
||||
{
|
||||
static constexpr bool is_losslessly_convertible_to_native = integer_limits<T>::max <= 9223372036854775807ULL;
|
||||
static constexpr bool can_represent_native = false;
|
||||
static constexpr bool is_losslessly_convertible_to_native =
|
||||
integer_limits<underlying_type<T>>::max <= 9223372036854775807ULL;
|
||||
static constexpr bool can_represent_native = false;
|
||||
};
|
||||
template <typename T>
|
||||
struct signed_integer_traits : integer_traits_base<T>
|
||||
{
|
||||
using native_type = int64_t;
|
||||
static constexpr bool is_losslessly_convertible_to_native =
|
||||
integer_limits<T>::min >= (-9223372036854775807LL - 1LL) && integer_limits<T>::max <= 9223372036854775807LL;
|
||||
integer_limits<underlying_type<T>>::min >= (-9223372036854775807LL - 1LL)
|
||||
&& integer_limits<underlying_type<T>>::max <= 9223372036854775807LL;
|
||||
static constexpr bool can_represent_native =
|
||||
integer_limits<T>::min <= (-9223372036854775807LL - 1LL) && integer_limits<T>::max >= 9223372036854775807LL;
|
||||
integer_limits<underlying_type<T>>::min <= (-9223372036854775807LL - 1LL)
|
||||
&& integer_limits<underlying_type<T>>::max >= 9223372036854775807LL;
|
||||
};
|
||||
template <typename T, bool S = integer_traits_base<T>::is_signed>
|
||||
struct integer_traits : signed_integer_traits<T>
|
||||
|
@ -59,7 +59,7 @@ TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||
TOML_SA_LIST_END \
|
||||
\
|
||||
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
|
||||
TOML_SA_LIST_BEG "any other integer type" \
|
||||
TOML_SA_LIST_BEG "any other integral type" \
|
||||
TOML_SA_LIST_SEP "any floating-point type" \
|
||||
TOML_SA_LIST_END \
|
||||
\
|
||||
@ -1221,7 +1221,7 @@ TOML_NAMESPACE_START
|
||||
TOML_SA_LIST_END
|
||||
|
||||
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
|
||||
TOML_SA_LIST_BEG "any other integer type"
|
||||
TOML_SA_LIST_BEG "any other integral type"
|
||||
TOML_SA_LIST_SEP "any floating-point type"
|
||||
TOML_SA_LIST_END
|
||||
|
||||
|
@ -393,4 +393,23 @@ b = []
|
||||
y = 2
|
||||
)"sv);
|
||||
}
|
||||
|
||||
SECTION("tomlplusplus/issues/207") // https://github.com/marzer/tomlplusplus/issues/207
|
||||
{
|
||||
enum class an_enum
|
||||
{
|
||||
zero,
|
||||
one,
|
||||
two,
|
||||
three
|
||||
};
|
||||
|
||||
parsing_should_succeed(FILE_LINE_ARGS,
|
||||
"val = 2\n",
|
||||
[](auto&& tbl)
|
||||
{
|
||||
const auto val = tbl["val"].template value_or<an_enum>(an_enum::zero);
|
||||
CHECK(val == an_enum::two);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
60
toml.hpp
60
toml.hpp
@ -1742,10 +1742,22 @@ TOML_IMPL_NAMESPACE_START
|
||||
template <typename T, typename... U>
|
||||
inline constexpr bool first_is_same<T, T, U...> = true;
|
||||
|
||||
template <typename T, bool = std::is_enum_v<T>>
|
||||
struct underlying_type_
|
||||
{
|
||||
using type = std::underlying_type_t<T>;
|
||||
};
|
||||
template <typename T>
|
||||
struct underlying_type_<T, false>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
using underlying_type = typename underlying_type_<T>::type;
|
||||
|
||||
// general value traits
|
||||
// (as they relate to their equivalent native TOML type)
|
||||
template <typename T>
|
||||
struct value_traits
|
||||
struct default_value_traits
|
||||
{
|
||||
using native_type = void;
|
||||
static constexpr bool is_native = false;
|
||||
@ -1755,6 +1767,27 @@ TOML_IMPL_NAMESPACE_START
|
||||
static constexpr auto type = node_type::none;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_traits;
|
||||
|
||||
template <typename T, bool = std::is_enum_v<T>>
|
||||
struct value_traits_base_selector
|
||||
{
|
||||
static_assert(!is_cvref<T>);
|
||||
|
||||
using type = default_value_traits;
|
||||
};
|
||||
template <typename T>
|
||||
struct value_traits_base_selector<T, true>
|
||||
{
|
||||
static_assert(!is_cvref<T>);
|
||||
|
||||
using type = value_traits<underlying_type<T>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_traits : value_traits_base_selector<T>::type
|
||||
{};
|
||||
template <typename T>
|
||||
struct value_traits<const T> : value_traits<T>
|
||||
{};
|
||||
@ -1775,32 +1808,35 @@ TOML_IMPL_NAMESPACE_START
|
||||
template <typename T>
|
||||
struct integer_limits
|
||||
{
|
||||
static constexpr auto min = (std::numeric_limits<T>::min)();
|
||||
static constexpr auto max = (std::numeric_limits<T>::max)();
|
||||
static constexpr T min = T{ (std::numeric_limits<underlying_type<T>>::min)() };
|
||||
static constexpr T max = T{ (std::numeric_limits<underlying_type<T>>::max)() };
|
||||
};
|
||||
template <typename T>
|
||||
struct integer_traits_base : integer_limits<T>
|
||||
{
|
||||
using native_type = int64_t;
|
||||
static constexpr bool is_native = std::is_same_v<T, native_type>;
|
||||
static constexpr bool is_signed = static_cast<T>(-1) < T{}; // for impls not specializing std::is_signed<T>
|
||||
static constexpr bool is_native = std::is_same_v<underlying_type<T>, native_type>;
|
||||
static constexpr bool is_signed = static_cast<underlying_type<T>>(-1) < underlying_type<T>{};
|
||||
static constexpr auto type = node_type::integer;
|
||||
static constexpr bool can_partially_represent_native = true;
|
||||
};
|
||||
template <typename T>
|
||||
struct unsigned_integer_traits : integer_traits_base<T>
|
||||
{
|
||||
static constexpr bool is_losslessly_convertible_to_native = integer_limits<T>::max <= 9223372036854775807ULL;
|
||||
static constexpr bool can_represent_native = false;
|
||||
static constexpr bool is_losslessly_convertible_to_native =
|
||||
integer_limits<underlying_type<T>>::max <= 9223372036854775807ULL;
|
||||
static constexpr bool can_represent_native = false;
|
||||
};
|
||||
template <typename T>
|
||||
struct signed_integer_traits : integer_traits_base<T>
|
||||
{
|
||||
using native_type = int64_t;
|
||||
static constexpr bool is_losslessly_convertible_to_native =
|
||||
integer_limits<T>::min >= (-9223372036854775807LL - 1LL) && integer_limits<T>::max <= 9223372036854775807LL;
|
||||
integer_limits<underlying_type<T>>::min >= (-9223372036854775807LL - 1LL)
|
||||
&& integer_limits<underlying_type<T>>::max <= 9223372036854775807LL;
|
||||
static constexpr bool can_represent_native =
|
||||
integer_limits<T>::min <= (-9223372036854775807LL - 1LL) && integer_limits<T>::max >= 9223372036854775807LL;
|
||||
integer_limits<underlying_type<T>>::min <= (-9223372036854775807LL - 1LL)
|
||||
&& integer_limits<underlying_type<T>>::max >= 9223372036854775807LL;
|
||||
};
|
||||
template <typename T, bool S = integer_traits_base<T>::is_signed>
|
||||
struct integer_traits : signed_integer_traits<T>
|
||||
@ -4765,7 +4801,7 @@ TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||
TOML_SA_LIST_END \
|
||||
\
|
||||
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
|
||||
TOML_SA_LIST_BEG "any other integer type" \
|
||||
TOML_SA_LIST_BEG "any other integral type" \
|
||||
TOML_SA_LIST_SEP "any floating-point type" \
|
||||
TOML_SA_LIST_END \
|
||||
\
|
||||
@ -5743,7 +5779,7 @@ TOML_NAMESPACE_START
|
||||
TOML_SA_LIST_END
|
||||
|
||||
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
|
||||
TOML_SA_LIST_BEG "any other integer type"
|
||||
TOML_SA_LIST_BEG "any other integral type"
|
||||
TOML_SA_LIST_SEP "any floating-point type"
|
||||
TOML_SA_LIST_END
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user