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) : ptr(small_ptr()), sz(0), cap(cap) {}
29 void *small_ptr() {
return static_cast<void *
>(
this + 1); }
30 const void *small_ptr()
const {
return static_cast<const void *
>(
this + 1); }
32 bool is_small()
const {
return ptr == small_ptr(); }
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());
74 SmallVectorBase &operator=(SmallVectorBase &&other) {
76 if (!other.is_small()) {
80 other.ptr = other.small_ptr();
84 reserve(other.size());
85 unpoison_memory_region(begin(), other.size() *
sizeof(T));
86 std::uninitialized_move(other.begin(), other.end(), begin());
94 pointer data() {
return reinterpret_cast<T *
>(ptr); }
95 const_pointer data()
const {
return reinterpret_cast<const T *
>(ptr); }
97 iterator begin() {
return data(); }
98 iterator end() {
return data() + sz; }
99 const_iterator begin()
const {
return data(); }
100 const_iterator end()
const {
return data() + sz; }
101 const_iterator cbegin()
const {
return data(); }
102 const_iterator cend()
const {
return data() + sz; }
105 static size_type max_size() {
return size_type(-1) /
sizeof(T); }
107 reference operator[](size_type idx) {
108 assert(idx < size());
111 const_reference operator[](size_type idx)
const {
112 assert(idx < size());
116 reference front() {
return (*
this)[0]; }
117 const_reference front()
const {
return (*
this)[0]; }
118 reference back() {
return (*
this)[size() - 1]; }
119 const_reference back()
const {
return (*
this)[size() - 1]; }
122 void ensure_space(size_type num_elems) {
123 assert(num_elems <= max_size() - size());
124 if (size() + num_elems > capacity()) [[unlikely]] {
125 grow(size() + num_elems);
129 void grow(size_type new_size)
132 grow_trivial(new_size,
sizeof(T));
135 void grow(size_type new_size)
136 requires(!IsTrivial);
140 void push_back(
const T &elem) {
142 unpoison_memory_region(end(),
sizeof(T));
143 ::new (
reinterpret_cast<void *
>(end())) T(elem);
148 void push_back(T &&elem) {
150 unpoison_memory_region(end(),
sizeof(T));
151 ::new (
reinterpret_cast<void *
>(end())) T(::std::move(elem));
155 template <typename... ArgT>
156 reference emplace_back(ArgT &&...args) {
158 unpoison_memory_region(end(),
sizeof(T));
159 ::new (
reinterpret_cast<void *
>(end())) T(::std::forward<ArgT>(args)...);
166 poison_memory_region(end(),
sizeof(T));
170 void reserve(size_type new_cap) {
177 template <
bool Initialize>
178 void resize(size_type new_size) {
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 for (pointer it = end(), e = begin() + new_size; it != e; ++it) {
187 Initialize ? ::new (it) T() : ::new (it) T;
194 void resize(size_type new_size) { resize<true>(new_size); }
195 void resize_uninitialized(size_type new_size) { resize<false>(new_size); }
197 void resize(size_type new_size,
const T &init) {
199 std::destroy(begin() + new_size, end());
200 poison_memory_region(begin() + new_size, (sz - new_size) *
sizeof(T));
202 }
else if (sz < new_size) {
204 unpoison_memory_region(end(), (new_size - sz) *
sizeof(T));
205 std::uninitialized_fill(begin() + sz, begin() + new_size, init);
210 iterator erase(iterator start_it, iterator end_it) {
211 iterator res = start_it;
212 while (end_it != end()) {
213 *start_it++ = std::move(*end_it++);
215 std::destroy(start_it, end_it);
216 sz = start_it - begin();
220 template <
typename It>
221 void append(It start_it, It end_it) {
222 size_type n = std::distance(start_it, end_it);
224 unpoison_memory_region(end(), n *
sizeof(T));
225 std::uninitialized_copy(start_it, end_it, end());
230 std::destroy(begin(), end());
231 poison_memory_region(begin(), sz *
sizeof(T));
237void SmallVectorBase<T>::grow(size_type new_size)
241 T *new_alloc =
static_cast<T *
>(grow_malloc(new_size,
sizeof(T), new_cap));
242 std::uninitialized_move(begin(), end(), new_alloc);
243 poison_memory_region(new_alloc + sz, (new_cap - sz) *
sizeof(T));
244 std::destroy(begin(), end());
248 poison_memory_region(data(), cap *
sizeof(T));
255constexpr size_t SmallVectorDefaultSize =
sizeof(T) < 256 ? 256 /
sizeof(T) : 1;
257template <
class T,
size_t N = SmallVectorDefaultSize<T>>
258class SmallVector :
public SmallVectorBase<T> {
263 alignas(T)
char elements[N == 0 ? 1 : N * sizeof(T)];
266 SmallVector() : SmallVectorBase<T>(N) {}
268 SmallVector(
const SmallVector &) =
delete;
269 SmallVector &operator=(
const SmallVector &) =
delete;
272 SmallVector(SmallVector &other) : SmallVectorBase<T>(N) {
273 SmallVectorBase<T>::operator=(other);
275 SmallVector(SmallVectorBase<T> &other) : SmallVectorBase<T>(N) {
276 SmallVectorBase<T>::operator=(other);
280 SmallVector(SmallVector &&other) : SmallVectorBase<T>(N) {
281 SmallVectorBase<T>::operator=(std::move(other));
283 SmallVector(SmallVectorBase<T> &&other) : SmallVectorBase<T>(N) {
284 SmallVectorBase<T>::operator=(std::move(other));
288 SmallVector &operator=(SmallVector &other) {
289 SmallVectorBase<T>::operator=(other);
292 SmallVector &operator=(SmallVectorBase<T> &other) {
293 SmallVectorBase<T>::operator=(other);
298 SmallVector &operator=(SmallVector &&other) {
299 SmallVectorBase<T>::operator=(std::move(other));
302 SmallVector &operator=(SmallVectorBase<T> &&other) {
303 SmallVectorBase<T>::operator=(std::move(other));