1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_CONTAINERS_CHECKED_ITERATORS_H_ 6 #define BASE_CONTAINERS_CHECKED_ITERATORS_H_ 7 8 #include <concepts> 9 #include <iterator> 10 #include <memory> 11 #include <type_traits> 12 13 #include "base/check_op.h" 14 #include "base/containers/util.h" 15 #include "base/memory/raw_ptr_exclusion.h" 16 #include "build/build_config.h" 17 18 namespace base { 19 20 template <typename T> 21 class CheckedContiguousIterator { 22 public: 23 using difference_type = std::ptrdiff_t; 24 using value_type = std::remove_cv_t<T>; 25 using pointer = T*; 26 using reference = T&; 27 using iterator_category = std::contiguous_iterator_tag; 28 using iterator_concept = std::contiguous_iterator_tag; 29 30 // Required for converting constructor below. 31 template <typename U> 32 friend class CheckedContiguousIterator; 33 34 // Required to be able to get to the underlying pointer without triggering 35 // CHECK failures. 36 template <typename Ptr> 37 friend struct std::pointer_traits; 38 39 constexpr CheckedContiguousIterator() = default; 40 CheckedContiguousIterator(T * start,const T * end)41 constexpr CheckedContiguousIterator(T* start, const T* end) 42 : CheckedContiguousIterator(start, start, end) {} 43 CheckedContiguousIterator(const T * start,T * current,const T * end)44 constexpr CheckedContiguousIterator(const T* start, T* current, const T* end) 45 : start_(start), current_(current), end_(end) { 46 CHECK_LE(start, current); 47 CHECK_LE(current, end); 48 } 49 50 constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) = 51 default; 52 53 // Converting constructor allowing conversions like CCI<T> to CCI<const T>, 54 // but disallowing CCI<const T> to CCI<T> or CCI<Derived> to CCI<Base>, which 55 // are unsafe. Furthermore, this is the same condition as used by the 56 // converting constructors of std::span<T> and std::unique_ptr<T[]>. 57 // See https://wg21.link/n4042 for details. 58 template <typename U> CheckedContiguousIterator(const CheckedContiguousIterator<U> & other)59 constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other) 60 requires(std::convertible_to<U (*)[], T (*)[]>) 61 : start_(other.start_), current_(other.current_), end_(other.end_) { 62 // We explicitly don't delegate to the 3-argument constructor here. Its 63 // CHECKs would be redundant, since we expect |other| to maintain its own 64 // invariant. However, DCHECKs never hurt anybody. Presumably. 65 DCHECK_LE(other.start_, other.current_); 66 DCHECK_LE(other.current_, other.end_); 67 } 68 69 ~CheckedContiguousIterator() = default; 70 71 constexpr CheckedContiguousIterator& operator=( 72 const CheckedContiguousIterator& other) = default; 73 74 friend constexpr bool operator==(const CheckedContiguousIterator& lhs, 75 const CheckedContiguousIterator& rhs) { 76 lhs.CheckComparable(rhs); 77 return lhs.current_ == rhs.current_; 78 } 79 80 friend constexpr auto operator<=>(const CheckedContiguousIterator& lhs, 81 const CheckedContiguousIterator& rhs) { 82 lhs.CheckComparable(rhs); 83 return lhs.current_ <=> rhs.current_; 84 } 85 86 constexpr CheckedContiguousIterator& operator++() { 87 CHECK_NE(current_, end_); 88 ++current_; 89 return *this; 90 } 91 92 constexpr CheckedContiguousIterator operator++(int) { 93 CheckedContiguousIterator old = *this; 94 ++*this; 95 return old; 96 } 97 98 constexpr CheckedContiguousIterator& operator--() { 99 CHECK_NE(current_, start_); 100 --current_; 101 return *this; 102 } 103 104 constexpr CheckedContiguousIterator operator--(int) { 105 CheckedContiguousIterator old = *this; 106 --*this; 107 return old; 108 } 109 110 constexpr CheckedContiguousIterator& operator+=(difference_type rhs) { 111 if (rhs > 0) { 112 CHECK_LE(rhs, end_ - current_); 113 } else { 114 CHECK_LE(-rhs, current_ - start_); 115 } 116 current_ += rhs; 117 return *this; 118 } 119 120 constexpr CheckedContiguousIterator operator+(difference_type rhs) const { 121 CheckedContiguousIterator it = *this; 122 it += rhs; 123 return it; 124 } 125 126 constexpr friend CheckedContiguousIterator operator+( 127 difference_type lhs, 128 const CheckedContiguousIterator& rhs) { 129 return rhs + lhs; 130 } 131 132 constexpr CheckedContiguousIterator& operator-=(difference_type rhs) { 133 if (rhs < 0) { 134 CHECK_LE(-rhs, end_ - current_); 135 } else { 136 CHECK_LE(rhs, current_ - start_); 137 } 138 current_ -= rhs; 139 return *this; 140 } 141 142 constexpr CheckedContiguousIterator operator-(difference_type rhs) const { 143 CheckedContiguousIterator it = *this; 144 it -= rhs; 145 return it; 146 } 147 148 constexpr friend difference_type operator-( 149 const CheckedContiguousIterator& lhs, 150 const CheckedContiguousIterator& rhs) { 151 lhs.CheckComparable(rhs); 152 return lhs.current_ - rhs.current_; 153 } 154 155 constexpr reference operator*() const { 156 CHECK_NE(current_, end_); 157 return *current_; 158 } 159 160 constexpr pointer operator->() const { 161 CHECK_NE(current_, end_); 162 return current_; 163 } 164 165 constexpr reference operator[](difference_type rhs) const { 166 CHECK_GE(rhs, 0); 167 CHECK_LT(rhs, end_ - current_); 168 return current_[rhs]; 169 } 170 IsRangeMoveSafe(const CheckedContiguousIterator & from_begin,const CheckedContiguousIterator & from_end,const CheckedContiguousIterator & to)171 [[nodiscard]] static bool IsRangeMoveSafe( 172 const CheckedContiguousIterator& from_begin, 173 const CheckedContiguousIterator& from_end, 174 const CheckedContiguousIterator& to) { 175 if (from_end < from_begin) 176 return false; 177 const auto from_begin_uintptr = get_uintptr(from_begin.current_); 178 const auto from_end_uintptr = get_uintptr(from_end.current_); 179 const auto to_begin_uintptr = get_uintptr(to.current_); 180 const auto to_end_uintptr = 181 get_uintptr((to + std::distance(from_begin, from_end)).current_); 182 183 return to_begin_uintptr >= from_end_uintptr || 184 to_end_uintptr <= from_begin_uintptr; 185 } 186 187 private: CheckComparable(const CheckedContiguousIterator & other)188 constexpr void CheckComparable(const CheckedContiguousIterator& other) const { 189 CHECK_EQ(start_, other.start_); 190 CHECK_EQ(end_, other.end_); 191 } 192 193 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 194 // #union, #constexpr-ctor-field-initializer 195 RAW_PTR_EXCLUSION const T* start_ = nullptr; 196 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 197 // #union, #constexpr-ctor-field-initializer 198 RAW_PTR_EXCLUSION T* current_ = nullptr; 199 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 200 // #union, #constexpr-ctor-field-initializer 201 RAW_PTR_EXCLUSION const T* end_ = nullptr; 202 }; 203 204 template <typename T> 205 using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>; 206 207 } // namespace base 208 209 // Specialize std::pointer_traits so that we can obtain the underlying raw 210 // pointer without resulting in CHECK failures. The important bit is the 211 // `to_address(pointer)` overload, which is the standard blessed way to 212 // customize `std::to_address(pointer)` in C++20 [1]. 213 // 214 // [1] https://wg21.link/pointer.traits.optmem 215 216 template <typename T> 217 struct std::pointer_traits<::base::CheckedContiguousIterator<T>> { 218 using pointer = ::base::CheckedContiguousIterator<T>; 219 using element_type = T; 220 using difference_type = ptrdiff_t; 221 222 template <typename U> 223 using rebind = ::base::CheckedContiguousIterator<U>; 224 225 static constexpr pointer pointer_to(element_type& r) noexcept { 226 return pointer(&r, &r); 227 } 228 229 static constexpr element_type* to_address(pointer p) noexcept { 230 return p.current_; 231 } 232 }; 233 234 #endif // BASE_CONTAINERS_CHECKED_ITERATORS_H_ 235