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