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