xref: /freebsd-src/contrib/llvm-project/libcxx/include/__iterator/bounded_iter.h (revision 36b606ae6aa4b24061096ba18582e0a08ccd5dba)
181ad6265SDimitry Andric // -*- C++ -*-
281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
381ad6265SDimitry Andric //
481ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
581ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
681ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
781ad6265SDimitry Andric //
881ad6265SDimitry Andric //===----------------------------------------------------------------------===//
981ad6265SDimitry Andric 
1081ad6265SDimitry Andric #ifndef _LIBCPP___ITERATOR_BOUNDED_ITER_H
1181ad6265SDimitry Andric #define _LIBCPP___ITERATOR_BOUNDED_ITER_H
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include <__assert>
14*36b606aeSDimitry Andric #include <__compare/ordering.h>
15*36b606aeSDimitry Andric #include <__compare/three_way_comparable.h>
1681ad6265SDimitry Andric #include <__config>
1781ad6265SDimitry Andric #include <__iterator/iterator_traits.h>
1881ad6265SDimitry Andric #include <__memory/pointer_traits.h>
19bdd1243dSDimitry Andric #include <__type_traits/enable_if.h>
20bdd1243dSDimitry Andric #include <__type_traits/integral_constant.h>
21bdd1243dSDimitry Andric #include <__type_traits/is_convertible.h>
2281ad6265SDimitry Andric #include <__utility/move.h>
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2581ad6265SDimitry Andric #  pragma GCC system_header
2681ad6265SDimitry Andric #endif
2781ad6265SDimitry Andric 
2806c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS
2906c3fb27SDimitry Andric #include <__undef_macros>
3006c3fb27SDimitry Andric 
3181ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric // Iterator wrapper that carries the valid range it is allowed to access.
3481ad6265SDimitry Andric //
3581ad6265SDimitry Andric // This is a simple iterator wrapper for contiguous iterators that points
360fca6ea1SDimitry Andric // within a [begin, end] range and carries these bounds with it. The iterator
370fca6ea1SDimitry Andric // ensures that it is pointing within [begin, end) range when it is
380fca6ea1SDimitry Andric // dereferenced. It also ensures that it is never iterated outside of
390fca6ea1SDimitry Andric // [begin, end]. This is important for two reasons:
4081ad6265SDimitry Andric //
410fca6ea1SDimitry Andric // 1. It allows `operator*` and `operator++` bounds checks to be `iter != end`.
420fca6ea1SDimitry Andric //    This is both less for the optimizer to prove, and aligns with how callers
430fca6ea1SDimitry Andric //    typically use iterators.
440fca6ea1SDimitry Andric //
450fca6ea1SDimitry Andric // 2. Advancing an iterator out of bounds is undefined behavior (see the table
460fca6ea1SDimitry Andric //    in [input.iterators]). In particular, when the underlying iterator is a
470fca6ea1SDimitry Andric //    pointer, it is undefined at the language level (see [expr.add]). If
480fca6ea1SDimitry Andric //    bounded iterators exhibited this undefined behavior, we risk compiler
490fca6ea1SDimitry Andric //    optimizations deleting non-redundant bounds checks.
5006c3fb27SDimitry Andric template <class _Iterator, class = __enable_if_t< __libcpp_is_contiguous_iterator<_Iterator>::value > >
5181ad6265SDimitry Andric struct __bounded_iter {
5281ad6265SDimitry Andric   using value_type        = typename iterator_traits<_Iterator>::value_type;
5381ad6265SDimitry Andric   using difference_type   = typename iterator_traits<_Iterator>::difference_type;
5481ad6265SDimitry Andric   using pointer           = typename iterator_traits<_Iterator>::pointer;
5581ad6265SDimitry Andric   using reference         = typename iterator_traits<_Iterator>::reference;
5681ad6265SDimitry Andric   using iterator_category = typename iterator_traits<_Iterator>::iterator_category;
5706c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
5881ad6265SDimitry Andric   using iterator_concept = contiguous_iterator_tag;
5981ad6265SDimitry Andric #endif
6081ad6265SDimitry Andric 
6181ad6265SDimitry Andric   // Create a singular iterator.
6281ad6265SDimitry Andric   //
630fca6ea1SDimitry Andric   // Such an iterator points past the end of an empty span, so it is not dereferenceable.
640fca6ea1SDimitry Andric   // Observing operations like comparison and assignment are valid.
6581ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __bounded_iter() = default;
6681ad6265SDimitry Andric 
6781ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter const&) = default;
6881ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter&&)      = default;
6981ad6265SDimitry Andric 
700fca6ea1SDimitry Andric   template <class _OtherIterator, __enable_if_t< is_convertible<_OtherIterator, _Iterator>::value, int> = 0>
7181ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter(__bounded_iter<_OtherIterator> const& __other) _NOEXCEPT
7281ad6265SDimitry Andric       : __current_(__other.__current_),
7381ad6265SDimitry Andric         __begin_(__other.__begin_),
7481ad6265SDimitry Andric         __end_(__other.__end_) {}
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric   // Assign a bounded iterator to another one, rebinding the bounds of the iterator as well.
7781ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __bounded_iter& operator=(__bounded_iter const&) = default;
7881ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __bounded_iter& operator=(__bounded_iter&&)      = default;
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric private:
8181ad6265SDimitry Andric   // Create an iterator wrapping the given iterator, and whose bounds are described
820fca6ea1SDimitry Andric   // by the provided [begin, end] range.
8381ad6265SDimitry Andric   //
840fca6ea1SDimitry Andric   // The constructor does not check whether the resulting iterator is within its bounds. It is a
850fca6ea1SDimitry Andric   // responsibility of the container to ensure that the given bounds are valid.
8681ad6265SDimitry Andric   //
8781ad6265SDimitry Andric   // Since it is non-standard for iterators to have this constructor, __bounded_iter must
8881ad6265SDimitry Andric   // be created via `std::__make_bounded_iter`.
890fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI
900fca6ea1SDimitry Andric   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __bounded_iter(_Iterator __current, _Iterator __begin, _Iterator __end)
9181ad6265SDimitry Andric       : __current_(__current), __begin_(__begin), __end_(__end) {
920fca6ea1SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(
930fca6ea1SDimitry Andric         __begin <= __current, "__bounded_iter(current, begin, end): current and begin are inconsistent");
940fca6ea1SDimitry Andric     _LIBCPP_ASSERT_INTERNAL(
950fca6ea1SDimitry Andric         __current <= __end, "__bounded_iter(current, begin, end): current and end are inconsistent");
9681ad6265SDimitry Andric   }
9781ad6265SDimitry Andric 
9881ad6265SDimitry Andric   template <class _It>
9981ad6265SDimitry Andric   friend _LIBCPP_CONSTEXPR __bounded_iter<_It> __make_bounded_iter(_It, _It, _It);
10081ad6265SDimitry Andric 
10181ad6265SDimitry Andric public:
10281ad6265SDimitry Andric   // Dereference and indexing operations.
10381ad6265SDimitry Andric   //
1040fca6ea1SDimitry Andric   // These operations check that the iterator is dereferenceable. Since the class invariant is
1050fca6ea1SDimitry Andric   // that the iterator is always within `[begin, end]`, we only need to check it's not pointing to
1060fca6ea1SDimitry Andric   // `end`. This is easier for the optimizer because it aligns with the `iter != container.end()`
1070fca6ea1SDimitry Andric   // checks that typical callers already use (see
1080fca6ea1SDimitry Andric   // https://github.com/llvm/llvm-project/issues/78829).
109bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT {
11006c3fb27SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1110fca6ea1SDimitry Andric         __current_ != __end_, "__bounded_iter::operator*: Attempt to dereference an iterator at the end");
11281ad6265SDimitry Andric     return *__current_;
11381ad6265SDimitry Andric   }
11481ad6265SDimitry Andric 
115bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT {
11606c3fb27SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1170fca6ea1SDimitry Andric         __current_ != __end_, "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
11881ad6265SDimitry Andric     return std::__to_address(__current_);
11981ad6265SDimitry Andric   }
12081ad6265SDimitry Andric 
121bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator[](difference_type __n) const _NOEXCEPT {
12206c3fb27SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1230fca6ea1SDimitry Andric         __n >= __begin_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator past the start");
1240fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1250fca6ea1SDimitry Andric         __n < __end_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator at or past the end");
12681ad6265SDimitry Andric     return __current_[__n];
12781ad6265SDimitry Andric   }
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric   // Arithmetic operations.
13081ad6265SDimitry Andric   //
1310fca6ea1SDimitry Andric   // These operations check that the iterator remains within `[begin, end]`.
132bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator++() _NOEXCEPT {
1330fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1340fca6ea1SDimitry Andric         __current_ != __end_, "__bounded_iter::operator++: Attempt to advance an iterator past the end");
13581ad6265SDimitry Andric     ++__current_;
13681ad6265SDimitry Andric     return *this;
13781ad6265SDimitry Andric   }
138bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter operator++(int) _NOEXCEPT {
13981ad6265SDimitry Andric     __bounded_iter __tmp(*this);
14081ad6265SDimitry Andric     ++*this;
14181ad6265SDimitry Andric     return __tmp;
14281ad6265SDimitry Andric   }
14381ad6265SDimitry Andric 
144bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator--() _NOEXCEPT {
1450fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1460fca6ea1SDimitry Andric         __current_ != __begin_, "__bounded_iter::operator--: Attempt to rewind an iterator past the start");
14781ad6265SDimitry Andric     --__current_;
14881ad6265SDimitry Andric     return *this;
14981ad6265SDimitry Andric   }
150bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter operator--(int) _NOEXCEPT {
15181ad6265SDimitry Andric     __bounded_iter __tmp(*this);
15281ad6265SDimitry Andric     --*this;
15381ad6265SDimitry Andric     return __tmp;
15481ad6265SDimitry Andric   }
15581ad6265SDimitry Andric 
156bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator+=(difference_type __n) _NOEXCEPT {
1570fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1580fca6ea1SDimitry Andric         __n >= __begin_ - __current_, "__bounded_iter::operator+=: Attempt to rewind an iterator past the start");
1590fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1600fca6ea1SDimitry Andric         __n <= __end_ - __current_, "__bounded_iter::operator+=: Attempt to advance an iterator past the end");
16181ad6265SDimitry Andric     __current_ += __n;
16281ad6265SDimitry Andric     return *this;
16381ad6265SDimitry Andric   }
164bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __bounded_iter
16581ad6265SDimitry Andric   operator+(__bounded_iter const& __self, difference_type __n) _NOEXCEPT {
16681ad6265SDimitry Andric     __bounded_iter __tmp(__self);
16781ad6265SDimitry Andric     __tmp += __n;
16881ad6265SDimitry Andric     return __tmp;
16981ad6265SDimitry Andric   }
170bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __bounded_iter
17181ad6265SDimitry Andric   operator+(difference_type __n, __bounded_iter const& __self) _NOEXCEPT {
17281ad6265SDimitry Andric     __bounded_iter __tmp(__self);
17381ad6265SDimitry Andric     __tmp += __n;
17481ad6265SDimitry Andric     return __tmp;
17581ad6265SDimitry Andric   }
17681ad6265SDimitry Andric 
177bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator-=(difference_type __n) _NOEXCEPT {
1780fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1790fca6ea1SDimitry Andric         __n <= __current_ - __begin_, "__bounded_iter::operator-=: Attempt to rewind an iterator past the start");
1800fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
1810fca6ea1SDimitry Andric         __n >= __current_ - __end_, "__bounded_iter::operator-=: Attempt to advance an iterator past the end");
18281ad6265SDimitry Andric     __current_ -= __n;
18381ad6265SDimitry Andric     return *this;
18481ad6265SDimitry Andric   }
185bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __bounded_iter
18681ad6265SDimitry Andric   operator-(__bounded_iter const& __self, difference_type __n) _NOEXCEPT {
18781ad6265SDimitry Andric     __bounded_iter __tmp(__self);
18881ad6265SDimitry Andric     __tmp -= __n;
18981ad6265SDimitry Andric     return __tmp;
19081ad6265SDimitry Andric   }
191bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend difference_type
19281ad6265SDimitry Andric   operator-(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
19381ad6265SDimitry Andric     return __x.__current_ - __y.__current_;
19481ad6265SDimitry Andric   }
19581ad6265SDimitry Andric 
19681ad6265SDimitry Andric   // Comparison operations.
19781ad6265SDimitry Andric   //
19881ad6265SDimitry Andric   // These operations do not check whether the iterators are within their bounds.
19981ad6265SDimitry Andric   // The valid range for each iterator is also not considered as part of the comparison,
20081ad6265SDimitry Andric   // i.e. two iterators pointing to the same location will be considered equal even
20181ad6265SDimitry Andric   // if they have different validity ranges.
20281ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
20381ad6265SDimitry Andric   operator==(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
20481ad6265SDimitry Andric     return __x.__current_ == __y.__current_;
20581ad6265SDimitry Andric   }
206*36b606aeSDimitry Andric 
207*36b606aeSDimitry Andric #if _LIBCPP_STD_VER <= 17
20881ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
20981ad6265SDimitry Andric   operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
21081ad6265SDimitry Andric     return __x.__current_ != __y.__current_;
21181ad6265SDimitry Andric   }
212*36b606aeSDimitry Andric #endif
213*36b606aeSDimitry Andric 
214*36b606aeSDimitry Andric   // TODO(mordante) disable these overloads in the LLVM 20 release.
21581ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
21681ad6265SDimitry Andric   operator<(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
21781ad6265SDimitry Andric     return __x.__current_ < __y.__current_;
21881ad6265SDimitry Andric   }
21981ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
22081ad6265SDimitry Andric   operator>(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
22181ad6265SDimitry Andric     return __x.__current_ > __y.__current_;
22281ad6265SDimitry Andric   }
22381ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
22481ad6265SDimitry Andric   operator<=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
22581ad6265SDimitry Andric     return __x.__current_ <= __y.__current_;
22681ad6265SDimitry Andric   }
22781ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool
22881ad6265SDimitry Andric   operator>=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT {
22981ad6265SDimitry Andric     return __x.__current_ >= __y.__current_;
23081ad6265SDimitry Andric   }
23181ad6265SDimitry Andric 
232*36b606aeSDimitry Andric #if _LIBCPP_STD_VER >= 20
233*36b606aeSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering
234*36b606aeSDimitry Andric   operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept {
235*36b606aeSDimitry Andric     if constexpr (three_way_comparable<_Iterator, strong_ordering>) {
236*36b606aeSDimitry Andric       return __x.__current_ <=> __y.__current_;
237*36b606aeSDimitry Andric     } else {
238*36b606aeSDimitry Andric       if (__x.__current_ < __y.__current_)
239*36b606aeSDimitry Andric         return strong_ordering::less;
240*36b606aeSDimitry Andric 
241*36b606aeSDimitry Andric       if (__x.__current_ == __y.__current_)
242*36b606aeSDimitry Andric         return strong_ordering::equal;
243*36b606aeSDimitry Andric 
244*36b606aeSDimitry Andric       return strong_ordering::greater;
245*36b606aeSDimitry Andric     }
246*36b606aeSDimitry Andric   }
247*36b606aeSDimitry Andric #endif // _LIBCPP_STD_VER >= 20
248*36b606aeSDimitry Andric 
24981ad6265SDimitry Andric private:
25081ad6265SDimitry Andric   template <class>
25181ad6265SDimitry Andric   friend struct pointer_traits;
2520fca6ea1SDimitry Andric   template <class, class>
2530fca6ea1SDimitry Andric   friend struct __bounded_iter;
25481ad6265SDimitry Andric   _Iterator __current_;       // current iterator
2550fca6ea1SDimitry Andric   _Iterator __begin_, __end_; // valid range represented as [begin, end]
25681ad6265SDimitry Andric };
25781ad6265SDimitry Andric 
25881ad6265SDimitry Andric template <class _It>
25981ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter<_It> __make_bounded_iter(_It __it, _It __begin, _It __end) {
26081ad6265SDimitry Andric   return __bounded_iter<_It>(std::move(__it), std::move(__begin), std::move(__end));
26181ad6265SDimitry Andric }
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric #if _LIBCPP_STD_VER <= 17
26481ad6265SDimitry Andric template <class _Iterator>
26506c3fb27SDimitry Andric struct __libcpp_is_contiguous_iterator<__bounded_iter<_Iterator> > : true_type {};
26681ad6265SDimitry Andric #endif
26781ad6265SDimitry Andric 
26881ad6265SDimitry Andric template <class _Iterator>
26981ad6265SDimitry Andric struct pointer_traits<__bounded_iter<_Iterator> > {
27081ad6265SDimitry Andric   using pointer         = __bounded_iter<_Iterator>;
27181ad6265SDimitry Andric   using element_type    = typename pointer_traits<_Iterator>::element_type;
27281ad6265SDimitry Andric   using difference_type = typename pointer_traits<_Iterator>::difference_type;
27381ad6265SDimitry Andric 
27481ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static element_type* to_address(pointer __it) _NOEXCEPT {
27581ad6265SDimitry Andric     return std::__to_address(__it.__current_);
27681ad6265SDimitry Andric   }
27781ad6265SDimitry Andric };
27881ad6265SDimitry Andric 
27981ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD
28081ad6265SDimitry Andric 
28106c3fb27SDimitry Andric _LIBCPP_POP_MACROS
28206c3fb27SDimitry Andric 
28381ad6265SDimitry Andric #endif // _LIBCPP___ITERATOR_BOUNDED_ITER_H
284