| // Copyright 2017 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_CONTAINERS_VECTOR_BUFFERS_H_ | 
 | #define BASE_CONTAINERS_VECTOR_BUFFERS_H_ | 
 |  | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 |  | 
 | #include <type_traits> | 
 | #include <utility> | 
 |  | 
 | #include "base/logging.h" | 
 |  | 
 | namespace base { | 
 | namespace internal { | 
 |  | 
 | // Internal implementation detail of base/containers. | 
 | // | 
 | // Implements a vector-like buffer that holds a certain capacity of T. Unlike | 
 | // std::vector, VectorBuffer never constructs or destructs its arguments, and | 
 | // can't change sizes. But it does implement templates to assist in efficient | 
 | // moving and destruction of those items manually. | 
 | // | 
 | // In particular, the destructor function does not iterate over the items if | 
 | // there is no destructor. Moves should be implemented as a memcpy/memmove for | 
 | // trivially copyable objects (POD) otherwise, it should be a std::move if | 
 | // possible, and as a last resort it falls back to a copy. This behavior is | 
 | // similar to std::vector. | 
 | // | 
 | // No special consideration is done for noexcept move constructors since | 
 | // we compile without exceptions. | 
 | // | 
 | // The current API does not support moving overlapping ranges. | 
 | template <typename T> | 
 | class VectorBuffer { | 
 |  public: | 
 |   constexpr VectorBuffer() = default; | 
 |  | 
 | #if defined(__clang__) | 
 |   // This constructor converts an uninitialized void* to a T* which triggers | 
 |   // clang Control Flow Integrity. Since this is as-designed, disable. | 
 |   __attribute__((no_sanitize("cfi-unrelated-cast", "vptr"))) | 
 | #endif | 
 |   VectorBuffer(size_t count) | 
 |       : buffer_(reinterpret_cast<T*>(malloc(sizeof(T) * count))), | 
 |         capacity_(count) { | 
 |   } | 
 |   VectorBuffer(VectorBuffer&& other) noexcept | 
 |       : buffer_(other.buffer_), capacity_(other.capacity_) { | 
 |     other.buffer_ = nullptr; | 
 |     other.capacity_ = 0; | 
 |   } | 
 |  | 
 |   ~VectorBuffer() { free(buffer_); } | 
 |  | 
 |   VectorBuffer& operator=(VectorBuffer&& other) { | 
 |     free(buffer_); | 
 |     buffer_ = other.buffer_; | 
 |     capacity_ = other.capacity_; | 
 |  | 
 |     other.buffer_ = nullptr; | 
 |     other.capacity_ = 0; | 
 |     return *this; | 
 |   } | 
 |  | 
 |   size_t capacity() const { return capacity_; } | 
 |  | 
 |   T& operator[](size_t i) { return buffer_[i]; } | 
 |   const T& operator[](size_t i) const { return buffer_[i]; } | 
 |   T* begin() { return buffer_; } | 
 |   T* end() { return &buffer_[capacity_]; } | 
 |  | 
 |   // DestructRange ------------------------------------------------------------ | 
 |  | 
 |   // Trivially destructible objects need not have their destructors called. | 
 |   template <typename T2 = T, | 
 |             typename std::enable_if<std::is_trivially_destructible<T2>::value, | 
 |                                     int>::type = 0> | 
 |   void DestructRange(T* begin, T* end) {} | 
 |  | 
 |   // Non-trivially destructible objects must have their destructors called | 
 |   // individually. | 
 |   template <typename T2 = T, | 
 |             typename std::enable_if<!std::is_trivially_destructible<T2>::value, | 
 |                                     int>::type = 0> | 
 |   void DestructRange(T* begin, T* end) { | 
 |     while (begin != end) { | 
 |       begin->~T(); | 
 |       begin++; | 
 |     } | 
 |   } | 
 |  | 
 |   // MoveRange ---------------------------------------------------------------- | 
 |   // | 
 |   // The destructor will be called (as necessary) for all moved types. The | 
 |   // ranges must not overlap. | 
 |   // | 
 |   // The parameters and begin and end (one past the last) of the input buffer, | 
 |   // and the address of the first element to copy to. There must be sufficient | 
 |   // room in the destination for all items in the range [begin, end). | 
 |  | 
 |   // Trivially copyable types can use memcpy. trivially copyable implies | 
 |   // that there is a trivial destructor as we don't have to call it. | 
 |   template <typename T2 = T, | 
 |             typename std::enable_if<std::is_trivially_copyable<T2>::value, | 
 |                                     int>::type = 0> | 
 |   static void MoveRange(T* from_begin, T* from_end, T* to) { | 
 |     DCHECK(!RangesOverlap(from_begin, from_end, to)); | 
 |     memcpy(to, from_begin, (from_end - from_begin) * sizeof(T)); | 
 |   } | 
 |  | 
 |   // Not trivially copyable, but movable: call the move constructor and | 
 |   // destruct the original. | 
 |   template <typename T2 = T, | 
 |             typename std::enable_if<std::is_move_constructible<T2>::value && | 
 |                                         !std::is_trivially_copyable<T2>::value, | 
 |                                     int>::type = 0> | 
 |   static void MoveRange(T* from_begin, T* from_end, T* to) { | 
 |     DCHECK(!RangesOverlap(from_begin, from_end, to)); | 
 |     while (from_begin != from_end) { | 
 |       new (to) T(std::move(*from_begin)); | 
 |       from_begin->~T(); | 
 |       from_begin++; | 
 |       to++; | 
 |     } | 
 |   } | 
 |  | 
 |   // Not movable, not trivially copyable: call the copy constructor and | 
 |   // destruct the original. | 
 |   template <typename T2 = T, | 
 |             typename std::enable_if<!std::is_move_constructible<T2>::value && | 
 |                                         !std::is_trivially_copyable<T2>::value, | 
 |                                     int>::type = 0> | 
 |   static void MoveRange(T* from_begin, T* from_end, T* to) { | 
 |     DCHECK(!RangesOverlap(from_begin, from_end, to)); | 
 |     while (from_begin != from_end) { | 
 |       new (to) T(*from_begin); | 
 |       from_begin->~T(); | 
 |       from_begin++; | 
 |       to++; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   static bool RangesOverlap(const T* from_begin, | 
 |                             const T* from_end, | 
 |                             const T* to) { | 
 |     return !(to >= from_end || to + (from_end - from_begin) <= from_begin); | 
 |   } | 
 |  | 
 |   T* buffer_ = nullptr; | 
 |   size_t capacity_ = 0; | 
 |  | 
 |   VectorBuffer(const VectorBuffer&) = delete; | 
 |   VectorBuffer& operator=(const VectorBuffer&) = delete; | 
 | }; | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_CONTAINERS_VECTOR_BUFFERS_H_ |