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;
|
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 detail
|
||||||
} // namespace nlohmann
|
} // namespace nlohmann
|
||||||
|
|||||||
@ -3768,6 +3768,101 @@ T conditional_static_cast(U value)
|
|||||||
return 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 detail
|
||||||
} // namespace nlohmann
|
} // namespace nlohmann
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,8 @@ SOFTWARE.
|
|||||||
|
|
||||||
#include "doctest_compatibility.h"
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <limits>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
@ -116,6 +118,113 @@ class SaxCountdown
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // 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")
|
TEST_CASE("BJData")
|
||||||
{
|
{
|
||||||
SECTION("individual values")
|
SECTION("individual values")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user