• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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