1 // Copyright (C) 2019 T. Zachary Laine
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_STL_INTERFACES_ITERATOR_INTERFACE_HPP
7 #define BOOST_STL_INTERFACES_ITERATOR_INTERFACE_HPP
12 #include <type_traits>
13 #if defined(__cpp_lib_three_way_comparison)
18 namespace boost
{ namespace stl_interfaces
{
20 /** A type for granting access to the private members of an iterator
21 derived from `iterator_interface`. */
24 #ifndef BOOST_STL_INTERFACES_DOXYGEN
27 static constexpr auto base(D
& d
) noexcept
28 -> decltype(d
.base_reference())
30 return d
.base_reference();
33 static constexpr auto base(D
const & d
) noexcept
34 -> decltype(d
.base_reference())
36 return d
.base_reference();
42 /** The return type of `operator->()` in a proxy iterator.
44 This template is used as the default `Pointer` template parameter in
45 the `proxy_iterator_interface` template alias. Note that the use of
46 this template implies a copy or move of the underlying object of type
49 struct proxy_arrow_result
51 constexpr proxy_arrow_result(T
const & value
) noexcept(
55 constexpr proxy_arrow_result(T
&& value
) noexcept(
56 noexcept(T(std::move(value
)))) :
57 value_(std::move(value
))
60 constexpr T
const * operator->() const noexcept
{ return &value_
; }
61 constexpr T
* operator->() noexcept
{ return &value_
; }
68 template<typename Pointer
, typename T
>
71 std::enable_if_t
<std::is_pointer
<Pointer
>::value
, int> = 0)
72 -> decltype(std::addressof(value
))
74 return std::addressof(value
);
77 template<typename Pointer
, typename T
>
80 std::enable_if_t
<!std::is_pointer
<Pointer
>::value
, int> = 0)
82 return Pointer(std::forward
<T
>(value
));
85 template<typename IteratorConcept
>
86 struct concept_category
88 using type
= IteratorConcept
;
90 template<typename IteratorConcept
>
91 using concept_category_t
=
92 typename concept_category
<IteratorConcept
>::type
;
94 template<typename Pointer
, typename IteratorConcept
>
99 template<typename Pointer
>
100 struct pointer
<Pointer
, std::output_iterator_tag
>
104 template<typename Pointer
, typename IteratorConcept
>
105 using pointer_t
= typename pointer
<Pointer
, IteratorConcept
>::type
;
107 template<typename T
, typename U
>
108 using interoperable
= std::integral_constant
<
110 (std::is_convertible
<T
, U
>::value
||
111 std::is_convertible
<U
, T
>::value
)>;
113 template<typename T
, typename U
>
115 std::conditional_t
<std::is_convertible
<T
, U
>::value
, U
, T
>;
118 using use_base
= decltype(access::base(std::declval
<T
&>()));
120 template<typename
... T
>
125 template<class...> class Template
,
127 struct detector
: std::false_type
131 template<template<class...> class Template
, typename
... Args
>
132 struct detector
<void_t
<Template
<Args
...>>, Template
, Args
...>
140 bool UseBase
= detector
<void, use_base
, T
>::value
>
143 static constexpr auto call(T lhs
, U rhs
)
145 return static_cast<common_t
<T
, U
>>(lhs
).derived() ==
146 static_cast<common_t
<T
, U
>>(rhs
).derived();
149 template<typename T
, typename U
>
150 struct common_eq
<T
, U
, true>
152 static constexpr auto call(T lhs
, U rhs
)
154 return access::base(lhs
) == access::base(rhs
);
158 template<typename T
, typename U
>
159 constexpr auto common_diff(T lhs
, U rhs
) noexcept(noexcept(
160 static_cast<common_t
<T
, U
>>(lhs
) -
161 static_cast<common_t
<T
, U
>>(rhs
)))
163 static_cast<common_t
<T
, U
>>(lhs
) -
164 static_cast<common_t
<T
, U
>>(rhs
))
166 return static_cast<common_t
<T
, U
>>(lhs
) -
167 static_cast<common_t
<T
, U
>>(rhs
);
173 namespace boost
{ namespace stl_interfaces
{ inline namespace v1
{
175 /** A CRTP template that one may derive from to make defining iterators
178 The template parameter `D` for `iterator_interface` may be an
179 incomplete type. Before any member of the resulting specialization of
180 `iterator_interface` other than special member functions is
181 referenced, `D` shall be complete, and model
182 `std::derived_from<iterator_interface<D>>`. */
185 typename IteratorConcept
,
187 typename Reference
= ValueType
&,
188 typename Pointer
= ValueType
*,
189 typename DifferenceType
= std::ptrdiff_t
190 #ifndef BOOST_STL_INTERFACES_DOXYGEN
192 typename E
= std::enable_if_t
<
193 std::is_class
<Derived
>::value
&&
194 std::is_same
<Derived
, std::remove_cv_t
<Derived
>>::value
>
197 struct iterator_interface
;
200 template<typename Iterator
, typename
= void>
201 struct ra_iter
: std::false_type
204 template<typename Iterator
>
205 struct ra_iter
<Iterator
, void_t
<typename
Iterator::iterator_concept
>>
206 : std::integral_constant
<
209 std::random_access_iterator_tag
,
210 typename
Iterator::iterator_concept
>::value
>
214 template<typename Iterator
, typename DifferenceType
, typename
= void>
215 struct plus_eq
: std::false_type
218 template<typename Iterator
, typename DifferenceType
>
223 std::declval
<Iterator
&>() += std::declval
<DifferenceType
>())>>
230 typename IteratorConcept
,
234 typename DifferenceType
>
235 void derived_iterator(iterator_interface
<
241 DifferenceType
> const &);
246 typename IteratorConcept
,
250 typename DifferenceType
251 #ifndef BOOST_STL_INTERFACES_DOXYGEN
256 struct iterator_interface
258 #ifndef BOOST_STL_INTERFACES_DOXYGEN
260 constexpr Derived
& derived() noexcept
262 return static_cast<Derived
&>(*this);
264 constexpr Derived
const & derived() const noexcept
266 return static_cast<Derived
const &>(*this);
269 template<typename T
, typename U
, bool UseBase
>
270 friend struct detail::common_eq
;
274 using iterator_concept
= IteratorConcept
;
275 using iterator_category
= detail::concept_category_t
<iterator_concept
>;
276 using value_type
= std::remove_const_t
<ValueType
>;
277 using reference
= Reference
;
278 using pointer
= detail::pointer_t
<Pointer
, iterator_concept
>;
279 using difference_type
= DifferenceType
;
281 template<typename D
= Derived
>
282 constexpr auto operator*() const
283 noexcept(noexcept(*access::base(std::declval
<D
const &>())))
284 -> decltype(*access::base(std::declval
<D
const &>()))
286 return *access::base(derived());
289 template<typename D
= Derived
>
290 constexpr auto operator-> () const noexcept(
291 noexcept(detail::make_pointer
<pointer
>(*std::declval
<D
const &>())))
293 detail::make_pointer
<pointer
>(*std::declval
<D
const &>()))
295 return detail::make_pointer
<pointer
>(*derived());
298 template<typename D
= Derived
>
299 constexpr auto operator[](difference_type i
) const noexcept(noexcept(
300 D(std::declval
<D
const &>()),
301 std::declval
<D
&>() += i
,
302 *std::declval
<D
&>()))
303 -> decltype(std::declval
<D
&>() += i
, *std::declval
<D
&>())
305 D retval
= derived();
311 typename D
= Derived
,
313 std::enable_if_t
<!v1_dtl::plus_eq
<D
, difference_type
>::value
>>
315 operator++() noexcept(noexcept(++access::base(std::declval
<D
&>())))
316 -> decltype(++access::base(std::declval
<D
&>()))
318 return ++access::base(derived());
321 template<typename D
= Derived
>
322 constexpr auto operator++() noexcept(
323 noexcept(std::declval
<D
&>() += difference_type(1)))
325 std::declval
<D
&>() += difference_type(1), std::declval
<D
&>())
327 derived() += difference_type(1);
330 template<typename D
= Derived
>
331 constexpr auto operator++(int)noexcept(
332 noexcept(D(std::declval
<D
&>()), ++std::declval
<D
&>()))
333 -> std::remove_reference_t
<decltype(
334 D(std::declval
<D
&>()),
335 ++std::declval
<D
&>(),
336 std::declval
<D
&>())>
338 D retval
= derived();
343 template<typename D
= Derived
>
344 constexpr auto operator+=(difference_type n
) noexcept(
345 noexcept(access::base(std::declval
<D
&>()) += n
))
346 -> decltype(access::base(std::declval
<D
&>()) += n
)
348 return access::base(derived()) += n
;
351 template<typename D
= Derived
>
352 constexpr auto operator+(difference_type i
) const
353 noexcept(noexcept(D(std::declval
<D
&>()), std::declval
<D
&>() += i
))
354 -> std::remove_reference_t
<decltype(
355 D(std::declval
<D
&>()),
356 std::declval
<D
&>() += i
,
357 std::declval
<D
&>())>
359 D retval
= derived();
363 friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR Derived
364 operator+(difference_type i
, Derived it
) noexcept
370 typename D
= Derived
,
372 std::enable_if_t
<!v1_dtl::plus_eq
<D
, difference_type
>::value
>>
374 operator--() noexcept(noexcept(--access::base(std::declval
<D
&>())))
375 -> decltype(--access::base(std::declval
<D
&>()))
377 return --access::base(derived());
380 template<typename D
= Derived
>
381 constexpr auto operator--() noexcept(noexcept(
382 D(std::declval
<D
&>()), std::declval
<D
&>() += -difference_type(1)))
384 std::declval
<D
&>() += -difference_type(1), std::declval
<D
&>())
386 derived() += -difference_type(1);
389 template<typename D
= Derived
>
390 constexpr auto operator--(int)noexcept(
391 noexcept(D(std::declval
<D
&>()), --std::declval
<D
&>()))
392 -> std::remove_reference_t
<decltype(
393 D(std::declval
<D
&>()),
394 --std::declval
<D
&>(),
395 std::declval
<D
&>())>
397 D retval
= derived();
402 template<typename D
= Derived
>
403 constexpr D
& operator-=(difference_type i
) noexcept
409 template<typename D
= Derived
>
410 constexpr auto operator-(D other
) const noexcept(noexcept(
411 access::base(std::declval
<D
const &>()) - access::base(other
)))
413 access::base(std::declval
<D
const &>()) - access::base(other
))
415 return access::base(derived()) - access::base(other
);
418 friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR Derived
419 operator-(Derived it
, difference_type i
) noexcept
427 /** Implementation of `operator==()`, implemented in terms of the iterator
428 underlying IteratorInterface, for all iterators derived from
429 `iterator_interface`, except those with an iterator category derived
430 from `std::random_access_iterator_tag`. */
432 typename IteratorInterface1
,
433 typename IteratorInterface2
,
435 std::enable_if_t
<!v1_dtl::ra_iter
<IteratorInterface1
>::value
>>
437 operator==(IteratorInterface1 lhs
, IteratorInterface2 rhs
) noexcept
439 access::base(std::declval
<IteratorInterface1
&>()) ==
440 access::base(std::declval
<IteratorInterface2
&>()))
442 return access::base(lhs
) == access::base(rhs
);
445 /** Implementation of `operator==()` for all iterators derived from
446 `iterator_interface` that have an iterator category derived from
447 `std::random_access_iterator_tag`. */
449 typename IteratorInterface1
,
450 typename IteratorInterface2
,
452 std::enable_if_t
<v1_dtl::ra_iter
<IteratorInterface1
>::value
>>
454 operator==(IteratorInterface1 lhs
, IteratorInterface2 rhs
) noexcept(
455 noexcept(detail::common_diff(lhs
, rhs
)))
457 v1_dtl::derived_iterator(lhs
), detail::common_diff(lhs
, rhs
) == 0)
459 return detail::common_diff(lhs
, rhs
) == 0;
462 /** Implementation of `operator!=()` for all iterators derived from
463 `iterator_interface`. */
464 template<typename IteratorInterface1
, typename IteratorInterface2
>
465 constexpr auto operator!=(
466 IteratorInterface1 lhs
,
467 IteratorInterface2 rhs
) noexcept(noexcept(!(lhs
== rhs
)))
468 -> decltype(v1_dtl::derived_iterator(lhs
), !(lhs
== rhs
))
470 return !(lhs
== rhs
);
473 /** Implementation of `operator<()` for all iterators derived from
474 `iterator_interface` that have an iterator category derived from
475 `std::random_access_iterator_tag`. */
476 template<typename IteratorInterface1
, typename IteratorInterface2
>
478 operator<(IteratorInterface1 lhs
, IteratorInterface2 rhs
) noexcept(
479 noexcept(detail::common_diff(lhs
, rhs
)))
481 v1_dtl::derived_iterator(lhs
), detail::common_diff(lhs
, rhs
) < 0)
483 return detail::common_diff(lhs
, rhs
) < 0;
486 /** Implementation of `operator<=()` for all iterators derived from
487 `iterator_interface` that have an iterator category derived from
488 `std::random_access_iterator_tag`. */
489 template<typename IteratorInterface1
, typename IteratorInterface2
>
491 operator<=(IteratorInterface1 lhs
, IteratorInterface2 rhs
) noexcept(
492 noexcept(detail::common_diff(lhs
, rhs
)))
494 v1_dtl::derived_iterator(lhs
), detail::common_diff(lhs
, rhs
) <= 0)
496 return detail::common_diff(lhs
, rhs
) <= 0;
499 /** Implementation of `operator>()` for all iterators derived from
500 `iterator_interface` that have an iterator category derived from
501 `std::random_access_iterator_tag`. */
502 template<typename IteratorInterface1
, typename IteratorInterface2
>
504 operator>(IteratorInterface1 lhs
, IteratorInterface2 rhs
) noexcept(
505 noexcept(detail::common_diff(lhs
, rhs
)))
507 v1_dtl::derived_iterator(lhs
), detail::common_diff(lhs
, rhs
) > 0)
509 return detail::common_diff(lhs
, rhs
) > 0;
512 /** Implementation of `operator>=()` for all iterators derived from
513 `iterator_interface` that have an iterator category derived from
514 `std::random_access_iterator_tag`. */
515 template<typename IteratorInterface1
, typename IteratorInterface2
>
517 operator>=(IteratorInterface1 lhs
, IteratorInterface2 rhs
) noexcept(
518 noexcept(detail::common_diff(lhs
, rhs
)))
520 v1_dtl::derived_iterator(lhs
), detail::common_diff(lhs
, rhs
) >= 0)
522 return detail::common_diff(lhs
, rhs
) >= 0;
526 /** A template alias useful for defining proxy iterators. \see
527 `iterator_interface`. */
530 typename IteratorConcept
,
532 typename Reference
= ValueType
,
533 typename DifferenceType
= std::ptrdiff_t>
534 using proxy_iterator_interface
= iterator_interface
<
539 proxy_arrow_result
<Reference
>,
544 #ifdef BOOST_STL_INTERFACES_DOXYGEN
546 /** `static_asserts` that type `type` models concept `concept_name`. This is
547 useful for checking that an iterator, view, etc. that you write using one
548 of the *`_interface` templates models the right C++ concept.
550 For example: `BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(my_iter,
551 std::input_iterator)`.
553 \note This macro expands to nothing when `__cpp_lib_concepts` is not
555 #define BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(type, concept_name)
557 /** `static_asserts` that the types of all typedefs in
558 `std::iterator_traits<iter>` match the remaining macro parameters. This
559 is useful for checking that an iterator you write using
560 `iterator_interface` has the correct iterator traits.
562 For example: `BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(my_iter,
563 std::input_iterator_tag, std::input_iterator_tag, int, int &, int *, std::ptrdiff_t)`.
565 \note This macro ignores the `concept` parameter when `__cpp_lib_concepts`
567 #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( \
568 iter, category, concept, value_type, reference, pointer, difference_type)
572 #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_CONCEPT_IMPL( \
573 type, concept_name) \
574 static_assert(concept_name<type>, "");
576 #define BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(iter, concept_name)
578 #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \
579 iter, category, value_t, ref, ptr, diff_t) \
582 typename std::iterator_traits<iter>::iterator_category, \
587 typename std::iterator_traits<iter>::value_type, \
591 std::is_same<typename std::iterator_traits<iter>::reference, ref>:: \
595 std::is_same<typename std::iterator_traits<iter>::pointer, ptr>:: \
600 typename std::iterator_traits<iter>::difference_type, \
604 #if 201703L < __cplusplus && defined(__cpp_lib_ranges)
605 #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( \
606 iter, category, concept, value_type, reference, pointer, difference_type) \
609 typename std::iterator_traits<iter>::iterator_concept, \
612 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \
613 iter, category, value_type, reference, pointer, difference_type)
615 #define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( \
616 iter, category, concept, value_type, reference, pointer, difference_type) \
617 BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \
618 iter, category, value_type, reference, pointer, difference_type)