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