6#include "tpde/util/AddressSanitizer.hpp"
16class SmallVectorUntypedBase {
18 using size_type = std::size_t;
19 using difference_type = ptrdiff_t;
26 SmallVectorUntypedBase() =
delete;
27 SmallVectorUntypedBase(size_type cap)
28 : ptr(reinterpret_cast<void *>(this + 1)), sz(0), cap(cap) {}
30 bool is_small()
const {
31 return ptr ==
reinterpret_cast<const void *
>(
this + 1);
34 void *grow_malloc(size_type min_size, size_type elem_sz, size_type &new_cap);
35 void grow_trivial(size_type min_size, size_type elem_sz);
38 size_type size()
const {
return sz; }
39 size_type capacity()
const {
return cap; }
40 bool empty()
const {
return size() == 0; }
44class SmallVectorBase :
public SmallVectorUntypedBase {
46 static_assert(
alignof(T) <=
alignof(SmallVectorUntypedBase),
47 "SmallVector only supports types with pointer-sized alignment");
52 using const_pointer =
const T *;
53 using reference = T &;
54 using const_reference =
const T &;
56 using const_iterator =
const T *;
58 static constexpr bool IsTrivial = std::is_trivially_copy_constructible_v<T> &&
59 std::is_trivially_move_constructible_v<T> &&
60 std::is_trivially_destructible_v<T>;
63 SmallVectorBase(size_type cap) : SmallVectorUntypedBase(cap) {
64 poison_memory_region(ptr, cap *
sizeof(T));
68 std::destroy(begin(), end());
75 pointer data() {
return reinterpret_cast<T *
>(ptr); }
76 const_pointer data()
const {
return reinterpret_cast<const T *
>(ptr); }
78 iterator begin() {
return data(); }
79 iterator end() {
return data() + sz; }
80 const_iterator begin()
const {
return data(); }
81 const_iterator end()
const {
return data() + sz; }
82 const_iterator cbegin()
const {
return data(); }
83 const_iterator cend()
const {
return data() + sz; }
86 static size_type max_size() {
return size_type(-1) /
sizeof(T); }
88 reference operator[](size_type idx) {
92 const_reference operator[](size_type idx)
const {
97 reference front() {
return (*
this)[0]; }
98 const_reference front()
const {
return (*
this)[0]; }
99 reference back() {
return (*
this)[size() - 1]; }
100 const_reference back()
const {
return (*
this)[size() - 1]; }
103 void ensure_space(size_type num_elems) {
104 assert(num_elems <= max_size() - size());
105 if (size() + num_elems > capacity()) [[unlikely]] {
106 grow(size() + num_elems);
110 void grow(size_type new_size)
113 grow_trivial(new_size,
sizeof(T));
116 void grow(size_type new_size)
117 requires(!IsTrivial);
121 void push_back(
const T &elem) {
123 unpoison_memory_region(end(),
sizeof(T));
124 ::new (
reinterpret_cast<void *
>(end())) T(elem);
129 void push_back(T &&elem) {
131 unpoison_memory_region(end(),
sizeof(T));
132 ::new (
reinterpret_cast<void *
>(end())) T(::std::move(elem));
136 template <typename... ArgT>
137 reference emplace_back(ArgT &&...args) {
139 unpoison_memory_region(end(),
sizeof(T));
140 ::new (
reinterpret_cast<void *
>(end())) T(::std::forward<ArgT>(args)...);
147 poison_memory_region(end(),
sizeof(T));
151 void reserve(size_type new_cap) {
158 template <
bool Initialize>
159 void resize(size_type new_size) {
161 std::destroy(begin() + new_size, end());
162 poison_memory_region(begin() + new_size, (sz - new_size) *
sizeof(T));
164 }
else if (sz < new_size) {
166 unpoison_memory_region(end(), (new_size - sz) *
sizeof(T));
167 for (pointer it = end(), e = begin() + new_size; it != e; ++it) {
168 Initialize ? ::new (it) T() : ::new (it) T;
175 void resize(size_type new_size) { resize<true>(new_size); }
176 void resize_uninitialized(size_type new_size) { resize<false>(new_size); }
178 void resize(size_type new_size,
const T &init) {
180 std::destroy(begin() + new_size, end());
181 poison_memory_region(begin() + new_size, (sz - new_size) *
sizeof(T));
183 }
else if (sz < new_size) {
185 unpoison_memory_region(end(), (new_size - sz) *
sizeof(T));
186 std::uninitialized_fill(begin() + sz, begin() + new_size, init);
191 iterator erase(iterator start_it, iterator end_it) {
192 iterator res = start_it;
193 while (end_it != end()) {
194 *start_it++ = std::move(*end_it++);
196 std::destroy(start_it, end_it);
197 sz = start_it - begin();
201 template <
typename It>
202 void append(It start_it, It end_it) {
203 size_type n = std::distance(start_it, end_it);
205 unpoison_memory_region(end(), n *
sizeof(T));
206 std::uninitialized_copy(start_it, end_it, end());
211 std::destroy(begin(), end());
212 poison_memory_region(begin(), sz *
sizeof(T));
218void SmallVectorBase<T>::grow(size_type new_size)
222 T *new_alloc =
static_cast<T *
>(grow_malloc(new_size,
sizeof(T), new_cap));
223 std::uninitialized_move(begin(), end(), new_alloc);
224 poison_memory_region(new_alloc + sz, (new_cap - sz) *
sizeof(T));
225 std::destroy(begin(), end());
229 poison_memory_region(data(), cap *
sizeof(T));
236constexpr size_t SmallVectorDefaultSize =
sizeof(T) < 256 ? 256 /
sizeof(T) : 1;
238template <
class T,
size_t N = SmallVectorDefaultSize<T>>
239class SmallVector :
public SmallVectorBase<T> {
244 alignas(T)
char elements[N == 0 ? 1 : N * sizeof(T)];
247 SmallVector() : SmallVectorBase<T>(N) {}
249 SmallVector(
const SmallVector &) =
delete;
250 SmallVector(SmallVector &&) =
delete;
251 SmallVector &operator=(
const SmallVector &) =
delete;
252 SmallVector &operator=(SmallVector &&) =
delete;
255 SmallVector(SmallVector &other) : SmallVectorBase<T>(N) {
256 SmallVectorBase<T>::operator=(other);
258 SmallVector(SmallVectorBase<T> &other) : SmallVectorBase<T>(N) {
259 SmallVectorBase<T>::operator=(other);
262 SmallVector(SmallVector &&other) : SmallVectorBase<T>(N) {
263 SmallVectorBase<T>::operator=(std::move(other));
265 SmallVector(SmallVectorBase<T> &&other) : SmallVectorBase<T>(N) {
266 SmallVectorBase<T>::operator=(std::move(other));
269 SmallVector &operator=(SmallVector &other) {
270 SmallVectorBase<T>::operator=(other);
273 SmallVector &operator=(SmallVectorBase<T> &other) {
274 SmallVectorBase<T>::operator=(other);
278 SmallVector &operator=(SmallVector &&other) {
279 SmallVectorBase<T>::operator=(std::move(other));
282 SmallVector &operator=(SmallVectorBase<T> &&other) {
283 SmallVectorBase<T>::operator=(std::move(other));