From 9e79f0cbfa074f7766f6fea04d41f7803c6cee58 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Feb 2020 07:13:29 +0100 Subject: newtype: implement end iterators --- doc/src/index.rst | 174 ++++++++++++++++ include/newtype/impl/type_traits_extensions.hpp | 184 ++++++++++++++++- include/newtype/new_type.hpp | 120 +++++++++++ test/src/iterable_suite.cpp | 264 +++++++++++++++++++++++- 4 files changed, 739 insertions(+), 3 deletions(-) diff --git a/doc/src/index.rst b/doc/src/index.rst index a54d54c..290f17e 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -287,6 +287,72 @@ Class template :cpp:class:`new_type` .. versionadded:: 1.1.0 + .. cpp:function:: constexpr iterator end() + + Get an iterator beyond the end of the object contained by this :cpp:class:`new_type` + + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) this :cpp:class:`new_type`'s :cpp:type:`base type ` has a non-static member function :cpp:func:`end() ` that returns an instance of type :cpp:type:`iterator` + + .. versionadded:: 1.1.0 + + .. cpp:function:: constexpr iterator end() const + + Get a constant iterator beyond the end of the object contained by this :cpp:class:`new_type` + + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) this :cpp:class:`new_type`'s :cpp:type:`base type ` has a non-static member function :cpp:func:`end() const ` that returns an instance of type :cpp:type:`const_iterator` + + .. versionadded:: 1.1.0 + + .. cpp:function:: constexpr iterator cend() const + + Get a constant iterator beyond the end of the object contained by this :cpp:class:`new_type` + + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) this :cpp:class:`new_type`'s :cpp:type:`base type ` has a non-static member function :cpp:func:`cend() const ` that returns an instance of type :cpp:type:`const_iterator` + + .. versionadded:: 1.1.0 + + .. cpp:function:: constexpr iterator rend() + + Get a reverse iterator beyond the end of the object contained by this :cpp:class:`new_type` + + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) this :cpp:class:`new_type`'s :cpp:type:`base type ` has a non-static member function :cpp:func:`rend() ` that returns an instance of type :cpp:type:`reverse_iterator` + + .. versionadded:: 1.1.0 + + .. cpp:function:: constexpr iterator rend() const + + Get a constant reverse iterator beyond the end of the object contained by this :cpp:class:`new_type` + + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) this :cpp:class:`new_type`'s :cpp:type:`base type ` has a non-static member function :cpp:func:`rend() const ` that returns an instance of type :cpp:type:`const_reverse_iterator` + + .. versionadded:: 1.1.0 + + .. cpp:function:: constexpr iterator crend() const + + Get a constant reverse iterator beyond the end of the object contained by this :cpp:class:`new_type` + + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) this :cpp:class:`new_type`'s :cpp:type:`base type ` has a non-static member function :cpp:func:`crend() const ` that returns an instance of type :cpp:type:`const_reverse_iterator` + + .. versionadded:: 1.1.0 + :literal:`namespace`-level functions and function templates ----------------------------------------------------------- @@ -849,6 +915,114 @@ Iterators .. versionadded:: 1.1.0 +.. cpp:function:: template \ + constexpr new_type::iterator end(new_type & obj) + + Get an iterator beyond the end of the object contained by an instance of :cpp:class:`new_type` + + :tparam BaseType: |BaseTypeDoc| + :tparam TagType: |TagTypeDoc| + :tparam DerivationClause: |DerivationClauseDoc| + :param obj: The object to retrieve the iterator from + :returns: An iterator beyond the end of the object of contained by :literal:`obj`. + :throws: Any exception + :enablement: This function shall be available iff. + + a) :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) for the :cpp:class:`new_type`'s :cpp:type:`base type ` exists a namespace-level function :literal:`end(BaseType &)` that returns an instance of type :cpp:type:`new_type::iterator` + + .. versionadded:: 1.1.0 + +.. cpp:function:: template \ + constexpr new_type::const_iterator end(new_type const & obj) + + Get a constant iterator beyond the end of the object contained by an instance of :cpp:class:`new_type` + + :tparam BaseType: |BaseTypeDoc| + :tparam TagType: |TagTypeDoc| + :tparam DerivationClause: |DerivationClauseDoc| + :param obj: The object to retrieve the iterator from + :returns: An iterator beyond the end of the object of contained by :cpp:var:`obj`. + :throws: Any exception + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) for the :cpp:class:`new_type`'s :cpp:type:`base type ` exists a namespace-level function :literal:`end(BaseType const &)` that returns an instance of type :cpp:type:`new_type::const_iterator` + + .. versionadded:: 1.1.0 + +.. cpp:function:: template \ + constexpr new_type::const_iterator cend(new_type const & obj) + + Get a constant iterator beyond the end of the object contained by an instance of :cpp:class:`new_type` + + :tparam BaseType: |BaseTypeDoc| + :tparam TagType: |TagTypeDoc| + :tparam DerivationClause: |DerivationClauseDoc| + :param obj: The object to retrieve the iterator from + :returns: An iterator beyond the end of the object of contained by :cpp:var:`obj`. + :throws: Any exception + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) for the :cpp:class:`new_type`'s :cpp:type:`base type ` exists a namespace-level function :literal:`cend(BaseType const &)` that returns an instance of type :cpp:type:`new_type::const_iterator` + + .. versionadded:: 1.1.0 + +.. cpp:function:: template \ + constexpr new_type::reverse_iterator rend(new_type & obj) + + Get a reverse iterator beyond the end of the object contained by an instance of :cpp:class:`new_type` + + :tparam BaseType: |BaseTypeDoc| + :tparam TagType: |TagTypeDoc| + :tparam DerivationClause: |DerivationClauseDoc| + :param obj: The object to retrieve the iterator from + :returns: An iterator beyond the end of the object of contained by :literal:`obj`. + :throws: Any exception + :enablement: This function shall be available iff. + + a) :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) for the :cpp:class:`new_type`'s :cpp:type:`base type ` exists a namespace-level function :literal:`rend(BaseType &)` that returns an instance of type :cpp:type:`new_type::reverse_iterator` + + .. versionadded:: 1.1.0 + +.. cpp:function:: template \ + constexpr new_type::const_reverse_iterator rend(new_type const & obj) + + Get a constant reverse iterator beyond the end of the object contained by an instance of :cpp:class:`new_type` + + :tparam BaseType: |BaseTypeDoc| + :tparam TagType: |TagTypeDoc| + :tparam DerivationClause: |DerivationClauseDoc| + :param obj: The object to retrieve the iterator from + :returns: An iterator beyond the end of the object of contained by :cpp:var:`obj`. + :throws: Any exception + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) for the :cpp:class:`new_type`'s :cpp:type:`base type ` exists a namespace-level function :literal:`rend(BaseType const &)` that returns an instance of type :cpp:type:`new_type::const_reverse_iterator` + + .. versionadded:: 1.1.0 + +.. cpp:function:: template \ + constexpr new_type::const_reverse_iterator crend(new_type const & obj) + + Get a constant reverse iterator beyond the end of the object contained by an instance of :cpp:class:`new_type` + + :tparam BaseType: |BaseTypeDoc| + :tparam TagType: |TagTypeDoc| + :tparam DerivationClause: |DerivationClauseDoc| + :param obj: The object to retrieve the iterator from + :returns: An iterator beyond the end of the object of contained by :cpp:var:`obj`. + :throws: Any exception + :enablement: This function shall be available iff. + + a) this :cpp:class:`new_type`'s :cpp:var:`derivation clause ` contains :cpp:var:`Iterable` and + b) for the :cpp:class:`new_type`'s :cpp:type:`base type ` exists a namespace-level function :literal:`crend(BaseType const &)` that returns an instance of type :cpp:type:`new_type::const_reverse_iterator` + + .. versionadded:: 1.1.0 + :cpp:class:`std::hash` Support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/newtype/impl/type_traits_extensions.hpp b/include/newtype/impl/type_traits_extensions.hpp index f7dafef..121e2c0 100644 --- a/include/newtype/impl/type_traits_extensions.hpp +++ b/include/newtype/impl/type_traits_extensions.hpp @@ -629,7 +629,7 @@ namespace nt::impl auto constexpr has_rbegin_v = has_rbegin::value; } // namespace iterable_rbegin - inline namespace iterable_rbegin + inline namespace iterable_crbegin { template struct has_free_crbegin : std::false_type @@ -666,7 +666,187 @@ namespace nt::impl template auto constexpr has_crbegin_v = has_crbegin::value; - } // namespace iterable_rbegin + } // namespace iterable_crbegin + + inline namespace iterable_end + { + template + struct has_free_end : std::false_type + { + }; + + template + struct has_free_end()))>> + : std::is_same()))>> + { + }; + + template + struct has_free_end()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_end_v = has_free_end::value; + + template + struct has_member_end : std::false_type + { + }; + + template + struct has_member_end().end())>> + : std::is_same().end())>> + { + }; + + template + struct has_member_end().end())>> + : std::is_same().end())>> + { + }; + + template + auto constexpr has_member_end_v = has_member_end::value; + + template + struct has_end : std::disjunction, has_member_end> + { + }; + + template + auto constexpr has_end_v = has_end::value; + } // namespace iterable_end + + inline namespace iterable_cend + { + template + struct has_free_cend : std::false_type + { + }; + + template + struct has_free_cend()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_cend_v = has_free_cend::value; + + template + struct has_member_cend : std::false_type + { + }; + + template + struct has_member_cend().cend())>> + : std::is_same().cend())> + { + }; + + template + auto constexpr has_member_cend_v = has_member_cend::value; + + template + struct has_cend : std::disjunction, has_member_cend> + { + }; + + template + auto constexpr has_cend_v = has_cend::value; + } // namespace iterable_cend + + inline namespace iterable_rend + { + template + struct has_free_rend : std::false_type + { + }; + + template + struct has_free_rend()))>> + : std::is_same()))>> + { + }; + + template + struct has_free_rend()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_rend_v = has_free_rend::value; + + template + struct has_member_rend : std::false_type + { + }; + + template + struct has_member_rend().rend())>> + : std::is_same().rend())>> + { + }; + + template + struct has_member_rend().rend())>> + : std::is_same().rend())>> + { + }; + + template + auto constexpr has_member_rend_v = has_member_rend::value; + + template + struct has_rend : std::disjunction, has_member_rend> + { + }; + + template + auto constexpr has_rend_v = has_rend::value; + } // namespace iterable_rend + + inline namespace iterable_crend + { + template + struct has_free_crend : std::false_type + { + }; + + template + struct has_free_crend()))>> + : std::is_same()))>> + { + }; + + template + auto constexpr has_free_crend_v = has_free_crend::value; + + template + struct has_member_crend : std::false_type + { + }; + + template + struct has_member_crend().crend())>> + : std::is_same().crend())>> + { + }; + + template + auto constexpr has_member_crend_v = has_member_crend::value; + + template + struct has_crend : std::disjunction, has_member_crend> + { + }; + + template + auto constexpr has_crend_v = has_crend::value; + } // namespace iterable_crend } // namespace nt::impl diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 36a3927..66ff332 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -88,6 +88,36 @@ namespace nt -> std::enable_if_t, typename new_type::const_reverse_iterator>; + template + auto constexpr friend end(new_type & obj) + -> std::enable_if_t, + typename new_type::iterator>; + + template + auto constexpr friend end(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator>; + + template + auto constexpr friend cend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator>; + + template + auto constexpr friend rend(new_type & obj) + -> std::enable_if_t, + typename new_type::reverse_iterator>; + + template + auto constexpr friend rend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator>; + + template + auto constexpr friend crend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator>; + using super = impl::new_type_move_assignment; public: @@ -176,6 +206,48 @@ namespace nt { return this->m_value.crbegin(); } + + template * = nullptr> + auto constexpr end() + -> std::enable_if_t, typename NewType::iterator> + { + return this->m_value.end(); + } + + template + auto constexpr end() const -> std::enable_if_t, + typename NewType::const_iterator> + { + return this->m_value.end(); + } + + template + auto constexpr cend() const -> std::enable_if_t, + typename NewType::const_iterator> + { + return this->m_value.cend(); + } + + template * = nullptr> + auto constexpr rend() + -> std::enable_if_t, typename NewType::reverse_iterator> + { + return this->m_value.rend(); + } + + template + auto constexpr rend() const -> std::enable_if_t, + typename NewType::const_reverse_iterator> + { + return this->m_value.rend(); + } + + template + auto constexpr crend() const -> std::enable_if_t, + typename NewType::const_reverse_iterator> + { + return this->m_value.crend(); + } }; template @@ -410,6 +482,54 @@ namespace nt return crbegin(obj.m_value); } + template + auto constexpr end(new_type & obj) + -> std::enable_if_t, + typename new_type::iterator> + { + return end(obj.m_value); + } + + template + auto constexpr end(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator> + { + return end(obj.m_value); + } + + template + auto constexpr cend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_iterator> + { + return cend(obj.m_value); + } + + template + auto constexpr rend(new_type & obj) + -> std::enable_if_t, + typename new_type::reverse_iterator> + { + return rend(obj.m_value); + } + + template + auto constexpr rend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator> + { + return rend(obj.m_value); + } + + template + auto constexpr crend(new_type const & obj) + -> std::enable_if_t, + typename new_type::const_reverse_iterator> + { + return crend(obj.m_value); + } + } // namespace nt namespace std diff --git a/test/src/iterable_suite.cpp b/test/src/iterable_suite.cpp index 778dc35..a75ab19 100644 --- a/test/src/iterable_suite.cpp +++ b/test/src/iterable_suite.cpp @@ -27,6 +27,13 @@ namespace auto rbegin() -> reverse_iterator; auto rbegin() const -> const_reverse_iterator; auto crbegin() const -> const_reverse_iterator; + + auto end() -> iterator; + auto end() const -> const_iterator; + auto cend() const -> const_iterator; + auto rend() -> reverse_iterator; + auto rend() const -> const_reverse_iterator; + auto crend() const -> const_reverse_iterator; }; } // namespace @@ -251,6 +258,225 @@ inline namespace crbegin_tests } // namespace crbegin_tests +inline namespace end_tests +{ + + auto a_new__type_not_deriving_iterable_has_no_end() -> void + { + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_end_v)); + } + + auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_end() -> void + { + static_assert(!nt::impl::has_end_v); + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_end_v)); + } + + auto a_new__type_based_on_an_iterable_type_with_member_end_deriving_iterable_has_member_end() -> void + { + static_assert(nt::impl::has_member_end_v); + using type_alias = nt::new_type; + ASSERT(nt::impl::has_member_end_v); + } + + auto a_new__type_based_on_an_iterable_type_with_constant_member_end_deriving_iterable_has_constant_member_end() -> void + { + static_assert(nt::impl::has_member_end_v); + using type_alias = nt::new_type; + ASSERT(nt::impl::has_member_end_v); + } + + auto a_new__type_based_on_an_iterable_type_without_free_end_deriving_iterable_has_no_free_end() -> void + { + static_assert(!nt::impl::has_free_end_v); + using type_alias = nt::new_type; + ASSERT(!nt::impl::has_free_end_v); + } + + auto a_new__type_based_on_an_iterable_type_without_constant_free_end_deriving_iterable_has_no_constant_free_end() -> void + { + static_assert(!nt::impl::has_free_end_v); + using type_alias = nt::new_type; + ASSERT(!nt::impl::has_free_end_v); + } + + auto accessing_the_last_element_of_an_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type() -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto weak = std::array{42, 21, 10}; + auto strong = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(*(weak.end() - 1), *(strong.end() - 1)); + } + + auto an_iterator_obtained_via_member_end_compares_equal_to_an_iterator_obtained_via_free_end() -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto instance = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(end(instance), instance.end()); + } + +} // namespace end_tests + +inline namespace cend_tests +{ + + auto a_new__type_not_deriving_iterable_has_no_cend() -> void + { + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_cend_v)); + } + + auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_cend() -> void + { + static_assert(!nt::impl::has_cend_v); + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_cend_v)); + } + + auto a_new__type_based_on_an_iterable_type_with_member_cend_deriving_iterable_has_member_cend() -> void + { + static_assert(nt::impl::has_member_cend_v); + using type_alias = nt::new_type; + ASSERT(nt::impl::has_member_cend_v); + } + + auto a_new__type_based_on_an_iterable_type_without_free_cend_deriving_iterable_has_no_free_cend() -> void + { + static_assert(!nt::impl::has_free_cend_v); + using type_alias = nt::new_type; + ASSERT(!nt::impl::has_free_cend_v); + } + + auto accessing_the_last_element_of_a_constant_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type() + -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto weak = std::array{42, 21, 10}; + auto strong = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(*(weak.cend() - 1), *(strong.cend() - 1)); + } + + auto an_iterator_obtained_via_member_cend_compares_equal_to_an_iterator_obtained_via_free_cend() -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto instance = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(cend(instance), instance.cend()); + } + +} // namespace cend_tests + +inline namespace rend_tests +{ + + auto a_new__type_not_deriving_iterable_has_no_rend() -> void + { + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_rend_v)); + } + + auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_rend() -> void + { + static_assert(!nt::impl::has_rend_v); + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_rend_v)); + } + + auto a_new__type_based_on_an_iterable_type_with_member_rend_deriving_iterable_has_member_rend() -> void + { + static_assert(nt::impl::has_member_rend_v); + using type_alias = nt::new_type; + ASSERT(nt::impl::has_member_rend_v); + } + + auto a_new__type_based_on_an_iterable_type_with_constant_member_rend_deriving_iterable_has_constant_member_rend() -> void + { + static_assert(nt::impl::has_member_rend_v); + using type_alias = nt::new_type; + ASSERT(nt::impl::has_member_rend_v); + } + + auto a_new__type_based_on_an_iterable_type_without_free_rend_deriving_iterable_has_no_free_rend() -> void + { + static_assert(!nt::impl::has_free_rend_v); + using type_alias = nt::new_type; + ASSERT(!nt::impl::has_free_rend_v); + } + + auto a_new__type_based_on_an_iterable_type_without_constant_free_rend_deriving_iterable_has_no_constant_free_rend() -> void + { + static_assert(!nt::impl::has_free_rend_v); + using type_alias = nt::new_type; + ASSERT(!nt::impl::has_free_rend_v); + } + + auto accessing_the_last_element_of_a_reverse_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type() -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto weak = std::array{42, 21, 10}; + auto strong = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(*(weak.rend() - 1), *(strong.rend() - 1)); + } + + auto an_iterator_obtained_via_member_rend_compares_equal_to_an_iterator_obtained_via_free_rend() -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto instance = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(rend(instance), instance.rend()); + } + +} // namespace rend_tests + +inline namespace crend_tests +{ + + auto a_new__type_not_deriving_iterable_has_no_crend() -> void + { + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_crend_v)); + } + + auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_crend() -> void + { + static_assert(!nt::impl::has_crend_v); + using type_alias = nt::new_type; + ASSERT(!(nt::impl::has_crend_v)); + } + + auto a_new__type_based_on_an_iterable_type_with_member_crend_deriving_iterable_has_member_crend() -> void + { + static_assert(nt::impl::has_member_crend_v); + using type_alias = nt::new_type; + ASSERT(nt::impl::has_member_crend_v); + } + + auto a_new__type_based_on_an_iterable_type_without_free_crend_deriving_iterable_has_no_free_crend() -> void + { + static_assert(!nt::impl::has_free_crend_v); + using type_alias = nt::new_type; + ASSERT(!nt::impl::has_free_crend_v); + } + + auto + accessing_the_last_element_of_a_constant_reverse_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type() + -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto weak = std::array{42, 21, 10}; + auto strong = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(*(weak.crend() - 1), *(strong.crend() - 1)); + } + + auto an_iterator_obtained_via_member_crend_compares_equal_to_an_iterator_obtained_via_free_crend() -> void + { + using type_alias = nt::new_type, struct tag, deriving(nt::Iterable)>; + auto instance = type_alias{{42, 21, 10}}; + ASSERT_EQUAL(crend(instance), instance.crend()); + } + +} // namespace crend_tests + auto iterable_suite() -> std::pair { return { @@ -284,13 +510,49 @@ auto iterable_suite() -> std::pair KAWAII(accessing_the_first_element_of_a_reverse_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type), KAWAII(an_iterator_obtained_via_member_rbegin_compares_equal_to_an_iterator_obtained_via_free_rbegin), - /// 'cbegin' Tests + /// 'crbegin' Tests KAWAII(a_new__type_not_deriving_iterable_has_no_crbegin), KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_crbegin), KAWAII(a_new__type_based_on_an_iterable_type_with_member_crbegin_deriving_iterable_has_member_crbegin), KAWAII(a_new__type_based_on_an_iterable_type_without_free_crbegin_deriving_iterable_has_no_free_crbegin), KAWAII(accessing_the_first_element_of_a_constant_reverse_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type), KAWAII(an_iterator_obtained_via_member_crbegin_compares_equal_to_an_iterator_obtained_via_free_crbegin), + + /// 'end' Tests + KAWAII(a_new__type_not_deriving_iterable_has_no_end), + KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_end), + KAWAII(a_new__type_based_on_an_iterable_type_with_member_end_deriving_iterable_has_member_end), + KAWAII(a_new__type_based_on_an_iterable_type_with_constant_member_end_deriving_iterable_has_constant_member_end), + KAWAII(a_new__type_based_on_an_iterable_type_without_free_end_deriving_iterable_has_no_free_end), + KAWAII(a_new__type_based_on_an_iterable_type_without_constant_free_end_deriving_iterable_has_no_constant_free_end), + KAWAII(accessing_the_last_element_of_an_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type), + KAWAII(an_iterator_obtained_via_member_end_compares_equal_to_an_iterator_obtained_via_free_end), + + /// 'cend' Tests + KAWAII(a_new__type_not_deriving_iterable_has_no_cend), + KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_cend), + KAWAII(a_new__type_based_on_an_iterable_type_with_member_cend_deriving_iterable_has_member_cend), + KAWAII(a_new__type_based_on_an_iterable_type_without_free_cend_deriving_iterable_has_no_free_cend), + KAWAII(accessing_the_last_element_of_a_constant_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type), + KAWAII(an_iterator_obtained_via_member_cend_compares_equal_to_an_iterator_obtained_via_free_cend), + + /// 'rend' Tests + KAWAII(a_new__type_not_deriving_iterable_has_no_rend), + KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_rend), + KAWAII(a_new__type_based_on_an_iterable_type_with_member_rend_deriving_iterable_has_member_rend), + KAWAII(a_new__type_based_on_an_iterable_type_with_constant_member_rend_deriving_iterable_has_constant_member_rend), + KAWAII(a_new__type_based_on_an_iterable_type_without_free_rend_deriving_iterable_has_no_free_rend), + KAWAII(a_new__type_based_on_an_iterable_type_without_constant_free_rend_deriving_iterable_has_no_constant_free_rend), + KAWAII(accessing_the_last_element_of_a_reverse_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type), + KAWAII(an_iterator_obtained_via_member_rend_compares_equal_to_an_iterator_obtained_via_free_rend), + + /// 'crend' Tests + KAWAII(a_new__type_not_deriving_iterable_has_no_crend), + KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_crend), + KAWAII(a_new__type_based_on_an_iterable_type_with_member_crend_deriving_iterable_has_member_crend), + KAWAII(a_new__type_based_on_an_iterable_type_without_free_crend_deriving_iterable_has_no_free_crend), + KAWAII(accessing_the_last_element_of_a_constant_reverse_iterator_on_a_new__type_yields_the_same_value_as_accessing_it_through_an_unwrapped_type), + KAWAII(an_iterator_obtained_via_member_crend_compares_equal_to_an_iterator_obtained_via_free_crend), // clang-format on }, "Iterable Tests"}; -- cgit v1.2.3