LMMS
Loading...
Searching...
No Matches
ArrayVector.h
Go to the documentation of this file.
1/*
2 * ArrayVector.h
3 *
4 * Copyright (c) 2023 Dominic Clark
5 *
6 * This file is part of LMMS - https://lmms.io
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program (see COPYING); if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25#ifndef LMMS_ARRAY_VECTOR_H
26#define LMMS_ARRAY_VECTOR_H
27
28#include <algorithm>
29#include <cassert>
30#include <cstddef>
31#include <iterator>
32#include <memory>
33#include <new>
34#include <stdexcept>
35#include <utility>
36#include <type_traits>
37
38namespace lmms {
39
49template<typename T, std::size_t N>
51{
52public:
53 using size_type = std::size_t;
54 using difference_type = std::ptrdiff_t;
55 using value_type = T;
56 using reference = T&;
57 using const_reference = const T&;
58 using pointer = T*;
59 using const_pointer = const T*;
62 using reverse_iterator = std::reverse_iterator<iterator>;
63 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
64
65 ArrayVector() = default;
66
67 ArrayVector(const ArrayVector& other) noexcept(std::is_nothrow_copy_constructible_v<T>) :
68 m_size{other.m_size}
69 {
70 std::uninitialized_copy(other.begin(), other.end(), begin());
71 }
72
73 ArrayVector(ArrayVector&& other) noexcept(std::is_nothrow_move_constructible_v<T>) :
74 m_size{other.m_size}
75 {
76 std::uninitialized_move(other.begin(), other.end(), begin());
77 other.clear();
78 }
79
80 ArrayVector(size_type count, const T& value) noexcept(std::is_nothrow_copy_constructible_v<T>) :
82 {
83 assert(count <= N);
84 std::uninitialized_fill_n(begin(), count, value);
85 }
86
87 explicit ArrayVector(size_type count) noexcept(std::is_nothrow_default_constructible_v<T>) :
89 {
90 assert(count <= N);
91 std::uninitialized_value_construct_n(begin(), count);
92 }
93
94 template<std::input_iterator It>
95 ArrayVector(It first, It last)
96 {
97 // Can't check the size first as the iterator may not be multipass
98 const auto end = std::uninitialized_copy(first, last, begin());
99 m_size = end - begin();
100 assert(m_size <= N);
101 }
102
103 ArrayVector(std::initializer_list<T> il) noexcept(std::is_nothrow_copy_constructible_v<T>) :
104 m_size{il.size()}
105 {
106 assert(il.size() <= N);
107 std::uninitialized_copy(il.begin(), il.end(), begin());
108 }
109
110 ~ArrayVector() { std::destroy(begin(), end()); }
111
113 noexcept(std::is_nothrow_copy_assignable_v<T> && std::is_nothrow_copy_constructible_v<T>)
114 {
115 if (this != &other) {
116 const auto toAssign = std::min(other.size(), size());
117 const auto assignedFromEnd = other.begin() + toAssign;
118 const auto assignedToEnd = std::copy(other.begin(), other.begin() + toAssign, begin());
119 std::destroy(assignedToEnd, end());
120 std::uninitialized_copy(assignedFromEnd, other.end(), end());
121 m_size = other.size();
122 }
123 return *this;
124 }
125
127 noexcept(std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>)
128 {
129 if (this != &other) {
130 const auto toAssign = std::min(other.size(), size());
131 const auto assignedFromEnd = other.begin() + toAssign;
132 const auto assignedToEnd = std::move(other.begin(), other.begin() + toAssign, begin());
133 std::destroy(assignedToEnd, end());
134 std::uninitialized_move(assignedFromEnd, other.end(), end());
135 m_size = other.size();
136 other.clear();
137 }
138 return *this;
139 }
140
141 ArrayVector& operator=(std::initializer_list<T> il)
142 noexcept(std::is_nothrow_copy_assignable_v<T> && std::is_nothrow_copy_constructible_v<T>)
143 {
144 assert(il.size() <= N);
145 const auto toAssign = std::min(il.size(), size());
146 const auto assignedFromEnd = il.begin() + toAssign;
147 const auto assignedToEnd = std::copy(il.begin(), assignedFromEnd, begin());
148 std::destroy(assignedToEnd, end());
149 std::uninitialized_copy(assignedFromEnd, il.end(), end());
150 m_size = il.size();
151 return *this;
152 }
153
154 void assign(size_type count, const T& value)
155 noexcept(std::is_nothrow_copy_assignable_v<T> && std::is_nothrow_copy_constructible_v<T>)
156 {
157 assert(count <= N);
158 const auto temp = value;
159 const auto toAssign = std::min(count, size());
160 const auto toConstruct = count - toAssign;
161 const auto assignedToEnd = std::fill_n(begin(), toAssign, temp);
162 std::destroy(assignedToEnd, end());
163 std::uninitialized_fill_n(assignedToEnd, toConstruct, temp);
164 m_size = count;
165 }
166
167 template<std::input_iterator It>
168 void assign(It first, It last)
169 {
170 // Can't check the size first as the iterator may not be multipass
171 auto pos = begin();
172 for (; first != last && pos != end(); ++pos, ++first) {
173 *pos = *first;
174 }
175 std::destroy(pos, end());
176 pos = std::uninitialized_copy(first, last, pos);
177 m_size = pos - begin();
178 assert(m_size <= N);
179 }
180
182 {
183 if (index >= m_size) { throw std::out_of_range{"index out of range"}; }
184 return data()[index];
185 }
186
188 {
189 if (index >= m_size) { throw std::out_of_range{"index out of range"}; }
190 return data()[index];
191 }
192
194 {
195 assert(index < m_size);
196 return data()[index];
197 }
198
200 {
201 assert(index < m_size);
202 return data()[index];
203 }
204
207
210
211 pointer data() noexcept { return *std::launder(reinterpret_cast<T(*)[N]>(m_data)); }
212 const_pointer data() const noexcept { return *std::launder(reinterpret_cast<const T(*)[N]>(m_data)); }
213
214 iterator begin() noexcept { return data(); }
217
218 iterator end() noexcept { return data() + m_size; }
221
222 reverse_iterator rbegin() noexcept { return std::reverse_iterator{end()}; }
223 const_reverse_iterator rbegin() const noexcept { return std::reverse_iterator{end()}; }
224 const_reverse_iterator crbegin() const noexcept { return std::reverse_iterator{cend()}; }
225
226 reverse_iterator rend() noexcept { return std::reverse_iterator{begin()}; }
227 const_reverse_iterator rend() const noexcept { return std::reverse_iterator{begin()}; }
228 const_reverse_iterator crend() const noexcept { return std::reverse_iterator{cbegin()}; }
229
230 bool empty() const noexcept { return m_size == 0; }
231 bool full() const noexcept { return m_size == N; }
235
237 {
238 std::destroy(begin(), end());
239 m_size = 0;
240 }
241
242 iterator insert(const_iterator pos, const T& value) { return emplace(pos, value); }
243 iterator insert(const_iterator pos, T&& value) { return emplace(pos, std::move(value)); }
244
246 {
247 assert(m_size + count <= N);
248 assert(cbegin() <= pos && pos <= cend());
249 const auto mutPos = begin() + (pos - cbegin());
250 const auto newEnd = std::uninitialized_fill_n(end(), count, value);
251 std::rotate(mutPos, end(), newEnd);
252 m_size += count;
253 return mutPos;
254 }
255
256 template<std::input_iterator It>
257 iterator insert(const_iterator pos, It first, It last)
258 {
259 // Can't check the size first as the iterator may not be multipass
260 assert(cbegin() <= pos && pos <= cend());
261 const auto mutPos = begin() + (pos - cbegin());
262 const auto newEnd = std::uninitialized_copy(first, last, end());
263 std::rotate(mutPos, end(), newEnd);
264 m_size = newEnd - begin();
265 assert(m_size <= N);
266 return mutPos;
267 }
268
269 iterator insert(const_iterator pos, std::initializer_list<T> il) { return insert(pos, il.begin(), il.end()); }
270
271 template<typename... Args>
272 iterator emplace(const_iterator pos, Args&&... args)
273 {
274 assert(cbegin() <= pos && pos <= cend());
275 const auto mutPos = begin() + (pos - cbegin());
276 emplace_back(std::forward<Args>(args)...);
277 std::rotate(mutPos, end() - 1, end());
278 return mutPos;
279 }
280
281 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
283 {
284 assert(cbegin() <= first && first <= last && last <= cend());
285 const auto mutFirst = begin() + (first - cbegin());
286 const auto mutLast = begin() + (last - cbegin());
287 const auto newEnd = std::move(mutLast, end(), mutFirst);
288 std::destroy(newEnd, end());
289 m_size = newEnd - begin();
290 return mutFirst;
291 }
292
293 void push_back(const T& value) { emplace_back(value); }
294 void push_back(T&& value) { emplace_back(std::move(value)); }
295
296 template<typename... Args>
297 reference emplace_back(Args&&... args)
298 {
299 assert(!full());
300 const auto result = std::construct_at(end(), std::forward<Args>(args)...);
301 ++m_size;
302 return *result;
303 }
304
305 void pop_back()
306 {
307 assert(!empty());
308 --m_size;
309 std::destroy_at(end());
310 }
311
313 {
314 if (size > N) { throw std::length_error{"size exceeds maximum size"}; }
315 if (size < m_size) {
316 std::destroy(begin() + size, end());
317 } else {
318 std::uninitialized_value_construct(end(), begin() + size);
319 }
320 m_size = size;
321 }
322
324 {
325 if (size > N) { throw std::length_error{"size exceeds maximum size"}; }
326 if (size < m_size) {
327 std::destroy(begin() + size, end());
328 } else {
329 std::uninitialized_fill(end(), begin() + size, value);
330 }
331 m_size = size;
332 }
333
334 void swap(ArrayVector& other)
335 noexcept(std::is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible_v<T>)
336 {
337 using std::swap;
338 swap(*this, other);
339 }
340
342 noexcept(std::is_nothrow_swappable_v<T> && std::is_nothrow_move_constructible_v<T>)
343 {
344 const auto toSwap = std::min(a.size(), b.size());
345 const auto aSwapEnd = a.begin() + toSwap;
346 const auto bSwapEnd = b.begin() + toSwap;
347 std::swap_ranges(a.begin(), aSwapEnd, b.begin());
348 std::uninitialized_move(aSwapEnd, a.end(), bSwapEnd);
349 std::uninitialized_move(bSwapEnd, b.end(), aSwapEnd);
350 std::destroy(aSwapEnd, a.end());
351 std::destroy(bSwapEnd, b.end());
352 std::swap(a.m_size, b.m_size);
353 }
354
355 friend constexpr auto operator<=>(const ArrayVector& l, const ArrayVector& r)
356 {
357 return std::lexicographical_compare_three_way(l.begin(), l.end(), r.begin(), r.end());
358 }
359
360 friend bool operator==(const ArrayVector& l, const ArrayVector& r)
361 {
362 return std::equal(l.begin(), l.end(), r.begin(), r.end());
363 }
364
365private:
366 alignas(T) std::byte m_data[std::max(N * sizeof(T), std::size_t{1})]; // Intentionally a raw array
368};
369
370} // namespace lmms
371
372#endif // LMMS_ARRAY_VECTOR_H
#define noexcept
Definition DistrhoDefines.h:72
assert(0)
uint8_t a
Definition Spc_Cpu.h:141
reference operator[](size_type index) noexcept
Definition ArrayVector.h:193
const T & const_reference
Definition ArrayVector.h:57
const T * const_pointer
Definition ArrayVector.h:59
ArrayVector(It first, It last)
Definition ArrayVector.h:95
reference emplace_back(Args &&... args)
Definition ArrayVector.h:297
friend bool operator==(const ArrayVector &l, const ArrayVector &r)
Definition ArrayVector.h:360
const_pointer const_iterator
Definition ArrayVector.h:61
ArrayVector & operator=(ArrayVector &&other) noexcept(std::is_nothrow_move_assignable_v< T > &&std::is_nothrow_move_constructible_v< T >)
Definition ArrayVector.h:126
const_iterator cbegin() const noexcept
Definition ArrayVector.h:216
void push_back(T &&value)
Definition ArrayVector.h:294
size_type max_size() const noexcept
Definition ArrayVector.h:233
reference front() noexcept
Definition ArrayVector.h:205
std::size_t size_type
Definition ArrayVector.h:53
bool empty() const noexcept
Definition ArrayVector.h:230
reverse_iterator rbegin() noexcept
Definition ArrayVector.h:222
iterator insert(const_iterator pos, It first, It last)
Definition ArrayVector.h:257
const_reference back() const noexcept
Definition ArrayVector.h:209
ArrayVector(const ArrayVector &other) noexcept(std::is_nothrow_copy_constructible_v< T >)
Definition ArrayVector.h:67
iterator erase(const_iterator pos)
Definition ArrayVector.h:281
~ArrayVector()
Definition ArrayVector.h:110
const_reverse_iterator rend() const noexcept
Definition ArrayVector.h:227
T value_type
Definition ArrayVector.h:55
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition ArrayVector.h:63
iterator emplace(const_iterator pos, Args &&... args)
Definition ArrayVector.h:272
const_reverse_iterator crbegin() const noexcept
Definition ArrayVector.h:224
std::reverse_iterator< iterator > reverse_iterator
Definition ArrayVector.h:62
const_iterator cend() const noexcept
Definition ArrayVector.h:220
iterator erase(const_iterator first, const_iterator last)
Definition ArrayVector.h:282
void swap(ArrayVector &other) noexcept(std::is_nothrow_swappable_v< T > &&std::is_nothrow_move_constructible_v< T >)
Definition ArrayVector.h:334
void resize(size_type size, const value_type &value)
Definition ArrayVector.h:323
void clear() noexcept
Definition ArrayVector.h:236
void push_back(const T &value)
Definition ArrayVector.h:293
ArrayVector(size_type count) noexcept(std::is_nothrow_default_constructible_v< T >)
Definition ArrayVector.h:87
reverse_iterator rend() noexcept
Definition ArrayVector.h:226
const_reference at(size_type index) const
Definition ArrayVector.h:187
std::byte m_data[std::max(N *sizeof(T), std::size_t{1})]
Definition ArrayVector.h:366
iterator insert(const_iterator pos, std::initializer_list< T > il)
Definition ArrayVector.h:269
size_type capacity() const noexcept
Definition ArrayVector.h:234
iterator insert(const_iterator pos, size_type count, const T &value)
Definition ArrayVector.h:245
size_type size() const noexcept
Definition ArrayVector.h:232
const_reference operator[](size_type index) const noexcept
Definition ArrayVector.h:199
ArrayVector(std::initializer_list< T > il) noexcept(std::is_nothrow_copy_constructible_v< T >)
Definition ArrayVector.h:103
void assign(size_type count, const T &value) noexcept(std::is_nothrow_copy_assignable_v< T > &&std::is_nothrow_copy_constructible_v< T >)
Definition ArrayVector.h:154
iterator begin() noexcept
Definition ArrayVector.h:214
const_iterator begin() const noexcept
Definition ArrayVector.h:215
reference at(size_type index)
Definition ArrayVector.h:181
pointer data() noexcept
Definition ArrayVector.h:211
T & reference
Definition ArrayVector.h:56
pointer iterator
Definition ArrayVector.h:60
const_iterator end() const noexcept
Definition ArrayVector.h:219
bool full() const noexcept
Definition ArrayVector.h:231
ArrayVector & operator=(std::initializer_list< T > il) noexcept(std::is_nothrow_copy_assignable_v< T > &&std::is_nothrow_copy_constructible_v< T >)
Definition ArrayVector.h:141
size_type m_size
Definition ArrayVector.h:367
iterator insert(const_iterator pos, T &&value)
Definition ArrayVector.h:243
const_reverse_iterator crend() const noexcept
Definition ArrayVector.h:228
ArrayVector(ArrayVector &&other) noexcept(std::is_nothrow_move_constructible_v< T >)
Definition ArrayVector.h:73
void assign(It first, It last)
Definition ArrayVector.h:168
const_pointer data() const noexcept
Definition ArrayVector.h:212
void pop_back()
Definition ArrayVector.h:305
ArrayVector()=default
ArrayVector(size_type count, const T &value) noexcept(std::is_nothrow_copy_constructible_v< T >)
Definition ArrayVector.h:80
T * pointer
Definition ArrayVector.h:58
reference back() noexcept
Definition ArrayVector.h:208
friend void swap(ArrayVector &a, ArrayVector &b) noexcept(std::is_nothrow_swappable_v< T > &&std::is_nothrow_move_constructible_v< T >)
Definition ArrayVector.h:341
friend constexpr auto operator<=>(const ArrayVector &l, const ArrayVector &r)
Definition ArrayVector.h:355
std::ptrdiff_t difference_type
Definition ArrayVector.h:54
const_reverse_iterator rbegin() const noexcept
Definition ArrayVector.h:223
ArrayVector & operator=(const ArrayVector &other) noexcept(std::is_nothrow_copy_assignable_v< T > &&std::is_nothrow_copy_constructible_v< T >)
Definition ArrayVector.h:112
iterator insert(const_iterator pos, const T &value)
Definition ArrayVector.h:242
const_reference front() const noexcept
Definition ArrayVector.h:206
iterator end() noexcept
Definition ArrayVector.h:218
void resize(size_type size)
Definition ArrayVector.h:312
int * l
Definition inflate.c:1579
static PuglViewHint int value
Definition pugl.h:1708
Definition AudioAlsa.cpp:35
#define N
Definition nseel-cfunc.c:36
int r
Definition crypt.c:458
b
Definition crypt.c:628
int result
Definition process.c:1455
_WDL_CSTRING_PREFIX void INT_PTR count
Definition wdlcstring.h:263
#define const
Definition zconf.h:137