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 <iterator> 9 #include <memory> 10 #include <type_traits> 11 12 #include "base/check_op.h" 13 #include "base/containers/util.h" 14 #include "base/memory/raw_ptr_exclusion.h" 15 #include "build/build_config.h" 16 17 namespace base { 18 19 template <typename T> 20 class CheckedContiguousIterator { 21 public: 22 using difference_type = std::ptrdiff_t; 23 using value_type = std::remove_cv_t<T>; 24 using pointer = T*; 25 using reference = T&; 26 using iterator_category = std::random_access_iterator_tag; 27 28 // Required for converting constructor below. 29 template <typename U> 30 friend class CheckedContiguousIterator; 31 32 // Required for certain libc++ algorithm optimizations that are not available 33 // for NaCl. 34 #if defined(_LIBCPP_VERSION) && !BUILDFLAG(IS_NACL) 35 template <typename Ptr> 36 friend struct std::pointer_traits; 37 #endif 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 < 59 typename U, 60 std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr> CheckedContiguousIterator(const CheckedContiguousIterator<U> & other)61 constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other) 62 : start_(other.start_), current_(other.current_), end_(other.end_) { 63 // We explicitly don't delegate to the 3-argument constructor here. Its 64 // CHECKs would be redundant, since we expect |other| to maintain its own 65 // invariant. However, DCHECKs never hurt anybody. Presumably. 66 DCHECK_LE(other.start_, other.current_); 67 DCHECK_LE(other.current_, other.end_); 68 } 69 70 ~CheckedContiguousIterator() = default; 71 72 constexpr CheckedContiguousIterator& operator=( 73 const CheckedContiguousIterator& other) = default; 74 75 friend constexpr bool operator==(const CheckedContiguousIterator& lhs, 76 const CheckedContiguousIterator& rhs) { 77 lhs.CheckComparable(rhs); 78 return lhs.current_ == rhs.current_; 79 } 80 81 friend constexpr bool operator!=(const CheckedContiguousIterator& lhs, 82 const CheckedContiguousIterator& rhs) { 83 lhs.CheckComparable(rhs); 84 return lhs.current_ != rhs.current_; 85 } 86 87 friend constexpr bool operator<(const CheckedContiguousIterator& lhs, 88 const CheckedContiguousIterator& rhs) { 89 lhs.CheckComparable(rhs); 90 return lhs.current_ < rhs.current_; 91 } 92 93 friend constexpr bool operator<=(const CheckedContiguousIterator& lhs, 94 const CheckedContiguousIterator& rhs) { 95 lhs.CheckComparable(rhs); 96 return lhs.current_ <= rhs.current_; 97 } 98 friend constexpr bool operator>(const CheckedContiguousIterator& lhs, 99 const CheckedContiguousIterator& rhs) { 100 lhs.CheckComparable(rhs); 101 return lhs.current_ > rhs.current_; 102 } 103 104 friend constexpr bool operator>=(const CheckedContiguousIterator& lhs, 105 const CheckedContiguousIterator& rhs) { 106 lhs.CheckComparable(rhs); 107 return lhs.current_ >= rhs.current_; 108 } 109 110 constexpr CheckedContiguousIterator& operator++() { 111 CHECK_NE(current_, end_); 112 ++current_; 113 return *this; 114 } 115 116 constexpr CheckedContiguousIterator operator++(int) { 117 CheckedContiguousIterator old = *this; 118 ++*this; 119 return old; 120 } 121 122 constexpr CheckedContiguousIterator& operator--() { 123 CHECK_NE(current_, start_); 124 --current_; 125 return *this; 126 } 127 128 constexpr CheckedContiguousIterator operator--(int) { 129 CheckedContiguousIterator old = *this; 130 --*this; 131 return old; 132 } 133 134 constexpr CheckedContiguousIterator& operator+=(difference_type rhs) { 135 if (rhs > 0) { 136 CHECK_LE(rhs, end_ - current_); 137 } else { 138 CHECK_LE(-rhs, current_ - start_); 139 } 140 current_ += rhs; 141 return *this; 142 } 143 144 constexpr CheckedContiguousIterator operator+(difference_type rhs) const { 145 CheckedContiguousIterator it = *this; 146 it += rhs; 147 return it; 148 } 149 150 constexpr CheckedContiguousIterator& operator-=(difference_type rhs) { 151 if (rhs < 0) { 152 CHECK_LE(-rhs, end_ - current_); 153 } else { 154 CHECK_LE(rhs, current_ - start_); 155 } 156 current_ -= rhs; 157 return *this; 158 } 159 160 constexpr CheckedContiguousIterator operator-(difference_type rhs) const { 161 CheckedContiguousIterator it = *this; 162 it -= rhs; 163 return it; 164 } 165 166 constexpr friend difference_type operator-( 167 const CheckedContiguousIterator& lhs, 168 const CheckedContiguousIterator& rhs) { 169 lhs.CheckComparable(rhs); 170 return lhs.current_ - rhs.current_; 171 } 172 173 constexpr reference operator*() const { 174 CHECK_NE(current_, end_); 175 return *current_; 176 } 177 178 constexpr pointer operator->() const { 179 CHECK_NE(current_, end_); 180 return current_; 181 } 182 183 constexpr reference operator[](difference_type rhs) const { 184 CHECK_GE(rhs, 0); 185 CHECK_LT(rhs, end_ - current_); 186 return current_[rhs]; 187 } 188 IsRangeMoveSafe(const CheckedContiguousIterator & from_begin,const CheckedContiguousIterator & from_end,const CheckedContiguousIterator & to)189 [[nodiscard]] static bool IsRangeMoveSafe( 190 const CheckedContiguousIterator& from_begin, 191 const CheckedContiguousIterator& from_end, 192 const CheckedContiguousIterator& to) { 193 if (from_end < from_begin) 194 return false; 195 const auto from_begin_uintptr = get_uintptr(from_begin.current_); 196 const auto from_end_uintptr = get_uintptr(from_end.current_); 197 const auto to_begin_uintptr = get_uintptr(to.current_); 198 const auto to_end_uintptr = 199 get_uintptr((to + std::distance(from_begin, from_end)).current_); 200 201 return to_begin_uintptr >= from_end_uintptr || 202 to_end_uintptr <= from_begin_uintptr; 203 } 204 205 private: CheckComparable(const CheckedContiguousIterator & other)206 constexpr void CheckComparable(const CheckedContiguousIterator& other) const { 207 CHECK_EQ(start_, other.start_); 208 CHECK_EQ(end_, other.end_); 209 } 210 211 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 212 // #union, #constexpr-ctor-field-initializer 213 RAW_PTR_EXCLUSION const T* start_ = nullptr; 214 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 215 // #union, #constexpr-ctor-field-initializer 216 RAW_PTR_EXCLUSION T* current_ = nullptr; 217 // This field is not a raw_ptr<> because it was filtered by the rewriter for: 218 // #union, #constexpr-ctor-field-initializer 219 RAW_PTR_EXCLUSION const T* end_ = nullptr; 220 }; 221 222 template <typename T> 223 using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>; 224 225 } // namespace base 226 227 #if defined(_LIBCPP_VERSION) && !BUILDFLAG(IS_NACL) 228 // Specialize both std::__is_cpp17_contiguous_iterator and std::pointer_traits 229 // for CCI in case we compile with libc++ outside of NaCl. The former is 230 // required to enable certain algorithm optimizations (e.g. std::copy can be a 231 // simple std::memmove under certain circumstances), and is a precursor to 232 // C++20's std::contiguous_iterator concept [1]. Once we actually use C++20 it 233 // will be enough to add `using iterator_concept = std::contiguous_iterator_tag` 234 // to the iterator class [2], and we can get rid of this non-standard 235 // specialization. 236 // 237 // The latter is required to obtain the underlying raw pointer without resulting 238 // in CHECK failures. The important bit is the `to_address(pointer)` overload, 239 // which is the standard blessed way to customize `std::to_address(pointer)` in 240 // C++20 [3]. 241 // 242 // [1] https://wg21.link/iterator.concept.contiguous 243 // [2] https://wg21.link/std.iterator.tags 244 // [3] https://wg21.link/pointer.traits.optmem 245 namespace std { 246 247 template <typename T> 248 struct __is_cpp17_contiguous_iterator<::base::CheckedContiguousIterator<T>> 249 : true_type {}; 250 251 template <typename T> 252 struct pointer_traits<::base::CheckedContiguousIterator<T>> { 253 using pointer = ::base::CheckedContiguousIterator<T>; 254 using element_type = T; 255 using difference_type = ptrdiff_t; 256 257 template <typename U> 258 using rebind = ::base::CheckedContiguousIterator<U>; 259 260 static constexpr pointer pointer_to(element_type& r) noexcept { 261 return pointer(&r, &r); 262 } 263 264 static constexpr element_type* to_address(pointer p) noexcept { 265 return p.current_; 266 } 267 }; 268 269 } // namespace std 270 #endif 271 272 #endif // BASE_CONTAINERS_CHECKED_ITERATORS_H_ 273