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