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