41class SmallVectorBase :
public SmallVectorHeader {
44 using size_type = SmallVectorHeader::size_type;
45 using difference_type = std::ptrdiff_t;
47 using const_reference = T
const&;
49 using const_pointer = T
const*;
50 using iterator = pointer;
51 using const_iterator = const_pointer;
52 using reverse_iterator = std::reverse_iterator<iterator>;
53 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
55 SmallVectorBase(SmallVectorBase
const&) =
delete;
56 SmallVectorBase(SmallVectorBase&&) =
delete;
58 SmallVectorBase& operator=(SmallVectorBase
const& other) {
59 if (
this != &other) assign(other.begin(), other.end());
62 SmallVectorBase& operator=(SmallVectorBase&& other)
noexcept(std::is_nothrow_move_constructible_v<T>) {
63 if (
this == &other)
return *
this;
64 if (other.isInline()) {
65 assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
70 mData = std::exchange(other.mData,
nullptr);
71 mSize = std::exchange(other.mSize, 0);
72 mCapacity = std::exchange(other.mCapacity, 0);
76 SmallVectorBase& operator=(std::initializer_list<T> list) {
81 [[nodiscard]] reference operator[](size_type i)
noexcept {
return data()[i]; }
82 [[nodiscard]] const_reference operator[](size_type i)
const noexcept {
return data()[i]; }
83 [[nodiscard]] reference at(size_type i) {
84 if (i >= mSize)
throw std::out_of_range(
"small_vector index out of range");
87 [[nodiscard]] const_reference at(size_type i)
const {
88 if (i >= mSize)
throw std::out_of_range(
"small_vector index out of range");
91 [[nodiscard]] reference front()
noexcept {
return data()[0]; }
92 [[nodiscard]] const_reference front()
const noexcept {
return data()[0]; }
93 [[nodiscard]] reference back()
noexcept {
return data()[mSize - 1]; }
94 [[nodiscard]] const_reference back()
const noexcept {
return data()[mSize - 1]; }
95 [[nodiscard]] pointer data()
noexcept {
return std::launder(
reinterpret_cast<T*
>(mData)); }
96 [[nodiscard]] const_pointer data()
const noexcept {
return std::launder(
reinterpret_cast<T const*
>(mData)); }
98 iterator begin()
noexcept {
return data(); }
99 const_iterator begin()
const noexcept {
return data(); }
100 const_iterator cbegin()
const noexcept {
return data(); }
101 iterator end()
noexcept {
return data() + mSize; }
102 const_iterator end()
const noexcept {
return data() + mSize; }
103 const_iterator cend()
const noexcept {
return end(); }
104 reverse_iterator rbegin()
noexcept {
return reverse_iterator{end()}; }
105 const_reverse_iterator rbegin()
const noexcept {
return const_reverse_iterator{end()}; }
106 const_reverse_iterator crbegin()
const noexcept {
return rbegin(); }
107 reverse_iterator rend()
noexcept {
return reverse_iterator{begin()}; }
108 const_reverse_iterator rend()
const noexcept {
return const_reverse_iterator{begin()}; }
109 const_reverse_iterator crend()
const noexcept {
return rend(); }
111 void reserve(size_type n) {
112 if (n > mCapacity) reallocate(n);
115 void shrink_to_fit() {
116 if (isInline() || mSize == mCapacity)
return;
126 template <
class... Args>
127 reference emplace_back(Args&&... args) {
128 if (mSize < mCapacity)
return emplaceBackNoAllocate(std::forward<Args>(args)...);
129 return *emplaceReallocate(end(), std::forward<Args>(args)...);
131 reference push_back(T
const& value) {
return emplace_back(value); }
132 reference push_back(T&& value) {
return emplace_back(std::move(value)); }
134 template <
class... Args>
135 iterator emplace(const_iterator pos, Args&&... args) {
136 if (pos == cend())
return &emplace_back(std::forward<Args>(args)...);
137 if (mSize == mCapacity)
return emplaceReallocate(pos, std::forward<Args>(args)...);
138 T tmp(std::forward<Args>(args)...);
141 std::construct_at(e, std::move(e[-1]));
143 std::move_backward(p, e - 1, e);
148 iterator insert(const_iterator pos, T
const& value) {
return emplace(pos, value); }
149 iterator insert(const_iterator pos, T&& value) {
return emplace(pos, std::move(value)); }
150 iterator insert(const_iterator pos, size_type count, T
const& value) {
151 auto idx =
static_cast<size_type
>(pos - cbegin());
152 if (count == 0)
return begin() + idx;
154 insertGap(idx, count, [&](T* first, T* last) { std::uninitialized_fill(first, last, tmp); });
155 return begin() + idx;
157 template <std::input_iterator It>
158 iterator insert(const_iterator pos, It first, It last) {
159 auto idx =
static_cast<size_type
>(pos - cbegin());
160 if constexpr (std::forward_iterator<It>) {
161 auto count =
static_cast<size_type
>(std::distance(first, last));
163 insertGap(idx, count, [&](T* f, T*) { std::uninitialized_copy(first, last, f); });
166 for (
auto i = idx; first != last; ++first, ++i) emplace(cbegin() + i, *first);
168 return begin() + idx;
170 iterator insert(const_iterator pos, std::initializer_list<T> list) {
return insert(pos, list.begin(), list.end()); }
172 void pop_back()
noexcept { std::destroy_at(data() + --mSize); }
174 iterator erase(const_iterator pos) {
return erase(pos, pos + 1); }
175 iterator erase(const_iterator first, const_iterator last) {
176 T* f = unwrap(first);
179 T* newEnd = std::move(l, end(), f);
180 std::destroy(newEnd, end());
181 mSize =
static_cast<size_type
>(newEnd - data());
186 void clear()
noexcept {
191 void resize(size_type n) {
192 resizeImpl(n, [](T* f, T* l) { std::uninitialized_value_construct(f, l); });
194 void resize(size_type n, T
const& value) {
195 resizeImpl(n, [&](T* f, T* l) { std::uninitialized_fill(f, l, value); });
198 void assign(size_type count, T
const& value) {
201 std::uninitialized_fill_n(data(), count, value);
204 template <std::input_iterator It>
205 void assign(It first, It last) {
207 if constexpr (std::forward_iterator<It>) {
208 auto count =
static_cast<size_type
>(std::distance(first, last));
210 std::uninitialized_copy(first, last, data());
213 for (; first != last; ++first) emplace_back(*first);
216 void assign(std::initializer_list<T> list) { assign(list.begin(), list.end()); }
218 void swap(SmallVectorBase& other) {
219 if (
this == &other)
return;
220 if (!isInline() && !other.isInline()) {
221 std::swap(mData, other.mData);
222 std::swap(mSize, other.mSize);
223 std::swap(mCapacity, other.mCapacity);
226 SmallVectorBase& small = mSize <= other.mSize ? *this : other;
227 SmallVectorBase& large = mSize <= other.mSize ? other : *
this;
228 small.reserve(large.mSize);
229 large.reserve(small.mSize);
230 size_type common = small.mSize;
231 std::swap_ranges(small.begin(), small.begin() + common, large.begin());
232 std::uninitialized_move(large.begin() + common, large.end(), small.end());
233 std::destroy(large.begin() + common, large.end());
234 std::swap(small.mSize, large.mSize);
237 friend bool operator==(SmallVectorBase
const& a, SmallVectorBase
const& b) {
238 return std::equal(a.begin(), a.end(), b.begin(), b.end());
240 friend auto operator<=>(SmallVectorBase
const& a, SmallVectorBase
const& b) {
241 return std::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end());
245 explicit SmallVectorBase(size_type inlineCap) noexcept : SmallVectorHeader(inlineData(), inlineCap) {}
253 std::byte* inlineData()
noexcept {
return reinterpret_cast<std::byte*
>(
this + 1); }
254 std::byte
const* inlineData()
const noexcept {
return reinterpret_cast<std::byte const*
>(
this + 1); }
256 bool isInline()
const noexcept {
return mData == inlineData(); }
258 static T* unwrap(const_iterator it)
noexcept {
return const_cast<T*
>(it); }
260 static T* allocate(size_type n) {
261 size_t bytes =
size_t{n} *
sizeof(T);
262 void* p = memory::getDefaultAllocator()._allocate(bytes);
263 if (!p) memory::throwMemoryException(bytes);
264 return static_cast<T*
>(p);
266 static void deallocate(
void* p)
noexcept {
267 if (p) memory::getDefaultAllocator()._release(p);
269 void freeHeap()
noexcept { freeHeap(data()); }
270 void freeHeap(T* p)
noexcept {
271 if (
reinterpret_cast<std::byte*
>(p) != inlineData()) deallocate(p);
274 void destroyAll()
noexcept { std::destroy(begin(), end()); }
276 static void relocate(T* first, T* last, T* dest) {
277 if constexpr (std::is_trivially_copyable_v<T>) {
278 if (first != last) std::memmove(dest, first, (last - first) *
sizeof(T));
280 std::uninitialized_move(first, last, dest);
281 std::destroy(first, last);
285 size_type newCapacity(size_type required)
const {
286 if (mCapacity > max_size() -
static_cast<size_type
>(mCapacity / growthFactor))
return max_size();
287 auto grown =
static_cast<size_type
>(mCapacity * growthFactor);
288 return std::max(grown, required);
291 void reallocate(size_type n) {
292 T* fresh = allocate(n);
295 relocate(old, old + mSize, fresh);
301 mData =
reinterpret_cast<std::byte*
>(fresh);
305 template <
class... Args>
306 reference emplaceBackNoAllocate(Args&&... args) {
307 T* p = std::construct_at(end(), std::forward<Args>(args)...);
312 template <
class Fill>
313 void insertGap(size_type idx, size_type count, Fill&& fill) {
314 if (mSize > max_size() - count)
throw std::length_error(
"New would be greater than max_size");
315 size_type required = mSize + count;
316 if (required > mCapacity) {
317 size_type cap = newCapacity(required);
318 T* fresh = allocate(cap);
321 fill(fresh + idx, fresh + idx + count);
326 relocate(old, old + idx, fresh);
327 relocate(old + idx, old + mSize, fresh + idx + count);
329 mData =
reinterpret_cast<std::byte*
>(fresh);
336 auto tail =
static_cast<size_type
>(e - p);
341 TempBuffer tmp(count);
342 fill(tmp.get(), tmp.get() + count);
345 std::uninitialized_move(e - count, e, e);
346 std::move_backward(p, e - count, e);
347 std::move(tmp.get(), tmp.get() + count, p);
349 std::uninitialized_move(p, e, p + count);
350 std::move(tmp.get(), tmp.get() + tail, p);
351 std::uninitialized_move(tmp.get() + tail, tmp.get() + count, e);
357 template <
class... Args>
358 iterator emplaceReallocate(const_iterator pos, Args&&... args) {
359 auto idx =
static_cast<size_type
>(pos - cbegin());
360 insertGap(idx, 1, [&](T* f, T*) { std::construct_at(f, std::forward<Args>(args)...); });
361 return begin() + idx;
364 template <
class Fill>
365 void resizeImpl(size_type n, Fill&& fill) {
367 std::destroy(begin() + n, end());
368 }
else if (n > mSize) {
370 fill(end(), data() + n);
381 explicit TempBuffer(size_type n) : mPtr(allocate(n)), mCount(n) {}
382 TempBuffer(TempBuffer
const&) =
delete;
383 TempBuffer& operator=(TempBuffer
const&) =
delete;
385 std::destroy(mPtr, mPtr + mBuilt);
388 T* get()
const noexcept {
return mPtr; }
389 void built()
noexcept { mBuilt = mCount; }