xref: /aosp_15_r20/external/libchrome/base/containers/vector_buffer.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_VECTOR_BUFFERS_H_
6*635a8641SAndroid Build Coastguard Worker #define BASE_CONTAINERS_VECTOR_BUFFERS_H_
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include <stdlib.h>
9*635a8641SAndroid Build Coastguard Worker #include <string.h>
10*635a8641SAndroid Build Coastguard Worker 
11*635a8641SAndroid Build Coastguard Worker #include <type_traits>
12*635a8641SAndroid Build Coastguard Worker #include <utility>
13*635a8641SAndroid Build Coastguard Worker 
14*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker namespace base {
18*635a8641SAndroid Build Coastguard Worker namespace internal {
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker // Internal implementation detail of base/containers.
21*635a8641SAndroid Build Coastguard Worker //
22*635a8641SAndroid Build Coastguard Worker // Implements a vector-like buffer that holds a certain capacity of T. Unlike
23*635a8641SAndroid Build Coastguard Worker // std::vector, VectorBuffer never constructs or destructs its arguments, and
24*635a8641SAndroid Build Coastguard Worker // can't change sizes. But it does implement templates to assist in efficient
25*635a8641SAndroid Build Coastguard Worker // moving and destruction of those items manually.
26*635a8641SAndroid Build Coastguard Worker //
27*635a8641SAndroid Build Coastguard Worker // In particular, the destructor function does not iterate over the items if
28*635a8641SAndroid Build Coastguard Worker // there is no destructor. Moves should be implemented as a memcpy/memmove for
29*635a8641SAndroid Build Coastguard Worker // trivially copyable objects (POD) otherwise, it should be a std::move if
30*635a8641SAndroid Build Coastguard Worker // possible, and as a last resort it falls back to a copy. This behavior is
31*635a8641SAndroid Build Coastguard Worker // similar to std::vector.
32*635a8641SAndroid Build Coastguard Worker //
33*635a8641SAndroid Build Coastguard Worker // No special consideration is done for noexcept move constructors since
34*635a8641SAndroid Build Coastguard Worker // we compile without exceptions.
35*635a8641SAndroid Build Coastguard Worker //
36*635a8641SAndroid Build Coastguard Worker // The current API does not support moving overlapping ranges.
37*635a8641SAndroid Build Coastguard Worker template <typename T>
38*635a8641SAndroid Build Coastguard Worker class VectorBuffer {
39*635a8641SAndroid Build Coastguard Worker  public:
40*635a8641SAndroid Build Coastguard Worker   constexpr VectorBuffer() = default;
41*635a8641SAndroid Build Coastguard Worker 
42*635a8641SAndroid Build Coastguard Worker #if defined(__clang__) && !defined(__native_client__)
43*635a8641SAndroid Build Coastguard Worker   // This constructor converts an uninitialized void* to a T* which triggers
44*635a8641SAndroid Build Coastguard Worker   // clang Control Flow Integrity. Since this is as-designed, disable.
45*635a8641SAndroid Build Coastguard Worker   __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
46*635a8641SAndroid Build Coastguard Worker #endif
VectorBuffer(size_t count)47*635a8641SAndroid Build Coastguard Worker   VectorBuffer(size_t count)
48*635a8641SAndroid Build Coastguard Worker       : buffer_(reinterpret_cast<T*>(malloc(sizeof(T) * count))),
49*635a8641SAndroid Build Coastguard Worker         capacity_(count) {
50*635a8641SAndroid Build Coastguard Worker   }
VectorBuffer(VectorBuffer && other)51*635a8641SAndroid Build Coastguard Worker   VectorBuffer(VectorBuffer&& other) noexcept
52*635a8641SAndroid Build Coastguard Worker       : buffer_(other.buffer_), capacity_(other.capacity_) {
53*635a8641SAndroid Build Coastguard Worker     other.buffer_ = nullptr;
54*635a8641SAndroid Build Coastguard Worker     other.capacity_ = 0;
55*635a8641SAndroid Build Coastguard Worker   }
56*635a8641SAndroid Build Coastguard Worker 
~VectorBuffer()57*635a8641SAndroid Build Coastguard Worker   ~VectorBuffer() { free(buffer_); }
58*635a8641SAndroid Build Coastguard Worker 
59*635a8641SAndroid Build Coastguard Worker   VectorBuffer& operator=(VectorBuffer&& other) {
60*635a8641SAndroid Build Coastguard Worker     free(buffer_);
61*635a8641SAndroid Build Coastguard Worker     buffer_ = other.buffer_;
62*635a8641SAndroid Build Coastguard Worker     capacity_ = other.capacity_;
63*635a8641SAndroid Build Coastguard Worker 
64*635a8641SAndroid Build Coastguard Worker     other.buffer_ = nullptr;
65*635a8641SAndroid Build Coastguard Worker     other.capacity_ = 0;
66*635a8641SAndroid Build Coastguard Worker     return *this;
67*635a8641SAndroid Build Coastguard Worker   }
68*635a8641SAndroid Build Coastguard Worker 
capacity()69*635a8641SAndroid Build Coastguard Worker   size_t capacity() const { return capacity_; }
70*635a8641SAndroid Build Coastguard Worker 
71*635a8641SAndroid Build Coastguard Worker   T& operator[](size_t i) { return buffer_[i]; }
72*635a8641SAndroid Build Coastguard Worker   const T& operator[](size_t i) const { return buffer_[i]; }
begin()73*635a8641SAndroid Build Coastguard Worker   T* begin() { return buffer_; }
end()74*635a8641SAndroid Build Coastguard Worker   T* end() { return &buffer_[capacity_]; }
75*635a8641SAndroid Build Coastguard Worker 
76*635a8641SAndroid Build Coastguard Worker   // DestructRange ------------------------------------------------------------
77*635a8641SAndroid Build Coastguard Worker 
78*635a8641SAndroid Build Coastguard Worker   // Trivially destructible objects need not have their destructors called.
79*635a8641SAndroid Build Coastguard Worker   template <typename T2 = T,
80*635a8641SAndroid Build Coastguard Worker             typename std::enable_if<std::is_trivially_destructible<T2>::value,
81*635a8641SAndroid Build Coastguard Worker                                     int>::type = 0>
DestructRange(T * begin,T * end)82*635a8641SAndroid Build Coastguard Worker   void DestructRange(T* begin, T* end) {}
83*635a8641SAndroid Build Coastguard Worker 
84*635a8641SAndroid Build Coastguard Worker   // Non-trivially destructible objects must have their destructors called
85*635a8641SAndroid Build Coastguard Worker   // individually.
86*635a8641SAndroid Build Coastguard Worker   template <typename T2 = T,
87*635a8641SAndroid Build Coastguard Worker             typename std::enable_if<!std::is_trivially_destructible<T2>::value,
88*635a8641SAndroid Build Coastguard Worker                                     int>::type = 0>
DestructRange(T * begin,T * end)89*635a8641SAndroid Build Coastguard Worker   void DestructRange(T* begin, T* end) {
90*635a8641SAndroid Build Coastguard Worker     while (begin != end) {
91*635a8641SAndroid Build Coastguard Worker       begin->~T();
92*635a8641SAndroid Build Coastguard Worker       begin++;
93*635a8641SAndroid Build Coastguard Worker     }
94*635a8641SAndroid Build Coastguard Worker   }
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker   // MoveRange ----------------------------------------------------------------
97*635a8641SAndroid Build Coastguard Worker   //
98*635a8641SAndroid Build Coastguard Worker   // The destructor will be called (as necessary) for all moved types. The
99*635a8641SAndroid Build Coastguard Worker   // ranges must not overlap.
100*635a8641SAndroid Build Coastguard Worker   //
101*635a8641SAndroid Build Coastguard Worker   // The parameters and begin and end (one past the last) of the input buffer,
102*635a8641SAndroid Build Coastguard Worker   // and the address of the first element to copy to. There must be sufficient
103*635a8641SAndroid Build Coastguard Worker   // room in the destination for all items in the range [begin, end).
104*635a8641SAndroid Build Coastguard Worker 
105*635a8641SAndroid Build Coastguard Worker   // Trivially copyable types can use memcpy. trivially copyable implies
106*635a8641SAndroid Build Coastguard Worker   // that there is a trivial destructor as we don't have to call it.
107*635a8641SAndroid Build Coastguard Worker   template <typename T2 = T,
108*635a8641SAndroid Build Coastguard Worker             typename std::enable_if<base::is_trivially_copyable<T2>::value,
109*635a8641SAndroid Build Coastguard Worker                                     int>::type = 0>
MoveRange(T * from_begin,T * from_end,T * to)110*635a8641SAndroid Build Coastguard Worker   static void MoveRange(T* from_begin, T* from_end, T* to) {
111*635a8641SAndroid Build Coastguard Worker     DCHECK(!RangesOverlap(from_begin, from_end, to));
112*635a8641SAndroid Build Coastguard Worker     memcpy(to, from_begin, (from_end - from_begin) * sizeof(T));
113*635a8641SAndroid Build Coastguard Worker   }
114*635a8641SAndroid Build Coastguard Worker 
115*635a8641SAndroid Build Coastguard Worker   // Not trivially copyable, but movable: call the move constructor and
116*635a8641SAndroid Build Coastguard Worker   // destruct the original.
117*635a8641SAndroid Build Coastguard Worker   template <typename T2 = T,
118*635a8641SAndroid Build Coastguard Worker             typename std::enable_if<std::is_move_constructible<T2>::value &&
119*635a8641SAndroid Build Coastguard Worker                                         !base::is_trivially_copyable<T2>::value,
120*635a8641SAndroid Build Coastguard Worker                                     int>::type = 0>
MoveRange(T * from_begin,T * from_end,T * to)121*635a8641SAndroid Build Coastguard Worker   static void MoveRange(T* from_begin, T* from_end, T* to) {
122*635a8641SAndroid Build Coastguard Worker     DCHECK(!RangesOverlap(from_begin, from_end, to));
123*635a8641SAndroid Build Coastguard Worker     while (from_begin != from_end) {
124*635a8641SAndroid Build Coastguard Worker       new (to) T(std::move(*from_begin));
125*635a8641SAndroid Build Coastguard Worker       from_begin->~T();
126*635a8641SAndroid Build Coastguard Worker       from_begin++;
127*635a8641SAndroid Build Coastguard Worker       to++;
128*635a8641SAndroid Build Coastguard Worker     }
129*635a8641SAndroid Build Coastguard Worker   }
130*635a8641SAndroid Build Coastguard Worker 
131*635a8641SAndroid Build Coastguard Worker   // Not movable, not trivially copyable: call the copy constructor and
132*635a8641SAndroid Build Coastguard Worker   // destruct the original.
133*635a8641SAndroid Build Coastguard Worker   template <typename T2 = T,
134*635a8641SAndroid Build Coastguard Worker             typename std::enable_if<!std::is_move_constructible<T2>::value &&
135*635a8641SAndroid Build Coastguard Worker                                         !base::is_trivially_copyable<T2>::value,
136*635a8641SAndroid Build Coastguard Worker                                     int>::type = 0>
MoveRange(T * from_begin,T * from_end,T * to)137*635a8641SAndroid Build Coastguard Worker   static void MoveRange(T* from_begin, T* from_end, T* to) {
138*635a8641SAndroid Build Coastguard Worker     DCHECK(!RangesOverlap(from_begin, from_end, to));
139*635a8641SAndroid Build Coastguard Worker     while (from_begin != from_end) {
140*635a8641SAndroid Build Coastguard Worker       new (to) T(*from_begin);
141*635a8641SAndroid Build Coastguard Worker       from_begin->~T();
142*635a8641SAndroid Build Coastguard Worker       from_begin++;
143*635a8641SAndroid Build Coastguard Worker       to++;
144*635a8641SAndroid Build Coastguard Worker     }
145*635a8641SAndroid Build Coastguard Worker   }
146*635a8641SAndroid Build Coastguard Worker 
147*635a8641SAndroid Build Coastguard Worker  private:
RangesOverlap(const T * from_begin,const T * from_end,const T * to)148*635a8641SAndroid Build Coastguard Worker   static bool RangesOverlap(const T* from_begin,
149*635a8641SAndroid Build Coastguard Worker                             const T* from_end,
150*635a8641SAndroid Build Coastguard Worker                             const T* to) {
151*635a8641SAndroid Build Coastguard Worker     return !(to >= from_end || to + (from_end - from_begin) <= from_begin);
152*635a8641SAndroid Build Coastguard Worker   }
153*635a8641SAndroid Build Coastguard Worker 
154*635a8641SAndroid Build Coastguard Worker   T* buffer_ = nullptr;
155*635a8641SAndroid Build Coastguard Worker   size_t capacity_ = 0;
156*635a8641SAndroid Build Coastguard Worker 
157*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(VectorBuffer);
158*635a8641SAndroid Build Coastguard Worker };
159*635a8641SAndroid Build Coastguard Worker 
160*635a8641SAndroid Build Coastguard Worker }  // namespace internal
161*635a8641SAndroid Build Coastguard Worker }  // namespace base
162*635a8641SAndroid Build Coastguard Worker 
163*635a8641SAndroid Build Coastguard Worker #endif  // BASE_CONTAINERS_VECTOR_BUFFERS_H_
164