// Copyright (C) 2019 T. Zachary Laine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_STL_INTERFACES_ITERATOR_INTERFACE_HPP #define BOOST_STL_INTERFACES_ITERATOR_INTERFACE_HPP #include #include #include #if defined(__cpp_lib_three_way_comparison) #include #endif namespace boost { namespace stl_interfaces { /** A type for granting access to the private members of an iterator derived from `iterator_interface`. */ struct access { #ifndef BOOST_STL_INTERFACES_DOXYGEN template static constexpr auto base(D & d) noexcept -> decltype(d.base_reference()) { return d.base_reference(); } template static constexpr auto base(D const & d) noexcept -> decltype(d.base_reference()) { return d.base_reference(); } #endif }; /** The return type of `operator->()` in a proxy iterator. This template is used as the default `Pointer` template parameter in the `proxy_iterator_interface` template alias. Note that the use of this template implies a copy or move of the underlying object of type `T`. */ template struct proxy_arrow_result { constexpr proxy_arrow_result(T const & value) noexcept( noexcept(T(value))) : value_(value) {} constexpr proxy_arrow_result(T && value) noexcept( noexcept(T(std::move(value)))) : value_(std::move(value)) {} constexpr T const * operator->() const noexcept { return &value_; } constexpr T * operator->() noexcept { return &value_; } private: T value_; }; namespace detail { template auto make_pointer( T && value, std::enable_if_t::value, int> = 0) -> decltype(std::addressof(value)) { return std::addressof(value); } template auto make_pointer( T && value, std::enable_if_t::value, int> = 0) { return Pointer(std::forward(value)); } template struct concept_category { using type = IteratorConcept; }; template using concept_category_t = typename concept_category::type; template struct pointer { using type = Pointer; }; template struct pointer { using type = void; }; template using pointer_t = typename pointer::type; template using interoperable = std::integral_constant< bool, (std::is_convertible::value || std::is_convertible::value)>; template using common_t = std::conditional_t::value, U, T>; template using use_base = decltype(access::base(std::declval())); template using void_t = void; template< typename AlwaysVoid, template class Template, typename... Args> struct detector : std::false_type { }; template class Template, typename... Args> struct detector>, Template, Args...> : std::true_type { }; template< typename T, typename U, bool UseBase = detector::value> struct common_eq { static constexpr auto call(T lhs, U rhs) { return static_cast>(lhs).derived() == static_cast>(rhs).derived(); } }; template struct common_eq { static constexpr auto call(T lhs, U rhs) { return access::base(lhs) == access::base(rhs); } }; template constexpr auto common_diff(T lhs, U rhs) noexcept(noexcept( static_cast>(lhs) - static_cast>(rhs))) -> decltype( static_cast>(lhs) - static_cast>(rhs)) { return static_cast>(lhs) - static_cast>(rhs); } } }} namespace boost { namespace stl_interfaces { inline namespace v1 { /** A CRTP template that one may derive from to make defining iterators easier. The template parameter `D` for `iterator_interface` may be an incomplete type. Before any member of the resulting specialization of `iterator_interface` other than special member functions is referenced, `D` shall be complete, and model `std::derived_from>`. */ template< typename Derived, typename IteratorConcept, typename ValueType, typename Reference = ValueType &, typename Pointer = ValueType *, typename DifferenceType = std::ptrdiff_t #ifndef BOOST_STL_INTERFACES_DOXYGEN , typename E = std::enable_if_t< std::is_class::value && std::is_same>::value> #endif > struct iterator_interface; namespace v1_dtl { template struct ra_iter : std::false_type { }; template struct ra_iter> : std::integral_constant< bool, std::is_base_of< std::random_access_iterator_tag, typename Iterator::iterator_concept>::value> { }; template struct plus_eq : std::false_type { }; template struct plus_eq< Iterator, DifferenceType, void_t() += std::declval())>> : std::true_type { }; template< typename D, typename IteratorConcept, typename ValueType, typename Reference, typename Pointer, typename DifferenceType> void derived_iterator(iterator_interface< D, IteratorConcept, ValueType, Reference, Pointer, DifferenceType> const &); } template< typename Derived, typename IteratorConcept, typename ValueType, typename Reference, typename Pointer, typename DifferenceType #ifndef BOOST_STL_INTERFACES_DOXYGEN , typename E #endif > struct iterator_interface { #ifndef BOOST_STL_INTERFACES_DOXYGEN private: constexpr Derived & derived() noexcept { return static_cast(*this); } constexpr Derived const & derived() const noexcept { return static_cast(*this); } template friend struct detail::common_eq; #endif public: using iterator_concept = IteratorConcept; using iterator_category = detail::concept_category_t; using value_type = std::remove_const_t; using reference = Reference; using pointer = detail::pointer_t; using difference_type = DifferenceType; template constexpr auto operator*() const noexcept(noexcept(*access::base(std::declval()))) -> decltype(*access::base(std::declval())) { return *access::base(derived()); } template constexpr auto operator-> () const noexcept( noexcept(detail::make_pointer(*std::declval()))) -> decltype( detail::make_pointer(*std::declval())) { return detail::make_pointer(*derived()); } template constexpr auto operator[](difference_type i) const noexcept(noexcept( D(std::declval()), std::declval() += i, *std::declval())) -> decltype(std::declval() += i, *std::declval()) { D retval = derived(); retval += i; return *retval; } template< typename D = Derived, typename Enable = std::enable_if_t::value>> constexpr auto operator++() noexcept(noexcept(++access::base(std::declval()))) -> decltype(++access::base(std::declval())) { return ++access::base(derived()); } template constexpr auto operator++() noexcept( noexcept(std::declval() += difference_type(1))) -> decltype( std::declval() += difference_type(1), std::declval()) { derived() += difference_type(1); return derived(); } template constexpr auto operator++(int)noexcept( noexcept(D(std::declval()), ++std::declval())) -> std::remove_reference_t()), ++std::declval(), std::declval())> { D retval = derived(); ++derived(); return retval; } template constexpr auto operator+=(difference_type n) noexcept( noexcept(access::base(std::declval()) += n)) -> decltype(access::base(std::declval()) += n) { return access::base(derived()) += n; } template constexpr auto operator+(difference_type i) const noexcept(noexcept(D(std::declval()), std::declval() += i)) -> std::remove_reference_t()), std::declval() += i, std::declval())> { D retval = derived(); retval += i; return retval; } friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR Derived operator+(difference_type i, Derived it) noexcept { return it + i; } template< typename D = Derived, typename Enable = std::enable_if_t::value>> constexpr auto operator--() noexcept(noexcept(--access::base(std::declval()))) -> decltype(--access::base(std::declval())) { return --access::base(derived()); } template constexpr auto operator--() noexcept(noexcept( D(std::declval()), std::declval() += -difference_type(1))) -> decltype( std::declval() += -difference_type(1), std::declval()) { derived() += -difference_type(1); return derived(); } template constexpr auto operator--(int)noexcept( noexcept(D(std::declval()), --std::declval())) -> std::remove_reference_t()), --std::declval(), std::declval())> { D retval = derived(); --derived(); return retval; } template constexpr D & operator-=(difference_type i) noexcept { derived() += -i; return derived(); } template constexpr auto operator-(D other) const noexcept(noexcept( access::base(std::declval()) - access::base(other))) -> decltype( access::base(std::declval()) - access::base(other)) { return access::base(derived()) - access::base(other); } friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR Derived operator-(Derived it, difference_type i) noexcept { Derived retval = it; retval += -i; return retval; } }; /** Implementation of `operator==()`, implemented in terms of the iterator underlying IteratorInterface, for all iterators derived from `iterator_interface`, except those with an iterator category derived from `std::random_access_iterator_tag`. */ template< typename IteratorInterface1, typename IteratorInterface2, typename Enable = std::enable_if_t::value>> constexpr auto operator==(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept -> decltype( access::base(std::declval()) == access::base(std::declval())) { return access::base(lhs) == access::base(rhs); } /** Implementation of `operator==()` for all iterators derived from `iterator_interface` that have an iterator category derived from `std::random_access_iterator_tag`. */ template< typename IteratorInterface1, typename IteratorInterface2, typename Enable = std::enable_if_t::value>> constexpr auto operator==(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept( noexcept(detail::common_diff(lhs, rhs))) -> decltype( v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) == 0) { return detail::common_diff(lhs, rhs) == 0; } /** Implementation of `operator!=()` for all iterators derived from `iterator_interface`. */ template constexpr auto operator!=( IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept(noexcept(!(lhs == rhs))) -> decltype(v1_dtl::derived_iterator(lhs), !(lhs == rhs)) { return !(lhs == rhs); } /** Implementation of `operator<()` for all iterators derived from `iterator_interface` that have an iterator category derived from `std::random_access_iterator_tag`. */ template constexpr auto operator<(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept( noexcept(detail::common_diff(lhs, rhs))) -> decltype( v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) < 0) { return detail::common_diff(lhs, rhs) < 0; } /** Implementation of `operator<=()` for all iterators derived from `iterator_interface` that have an iterator category derived from `std::random_access_iterator_tag`. */ template constexpr auto operator<=(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept( noexcept(detail::common_diff(lhs, rhs))) -> decltype( v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) <= 0) { return detail::common_diff(lhs, rhs) <= 0; } /** Implementation of `operator>()` for all iterators derived from `iterator_interface` that have an iterator category derived from `std::random_access_iterator_tag`. */ template constexpr auto operator>(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept( noexcept(detail::common_diff(lhs, rhs))) -> decltype( v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) > 0) { return detail::common_diff(lhs, rhs) > 0; } /** Implementation of `operator>=()` for all iterators derived from `iterator_interface` that have an iterator category derived from `std::random_access_iterator_tag`. */ template constexpr auto operator>=(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept( noexcept(detail::common_diff(lhs, rhs))) -> decltype( v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) >= 0) { return detail::common_diff(lhs, rhs) >= 0; } /** A template alias useful for defining proxy iterators. \see `iterator_interface`. */ template< typename Derived, typename IteratorConcept, typename ValueType, typename Reference = ValueType, typename DifferenceType = std::ptrdiff_t> using proxy_iterator_interface = iterator_interface< Derived, IteratorConcept, ValueType, Reference, proxy_arrow_result, DifferenceType>; }}} #if 201703L < __cplusplus && defined(__cpp_lib_ranges) namespace boost { namespace stl_interfaces { namespace v2 { namespace detail { template struct iter_concept; template requires requires { typename std::iterator_traits::iterator_concept; } struct iter_concept { using type = typename std::iterator_traits::iterator_concept; }; template requires( !requires { typename std::iterator_traits::iterator_concept; } && requires { typename std::iterator_traits::iterator_category; }) struct iter_concept { using type = typename std::iterator_traits::iterator_category; }; template requires( !requires { typename std::iterator_traits::iterator_concept; } && !requires { typename std::iterator_traits::iterator_category; }) struct iter_concept { using type = std::random_access_iterator_tag; }; template struct iter_concept {}; template using iter_concept_t = typename iter_concept::type; }}}} #endif #ifdef BOOST_STL_INTERFACES_DOXYGEN /** `static_asserts` that type `type` models concept `concept_name`. This is useful for checking that an iterator, view, etc. that you write using one of the *`_interface` templates models the right C++ concept. For example: `BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(my_iter, std::input_iterator)`. \note This macro expands to nothing when `__cpp_lib_concepts` is not defined. */ #define BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(type, concept_name) /** `static_asserts` that the types of all typedefs in `std::iterator_traits` match the remaining macro parameters. This is useful for checking that an iterator you write using `iterator_interface` has the correct iterator traits. For example: `BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(my_iter, std::input_iterator_tag, std::input_iterator_tag, int, int &, int *, std::ptrdiff_t)`. \note This macro ignores the `concept` parameter when `__cpp_lib_concepts` is not defined. */ #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( \ iter, category, concept, value_type, reference, pointer, difference_type) #else #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_CONCEPT_IMPL( \ type, concept_name) \ static_assert(concept_name, ""); #define BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(iter, concept_name) #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \ iter, category, value_t, ref, ptr, diff_t) \ static_assert( \ std::is_same< \ typename std::iterator_traits::iterator_category, \ category>::value, \ ""); \ static_assert( \ std::is_same< \ typename std::iterator_traits::value_type, \ value_t>::value, \ ""); \ static_assert( \ std::is_same::reference, ref>:: \ value, \ ""); \ static_assert( \ std::is_same::pointer, ptr>:: \ value, \ ""); \ static_assert( \ std::is_same< \ typename std::iterator_traits::difference_type, \ diff_t>::value, \ ""); #if 201703L < __cplusplus && defined(__cpp_lib_ranges) #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( \ iter, category, concept, value_type, reference, pointer, difference_type) \ static_assert( \ std::is_same_v< \ boost::stl_interfaces::v2::detail::iter_concept_t, \ concept>, \ ""); \ BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \ iter, category, value_type, reference, pointer, difference_type) #else #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( \ iter, category, concept, value_type, reference, pointer, difference_type) \ BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \ iter, category, value_type, reference, pointer, difference_type) #endif #endif #endif