From d8c5b02674d905f47f288b2fd20f88cb1f5fc792 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 28 Dec 2019 18:39:54 +0100 Subject: new_type: implement support for nt::Relational --- CMakeLists.txt | 1 + doc/src/index.rst | 12 +- include/newtype/derivable.hpp | 7 + include/newtype/new_type.hpp | 64 ++++++ test/include/relational_operators_suite.hpp | 11 + test/src/driver.cpp | 2 + test/src/relational_operators_suite.cpp | 321 ++++++++++++++++++++++++++++ 7 files changed, 412 insertions(+), 6 deletions(-) create mode 100644 test/include/relational_operators_suite.hpp create mode 100644 test/src/relational_operators_suite.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b78a58e..5f28c54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ if(BUILD_TESTING) "${PROJECT_SOURCE_DIR}/test/src/conversion_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/equality_comparison_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/new_type_constructor_suite.cpp" + "${PROJECT_SOURCE_DIR}/test/src/relational_operators_suite.cpp" ) target_include_directories("${PROJECT_NAME}_tests" PRIVATE diff --git a/doc/src/index.rst b/doc/src/index.rst index e9c69c0..907b58d 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -132,7 +132,7 @@ Synopsis template + typename = std::enable_if_t> auto constexpr operator<(new_type const &, new_type const &) noexcept(/*see below*/) -> bool; @@ -140,7 +140,7 @@ Synopsis template + typename = std::enable_if_t> auto constexpr operator>(new_type const &, new_type const &) noexcept(/*see below*/) -> bool; @@ -148,7 +148,7 @@ Synopsis template + typename = std::enable_if_t> auto constexpr operator<=(new_type const &, new_type const &) noexcept(/*see below*/) -> bool; @@ -156,7 +156,7 @@ Synopsis template + typename = std::enable_if_t> auto constexpr operator>=(new_type const &, new_type const &) noexcept(/*see below*/) -> bool; @@ -168,7 +168,7 @@ Synopsis auto DerivationClause, typename CharType, typename StreamTraits, - typename = std::enable_if_t + typename = std::enable_if_t> auto operator<<(std::basic_ostream &&, new_type const &) noexcept(/*see below*/) -> std::basic_ostream &; @@ -178,7 +178,7 @@ Synopsis auto DerivationClause, typename CharType, typename StreamTraits, - typename = std::enable_if_t + typename = std::enable_if_t> auto operator>>(std::basic_istream &&, new_type &&) noexcept(/*see below*/) -> std::basic_istream &; diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp index 4fec2b7..157bac7 100644 --- a/include/newtype/derivable.hpp +++ b/include/newtype/derivable.hpp @@ -49,6 +49,13 @@ namespace nt */ auto constexpr Read = derivable{}; + /** + * A tag to enable derivation of the relational operators + * + * @since 1.0.0 + */ + auto constexpr Relational = derivable{}; + /** * A tag to enable derivation of the stream output operator * diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index c0fb8d3..17959ba 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -153,6 +153,70 @@ namespace nt return lhs.decay() != rhs.decay(); } + /** + * Check if one nt::new_type object is less-than an other + * + * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain + * nt::Relational + * @return true iff. the object contained by lhs is less-than the one contained by rhs + */ + template> + auto constexpr operator<(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() < + std::declval())) + -> bool + { + return lhs.decay() < rhs.decay(); + } + + /** + * Check if one nt::new_type object is greater-than an other + * + * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain + * nt::Relational + * @return true iff. the object contained by lhs is greater-than the one contained by rhs + */ + template> + auto constexpr operator>(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() > + std::declval())) + -> bool + { + return lhs.decay() > rhs.decay(); + } + + /** + * Check if one nt::new_type object is less-than or equal-to an other + * + * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain + * nt::Relational + * @return true iff. the object contained by lhs is less-than or equal-to the one contained by rhs + */ + template> + auto constexpr operator<=(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() <= + std::declval())) + -> bool + { + return lhs.decay() <= rhs.decay(); + } + + /** + * Check if one nt::new_type object is greater-than or equal-to an other + * + * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain + * nt::Relational + * @return true iff. the object contained by lhs is greater-than or equal-to the one contained by rhs + */ + template> + auto constexpr operator>=(new_type const & lhs, + new_type const & rhs) noexcept(noexcept(std::declval() >= + std::declval())) + -> bool + { + return lhs.decay() >= rhs.decay(); + } + } // namespace nt #endif diff --git a/test/include/relational_operators_suite.hpp b/test/include/relational_operators_suite.hpp new file mode 100644 index 0000000..259834b --- /dev/null +++ b/test/include/relational_operators_suite.hpp @@ -0,0 +1,11 @@ +#ifndef NEWTYPE_TEST_RELATIONAL_OPERATORS_SUITE_HPP +#define NEWTYPE_TEST_RELATIONAL_OPERATORS_SUITE_HPP + +#include + +#include +#include + +auto relational_operators_suite() -> std::pair; + +#endif \ No newline at end of file diff --git a/test/src/driver.cpp b/test/src/driver.cpp index f6afe58..1ba3d68 100644 --- a/test/src/driver.cpp +++ b/test/src/driver.cpp @@ -2,6 +2,7 @@ #include "derivation_clause_suite.hpp" #include "equality_comparison_suite.hpp" #include "new_type_constructor_suite.hpp" +#include "relational_operators_suite.hpp" #include #include @@ -53,6 +54,7 @@ int main(int argc, char ** argv) new_type_constructor_suite(), conversion_suite(), equality_comparison_suite(), + relational_operators_suite(), }; auto selectors = get_test_selectors(suites); diff --git a/test/src/relational_operators_suite.cpp b/test/src/relational_operators_suite.cpp new file mode 100644 index 0000000..31955dd --- /dev/null +++ b/test/src/relational_operators_suite.cpp @@ -0,0 +1,321 @@ +#include "relational_operators_suite.hpp" + +#include "kawaii.hpp" +#include "newtype/derivable.hpp" +#include "newtype/deriving.hpp" +#include "newtype/new_type.hpp" + +#include + +#include +#include +#include + +inline namespace traits_extensions +{ + + template + struct has_less_than : std::false_type + { + }; + + template + struct has_less_than() < std::declval())>> : std::true_type + { + }; + + template + auto constexpr has_less_than_v = has_less_than::value; + + template + struct has_greater_than : std::false_type + { + }; + + template + struct has_greater_than() > std::declval())>> : std::true_type + { + }; + + template + auto constexpr has_greater_than_v = has_greater_than::value; + + template + struct has_less_than_equal_to : std::false_type + { + }; + + template + struct has_less_than_equal_to() <= std::declval())>> : std::true_type + { + }; + + template + auto constexpr has_less_than_equal_to_v = has_less_than_equal_to::value; + + template + struct has_greater_than_equal_to : std::false_type + { + }; + + template + struct has_greater_than_equal_to() >= std::declval())>> : std::true_type + { + }; + + template + auto constexpr has_greater_than_equal_to_v = has_greater_than_equal_to::value; + +} // namespace traits_extensions + +inline namespace relational_operator_presence_tests +{ + + auto an_instance_of_new__type_has_less_than_if_its_derivation_clause_contains_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(has_less_than_v); + } + + auto an_instance_of_new__type_does_not_have_less_than_if_its_derivation_clause_does_not_contain_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(!has_less_than_v); + } + + auto an_instance_of_new__type_has_greater_than_if_its_derivation_clause_contains_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(has_greater_than_v); + } + + auto an_instance_of_new__type_does_not_have_greater_than_if_its_derivation_clause_does_not_contain_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(!has_greater_than_v); + } + + auto an_instance_of_new__type_has_less_than_or_equal_to_if_its_derivation_clause_contains_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(has_less_than_equal_to_v); + } + + auto an_instance_of_new__type_does_not_have_less_than_or_equal_to_if_its_derivation_clause_does_not_contain_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(!has_less_than_equal_to_v); + } + + auto an_instance_of_new__type_has_greater_than_or_equal_to_if_its_derivation_clause_contains_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(has_greater_than_equal_to_v); + } + + auto an_instance_of_new__type_does_not_have_greater_than_or_equal_to_if_its_derivation_clause_does_not_contain_relational() -> void + { + using type_alias = nt::new_type; + ASSERT(!has_greater_than_equal_to_v); + } + +} // namespace relational_operator_presence_tests + +inline namespace less_than_tests +{ + + auto two_instances_of_the_same_new__type_compare_less_than_if_both_contained_values_would_compare_less_than() -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{21}; + auto constexpr rhs{42}; + static_assert(lhs < rhs, "Sanity Check"); + ASSERT_LESS(type_alias{lhs}, type_alias{rhs}); + } + + auto two_instances_of_the_same_new__type_do_not_compare_less_than_if_both_contained_values_would_not_compare_less_than() -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{44}; + auto constexpr rhs{42}; + static_assert(!(lhs < rhs), "Sanity Check"); + ASSERT(!(type_alias{lhs} < type_alias{rhs})); + } + + auto two_instances_of_the_same_new__type_compare_less_than_or_equal_if_both_contained_values_would_compare_less_than_or_equal() -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{33}; + auto constexpr rhs{42}; + static_assert(lhs <= rhs, "Sanity Check"); + ASSERT_LESS_EQUAL(type_alias{lhs}, type_alias{rhs}); + } + + auto two_instances_of_the_same_new__type_do_not_compare_less_than_or_equal_if_both_contained_values_would_not_compare_less_than_or_equal() + -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{87}; + auto constexpr rhs{42}; + static_assert(!(lhs < rhs), "Sanity Check"); + ASSERT(!(type_alias{lhs} < type_alias{rhs})); + } + +} // namespace less_than_tests + +inline namespace greater_than_tests +{ + + auto two_instances_of_the_same_new__type_compare_greater_than_if_both_contained_values_would_compare_greater_than() -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{42}; + auto constexpr rhs{21}; + static_assert(lhs > rhs, "Sanity Check"); + ASSERT_GREATER(type_alias{lhs}, type_alias{rhs}); + } + + auto two_instances_of_the_same_new__type_do_not_compare_greater_than_if_both_contained_values_would_not_compare_greater_than() -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{42}; + auto constexpr rhs{44}; + static_assert(!(lhs > rhs), "Sanity Check"); + ASSERT(!(type_alias{lhs} > type_alias{rhs})); + } + + auto two_instances_of_the_same_new__type_compare_greater_than_or_equal_if_both_contained_values_would_compare_greater_than_or_equal() -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{42}; + auto constexpr rhs{33}; + static_assert(lhs >= rhs, "Sanity Check"); + ASSERT_GREATER_EQUAL(type_alias{lhs}, type_alias{rhs}); + } + + auto + two_instances_of_the_same_new__type_do_not_compare_greater_than_or_equal_if_both_contained_values_would_not_compare_greater_than_or_equal() + -> void + { + using type_alias = nt::new_type; + auto constexpr lhs{42}; + auto constexpr rhs{87}; + static_assert(!(lhs > rhs), "Sanity Check"); + ASSERT(!(type_alias{lhs} > type_alias{rhs})); + } + +} // namespace greater_than_tests + +inline namespace relational_operator_noexcept_tests +{ + + struct strange_type + { + auto constexpr operator<(strange_type const & other) const noexcept(false) -> bool; + auto constexpr operator>(strange_type const & other) const noexcept(false) -> bool; + auto constexpr operator<=(strange_type const & other) const noexcept(false) -> bool; + auto constexpr operator>=(strange_type const & other) const noexcept(false) -> bool; + }; + + auto less_than_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept() -> void + { + using type_alias = nt::new_type; + static_assert(noexcept(std::declval() < std::declval()), "Sanity Check"); + ASSERT(noexcept(std::declval() < std::declval())); + } + + auto less_than_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept() -> void + { + using type_alias = nt::new_type; + static_assert(!noexcept(std::declval() < std::declval()), "Sanity Check"); + ASSERT(!noexcept(std::declval() < std::declval())); + } + + auto less_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept() -> void + { + using type_alias = nt::new_type; + static_assert(noexcept(std::declval() <= std::declval()), "Sanity Check"); + ASSERT(noexcept(std::declval() <= std::declval())); + } + + auto less_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept() + -> void + { + using type_alias = nt::new_type; + static_assert(!noexcept(std::declval() <= std::declval()), "Sanity Check"); + ASSERT(!noexcept(std::declval() <= std::declval())); + } + + auto greater_than_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept() -> void + { + using type_alias = nt::new_type; + static_assert(noexcept(std::declval() > std::declval()), "Sanity Check"); + ASSERT(noexcept(std::declval() > std::declval())); + } + + auto greater_than_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept() -> void + { + using type_alias = nt::new_type; + static_assert(!noexcept(std::declval() > std::declval()), "Sanity Check"); + ASSERT(!noexcept(std::declval() > std::declval())); + } + + auto greater_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept() -> void + { + using type_alias = nt::new_type; + static_assert(noexcept(std::declval() >= std::declval()), "Sanity Check"); + ASSERT(noexcept(std::declval() >= std::declval())); + } + + auto greater_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept() + -> void + { + using type_alias = nt::new_type; + static_assert(!noexcept(std::declval() >= std::declval()), "Sanity Check"); + ASSERT(!noexcept(std::declval() >= std::declval())); + } + +} // namespace relational_operator_noexcept_tests + +auto relational_operators_suite() -> std::pair +{ + return { + { + // clang-format off + + // Relational Operator Presensence Tests + KAWAII(an_instance_of_new__type_has_less_than_if_its_derivation_clause_contains_relational), + KAWAII(an_instance_of_new__type_does_not_have_less_than_if_its_derivation_clause_does_not_contain_relational), + KAWAII(an_instance_of_new__type_has_greater_than_if_its_derivation_clause_contains_relational), + KAWAII(an_instance_of_new__type_does_not_have_greater_than_if_its_derivation_clause_does_not_contain_relational), + KAWAII(an_instance_of_new__type_has_less_than_or_equal_to_if_its_derivation_clause_contains_relational), + KAWAII(an_instance_of_new__type_does_not_have_less_than_or_equal_to_if_its_derivation_clause_does_not_contain_relational), + KAWAII(an_instance_of_new__type_has_greater_than_or_equal_to_if_its_derivation_clause_contains_relational), + KAWAII(an_instance_of_new__type_does_not_have_greater_than_or_equal_to_if_its_derivation_clause_does_not_contain_relational), + + // Less-than Comparison Tests + KAWAII(two_instances_of_the_same_new__type_compare_less_than_if_both_contained_values_would_compare_less_than), + KAWAII(two_instances_of_the_same_new__type_do_not_compare_less_than_if_both_contained_values_would_not_compare_less_than), + KAWAII(two_instances_of_the_same_new__type_compare_less_than_or_equal_if_both_contained_values_would_compare_less_than_or_equal), + KAWAII(two_instances_of_the_same_new__type_do_not_compare_less_than_or_equal_if_both_contained_values_would_not_compare_less_than_or_equal), + + // Greater-than Comparison Tests + KAWAII(two_instances_of_the_same_new__type_compare_greater_than_if_both_contained_values_would_compare_greater_than), + KAWAII(two_instances_of_the_same_new__type_do_not_compare_greater_than_if_both_contained_values_would_not_compare_greater_than), + KAWAII(two_instances_of_the_same_new__type_compare_greater_than_or_equal_if_both_contained_values_would_compare_greater_than_or_equal), + KAWAII(two_instances_of_the_same_new__type_do_not_compare_greater_than_or_equal_if_both_contained_values_would_not_compare_greater_than_or_equal), + + // Relational Operators noexcept Tests + KAWAII(less_than_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept), + KAWAII(less_than_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept), + KAWAII(less_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept), + KAWAII(less_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept), + KAWAII(greater_than_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept), + KAWAII(greater_than_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept), + KAWAII(greater_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_noexcept_if_comparison_of_the_base_type_is_noexcept), + KAWAII(greater_than_equal_to_comparison_of_two_intances_of_the_same_new__type_is_not_noexcept_if_comparison_of_the_base_type_is_not_noexcept), + + // clang-format on + }, + "Relational Operators Tests"}; +} \ No newline at end of file -- cgit v1.2.3