aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/index.rst174
-rw-r--r--include/newtype/impl/type_traits_extensions.hpp184
-rw-r--r--include/newtype/new_type.hpp120
-rw-r--r--test/src/iterable_suite.cpp264
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 <derivation_clause>` contains :cpp:var:`Iterable` and
+ b) this :cpp:class:`new_type`'s :cpp:type:`base type <base_type>` has a non-static member function :cpp:func:`end() <new_type::base_type::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 <derivation_clause>` contains :cpp:var:`Iterable` and
+ b) this :cpp:class:`new_type`'s :cpp:type:`base type <base_type>` has a non-static member function :cpp:func:`end() const <new_type::base_type::end()>` 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 <derivation_clause>` contains :cpp:var:`Iterable` and
+ b) this :cpp:class:`new_type`'s :cpp:type:`base type <base_type>` has a non-static member function :cpp:func:`cend() const <new_type::base_type::cend()>` 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 <derivation_clause>` contains :cpp:var:`Iterable` and
+ b) this :cpp:class:`new_type`'s :cpp:type:`base type <base_type>` has a non-static member function :cpp:func:`rend() <new_type::base_type::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 <derivation_clause>` contains :cpp:var:`Iterable` and
+ b) this :cpp:class:`new_type`'s :cpp:type:`base type <base_type>` has a non-static member function :cpp:func:`rend() const <new_type::base_type::rend()>` 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 <derivation_clause>` contains :cpp:var:`Iterable` and
+ b) this :cpp:class:`new_type`'s :cpp:type:`base type <base_type>` has a non-static member function :cpp:func:`crend() const <new_type::base_type::crend()>` 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<typename BaseType, typename TagType, auto DerivationClause> \
+ constexpr new_type<BaseType, TagType, DerivationClause>::iterator end(new_type<BaseType, TagType, DerivationClause> & 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 <DerivationClause>` contains :cpp:var:`Iterable` and
+ b) for the :cpp:class:`new_type`'s :cpp:type:`base type <BaseType>` 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<typename BaseType, typename TagType, auto DerivationClause> \
+ constexpr new_type<BaseType, TagType, DerivationClause>::const_iterator end(new_type<BaseType, TagType, DerivationClause> 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 <DerivationClause>` contains :cpp:var:`Iterable` and
+ b) for the :cpp:class:`new_type`'s :cpp:type:`base type <BaseType>` 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<typename BaseType, typename TagType, auto DerivationClause> \
+ constexpr new_type<BaseType, TagType, DerivationClause>::const_iterator cend(new_type<BaseType, TagType, DerivationClause> 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 <DerivationClause>` contains :cpp:var:`Iterable` and
+ b) for the :cpp:class:`new_type`'s :cpp:type:`base type <BaseType>` 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<typename BaseType, typename TagType, auto DerivationClause> \
+ constexpr new_type<BaseType, TagType, DerivationClause>::reverse_iterator rend(new_type<BaseType, TagType, DerivationClause> & 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 <DerivationClause>` contains :cpp:var:`Iterable` and
+ b) for the :cpp:class:`new_type`'s :cpp:type:`base type <BaseType>` 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<typename BaseType, typename TagType, auto DerivationClause> \
+ constexpr new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator rend(new_type<BaseType, TagType, DerivationClause> 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 <DerivationClause>` contains :cpp:var:`Iterable` and
+ b) for the :cpp:class:`new_type`'s :cpp:type:`base type <BaseType>` 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<typename BaseType, typename TagType, auto DerivationClause> \
+ constexpr new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator crend(new_type<BaseType, TagType, DerivationClause> 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 <DerivationClause>` contains :cpp:var:`Iterable` and
+ b) for the :cpp:class:`new_type`'s :cpp:type:`base type <BaseType>` 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<T>::value;
} // namespace iterable_rbegin
- inline namespace iterable_rbegin
+ inline namespace iterable_crbegin
{
template<typename T, typename = void>
struct has_free_crbegin : std::false_type
@@ -666,7 +666,187 @@ namespace nt::impl
template<typename T>
auto constexpr has_crbegin_v = has_crbegin<T>::value;
- } // namespace iterable_rbegin
+ } // namespace iterable_crbegin
+
+ inline namespace iterable_end
+ {
+ template<typename T, typename = void>
+ struct has_free_end : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_end<T, std::void_t<decltype(end(std::declval<T &>()))>>
+ : std::is_same<typename T::iterator, std::remove_cvref_t<decltype(end(std::declval<T &>()))>>
+ {
+ };
+
+ template<typename T>
+ struct has_free_end<T const, std::void_t<decltype(end(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(end(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_end_v = has_free_end<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_end : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_end<T, std::void_t<decltype(std::declval<T &>().end())>>
+ : std::is_same<typename T::iterator, std::remove_cvref_t<decltype(std::declval<T &>().end())>>
+ {
+ };
+
+ template<typename T>
+ struct has_member_end<T const, std::void_t<decltype(std::declval<T const &>().end())>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().end())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_end_v = has_member_end<T>::value;
+
+ template<typename T>
+ struct has_end : std::disjunction<has_free_end<T>, has_member_end<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_end_v = has_end<T>::value;
+ } // namespace iterable_end
+
+ inline namespace iterable_cend
+ {
+ template<typename T, typename = void>
+ struct has_free_cend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_cend<T, std::void_t<decltype(cend(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(cend(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_cend_v = has_free_cend<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_cend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_cend<T, std::void_t<decltype(std::declval<T const &>().cend())>>
+ : std::is_same<typename T::const_iterator, decltype(std::declval<T const &>().cend())>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_cend_v = has_member_cend<T>::value;
+
+ template<typename T>
+ struct has_cend : std::disjunction<has_free_cend<T>, has_member_cend<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_cend_v = has_cend<T>::value;
+ } // namespace iterable_cend
+
+ inline namespace iterable_rend
+ {
+ template<typename T, typename = void>
+ struct has_free_rend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_rend<T, std::void_t<decltype(rend(std::declval<T &>()))>>
+ : std::is_same<typename T::reverse_iterator, std::remove_cvref_t<decltype(end(std::declval<T &>()))>>
+ {
+ };
+
+ template<typename T>
+ struct has_free_rend<T const, std::void_t<decltype(rend(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(rend(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_rend_v = has_free_rend<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_rend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_rend<T, std::void_t<decltype(std::declval<T &>().rend())>>
+ : std::is_same<typename T::reverse_iterator, std::remove_cvref_t<decltype(std::declval<T &>().rend())>>
+ {
+ };
+
+ template<typename T>
+ struct has_member_rend<T const, std::void_t<decltype(std::declval<T const &>().rend())>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().rend())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_rend_v = has_member_rend<T>::value;
+
+ template<typename T>
+ struct has_rend : std::disjunction<has_free_rend<T>, has_member_rend<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_rend_v = has_rend<T>::value;
+ } // namespace iterable_rend
+
+ inline namespace iterable_crend
+ {
+ template<typename T, typename = void>
+ struct has_free_crend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_free_crend<T, std::void_t<decltype(crend(std::declval<T const &>()))>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(crend(std::declval<T const &>()))>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_free_crend_v = has_free_crend<T>::value;
+
+ template<typename T, typename = void>
+ struct has_member_crend : std::false_type
+ {
+ };
+
+ template<typename T>
+ struct has_member_crend<T, std::void_t<decltype(std::declval<T const &>().crend())>>
+ : std::is_same<typename T::const_reverse_iterator, std::remove_cvref_t<decltype(std::declval<T const &>().crend())>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_member_crend_v = has_member_crend<T>::value;
+
+ template<typename T>
+ struct has_crend : std::disjunction<has_free_crend<T>, has_member_crend<T>>
+ {
+ };
+
+ template<typename T>
+ auto constexpr has_crend_v = has_crend<T>::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<DerivationClauseV(nt::Iterable) && impl::has_free_crbegin_v<BaseTypeT const>,
typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend end(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_end_v<BaseTypeT>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend end(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_end_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend cend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_cend_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend rend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_rend_v<BaseTypeT>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend rend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_rend_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+
+ template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV>
+ auto constexpr friend crend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj)
+ -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_crend_v<BaseTypeT const>,
+ typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator>;
+
using super = impl::new_type_move_assignment<BaseType, TagType>;
public:
@@ -176,6 +206,48 @@ namespace nt
{
return this->m_value.crbegin();
}
+
+ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::Iterable)> * = nullptr>
+ auto constexpr end()
+ -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_end_v<BaseType>, typename NewType::iterator>
+ {
+ return this->m_value.end();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr end() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_end_v<BaseType const>,
+ typename NewType::const_iterator>
+ {
+ return this->m_value.end();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr cend() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_cend_v<BaseType const>,
+ typename NewType::const_iterator>
+ {
+ return this->m_value.cend();
+ }
+
+ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::Iterable)> * = nullptr>
+ auto constexpr rend()
+ -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_rend_v<BaseType>, typename NewType::reverse_iterator>
+ {
+ return this->m_value.rend();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr rend() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_rend_v<BaseType const>,
+ typename NewType::const_reverse_iterator>
+ {
+ return this->m_value.rend();
+ }
+
+ template<typename NewType = new_type>
+ auto constexpr crend() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_crend_v<BaseType const>,
+ typename NewType::const_reverse_iterator>
+ {
+ return this->m_value.crend();
+ }
};
template<typename BaseType, typename TagType, auto DerivationClause>
@@ -410,6 +482,54 @@ namespace nt
return crbegin(obj.m_value);
}
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr end(new_type<BaseType, TagType, DerivationClause> & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_end_v<BaseType>,
+ typename new_type<BaseType, TagType, DerivationClause>::iterator>
+ {
+ return end(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr end(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_end_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_iterator>
+ {
+ return end(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr cend(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_cend_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_iterator>
+ {
+ return cend(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr rend(new_type<BaseType, TagType, DerivationClause> & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_rend_v<BaseType>,
+ typename new_type<BaseType, TagType, DerivationClause>::reverse_iterator>
+ {
+ return rend(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr rend(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_rend_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::const_reverse_iterator>
+ {
+ return rend(obj.m_value);
+ }
+
+ template<typename BaseType, typename TagType, auto DerivationClause>
+ auto constexpr crend(new_type<BaseType, TagType, DerivationClause> const & obj)
+ -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_crend_v<BaseType const>,
+ typename new_type<BaseType, TagType, DerivationClause>::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<int, struct tag>;
+ ASSERT(!(nt::impl::has_end_v<type_alias>));
+ }
+
+ auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_end() -> void
+ {
+ static_assert(!nt::impl::has_end_v<int>);
+ using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!(nt::impl::has_end_v<type_alias>));
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(nt::impl::has_member_end_v<type_alias>);
+ }
+
+ 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<with_member const>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(nt::impl::has_member_end_v<type_alias const>);
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!nt::impl::has_free_end_v<type_alias>);
+ }
+
+ 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<with_member const>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!nt::impl::has_free_end_v<type_alias const>);
+ }
+
+ 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<std::array<int, 3>, 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<std::array<int, 3>, 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<int, struct tag>;
+ ASSERT(!(nt::impl::has_cend_v<type_alias>));
+ }
+
+ auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_cend() -> void
+ {
+ static_assert(!nt::impl::has_cend_v<int>);
+ using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!(nt::impl::has_cend_v<type_alias>));
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(nt::impl::has_member_cend_v<type_alias>);
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!nt::impl::has_free_cend_v<type_alias>);
+ }
+
+ 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<std::array<int, 3>, 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<std::array<int, 3>, 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<int, struct tag>;
+ ASSERT(!(nt::impl::has_rend_v<type_alias>));
+ }
+
+ auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_rend() -> void
+ {
+ static_assert(!nt::impl::has_rend_v<int>);
+ using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!(nt::impl::has_rend_v<type_alias>));
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(nt::impl::has_member_rend_v<type_alias>);
+ }
+
+ 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<with_member const>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(nt::impl::has_member_rend_v<type_alias const>);
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!nt::impl::has_free_rend_v<type_alias>);
+ }
+
+ 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<with_member const>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!nt::impl::has_free_rend_v<type_alias const>);
+ }
+
+ 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<std::array<int, 3>, 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<std::array<int, 3>, 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<int, struct tag>;
+ ASSERT(!(nt::impl::has_crend_v<type_alias>));
+ }
+
+ auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_crend() -> void
+ {
+ static_assert(!nt::impl::has_crend_v<int>);
+ using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!(nt::impl::has_crend_v<type_alias>));
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(nt::impl::has_member_crend_v<type_alias>);
+ }
+
+ 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<with_member>);
+ using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>;
+ ASSERT(!nt::impl::has_free_crend_v<type_alias>);
+ }
+
+ 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<std::array<int, 3>, 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<std::array<int, 3>, 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<cute::suite, std::string>
{
return {
@@ -284,13 +510,49 @@ auto iterable_suite() -> std::pair<cute::suite, std::string>
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