1 // Copyright 2018 The Chromium Authors. All rights reserved. 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 15 namespace base { 16 17 template <typename T> 18 class CheckedContiguousIterator { 19 public: 20 using difference_type = std::ptrdiff_t; 21 using value_type = std::remove_cv_t<T>; 22 using pointer = T*; 23 using reference = T&; 24 using iterator_category = std::random_access_iterator_tag; 25 26 // Required for converting constructor below. 27 template <typename U> 28 friend class CheckedContiguousIterator; 29 30 constexpr CheckedContiguousIterator() = default; 31 32 #if defined(_LIBCPP_VERSION) 33 // The following using declaration, single argument implicit constructor and 34 // friended `__unwrap_iter` overload are required to use an optimized code 35 // path when using a CheckedContiguousIterator with libc++ algorithms such as 36 // std::copy(first, last, result), std::copy_backward(first, last, result), 37 // std::move(first, last, result) and std::move_backward(first, last, result). 38 // 39 // Each of these algorithms dispatches to a std::memmove if this is safe to do 40 // so, i.e. when all of `first`, `last` and `result` are iterators over 41 // contiguous storage of the same type modulo const qualifiers. 42 // 43 // libc++ implements this for its contiguous iterators by invoking the 44 // unqualified __unwrap_iter, which returns the underlying pointer for 45 // iterators over std::vector and std::string, and returns the original 46 // iterator otherwise. 47 // 48 // Thus in order to opt into this optimization for CCI, we need to provide our 49 // own __unwrap_iter, returning the underlying raw pointer if it is safe to do 50 // so. 51 // 52 // Furthermore, considering that std::copy is implemented as follows, the 53 // return type of __unwrap_iter(CCI) needs to be convertible to CCI, which is 54 // why an appropriate implicit single argument constructor is provided for the 55 // optimized case: 56 // 57 // template <class InIter, class OutIter> 58 // OutIter copy(InIter first, InIter last, OutIter result) { 59 // return __copy(__unwrap_iter(first), __unwrap_iter(last), 60 // __unwrap_iter(result)); 61 // } 62 // 63 // Unoptimized __copy() signature: 64 // template <class InIter, class OutIter> 65 // OutIter __copy(InIter first, InIter last, OutIter result); 66 // 67 // Optimized __copy() signature: 68 // template <class T, class U> 69 // U* __copy(T* first, T* last, U* result); 70 // 71 // Finally, this single argument constructor sets all internal fields to the 72 // passed in pointer. This allows the resulting CCI to be used in other 73 // optimized calls to std::copy (or std::move, std::copy_backward, 74 // std::move_backward). However, it should not be used otherwise, since 75 // invoking any of its public API will result in a CHECK failure. This also 76 // means that callers should never use the single argument constructor 77 // directly. 78 template <typename U> 79 using PtrIfSafeToMemmove = std::enable_if_t< 80 std::is_trivially_copy_assignable<std::remove_const_t<U>>::value, 81 U*>; 82 83 template <int&... ExplicitArgumentBarrier, typename U = T> CheckedContiguousIterator(PtrIfSafeToMemmove<U> ptr)84 constexpr CheckedContiguousIterator(PtrIfSafeToMemmove<U> ptr) 85 : start_(ptr), current_(ptr), end_(ptr) {} 86 87 template <int&... ExplicitArgumentBarrier, typename U = T> __unwrap_iter(CheckedContiguousIterator iter)88 friend constexpr PtrIfSafeToMemmove<U> __unwrap_iter( 89 CheckedContiguousIterator iter) { 90 return iter.current_; 91 } 92 #endif 93 CheckedContiguousIterator(T * start,const T * end)94 constexpr CheckedContiguousIterator(T* start, const T* end) 95 : CheckedContiguousIterator(start, start, end) {} CheckedContiguousIterator(const T * start,T * current,const T * end)96 constexpr CheckedContiguousIterator(const T* start, T* current, const T* end) 97 : start_(start), current_(current), end_(end) { 98 CHECK_LE(start, current); 99 CHECK_LE(current, end); 100 } 101 constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) = 102 default; 103 104 // Converting constructor allowing conversions like CCI<T> to CCI<const T>, 105 // but disallowing CCI<const T> to CCI<T> or CCI<Derived> to CCI<Base>, which 106 // are unsafe. Furthermore, this is the same condition as used by the 107 // converting constructors of std::span<T> and std::unique_ptr<T[]>. 108 // See https://wg21.link/n4042 for details. 109 template < 110 typename U, 111 std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr> CheckedContiguousIterator(const CheckedContiguousIterator<U> & other)112 constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other) 113 : start_(other.start_), current_(other.current_), end_(other.end_) { 114 // We explicitly don't delegate to the 3-argument constructor here. Its 115 // CHECKs would be redundant, since we expect |other| to maintain its own 116 // invariant. However, DCHECKs never hurt anybody. Presumably. 117 DCHECK_LE(other.start_, other.current_); 118 DCHECK_LE(other.current_, other.end_); 119 } 120 121 ~CheckedContiguousIterator() = default; 122 123 constexpr CheckedContiguousIterator& operator=( 124 const CheckedContiguousIterator& other) = default; 125 126 friend constexpr bool operator==(const CheckedContiguousIterator& lhs, 127 const CheckedContiguousIterator& rhs) { 128 lhs.CheckComparable(rhs); 129 return lhs.current_ == rhs.current_; 130 } 131 132 friend constexpr bool operator!=(const CheckedContiguousIterator& lhs, 133 const CheckedContiguousIterator& rhs) { 134 lhs.CheckComparable(rhs); 135 return lhs.current_ != rhs.current_; 136 } 137 138 friend constexpr bool operator<(const CheckedContiguousIterator& lhs, 139 const CheckedContiguousIterator& rhs) { 140 lhs.CheckComparable(rhs); 141 return lhs.current_ < rhs.current_; 142 } 143 144 friend constexpr bool operator<=(const CheckedContiguousIterator& lhs, 145 const CheckedContiguousIterator& rhs) { 146 lhs.CheckComparable(rhs); 147 return lhs.current_ <= rhs.current_; 148 } 149 friend constexpr bool operator>(const CheckedContiguousIterator& lhs, 150 const CheckedContiguousIterator& rhs) { 151 lhs.CheckComparable(rhs); 152 return lhs.current_ > rhs.current_; 153 } 154 155 friend constexpr bool operator>=(const CheckedContiguousIterator& lhs, 156 const CheckedContiguousIterator& rhs) { 157 lhs.CheckComparable(rhs); 158 return lhs.current_ >= rhs.current_; 159 } 160 161 constexpr CheckedContiguousIterator& operator++() { 162 CHECK_NE(current_, end_); 163 ++current_; 164 return *this; 165 } 166 167 constexpr CheckedContiguousIterator operator++(int) { 168 CheckedContiguousIterator old = *this; 169 ++*this; 170 return old; 171 } 172 173 constexpr CheckedContiguousIterator& operator--() { 174 CHECK_NE(current_, start_); 175 --current_; 176 return *this; 177 } 178 179 constexpr CheckedContiguousIterator operator--(int) { 180 CheckedContiguousIterator old = *this; 181 --*this; 182 return old; 183 } 184 185 constexpr CheckedContiguousIterator& operator+=(difference_type rhs) { 186 if (rhs > 0) { 187 CHECK_LE(rhs, end_ - current_); 188 } else { 189 CHECK_LE(-rhs, current_ - start_); 190 } 191 current_ += rhs; 192 return *this; 193 } 194 195 constexpr CheckedContiguousIterator operator+(difference_type rhs) const { 196 CheckedContiguousIterator it = *this; 197 it += rhs; 198 return it; 199 } 200 201 constexpr CheckedContiguousIterator& operator-=(difference_type rhs) { 202 if (rhs < 0) { 203 CHECK_LE(-rhs, end_ - current_); 204 } else { 205 CHECK_LE(rhs, current_ - start_); 206 } 207 current_ -= rhs; 208 return *this; 209 } 210 211 constexpr CheckedContiguousIterator operator-(difference_type rhs) const { 212 CheckedContiguousIterator it = *this; 213 it -= rhs; 214 return it; 215 } 216 217 constexpr friend difference_type operator-( 218 const CheckedContiguousIterator& lhs, 219 const CheckedContiguousIterator& rhs) { 220 lhs.CheckComparable(rhs); 221 return lhs.current_ - rhs.current_; 222 } 223 224 constexpr reference operator*() const { 225 CHECK_NE(current_, end_); 226 return *current_; 227 } 228 229 constexpr pointer operator->() const { 230 CHECK_NE(current_, end_); 231 return current_; 232 } 233 234 constexpr reference operator[](difference_type rhs) const { 235 CHECK_GE(rhs, 0); 236 CHECK_LT(rhs, end_ - current_); 237 return current_[rhs]; 238 } 239 IsRangeMoveSafe(const CheckedContiguousIterator & from_begin,const CheckedContiguousIterator & from_end,const CheckedContiguousIterator & to)240 static bool IsRangeMoveSafe(const CheckedContiguousIterator& from_begin, 241 const CheckedContiguousIterator& from_end, 242 const CheckedContiguousIterator& to) 243 WARN_UNUSED_RESULT { 244 if (from_end < from_begin) 245 return false; 246 const auto from_begin_uintptr = get_uintptr(from_begin.current_); 247 const auto from_end_uintptr = get_uintptr(from_end.current_); 248 const auto to_begin_uintptr = get_uintptr(to.current_); 249 const auto to_end_uintptr = 250 get_uintptr((to + std::distance(from_begin, from_end)).current_); 251 252 return to_begin_uintptr >= from_end_uintptr || 253 to_end_uintptr <= from_begin_uintptr; 254 } 255 256 private: CheckComparable(const CheckedContiguousIterator & other)257 constexpr void CheckComparable(const CheckedContiguousIterator& other) const { 258 CHECK_EQ(start_, other.start_); 259 CHECK_EQ(end_, other.end_); 260 } 261 262 const T* start_ = nullptr; 263 T* current_ = nullptr; 264 const T* end_ = nullptr; 265 }; 266 267 template <typename T> 268 using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>; 269 270 } // namespace base 271 272 #endif // BASE_CONTAINERS_CHECKED_ITERATORS_H_ 273