diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2020-01-02 22:38:18 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2020-01-02 22:39:49 +0100 |
| commit | b196e2c10ed8823c681623dfd7bc09b0eb3ad1d2 (patch) | |
| tree | 68a0670dba2ac95f71189383ce202e08345d9373 | |
| parent | 6998183b580b60ac72f79b3ebc4f206fa35937ac (diff) | |
| download | newtype-b196e2c10ed8823c681623dfd7bc09b0eb3ad1d2.tar.xz newtype-b196e2c10ed8823c681623dfd7bc09b0eb3ad1d2.zip | |
new_type: implement support for base comparison
| -rw-r--r-- | doc/src/index.rst | 54 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 62 | ||||
| -rw-r--r-- | test/src/equality_comparison_suite.cpp | 63 |
3 files changed, 166 insertions, 13 deletions
diff --git a/doc/src/index.rst b/doc/src/index.rst index 3ef593d..0a92d90 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -181,6 +181,30 @@ Equality Comparison Operators .. cpp:function:: template<typename BaseType, \ typename TagType, \ auto DerivationClause> \ + constexpr bool operator==(new_type<BaseType, TagType, DerivationClause> const &,\ + BaseType const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` supports comparison using the operator :literal:`==` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + +.. cpp:function:: template<typename BaseType, \ + typename TagType, \ + auto DerivationClause> \ + constexpr bool operator==(BaseType const &,\ + new_type<BaseType, TagType, DerivationClause> const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` supports comparison using the operator :literal:`==` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + +.. cpp:function:: template<typename BaseType, \ + typename TagType, \ + auto DerivationClause> \ constexpr bool operator!=(new_type<BaseType, TagType, DerivationClause> const &,\ new_type<BaseType, TagType, DerivationClause> const &) @@ -190,6 +214,30 @@ Equality Comparison Operators .. versionadded:: 1.0.0 +.. cpp:function:: template<typename BaseType, \ + typename TagType, \ + auto DerivationClause> \ + constexpr bool operator!=(new_type<BaseType, TagType, DerivationClause> const &,\ + BaseType const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` supports comparison using the operator :literal:`!=` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + +.. cpp:function:: template<typename BaseType, \ + typename TagType, \ + auto DerivationClause> \ + constexpr bool operator!=(BaseType const &,\ + new_type<BaseType, TagType, DerivationClause> const &) + + **noexcept specification:** This comparison operator shall be noexcept iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` is nothrow equals-comparable. + + **enablement:** This operator shall be available iff. a) :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` supports comparison using the operator :literal:`!=` and b) the derivation clause contains :cpp:var:`EqBase` + + .. versionadded:: 1.0.0 + Relational Comparison Operators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -355,8 +403,8 @@ This header defines the alias template :cpp:type:`derivable` as well as the set Alias template :cpp:type:`derivable` ------------------------------------ -.. cpp:type:: template<typename NameTag> \ - derivable = type<NameTag> +.. cpp:struct:: template<typename NameTag> \ + derivable .. versionadded:: 1.0.0 @@ -373,7 +421,7 @@ Standard derivation tags .. cpp:var:: auto constexpr EqBase = derivable<struct eq_base_tag>{} - This tag enables the derivation of "Equality comparison with base type" operators :literal:`==` and :literal:`!=` + This tag enables the derivation of "Equality comparison with base type" operators :cpp:func:`template\<typename BaseType, typename TagType, auto DerivationClause> constexpr bool nt::operator==(BaseType const &, new_type<BaseType, TagType, DerivationClause> const &)`, :cpp:func:`template\<typename BaseType, typename TagType, auto DerivationClause> constexpr bool nt::operator==(new_type<BaseType, TagType, DerivationClause> const &, BaseType const &)` :cpp:func:`template\<typename BaseType, typename TagType, auto DerivationClause> constexpr bool nt::operator!=(BaseType const &, new_type<BaseType, TagType, DerivationClause> const &)`, and :cpp:func:`template\<typename BaseType, typename TagType, auto DerivationClause> constexpr bool nt::operator!=(new_type<BaseType, TagType, DerivationClause> const &, BaseType const &)` By virtue of its nature, deriving this feature compromises the strength of the given :cpp:class:`new_type`. .. versionadded:: 1.0.0 diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index d22732a..b599c45 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -229,6 +229,37 @@ namespace nt } /** + * @brief Compare an instance of a given nt::new_type with an object of its base type + * + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. + */ + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs, + BaseType const & rhs) noexcept(impl::is_nothrow_equality_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_equality_comparable_v<BaseType>, bool> + { + return lhs.decay() == rhs; + } + + /** + * @brief Compare an instance of the base type with an instance of a given nt::new_type + * + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. + */ + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr + operator==(BaseType const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_equality_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_equality_comparable_v<BaseType>, bool> + { + return lhs == rhs.decay(); + } + + /** * @brief Compare two objects for non-equality * * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type @@ -244,6 +275,37 @@ namespace nt return lhs.decay() != rhs.decay(); } + /** + * @brief Compare an instance of a given nt::new_type with an object of its base type + * + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. + */ + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs, + BaseType const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_inequality_comparable_v<BaseType>, bool> + { + return lhs.decay() != rhs; + } + + /** + * @brief Compare an instance of the base type with an instance of a given nt::new_type + * + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. + */ + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr + operator!=(BaseType const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(impl::is_nothrow_inequality_comparable_v<BaseType>) + -> std::enable_if_t<DerivationClause(nt::EqBase) && impl::is_inequality_comparable_v<BaseType>, bool> + { + return lhs != rhs.decay(); + } + /// @section Relational operators /** diff --git a/test/src/equality_comparison_suite.cpp b/test/src/equality_comparison_suite.cpp index 64c7521..0789ae8 100644 --- a/test/src/equality_comparison_suite.cpp +++ b/test/src/equality_comparison_suite.cpp @@ -16,7 +16,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_the_same_value_compare_equal() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_1>; + using type_alias = nt::new_type<int, struct tag>; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{42}; @@ -26,7 +26,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_the_same_value_do_not_compare_not_equal() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_1>; + using type_alias = nt::new_type<int, struct tag>; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{42}; @@ -36,7 +36,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_differing_values_do_compare_not_equal() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_1>; + using type_alias = nt::new_type<int, struct tag>; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{43}; @@ -46,7 +46,7 @@ inline namespace basic_equality_comparsion_tests auto two_instances_of_the_same_new__type_with_differing_values_do_not_compare_equal() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_1>; + using type_alias = nt::new_type<int, struct tag>; auto constexpr lhs = type_alias{42}; auto constexpr rhs = type_alias{43}; @@ -61,7 +61,7 @@ inline namespace equality_comparsion_noexcept_tests auto equality_comparison_on_a_new__type_is_noexcept_if_the_base_type_is_noexcept_comparable() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_2>; + using type_alias = nt::new_type<int, struct tag>; static_assert(noexcept(std::declval<int &>() == std::declval<int &>()), "Sanity Check"); ASSERT(noexcept(std::declval<type_alias &>() == std::declval<type_alias &>())); } @@ -76,14 +76,14 @@ inline namespace equality_comparsion_noexcept_tests } }; - using type_alias = nt::new_type<strange_type, struct eq_test_tag_3>; + using type_alias = nt::new_type<strange_type, struct tag>; static_assert(!noexcept(std::declval<strange_type &>() == std::declval<strange_type &>()), "Sanity Check"); ASSERT(!noexcept(std::declval<type_alias &>() == std::declval<type_alias &>())); } auto inequality_comparison_on_a_new__type_is_noexcept_if_the_base_type_is_noexcept_comparable() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_4>; + using type_alias = nt::new_type<int, struct tag>; static_assert(noexcept(std::declval<int &>() != std::declval<int &>()), "Sanity Check"); ASSERT(noexcept(std::declval<type_alias &>() != std::declval<type_alias &>())); } @@ -98,7 +98,7 @@ inline namespace equality_comparsion_noexcept_tests } }; - using type_alias = nt::new_type<strange_type, struct eq_test_tag_5>; + using type_alias = nt::new_type<strange_type, struct tag>; static_assert(!noexcept(std::declval<strange_type &>() != std::declval<strange_type &>()), "Sanity Check"); ASSERT(!noexcept(std::declval<type_alias &>() != std::declval<type_alias &>())); } @@ -110,18 +110,55 @@ inline namespace equality_comparison_return_type_tests auto equality_comparsion_of_two_new__type_instances_returns_bool() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_6>; + using type_alias = nt::new_type<int, struct tag>; ASSERT((std::is_same_v<bool, decltype(std::declval<type_alias &>() == std::declval<type_alias &>())>)); } auto inequality_comparsion_of_two_new__type_instances_returns_bool() -> void { - using type_alias = nt::new_type<int, struct eq_test_tag_7>; + using type_alias = nt::new_type<int, struct tag>; ASSERT((std::is_same_v<bool, decltype(std::declval<type_alias &>() != std::declval<type_alias &>())>)); } } // namespace equality_comparison_return_type_tests +inline namespace base_type_equality_comparison_tests +{ + + auto an_instance_of_a_new__type_compares_equal_to_an_instance_of_its_base_type_with_the_same_value() -> void + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::EqBase)>; + auto lhs = type_alias{42}; + auto rhs = 42; + ASSERT_EQUAL(lhs, rhs); + } + + auto an_instance_of_the_base_type_of_a_new__type_compares_equal_to_an_instance_of_the_new__type_with_the_same_value() -> void + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::EqBase)>; + auto lhs = 42; + auto rhs = type_alias{42}; + ASSERT_EQUAL(lhs, rhs); + } + + auto an_instance_of_a_new__type_compares_not_equal_to_an_instance_of_its_base_type_with_a_differing_value() -> void + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::EqBase)>; + auto lhs = type_alias{42}; + auto rhs = 43; + ASSERT(lhs != rhs); + } + + auto an_instance_of_the_base_type_of_a_new__type_compares_not_equal_to_an_instance_of_the_new__type_with_a_differing_value() -> void + { + using type_alias = nt::new_type<int, struct tag, deriving(nt::EqBase)>; + auto lhs = 43; + auto rhs = type_alias{42}; + ASSERT(lhs != rhs); + } + +} // namespace base_type_equality_comparison_tests + auto equality_comparison_suite() -> std::pair<cute::suite, std::string> { return {{ @@ -140,6 +177,12 @@ auto equality_comparison_suite() -> std::pair<cute::suite, std::string> // Equality Comparison Return Type Tests KAWAII(equality_comparsion_of_two_new__type_instances_returns_bool), KAWAII(inequality_comparsion_of_two_new__type_instances_returns_bool), + + // Base-type Equality Comparison Tests + KAWAII(an_instance_of_a_new__type_compares_equal_to_an_instance_of_its_base_type_with_the_same_value), + KAWAII(an_instance_of_the_base_type_of_a_new__type_compares_equal_to_an_instance_of_the_new__type_with_the_same_value), + KAWAII(an_instance_of_a_new__type_compares_not_equal_to_an_instance_of_its_base_type_with_a_differing_value), + KAWAII(an_instance_of_the_base_type_of_a_new__type_compares_not_equal_to_an_instance_of_the_new__type_with_a_differing_value), }, "Equality Comparison Tests"}; }
\ No newline at end of file |
