16d528ed9Sopenharmony_ci// Copyright 2017 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#ifndef BASE_CONTAINERS_VECTOR_BUFFERS_H_ 66d528ed9Sopenharmony_ci#define BASE_CONTAINERS_VECTOR_BUFFERS_H_ 76d528ed9Sopenharmony_ci 86d528ed9Sopenharmony_ci#include <stdlib.h> 96d528ed9Sopenharmony_ci#include <string.h> 106d528ed9Sopenharmony_ci 116d528ed9Sopenharmony_ci#include <type_traits> 126d528ed9Sopenharmony_ci#include <utility> 136d528ed9Sopenharmony_ci 146d528ed9Sopenharmony_ci#include "base/logging.h" 156d528ed9Sopenharmony_ci 166d528ed9Sopenharmony_cinamespace base { 176d528ed9Sopenharmony_cinamespace internal { 186d528ed9Sopenharmony_ci 196d528ed9Sopenharmony_ci// Internal implementation detail of base/containers. 206d528ed9Sopenharmony_ci// 216d528ed9Sopenharmony_ci// Implements a vector-like buffer that holds a certain capacity of T. Unlike 226d528ed9Sopenharmony_ci// std::vector, VectorBuffer never constructs or destructs its arguments, and 236d528ed9Sopenharmony_ci// can't change sizes. But it does implement templates to assist in efficient 246d528ed9Sopenharmony_ci// moving and destruction of those items manually. 256d528ed9Sopenharmony_ci// 266d528ed9Sopenharmony_ci// In particular, the destructor function does not iterate over the items if 276d528ed9Sopenharmony_ci// there is no destructor. Moves should be implemented as a memcpy/memmove for 286d528ed9Sopenharmony_ci// trivially copyable objects (POD) otherwise, it should be a std::move if 296d528ed9Sopenharmony_ci// possible, and as a last resort it falls back to a copy. This behavior is 306d528ed9Sopenharmony_ci// similar to std::vector. 316d528ed9Sopenharmony_ci// 326d528ed9Sopenharmony_ci// No special consideration is done for noexcept move constructors since 336d528ed9Sopenharmony_ci// we compile without exceptions. 346d528ed9Sopenharmony_ci// 356d528ed9Sopenharmony_ci// The current API does not support moving overlapping ranges. 366d528ed9Sopenharmony_citemplate <typename T> 376d528ed9Sopenharmony_ciclass VectorBuffer { 386d528ed9Sopenharmony_ci public: 396d528ed9Sopenharmony_ci constexpr VectorBuffer() = default; 406d528ed9Sopenharmony_ci 416d528ed9Sopenharmony_ci#if defined(__clang__) 426d528ed9Sopenharmony_ci // This constructor converts an uninitialized void* to a T* which triggers 436d528ed9Sopenharmony_ci // clang Control Flow Integrity. Since this is as-designed, disable. 446d528ed9Sopenharmony_ci __attribute__((no_sanitize("cfi-unrelated-cast", "vptr"))) 456d528ed9Sopenharmony_ci#endif 466d528ed9Sopenharmony_ci VectorBuffer(size_t count) 476d528ed9Sopenharmony_ci : buffer_(reinterpret_cast<T*>(malloc(sizeof(T) * count))), 486d528ed9Sopenharmony_ci capacity_(count) { 496d528ed9Sopenharmony_ci } 506d528ed9Sopenharmony_ci VectorBuffer(VectorBuffer&& other) noexcept 516d528ed9Sopenharmony_ci : buffer_(other.buffer_), capacity_(other.capacity_) { 526d528ed9Sopenharmony_ci other.buffer_ = nullptr; 536d528ed9Sopenharmony_ci other.capacity_ = 0; 546d528ed9Sopenharmony_ci } 556d528ed9Sopenharmony_ci 566d528ed9Sopenharmony_ci ~VectorBuffer() { free(buffer_); } 576d528ed9Sopenharmony_ci 586d528ed9Sopenharmony_ci VectorBuffer& operator=(VectorBuffer&& other) { 596d528ed9Sopenharmony_ci free(buffer_); 606d528ed9Sopenharmony_ci buffer_ = other.buffer_; 616d528ed9Sopenharmony_ci capacity_ = other.capacity_; 626d528ed9Sopenharmony_ci 636d528ed9Sopenharmony_ci other.buffer_ = nullptr; 646d528ed9Sopenharmony_ci other.capacity_ = 0; 656d528ed9Sopenharmony_ci return *this; 666d528ed9Sopenharmony_ci } 676d528ed9Sopenharmony_ci 686d528ed9Sopenharmony_ci size_t capacity() const { return capacity_; } 696d528ed9Sopenharmony_ci 706d528ed9Sopenharmony_ci T& operator[](size_t i) { return buffer_[i]; } 716d528ed9Sopenharmony_ci const T& operator[](size_t i) const { return buffer_[i]; } 726d528ed9Sopenharmony_ci T* begin() { return buffer_; } 736d528ed9Sopenharmony_ci T* end() { return &buffer_[capacity_]; } 746d528ed9Sopenharmony_ci 756d528ed9Sopenharmony_ci // DestructRange ------------------------------------------------------------ 766d528ed9Sopenharmony_ci 776d528ed9Sopenharmony_ci // Trivially destructible objects need not have their destructors called. 786d528ed9Sopenharmony_ci template <typename T2 = T, 796d528ed9Sopenharmony_ci typename std::enable_if<std::is_trivially_destructible<T2>::value, 806d528ed9Sopenharmony_ci int>::type = 0> 816d528ed9Sopenharmony_ci void DestructRange(T* begin, T* end) {} 826d528ed9Sopenharmony_ci 836d528ed9Sopenharmony_ci // Non-trivially destructible objects must have their destructors called 846d528ed9Sopenharmony_ci // individually. 856d528ed9Sopenharmony_ci template <typename T2 = T, 866d528ed9Sopenharmony_ci typename std::enable_if<!std::is_trivially_destructible<T2>::value, 876d528ed9Sopenharmony_ci int>::type = 0> 886d528ed9Sopenharmony_ci void DestructRange(T* begin, T* end) { 896d528ed9Sopenharmony_ci while (begin != end) { 906d528ed9Sopenharmony_ci begin->~T(); 916d528ed9Sopenharmony_ci begin++; 926d528ed9Sopenharmony_ci } 936d528ed9Sopenharmony_ci } 946d528ed9Sopenharmony_ci 956d528ed9Sopenharmony_ci // MoveRange ---------------------------------------------------------------- 966d528ed9Sopenharmony_ci // 976d528ed9Sopenharmony_ci // The destructor will be called (as necessary) for all moved types. The 986d528ed9Sopenharmony_ci // ranges must not overlap. 996d528ed9Sopenharmony_ci // 1006d528ed9Sopenharmony_ci // The parameters and begin and end (one past the last) of the input buffer, 1016d528ed9Sopenharmony_ci // and the address of the first element to copy to. There must be sufficient 1026d528ed9Sopenharmony_ci // room in the destination for all items in the range [begin, end). 1036d528ed9Sopenharmony_ci 1046d528ed9Sopenharmony_ci // Trivially copyable types can use memcpy. trivially copyable implies 1056d528ed9Sopenharmony_ci // that there is a trivial destructor as we don't have to call it. 1066d528ed9Sopenharmony_ci template <typename T2 = T, 1076d528ed9Sopenharmony_ci typename std::enable_if<std::is_trivially_copyable<T2>::value, 1086d528ed9Sopenharmony_ci int>::type = 0> 1096d528ed9Sopenharmony_ci static void MoveRange(T* from_begin, T* from_end, T* to) { 1106d528ed9Sopenharmony_ci DCHECK(!RangesOverlap(from_begin, from_end, to)); 1116d528ed9Sopenharmony_ci memcpy(to, from_begin, (from_end - from_begin) * sizeof(T)); 1126d528ed9Sopenharmony_ci } 1136d528ed9Sopenharmony_ci 1146d528ed9Sopenharmony_ci // Not trivially copyable, but movable: call the move constructor and 1156d528ed9Sopenharmony_ci // destruct the original. 1166d528ed9Sopenharmony_ci template <typename T2 = T, 1176d528ed9Sopenharmony_ci typename std::enable_if<std::is_move_constructible<T2>::value && 1186d528ed9Sopenharmony_ci !std::is_trivially_copyable<T2>::value, 1196d528ed9Sopenharmony_ci int>::type = 0> 1206d528ed9Sopenharmony_ci static void MoveRange(T* from_begin, T* from_end, T* to) { 1216d528ed9Sopenharmony_ci DCHECK(!RangesOverlap(from_begin, from_end, to)); 1226d528ed9Sopenharmony_ci while (from_begin != from_end) { 1236d528ed9Sopenharmony_ci new (to) T(std::move(*from_begin)); 1246d528ed9Sopenharmony_ci from_begin->~T(); 1256d528ed9Sopenharmony_ci from_begin++; 1266d528ed9Sopenharmony_ci to++; 1276d528ed9Sopenharmony_ci } 1286d528ed9Sopenharmony_ci } 1296d528ed9Sopenharmony_ci 1306d528ed9Sopenharmony_ci // Not movable, not trivially copyable: call the copy constructor and 1316d528ed9Sopenharmony_ci // destruct the original. 1326d528ed9Sopenharmony_ci template <typename T2 = T, 1336d528ed9Sopenharmony_ci typename std::enable_if<!std::is_move_constructible<T2>::value && 1346d528ed9Sopenharmony_ci !std::is_trivially_copyable<T2>::value, 1356d528ed9Sopenharmony_ci int>::type = 0> 1366d528ed9Sopenharmony_ci static void MoveRange(T* from_begin, T* from_end, T* to) { 1376d528ed9Sopenharmony_ci DCHECK(!RangesOverlap(from_begin, from_end, to)); 1386d528ed9Sopenharmony_ci while (from_begin != from_end) { 1396d528ed9Sopenharmony_ci new (to) T(*from_begin); 1406d528ed9Sopenharmony_ci from_begin->~T(); 1416d528ed9Sopenharmony_ci from_begin++; 1426d528ed9Sopenharmony_ci to++; 1436d528ed9Sopenharmony_ci } 1446d528ed9Sopenharmony_ci } 1456d528ed9Sopenharmony_ci 1466d528ed9Sopenharmony_ci private: 1476d528ed9Sopenharmony_ci static bool RangesOverlap(const T* from_begin, 1486d528ed9Sopenharmony_ci const T* from_end, 1496d528ed9Sopenharmony_ci const T* to) { 1506d528ed9Sopenharmony_ci return !(to >= from_end || to + (from_end - from_begin) <= from_begin); 1516d528ed9Sopenharmony_ci } 1526d528ed9Sopenharmony_ci 1536d528ed9Sopenharmony_ci T* buffer_ = nullptr; 1546d528ed9Sopenharmony_ci size_t capacity_ = 0; 1556d528ed9Sopenharmony_ci 1566d528ed9Sopenharmony_ci VectorBuffer(const VectorBuffer&) = delete; 1576d528ed9Sopenharmony_ci VectorBuffer& operator=(const VectorBuffer&) = delete; 1586d528ed9Sopenharmony_ci}; 1596d528ed9Sopenharmony_ci 1606d528ed9Sopenharmony_ci} // namespace internal 1616d528ed9Sopenharmony_ci} // namespace base 1626d528ed9Sopenharmony_ci 1636d528ed9Sopenharmony_ci#endif // BASE_CONTAINERS_VECTOR_BUFFERS_H_ 164