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