Add value_in_range_of trait
This commit is contained in:
parent
b2bbd2b1c8
commit
329e1871f7
@ -577,5 +577,100 @@ T conditional_static_cast(U value)
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename... Types>
|
||||
using all_integral = conjunction<std::is_integral<Types>...>;
|
||||
|
||||
template<typename... Types>
|
||||
using all_signed = conjunction<std::is_signed<Types>...>;
|
||||
|
||||
template<typename... Types>
|
||||
using all_unsigned = conjunction<std::is_unsigned<Types>...>;
|
||||
|
||||
// there's a disjunction trait in another PR; replace when merged
|
||||
template<typename... Types>
|
||||
using same_sign = std::integral_constant < bool,
|
||||
all_signed<Types...>::value || all_unsigned<Types...>::value >;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
using never_out_of_range = std::integral_constant < bool,
|
||||
(std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
|
||||
|| (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
|
||||
|
||||
template<typename OfType, typename T,
|
||||
bool OfTypeSigned = std::is_signed<OfType>::value,
|
||||
bool TSigned = std::is_signed<T>::value>
|
||||
struct value_in_range_of_impl2;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, false, false>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, true, false>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, false, true>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, true, true>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return static_cast<CommonType>(val) >= static_cast<CommonType>(std::numeric_limits<OfType>::min())
|
||||
&& static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T,
|
||||
bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
|
||||
typename = detail::enable_if_t<all_integral<OfType, T>::value>>
|
||||
struct value_in_range_of_impl1;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl1<OfType, T, false>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
return value_in_range_of_impl2<OfType, T>::test(val);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl1<OfType, T, true>
|
||||
{
|
||||
static constexpr bool test(T /*val*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
inline constexpr bool value_in_range_of(T val)
|
||||
{
|
||||
return value_in_range_of_impl1<OfType, T>::test(val);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
@ -3768,6 +3768,101 @@ T conditional_static_cast(U value)
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename... Types>
|
||||
using all_integral = conjunction<std::is_integral<Types>...>;
|
||||
|
||||
template<typename... Types>
|
||||
using all_signed = conjunction<std::is_signed<Types>...>;
|
||||
|
||||
template<typename... Types>
|
||||
using all_unsigned = conjunction<std::is_unsigned<Types>...>;
|
||||
|
||||
// there's a disjunction trait in another PR; replace when merged
|
||||
template<typename... Types>
|
||||
using same_sign = std::integral_constant < bool,
|
||||
all_signed<Types...>::value || all_unsigned<Types...>::value >;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
using never_out_of_range = std::integral_constant < bool,
|
||||
(std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
|
||||
|| (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
|
||||
|
||||
template<typename OfType, typename T,
|
||||
bool OfTypeSigned = std::is_signed<OfType>::value,
|
||||
bool TSigned = std::is_signed<T>::value>
|
||||
struct value_in_range_of_impl2;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, false, false>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, true, false>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, false, true>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl2<OfType, T, true, true>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
using CommonType = typename std::common_type<OfType, T>::type;
|
||||
return static_cast<CommonType>(val) >= static_cast<CommonType>(std::numeric_limits<OfType>::min())
|
||||
&& static_cast<CommonType>(val) <= static_cast<CommonType>(std::numeric_limits<OfType>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T,
|
||||
bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
|
||||
typename = detail::enable_if_t<all_integral<OfType, T>::value>>
|
||||
struct value_in_range_of_impl1;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl1<OfType, T, false>
|
||||
{
|
||||
static constexpr bool test(T val)
|
||||
{
|
||||
return value_in_range_of_impl2<OfType, T>::test(val);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
struct value_in_range_of_impl1<OfType, T, true>
|
||||
{
|
||||
static constexpr bool test(T /*val*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OfType, typename T>
|
||||
inline constexpr bool value_in_range_of(T val)
|
||||
{
|
||||
return value_in_range_of_impl1<OfType, T>::test(val);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
|
||||
@ -29,6 +29,8 @@ SOFTWARE.
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@ -116,6 +118,113 @@ class SaxCountdown
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// at some point in the future, a unit test dedicated to type traits might be a good idea
|
||||
template <typename OfType, typename T, bool MinInRange, bool MaxInRange>
|
||||
struct trait_test_arg
|
||||
{
|
||||
using of_type = OfType;
|
||||
using type = T;
|
||||
static constexpr bool min_in_range = MinInRange;
|
||||
static constexpr bool max_in_range = MaxInRange;
|
||||
};
|
||||
|
||||
TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test)
|
||||
{
|
||||
//using namespace nlohmann::detail; // NOLINT(google-build-using-namespace)
|
||||
using nlohmann::detail::value_in_range_of;
|
||||
|
||||
using of_type = typename T::of_type;
|
||||
using type = typename T::type;
|
||||
constexpr bool min_in_range = T::min_in_range;
|
||||
constexpr bool max_in_range = T::max_in_range;
|
||||
|
||||
type val_min = std::numeric_limits<type>::min();
|
||||
type val_min2 = val_min + 1;
|
||||
type val_max = std::numeric_limits<type>::max();
|
||||
type val_max2 = val_max - 1;
|
||||
|
||||
REQUIRE(CHAR_BIT == 8);
|
||||
|
||||
std::string of_type_str;
|
||||
if (std::is_unsigned<of_type>::value)
|
||||
{
|
||||
of_type_str += "u";
|
||||
}
|
||||
of_type_str += "int";
|
||||
of_type_str += std::to_string(sizeof(of_type) * 8);
|
||||
|
||||
INFO("of_type := ", of_type_str);
|
||||
|
||||
std::string type_str;
|
||||
if (std::is_unsigned<type>::value)
|
||||
{
|
||||
type_str += "u";
|
||||
}
|
||||
type_str += "int";
|
||||
type_str += std::to_string(sizeof(type) * 8);
|
||||
|
||||
INFO("type := ", type_str);
|
||||
|
||||
CAPTURE(val_min);
|
||||
CAPTURE(min_in_range);
|
||||
CAPTURE(val_max);
|
||||
CAPTURE(max_in_range);
|
||||
|
||||
if (min_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_min));
|
||||
CHECK(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
|
||||
if (max_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_max));
|
||||
CHECK(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
trait_test_arg<std::int32_t, std::int32_t, true, true>, \
|
||||
trait_test_arg<std::int32_t, std::uint32_t, true, false>, \
|
||||
trait_test_arg<std::uint32_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::uint32_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::int32_t, std::int64_t, false, false>, \
|
||||
trait_test_arg<std::int32_t, std::uint64_t, true, false>, \
|
||||
trait_test_arg<std::uint32_t, std::int64_t, false, false>, \
|
||||
trait_test_arg<std::uint32_t, std::uint64_t, true, false>, \
|
||||
trait_test_arg<std::int64_t, std::int32_t, true, true>, \
|
||||
trait_test_arg<std::int64_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::uint64_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::uint64_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::int64_t, std::int64_t, true, true>, \
|
||||
trait_test_arg<std::int64_t, std::uint64_t, true, false>, \
|
||||
trait_test_arg<std::uint64_t, std::int64_t, false, true>, \
|
||||
trait_test_arg<std::uint64_t, std::uint64_t, true, true>);
|
||||
|
||||
#if SIZE_MAX == 0xffffffff
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
trait_test_arg<std::size_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::size_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::size_t, std::int64_t, false, false>, \
|
||||
trait_test_arg<std::size_t, std::uint64_t, true, false>);
|
||||
#else
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
trait_test_arg<std::size_t, std::int32_t, false, true>, \
|
||||
trait_test_arg<std::size_t, std::uint32_t, true, true>, \
|
||||
trait_test_arg<std::size_t, std::int64_t, false, true>, \
|
||||
trait_test_arg<std::size_t, std::uint64_t, true, true>);
|
||||
#endif
|
||||
|
||||
TEST_CASE("BJData")
|
||||
{
|
||||
SECTION("individual values")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user