aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2020-02-25 20:57:06 +0100
committerFelix Morgner <felix.morgner@gmail.com>2020-02-25 20:57:06 +0100
commitbb58e65e6596a2ffac2e85e9fda1e8568aa9b4b1 (patch)
treee02730d64bd32c9b3251bc5d19448f197741ba12
parent62ca586910736b5aba6d622ec27a7b00e3c37359 (diff)
downloadnewtype-bb58e65e6596a2ffac2e85e9fda1e8568aa9b4b1.tar.xz
newtype-bb58e65e6596a2ffac2e85e9fda1e8568aa9b4b1.zip
new_type: implement cbegin
-rw-r--r--doc/src/index.rst29
-rw-r--r--include/newtype/impl/type_traits_extensions.hpp43
-rw-r--r--include/newtype/new_type.hpp20
-rw-r--r--test/src/iterable_suite.cpp84
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