xref: /aosp_15_r20/external/cronet/base/containers/vector_buffer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 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_VECTOR_BUFFER_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_VECTOR_BUFFER_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
9*6777b538SAndroid Build Coastguard Worker #include <string.h>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include <type_traits>
12*6777b538SAndroid Build Coastguard Worker #include <utility>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/containers/util.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr_exclusion.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/numerics/checked_math.h"
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace base::internal {
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker // Internal implementation detail of base/containers.
24*6777b538SAndroid Build Coastguard Worker //
25*6777b538SAndroid Build Coastguard Worker // Implements a vector-like buffer that holds a certain capacity of T. Unlike
26*6777b538SAndroid Build Coastguard Worker // std::vector, VectorBuffer never constructs or destructs its arguments, and
27*6777b538SAndroid Build Coastguard Worker // can't change sizes. But it does implement templates to assist in efficient
28*6777b538SAndroid Build Coastguard Worker // moving and destruction of those items manually.
29*6777b538SAndroid Build Coastguard Worker //
30*6777b538SAndroid Build Coastguard Worker // In particular, the destructor function does not iterate over the items if
31*6777b538SAndroid Build Coastguard Worker // there is no destructor. Moves should be implemented as a memcpy/memmove for
32*6777b538SAndroid Build Coastguard Worker // trivially copyable objects (POD) otherwise, it should be a std::move if
33*6777b538SAndroid Build Coastguard Worker // possible, and as a last resort it falls back to a copy. This behavior is
34*6777b538SAndroid Build Coastguard Worker // similar to std::vector.
35*6777b538SAndroid Build Coastguard Worker //
36*6777b538SAndroid Build Coastguard Worker // No special consideration is done for noexcept move constructors since
37*6777b538SAndroid Build Coastguard Worker // we compile without exceptions.
38*6777b538SAndroid Build Coastguard Worker //
39*6777b538SAndroid Build Coastguard Worker // The current API does not support moving overlapping ranges.
40*6777b538SAndroid Build Coastguard Worker template <typename T>
41*6777b538SAndroid Build Coastguard Worker class VectorBuffer {
42*6777b538SAndroid Build Coastguard Worker  public:
43*6777b538SAndroid Build Coastguard Worker   constexpr VectorBuffer() = default;
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker #if defined(__clang__) && !defined(__native_client__)
46*6777b538SAndroid Build Coastguard Worker   // This constructor converts an uninitialized void* to a T* which triggers
47*6777b538SAndroid Build Coastguard Worker   // clang Control Flow Integrity. Since this is as-designed, disable.
48*6777b538SAndroid Build Coastguard Worker   __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
49*6777b538SAndroid Build Coastguard Worker #endif
VectorBuffer(size_t count)50*6777b538SAndroid Build Coastguard Worker   VectorBuffer(size_t count)
51*6777b538SAndroid Build Coastguard Worker       : buffer_(reinterpret_cast<T*>(
52*6777b538SAndroid Build Coastguard Worker             malloc(CheckMul(sizeof(T), count).ValueOrDie()))),
53*6777b538SAndroid Build Coastguard Worker         capacity_(count) {
54*6777b538SAndroid Build Coastguard Worker   }
VectorBuffer(VectorBuffer && other)55*6777b538SAndroid Build Coastguard Worker   VectorBuffer(VectorBuffer&& other) noexcept
56*6777b538SAndroid Build Coastguard Worker       : buffer_(other.buffer_), capacity_(other.capacity_) {
57*6777b538SAndroid Build Coastguard Worker     other.buffer_ = nullptr;
58*6777b538SAndroid Build Coastguard Worker     other.capacity_ = 0;
59*6777b538SAndroid Build Coastguard Worker   }
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker   VectorBuffer(const VectorBuffer&) = delete;
62*6777b538SAndroid Build Coastguard Worker   VectorBuffer& operator=(const VectorBuffer&) = delete;
63*6777b538SAndroid Build Coastguard Worker 
~VectorBuffer()64*6777b538SAndroid Build Coastguard Worker   ~VectorBuffer() { free(buffer_); }
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker   VectorBuffer& operator=(VectorBuffer&& other) {
67*6777b538SAndroid Build Coastguard Worker     free(buffer_);
68*6777b538SAndroid Build Coastguard Worker     buffer_ = other.buffer_;
69*6777b538SAndroid Build Coastguard Worker     capacity_ = other.capacity_;
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker     other.buffer_ = nullptr;
72*6777b538SAndroid Build Coastguard Worker     other.capacity_ = 0;
73*6777b538SAndroid Build Coastguard Worker     return *this;
74*6777b538SAndroid Build Coastguard Worker   }
75*6777b538SAndroid Build Coastguard Worker 
capacity()76*6777b538SAndroid Build Coastguard Worker   size_t capacity() const { return capacity_; }
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker   T& operator[](size_t i) {
79*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/817982): Some call sites (at least circular_deque.h) are
80*6777b538SAndroid Build Coastguard Worker     // calling this with `i == capacity_` as a way of getting `end()`. Therefore
81*6777b538SAndroid Build Coastguard Worker     // we have to allow this for now (`i <= capacity_`), until we fix those call
82*6777b538SAndroid Build Coastguard Worker     // sites to use real iterators. This comment applies here and to `const T&
83*6777b538SAndroid Build Coastguard Worker     // operator[]`, below.
84*6777b538SAndroid Build Coastguard Worker     CHECK_LE(i, capacity_);
85*6777b538SAndroid Build Coastguard Worker     return buffer_[i];
86*6777b538SAndroid Build Coastguard Worker   }
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker   const T& operator[](size_t i) const {
89*6777b538SAndroid Build Coastguard Worker     CHECK_LE(i, capacity_);
90*6777b538SAndroid Build Coastguard Worker     return buffer_[i];
91*6777b538SAndroid Build Coastguard Worker   }
92*6777b538SAndroid Build Coastguard Worker 
begin()93*6777b538SAndroid Build Coastguard Worker   T* begin() { return buffer_; }
end()94*6777b538SAndroid Build Coastguard Worker   T* end() { return &buffer_[capacity_]; }
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker   // DestructRange ------------------------------------------------------------
97*6777b538SAndroid Build Coastguard Worker 
DestructRange(T * begin,T * end)98*6777b538SAndroid Build Coastguard Worker   void DestructRange(T* begin, T* end) {
99*6777b538SAndroid Build Coastguard Worker     // Trivially destructible objects need not have their destructors called.
100*6777b538SAndroid Build Coastguard Worker     if constexpr (!std::is_trivially_destructible_v<T>) {
101*6777b538SAndroid Build Coastguard Worker       CHECK_LE(begin, end);
102*6777b538SAndroid Build Coastguard Worker       while (begin != end) {
103*6777b538SAndroid Build Coastguard Worker         begin->~T();
104*6777b538SAndroid Build Coastguard Worker         begin++;
105*6777b538SAndroid Build Coastguard Worker       }
106*6777b538SAndroid Build Coastguard Worker     }
107*6777b538SAndroid Build Coastguard Worker   }
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   // MoveRange ----------------------------------------------------------------
110*6777b538SAndroid Build Coastguard Worker   //
111*6777b538SAndroid Build Coastguard Worker   // The destructor will be called (as necessary) for all moved types. The
112*6777b538SAndroid Build Coastguard Worker   // ranges must not overlap.
113*6777b538SAndroid Build Coastguard Worker   //
114*6777b538SAndroid Build Coastguard Worker   // The parameters and begin and end (one past the last) of the input buffer,
115*6777b538SAndroid Build Coastguard Worker   // and the address of the first element to copy to. There must be sufficient
116*6777b538SAndroid Build Coastguard Worker   // room in the destination for all items in the range [begin, end).
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker   // Trivially copyable types can use memcpy. Trivially copyable implies
119*6777b538SAndroid Build Coastguard Worker   // that there is a trivial destructor as we don't have to call it.
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   // Trivially relocatable types can also use memcpy. Trivially relocatable
122*6777b538SAndroid Build Coastguard Worker   // imples that memcpy is equivalent to move + destroy.
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker   template <typename T2>
125*6777b538SAndroid Build Coastguard Worker   static inline constexpr bool is_trivially_copyable_or_relocatable =
126*6777b538SAndroid Build Coastguard Worker       std::is_trivially_copyable_v<T2> || IS_TRIVIALLY_RELOCATABLE(T2);
127*6777b538SAndroid Build Coastguard Worker 
MoveRange(T * from_begin,T * from_end,T * to)128*6777b538SAndroid Build Coastguard Worker   static void MoveRange(T* from_begin, T* from_end, T* to) {
129*6777b538SAndroid Build Coastguard Worker     CHECK(!RangesOverlap(from_begin, from_end, to));
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker     if constexpr (is_trivially_copyable_or_relocatable<T>) {
132*6777b538SAndroid Build Coastguard Worker       memcpy(to, from_begin,
133*6777b538SAndroid Build Coastguard Worker              CheckSub(get_uintptr(from_end), get_uintptr(from_begin))
134*6777b538SAndroid Build Coastguard Worker                  .ValueOrDie());
135*6777b538SAndroid Build Coastguard Worker     } else {
136*6777b538SAndroid Build Coastguard Worker       while (from_begin != from_end) {
137*6777b538SAndroid Build Coastguard Worker         if constexpr (std::move_constructible<T>) {
138*6777b538SAndroid Build Coastguard Worker           new (to) T(std::move(*from_begin));
139*6777b538SAndroid Build Coastguard Worker         } else {
140*6777b538SAndroid Build Coastguard Worker           new (to) T(*from_begin);
141*6777b538SAndroid Build Coastguard Worker         }
142*6777b538SAndroid Build Coastguard Worker         from_begin->~T();
143*6777b538SAndroid Build Coastguard Worker         from_begin++;
144*6777b538SAndroid Build Coastguard Worker         to++;
145*6777b538SAndroid Build Coastguard Worker       }
146*6777b538SAndroid Build Coastguard Worker     }
147*6777b538SAndroid Build Coastguard Worker   }
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker  private:
RangesOverlap(const T * from_begin,const T * from_end,const T * to)150*6777b538SAndroid Build Coastguard Worker   static bool RangesOverlap(const T* from_begin,
151*6777b538SAndroid Build Coastguard Worker                             const T* from_end,
152*6777b538SAndroid Build Coastguard Worker                             const T* to) {
153*6777b538SAndroid Build Coastguard Worker     const auto from_begin_uintptr = get_uintptr(from_begin);
154*6777b538SAndroid Build Coastguard Worker     const auto from_end_uintptr = get_uintptr(from_end);
155*6777b538SAndroid Build Coastguard Worker     const auto to_uintptr = get_uintptr(to);
156*6777b538SAndroid Build Coastguard Worker     return !(
157*6777b538SAndroid Build Coastguard Worker         to >= from_end ||
158*6777b538SAndroid Build Coastguard Worker         CheckAdd(to_uintptr, CheckSub(from_end_uintptr, from_begin_uintptr))
159*6777b538SAndroid Build Coastguard Worker                 .ValueOrDie() <= from_begin_uintptr);
160*6777b538SAndroid Build Coastguard Worker   }
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   // `buffer_` is not a raw_ptr<...> for performance reasons (based on analysis
163*6777b538SAndroid Build Coastguard Worker   // of sampling profiler data and tab_search:top100:2020).
164*6777b538SAndroid Build Coastguard Worker   RAW_PTR_EXCLUSION T* buffer_ = nullptr;
165*6777b538SAndroid Build Coastguard Worker   size_t capacity_ = 0;
166*6777b538SAndroid Build Coastguard Worker };
167*6777b538SAndroid Build Coastguard Worker 
168*6777b538SAndroid Build Coastguard Worker }  // namespace base::internal
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker #endif  // BASE_CONTAINERS_VECTOR_BUFFER_H_
171