diff options
| -rw-r--r-- | doc/src/index.rst | 29 | ||||
| -rw-r--r-- | include/newtype/impl/type_traits_extensions.hpp | 43 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 20 | ||||
| -rw-r--r-- | test/src/iterable_suite.cpp | 84 |
4 files changed, 162 insertions, 14 deletions
diff --git a/doc/src/index.rst b/doc/src/index.rst index 8ef515f..cd016b9 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -231,6 +231,17 @@ Class template :cpp:class:`new_type` .. versionadded:: 1.1.0 + .. cpp:function:: constexpr iterator cbegin() const + + Get a constant iterator to the beginning 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:`cbegin() const <new_type::base_type::cbegin()>` that returns an instance of type :cpp:type:`const_iterator` + + .. versionadded:: 1.1.0 + :literal:`namespace`-level functions and function templates ----------------------------------------------------------- @@ -721,6 +732,24 @@ Iterators .. versionadded:: 1.1.0 +.. cpp:function:: template<typename BaseType, typename TagType, auto DerivationClause> \ + constexpr new_type<BaseType, TagType, DerivationClause>::const_iterator cbegin(new_type<BaseType, TagType, DerivationClause> const & obj) + + Get a constant iterator to the beginning 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 to the begining 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:`cbegin(BaseType const &)` that returns an instance of type :cpp:type:`new_type::const_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 80ba5b0..ee33730 100644 --- a/include/newtype/impl/type_traits_extensions.hpp +++ b/include/newtype/impl/type_traits_extensions.hpp @@ -1051,7 +1051,7 @@ namespace nt::impl } // namespace std_support - inline namespace iterable + inline namespace iterable_begin { template<typename T, typename = void> struct has_free_begin : std::false_type @@ -1100,7 +1100,46 @@ namespace nt::impl template<typename T> auto constexpr has_begin_v = has_begin<T>::value; - } // namespace iterable + } // namespace iterable_begin + + inline namespace iterable_cbegin + { + template<typename T, typename = void> + struct has_free_cbegin : std::false_type + { + }; + + template<typename T> + struct has_free_cbegin<T, std::void_t<decltype(cbegin(std::declval<T const &>()))>> + : std::is_same<typename T::const_iterator, std::remove_cvref_t<decltype(cbegin(std::declval<T const &>()))>> + { + }; + + template<typename T> + auto constexpr has_free_cbegin_v = has_free_cbegin<T>::value; + + template<typename T, typename = void> + struct has_member_cbegin : std::false_type + { + }; + + template<typename T> + struct has_member_cbegin<T, std::void_t<decltype(std::declval<T const &>().cbegin())>> + : std::is_same<typename T::const_iterator, decltype(std::declval<T const &>().cbegin())> + { + }; + + template<typename T> + auto constexpr has_member_cbegin_v = has_member_cbegin<T>::value; + + template<typename T> + struct has_cbegin : std::disjunction<has_free_cbegin<T>, has_member_cbegin<T>> + { + }; + + template<typename T> + auto constexpr has_cbegin_v = has_cbegin<T>::value; + } // namespace iterable_cbegin } // namespace nt::impl diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 0db01b2..474ac88 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -71,6 +71,11 @@ namespace nt -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_begin_v<BaseTypeT>, typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>; + template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV> + auto constexpr friend cbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) + -> std::enable_if_t<DerivationClauseV(nt::Iterable) && impl::has_free_cbegin_v<BaseTypeT const>, + typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator>; + using super = impl::new_type_move_assignment<BaseType, TagType>; public: @@ -198,6 +203,13 @@ namespace nt { return this->m_value.begin(); } + + template<typename NewType = new_type> + auto constexpr cbegin() const -> std::enable_if_t<NewType::derivation_clause(nt::Iterable) && impl::has_member_cbegin_v<BaseType const>, + typename NewType::const_iterator> + { + return this->m_value.cbegin(); + } }; /// Equality Comparison Operators @@ -476,6 +488,14 @@ namespace nt return begin(obj.m_value); } + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr cbegin(new_type<BaseType, TagType, DerivationClause> const & obj) + -> std::enable_if_t<DerivationClause(nt::Iterable) && impl::has_free_cbegin_v<BaseType const>, + typename new_type<BaseType, TagType, DerivationClause>::const_iterator> + { + return cbegin(obj.m_value); + } + } // namespace nt namespace std diff --git a/test/src/iterable_suite.cpp b/test/src/iterable_suite.cpp index 8c08a66..3bdb16b 100644 --- a/test/src/iterable_suite.cpp +++ b/test/src/iterable_suite.cpp @@ -21,6 +21,7 @@ namespace auto begin() -> iterator; auto begin() const -> const_iterator; + auto cbegin() const -> const_iterator; }; } // namespace @@ -86,18 +87,77 @@ inline namespace begin_tests } // namespace begin_tests +inline namespace cbegin_tests +{ + + auto a_new__type_not_deriving_iterable_has_no_cbegin() -> void + { + using type_alias = nt::new_type<int, struct tag>; + ASSERT(!(nt::impl::has_cbegin_v<type_alias>)); + } + + auto a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_cbegin() -> void + { + static_assert(!nt::impl::has_cbegin_v<int>); + using type_alias = nt::new_type<int, struct tag, deriving(nt::Iterable)>; + ASSERT(!(nt::impl::has_cbegin_v<type_alias>)); + } + + auto a_new__type_based_on_an_iterable_type_with_member_cbegin_deriving_iterable_has_member_cbegin() -> void + { + static_assert(nt::impl::has_member_cbegin_v<with_member>); + using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>; + ASSERT(nt::impl::has_member_cbegin_v<type_alias>); + } + + auto a_new__type_based_on_an_iterable_type_without_free_cbegin_deriving_iterable_has_no_free_cbegin() -> void + { + static_assert(!nt::impl::has_free_cbegin_v<with_member>); + using type_alias = nt::new_type<with_member, struct tag, deriving(nt::Iterable)>; + ASSERT(!nt::impl::has_free_cbegin_v<type_alias>); + } + + auto accessing_the_first_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.cbegin(), *strong.cbegin()); + } + + auto an_iterator_obtained_via_member_cbegin_compares_equal_to_an_iterator_obtained_via_free_cbegin() -> 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(cbegin(instance), instance.cbegin()); + } + +} // namespace cbegin_tests + auto iterable_suite() -> std::pair<cute::suite, std::string> { - return {{ - /// 'begin' Tests - KAWAII(a_new__type_not_deriving_iterable_has_no_begin), - KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_begin), - KAWAII(a_new__type_based_on_an_iterable_type_with_member_begin_deriving_iterable_has_member_begin), - KAWAII(a_new__type_based_on_an_iterable_type_with_constant_member_begin_deriving_iterable_has_constant_member_begin), - KAWAII(a_new__type_based_on_an_iterable_type_without_free_begin_deriving_iterable_has_no_free_begin), - KAWAII(a_new__type_based_on_an_iterable_type_without_constant_free_begin_deriving_iterable_has_no_constant_free_begin), - KAWAII(accessing_the_first_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_begin_compares_equal_to_an_iterator_obtained_via_free_begin), - }, - "Iterable Tests"}; + return { + { + // clang-format off + /// 'begin' Tests + KAWAII(a_new__type_not_deriving_iterable_has_no_begin), + KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_begin), + KAWAII(a_new__type_based_on_an_iterable_type_with_member_begin_deriving_iterable_has_member_begin), + KAWAII(a_new__type_based_on_an_iterable_type_with_constant_member_begin_deriving_iterable_has_constant_member_begin), + KAWAII(a_new__type_based_on_an_iterable_type_without_free_begin_deriving_iterable_has_no_free_begin), + KAWAII(a_new__type_based_on_an_iterable_type_without_constant_free_begin_deriving_iterable_has_no_constant_free_begin), + KAWAII(accessing_the_first_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_begin_compares_equal_to_an_iterator_obtained_via_free_begin), + + /// 'begin' Tests + KAWAII(a_new__type_not_deriving_iterable_has_no_cbegin), + KAWAII(a_new__type_based_on_a_non_iterable_type_deriving_iterable_has_no_cbegin), + KAWAII(a_new__type_based_on_an_iterable_type_with_member_cbegin_deriving_iterable_has_member_cbegin), + KAWAII(a_new__type_based_on_an_iterable_type_without_free_cbegin_deriving_iterable_has_no_free_cbegin), + KAWAII(accessing_the_first_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_cbegin_compares_equal_to_an_iterator_obtained_via_free_cbegin), + // clang-format on + }, + "Iterable Tests"}; }
\ No newline at end of file |
