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