From 329e1871f7ede39d45dde59aa9c1cce6e2ad013b Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Wed, 8 Jun 2022 08:50:54 +0200 Subject: [PATCH] Add value_in_range_of trait --- include/nlohmann/detail/meta/type_traits.hpp | 95 ++++++++++++++++ single_include/nlohmann/json.hpp | 95 ++++++++++++++++ tests/src/unit-bjdata.cpp | 109 +++++++++++++++++++ 3 files changed, 299 insertions(+) diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 5e3ea3737..0901b71bb 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -577,5 +577,100 @@ T conditional_static_cast(U value) return value; } +template +using all_integral = conjunction...>; + +template +using all_signed = conjunction...>; + +template +using all_unsigned = conjunction...>; + +// there's a disjunction trait in another PR; replace when merged +template +using same_sign = std::integral_constant < bool, + all_signed::value || all_unsigned::value >; + +template +using never_out_of_range = std::integral_constant < bool, + (std::is_signed::value && (sizeof(T) < sizeof(OfType))) + || (same_sign::value && sizeof(OfType) == sizeof(T)) >; + +template::value, + bool TSigned = std::is_signed::value> +struct value_in_range_of_impl2; + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return val >= 0 && static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return static_cast(val) >= static_cast(std::numeric_limits::min()) + && static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + +template::value, + typename = detail::enable_if_t::value>> +struct value_in_range_of_impl1; + +template +struct value_in_range_of_impl1 +{ + static constexpr bool test(T val) + { + return value_in_range_of_impl2::test(val); + } +}; + +template +struct value_in_range_of_impl1 +{ + static constexpr bool test(T /*val*/) + { + return true; + } +}; + +template +inline constexpr bool value_in_range_of(T val) +{ + return value_in_range_of_impl1::test(val); +} + } // namespace detail } // namespace nlohmann diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ac96dce1d..281f66d88 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3768,6 +3768,101 @@ T conditional_static_cast(U value) return value; } +template +using all_integral = conjunction...>; + +template +using all_signed = conjunction...>; + +template +using all_unsigned = conjunction...>; + +// there's a disjunction trait in another PR; replace when merged +template +using same_sign = std::integral_constant < bool, + all_signed::value || all_unsigned::value >; + +template +using never_out_of_range = std::integral_constant < bool, + (std::is_signed::value && (sizeof(T) < sizeof(OfType))) + || (same_sign::value && sizeof(OfType) == sizeof(T)) >; + +template::value, + bool TSigned = std::is_signed::value> +struct value_in_range_of_impl2; + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return val >= 0 && static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + + +template +struct value_in_range_of_impl2 +{ + static constexpr bool test(T val) + { + using CommonType = typename std::common_type::type; + return static_cast(val) >= static_cast(std::numeric_limits::min()) + && static_cast(val) <= static_cast(std::numeric_limits::max()); + } +}; + +template::value, + typename = detail::enable_if_t::value>> +struct value_in_range_of_impl1; + +template +struct value_in_range_of_impl1 +{ + static constexpr bool test(T val) + { + return value_in_range_of_impl2::test(val); + } +}; + +template +struct value_in_range_of_impl1 +{ + static constexpr bool test(T /*val*/) + { + return true; + } +}; + +template +inline constexpr bool value_in_range_of(T val) +{ + return value_in_range_of_impl1::test(val); +} + } // namespace detail } // namespace nlohmann diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index 70c37dec1..81b16f97d 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -29,6 +29,8 @@ SOFTWARE. #include "doctest_compatibility.h" +#include +#include #include 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 +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::min(); + type val_min2 = val_min + 1; + type val_max = std::numeric_limits::max(); + type val_max2 = val_max - 1; + + REQUIRE(CHAR_BIT == 8); + + std::string of_type_str; + if (std::is_unsigned::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::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(val_min)); + CHECK(value_in_range_of(val_min2)); + } + else + { + CHECK_FALSE(value_in_range_of(val_min)); + CHECK_FALSE(value_in_range_of(val_min2)); + } + + if (max_in_range) + { + CHECK(value_in_range_of(val_max)); + CHECK(value_in_range_of(val_max2)); + } + else + { + CHECK_FALSE(value_in_range_of(val_max)); + CHECK_FALSE(value_in_range_of(val_max2)); + } +} + +TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg); + +#if SIZE_MAX == 0xffffffff +TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg); +#else +TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg, \ + trait_test_arg); +#endif + TEST_CASE("BJData") { SECTION("individual values")