Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 65890f62ba73234c6bfbf0b0a220acb4456fff14 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2017 The Chromium Authors
Brett Wilson322a5462017-08-03 23:59:122// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tom Sepez8726d30e2025-01-29 02:11:085#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
7#pragma allow_unsafe_libc_calls
8#endif
9
Lei Zhang6825df462020-06-23 16:17:4310#ifndef BASE_CONTAINERS_VECTOR_BUFFER_H_
11#define BASE_CONTAINERS_VECTOR_BUFFER_H_
Brett Wilson322a5462017-08-03 23:59:1212
13#include <stdlib.h>
14#include <string.h>
15
16#include <type_traits>
17#include <utility>
18
David Sanders8cfb63a2022-04-14 19:36:3019#include "base/check.h"
Hans Wennborg7b533712020-06-22 20:52:2720#include "base/check_op.h"
Adam Ricefb288d02023-10-13 08:36:2121#include "base/compiler_specific.h"
danakj91c715bb2024-07-10 13:24:2622#include "base/containers/span.h"
Keishi Hattori488b7602022-05-02 13:09:3123#include "base/memory/raw_ptr_exclusion.h"
Chris Palmerb586d7702018-08-15 03:57:3724#include "base/numerics/checked_math.h"
Brett Wilson322a5462017-08-03 23:59:1225
Adam Ricefb288d02023-10-13 08:36:2126namespace base::internal {
Brett Wilson322a5462017-08-03 23:59:1227
28// Internal implementation detail of base/containers.
29//
30// Implements a vector-like buffer that holds a certain capacity of T. Unlike
31// std::vector, VectorBuffer never constructs or destructs its arguments, and
32// can't change sizes. But it does implement templates to assist in efficient
33// moving and destruction of those items manually.
34//
35// In particular, the destructor function does not iterate over the items if
36// there is no destructor. Moves should be implemented as a memcpy/memmove for
37// trivially copyable objects (POD) otherwise, it should be a std::move if
38// possible, and as a last resort it falls back to a copy. This behavior is
39// similar to std::vector.
40//
41// No special consideration is done for noexcept move constructors since
42// we compile without exceptions.
43//
44// The current API does not support moving overlapping ranges.
45template <typename T>
46class VectorBuffer {
47 public:
Gabriel Charette63fe7062018-01-25 14:14:2948 constexpr VectorBuffer() = default;
Brett Wilsoncff2c652017-08-22 23:46:4049
Nico Webere98208d72025-07-10 15:18:2050#if defined(__clang__)
Brett Wilsoncff2c652017-08-22 23:46:4051 // This constructor converts an uninitialized void* to a T* which triggers
52 // clang Control Flow Integrity. Since this is as-designed, disable.
53 __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
54#endif
Brett Wilson322a5462017-08-03 23:59:1255 VectorBuffer(size_t count)
Chris Palmerb586d7702018-08-15 03:57:3756 : buffer_(reinterpret_cast<T*>(
57 malloc(CheckMul(sizeof(T), count).ValueOrDie()))),
Brett Wilsoncff2c652017-08-22 23:46:4058 capacity_(count) {
59 }
Brett Wilson322a5462017-08-03 23:59:1260 VectorBuffer(VectorBuffer&& other) noexcept
61 : buffer_(other.buffer_), capacity_(other.capacity_) {
62 other.buffer_ = nullptr;
63 other.capacity_ = 0;
64 }
65
Lei Zhang6825df462020-06-23 16:17:4366 VectorBuffer(const VectorBuffer&) = delete;
67 VectorBuffer& operator=(const VectorBuffer&) = delete;
68
Brett Wilson322a5462017-08-03 23:59:1269 ~VectorBuffer() { free(buffer_); }
70
71 VectorBuffer& operator=(VectorBuffer&& other) {
72 free(buffer_);
73 buffer_ = other.buffer_;
74 capacity_ = other.capacity_;
75
76 other.buffer_ = nullptr;
77 other.capacity_ = 0;
78 return *this;
79 }
80
81 size_t capacity() const { return capacity_; }
82
Chris Palmerb586d7702018-08-15 03:57:3783 T& operator[](size_t i) {
danakj91c715bb2024-07-10 13:24:2684 CHECK_LT(i, capacity_);
85 // SAFETY: `capacity_` is the size of the array pointed to by `buffer_`,
86 // which `i` is less than, so the dereference is inside the allocation.
87 return UNSAFE_BUFFERS(buffer_[i]);
Chris Palmerb586d7702018-08-15 03:57:3788 }
89
90 const T& operator[](size_t i) const {
danakj91c715bb2024-07-10 13:24:2691 CHECK_LT(i, capacity_);
92 // SAFETY: `capacity_` is the size of the array pointed to by `buffer_`,
93 // which `i` is less than, so the dereference is inside the allocation.
94 return UNSAFE_BUFFERS(buffer_[i]);
Chris Palmerb586d7702018-08-15 03:57:3795 }
96
danakj91c715bb2024-07-10 13:24:2697 const T* data() const { return buffer_; }
98 T* data() { return buffer_; }
99
Daniel Chengc8823762019-08-20 00:14:09100 T* begin() { return buffer_; }
danakj91c715bb2024-07-10 13:24:26101 T* end() {
102 // SAFETY: `capacity_` is the size of the array pointed to by `buffer_`.
103 return UNSAFE_BUFFERS(buffer_ + capacity_);
104 }
105
danakjd5b80ea2024-07-11 22:40:43106 span<T> as_span() {
107 // SAFETY: The `buffer_` array's size is `capacity_` so this gives the
108 // pointer to the start and one-past-the-end of the `buffer_`.
109 return UNSAFE_BUFFERS(span(buffer_, buffer_ + capacity_));
110 }
danakj91c715bb2024-07-10 13:24:26111
danakjd5b80ea2024-07-11 22:40:43112 span<T> subspan(size_t index) { return as_span().subspan(index); }
danakj91c715bb2024-07-10 13:24:26113
114 span<T> subspan(size_t index, size_t size) {
danakjd5b80ea2024-07-11 22:40:43115 return as_span().subspan(index, size);
danakj91c715bb2024-07-10 13:24:26116 }
Brett Wilson322a5462017-08-03 23:59:12117
danakj26ede222024-11-06 21:36:34118 T* get_at(size_t index) { return as_span().get_at(index); }
119
Brett Wilson322a5462017-08-03 23:59:12120 // DestructRange ------------------------------------------------------------
121
danakj91c715bb2024-07-10 13:24:26122 static void DestructRange(span<T> range) {
Daniel Chengbd6da0002023-11-14 22:58:56123 // Trivially destructible objects need not have their destructors called.
124 if constexpr (!std::is_trivially_destructible_v<T>) {
danakj91c715bb2024-07-10 13:24:26125 for (T& t : range) {
126 t.~T();
Daniel Chengbd6da0002023-11-14 22:58:56127 }
Brett Wilson322a5462017-08-03 23:59:12128 }
129 }
130
131 // MoveRange ----------------------------------------------------------------
Adam Ricefb288d02023-10-13 08:36:21132
133 template <typename T2>
134 static inline constexpr bool is_trivially_copyable_or_relocatable =
135 std::is_trivially_copyable_v<T2> || IS_TRIVIALLY_RELOCATABLE(T2);
136
danakj91c715bb2024-07-10 13:24:26137 // Moves or copies elements from the `from` span to the `to` span. Uses memcpy
138 // when possible. The memory in `to` must be uninitialized and the ranges must
139 // not overlap.
140 //
141 // The objects in `from` are destroyed afterward.
142 static void MoveConstructRange(span<T> from, span<T> to) {
143 CHECK(!RangesOverlap(from, to));
144 CHECK_EQ(from.size(), to.size());
Jan Wilken Dörried6e18a42021-02-17 21:25:10145
Daniel Chengbd6da0002023-11-14 22:58:56146 if constexpr (is_trivially_copyable_or_relocatable<T>) {
danakj91c715bb2024-07-10 13:24:26147 // We can't use span::copy_from() as it tries to call copy constructors,
148 // and fails to compile on move-only trivially-relocatable types.
Adrian Ratiue8fd45e92025-07-19 13:03:24149 // TODO(https://crbug.com/432507886): find a way to remove the void* cast
150 memcpy(static_cast<void*>(to.data()), from.data(), to.size_bytes());
danakj91c715bb2024-07-10 13:24:26151 // Destructors are skipped because they are trivial or should be elided in
152 // trivial relocation (https://reviews.llvm.org/D114732).
Daniel Chengbd6da0002023-11-14 22:58:56153 } else {
danakj91c715bb2024-07-10 13:24:26154 for (size_t i = 0; i < from.size(); ++i) {
155 T* to_pointer = to.subspan(i).data();
Daniel Chengbd6da0002023-11-14 22:58:56156 if constexpr (std::move_constructible<T>) {
danakj91c715bb2024-07-10 13:24:26157 new (to_pointer) T(std::move(from[i]));
Daniel Chengbd6da0002023-11-14 22:58:56158 } else {
danakj91c715bb2024-07-10 13:24:26159 new (to_pointer) T(from[i]);
Daniel Chengbd6da0002023-11-14 22:58:56160 }
danakj91c715bb2024-07-10 13:24:26161 from[i].~T();
Daniel Chengbd6da0002023-11-14 22:58:56162 }
Brett Wilson322a5462017-08-03 23:59:12163 }
164 }
165
166 private:
danakj91c715bb2024-07-10 13:24:26167 static bool RangesOverlap(span<T> a, span<T> b) {
168 const auto a_start = reinterpret_cast<uintptr_t>(a.data());
169 const auto a_end = reinterpret_cast<uintptr_t>(a.data()) + a.size();
170 const auto b_start = reinterpret_cast<uintptr_t>(b.data());
171 const auto b_end = reinterpret_cast<uintptr_t>(b.data()) + b.size();
172 return a_end > b_start && a_start < b_end;
Daniel Chengc8823762019-08-20 00:14:09173 }
174
Lukasz Anforowicz877e6222021-11-26 00:03:23175 // `buffer_` is not a raw_ptr<...> for performance reasons (based on analysis
176 // of sampling profiler data and tab_search:top100:2020).
Keishi Hattori488b7602022-05-02 13:09:31177 RAW_PTR_EXCLUSION T* buffer_ = nullptr;
Brett Wilson322a5462017-08-03 23:59:12178 size_t capacity_ = 0;
Brett Wilson322a5462017-08-03 23:59:12179};
180
Adam Ricefb288d02023-10-13 08:36:21181} // namespace base::internal
Brett Wilson322a5462017-08-03 23:59:12182
Lei Zhang6825df462020-06-23 16:17:43183#endif // BASE_CONTAINERS_VECTOR_BUFFER_H_