34 using const_reference =
const T&;
36 using const_pointer =
const T*;
38 using difference_type = darr_ext_detail::difference_type;
39 using size_type = darr_ext_detail::size_type;
41 using iterator = pointer;
42 using const_iterator = const_pointer;
45 static constexpr size_t value_size =
sizeof(T);
46 static constexpr size_type extent = N;
47 static constexpr uint32_t allocated_bytes = view_policy::get_min_byte_size(0, N);
53 uint8_t* m_pDataHeap =
nullptr;
55 uint8_t* m_pData = m_data;
57 size_type m_cnt = size_type(0);
59 size_type m_cap = extent;
62 const auto cnt = size();
63 const auto cap = capacity();
66 if GAIA_LIKELY (cnt < cap)
71 m_cap = (cap * 3 + 1) / 2;
73 if GAIA_UNLIKELY (m_pDataHeap ==
nullptr) {
75 m_pDataHeap = view_policy::template alloc<Allocator>(m_cap);
76 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_pDataHeap, m_cap, cnt);
77 mem::move_elements<T, false>(m_pDataHeap, m_data, cnt, 0, m_cap, cap);
80 auto* pDataOld = m_pDataHeap;
81 m_pDataHeap = view_policy::template alloc<Allocator>(m_cap);
82 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_pDataHeap, m_cap, cnt);
83 mem::move_elements<T, false>(m_pDataHeap, pDataOld, cnt, 0, m_cap, cap);
84 view_policy::template free<Allocator>(pDataOld, cap, cnt);
87 m_pData = m_pDataHeap;
94 darr_ext(size_type count, const_reference value) {
102 template <
typename InputIt>
103 darr_ext(InputIt first, InputIt last) {
104 const auto count = (size_type)core::distance(first, last);
107 if constexpr (std::is_pointer_v<InputIt>) {
108 for (size_type i = 0; i < count; ++i)
109 operator[](i) = first[i];
110 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
111 for (size_type i = 0; i < count; ++i)
112 operator[](i) = *(first[i]);
115 for (
auto it = first; it != last; ++it)
116 operator[](++i) = *it;
125 GAIA_ASSERT(core::addressof(other) !=
this);
128 if (other.m_pDataHeap ==
nullptr) {
129 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_data, extent, other.size());
130 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
131 GAIA_MEM_SANI_DEL_BLOCK(value_size, other.m_data, extent, other.size());
132 m_pDataHeap =
nullptr;
135 m_pDataHeap = other.m_pDataHeap;
136 m_pData = m_pDataHeap;
142 other.m_pDataHeap =
nullptr;
143 other.m_pData = other.m_data;
144 other.m_cnt = size_type(0);
145 other.m_cap = extent;
148 darr_ext& operator=(std::initializer_list<T> il) {
149 *
this =
darr_ext(il.begin(), il.end());
154 GAIA_ASSERT(core::addressof(other) !=
this);
156 resize(other.size());
157 mem::copy_elements<T, false>(
158 m_pData, (
const uint8_t*)other.m_pData, other.size(), 0, capacity(), other.capacity());
164 GAIA_ASSERT(core::addressof(other) !=
this);
167 view_policy::template free<Allocator>(m_pDataHeap, m_cap, m_cnt);
170 if (other.m_pDataHeap ==
nullptr) {
171 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_data, extent, other.size());
172 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
173 GAIA_MEM_SANI_DEL_BLOCK(value_size, other.m_data, extent, other.size());
174 m_pDataHeap =
nullptr;
177 m_pDataHeap = other.m_pDataHeap;
178 m_pData = m_pDataHeap;
184 other.m_pDataHeap =
nullptr;
185 other.m_pData = other.m_data;
186 other.m_cnt = size_type(0);
187 other.m_cap = extent;
193 view_policy::template free<Allocator>(m_pDataHeap, m_cap, m_cnt);
196 GAIA_CLANG_WARNING_PUSH()
198 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
200 GAIA_NODISCARD pointer data()
noexcept {
201 return reinterpret_cast<pointer
>(m_pData);
204 GAIA_NODISCARD const_pointer data()
const noexcept {
205 return reinterpret_cast<const_pointer
>(m_pData);
208 GAIA_NODISCARD
decltype(
auto)
operator[](size_type pos)
noexcept {
209 GAIA_ASSERT(pos < size());
210 return view_policy::set({(
typename view_policy::TargetCastType)m_pData, size()}, pos);
213 GAIA_NODISCARD
decltype(
auto)
operator[](size_type pos)
const noexcept {
214 GAIA_ASSERT(pos < size());
215 return view_policy::get({(
typename view_policy::TargetCastType)m_pData, size()}, pos);
218 GAIA_CLANG_WARNING_POP()
220 void reserve(size_type cap) {
224 auto* pDataOld = m_pDataHeap;
225 m_pDataHeap = view_policy::template alloc<Allocator>(cap);
226 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_pDataHeap, cap, m_cnt);
227 if (pDataOld !=
nullptr) {
228 mem::move_elements<T, false>(m_pDataHeap, pDataOld, m_cnt, 0, cap, m_cap);
229 view_policy::template free<Allocator>(pDataOld, m_cap, m_cnt);
231 mem::move_elements<T, false>(m_pDataHeap, m_data, m_cnt, 0, cap, m_cap);
232 GAIA_MEM_SANI_DEL_BLOCK(value_size, m_data, m_cap, m_cnt);
236 m_pData = m_pDataHeap;
239 void resize(size_type count) {
246 core::call_dtor_n(&data()[count], m_cnt - count);
247 GAIA_MEM_SANI_POP_N(value_size, data(), m_cap, m_cnt, m_cnt - count);
254 if (count <= m_cap) {
256 GAIA_MEM_SANI_PUSH_N(value_size, data(), m_cap, m_cnt, count - m_cnt);
257 core::call_ctor_n(&data()[m_cnt], count - m_cnt);
263 auto* pDataOld = m_pDataHeap;
264 m_pDataHeap = view_policy::template alloc<Allocator>(count);
265 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_pDataHeap, count, count);
266 auto* pDataNew =
reinterpret_cast<pointer
>(m_pDataHeap);
267 if (pDataOld !=
nullptr) {
268 mem::move_elements<T, false>(m_pDataHeap, pDataOld, m_cnt, 0, count, m_cap);
269 core::call_ctor_n(&pDataNew[m_cnt], count - m_cnt);
270 view_policy::template free<Allocator>(pDataOld, m_cap, m_cnt);
272 mem::move_elements<T, false>(m_pDataHeap, m_data, m_cnt, 0, count, m_cap);
273 GAIA_MEM_SANI_DEL_BLOCK(value_size, m_data, m_cap, m_cnt);
278 m_pData = m_pDataHeap;
281 void resize(size_type count, const_reference value) {
282 const auto oldCount = m_cnt;
285 if constexpr (std::is_copy_constructible_v<value_type>) {
286 const value_type valueCopy = value;
287 for (size_type i = oldCount; i < m_cnt; ++i)
288 operator[](i) = valueCopy;
290 for (size_type i = oldCount; i < m_cnt; ++i)
291 operator[](i) = value;
295 void push_back(
const T& arg) {
298 GAIA_MEM_SANI_PUSH(value_size, data(), m_cap, m_cnt);
299 auto* ptr = &data()[m_cnt++];
300 core::call_ctor(ptr, arg);
303 void push_back(T&& arg) {
306 GAIA_MEM_SANI_PUSH(value_size, data(), m_cap, m_cnt);
307 auto* ptr = &data()[m_cnt++];
308 core::call_ctor(ptr, GAIA_MOV(arg));
311 template <
typename... Args>
312 decltype(
auto) emplace_back(Args&&... args) {
315 GAIA_MEM_SANI_PUSH(value_size, data(), m_cap, m_cnt);
316 auto* ptr = &data()[m_cnt++];
317 core::call_ctor(ptr, GAIA_FWD(args)...);
318 return (reference)*ptr;
321 void pop_back()
noexcept {
322 GAIA_ASSERT(!empty());
324 auto* ptr = &data()[m_cnt - 1];
325 core::call_dtor(ptr);
326 GAIA_MEM_SANI_POP(value_size, data(), m_cap, m_cnt);
334 iterator
insert(iterator pos,
const T& arg) {
335 GAIA_ASSERT(pos >= data());
336 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
338 const auto idxSrc = (size_type)core::distance(begin(), pos);
340 const auto idxDst = (size_type)core::distance(begin(), end()) + 1;
342 GAIA_MEM_SANI_PUSH(value_size, data(), m_cap, m_cnt);
343 mem::shift_elements_right<T, false>(m_pData, idxDst, idxSrc, m_cap);
344 auto* ptr = &data()[idxSrc];
345 core::call_ctor(ptr, arg);
349 return iterator(ptr);
356 GAIA_ASSERT(pos >= data());
357 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
359 const auto idxSrc = (size_type)core::distance(begin(), pos);
361 const auto idxDst = (size_type)core::distance(begin(), end());
363 GAIA_MEM_SANI_PUSH(value_size, data(), m_cap, m_cnt);
364 mem::shift_elements_right<T, false>(m_pData, idxDst, idxSrc, m_cap);
365 auto* ptr = &data()[idxSrc];
366 core::call_ctor(ptr, GAIA_MOV(arg));
370 return iterator(ptr);
375 iterator
erase(iterator pos)
noexcept {
376 GAIA_ASSERT(pos >= data());
377 GAIA_ASSERT(empty() || (pos < iterator(data() + size())));
382 const auto idxSrc = (size_type)core::distance(begin(), pos);
383 const auto idxDst = (size_type)core::distance(begin(), end()) - 1;
385 mem::shift_elements_left<T, false>(m_pData, idxDst, idxSrc, m_cap);
387 auto* ptr = &data()[m_cnt - 1];
388 core::call_dtor(ptr);
389 GAIA_MEM_SANI_POP(value_size, data(), m_cap, m_cnt);
393 return iterator(&data()[idxSrc]);
399 iterator
erase(iterator first, iterator last)
noexcept {
400 GAIA_ASSERT(first >= data())
401 GAIA_ASSERT(empty() || (first < iterator(data() + size())));
402 GAIA_ASSERT(last > first);
403 GAIA_ASSERT(last <= iterator(data() + size()));
408 const auto idxSrc = (size_type)core::distance(begin(), first);
409 const auto idxDst = size();
410 const auto cnt = (size_type)(last - first);
412 mem::shift_elements_left_fast<T, false>(m_pData, idxDst, idxSrc, cnt, m_cap);
414 core::call_dtor_n(&data()[m_cnt - cnt], cnt);
415 GAIA_MEM_SANI_POP_N(value_size, data(), m_cap, m_cnt, cnt);
419 return iterator(&data()[idxSrc]);
422 void clear() noexcept {
426 void shrink_to_fit() {
427 const auto cap = capacity();
428 const auto cnt = size();
433 if (m_pDataHeap !=
nullptr) {
434 auto* pDataOld = m_pDataHeap;
437 mem::move_elements<T, false>(m_data, pDataOld, cnt, 0);
441 m_pDataHeap = view_policy::template alloc<Allocator>(m_cap = cnt);
442 GAIA_MEM_SANI_ADD_BLOCK(value_size, m_pDataHeap, m_cap, m_cnt);
443 mem::move_elements<T, false>(m_pDataHeap, pDataOld, cnt, 0);
444 m_pData = m_pDataHeap;
447 GAIA_MEM_SANI_DEL_BLOCK(value_size, pDataOld, cap, cnt);
448 view_policy::template free<Allocator>(pDataOld);
456 template <
typename Func>
458 size_type erased = 0;
459 size_type idxDst = 0;
460 size_type idxSrc = 0;
462 while (idxSrc < m_cnt) {
463 if (func(
operator[](idxSrc))) {
464 if (idxDst < idxSrc) {
465 auto* ptr = (uint8_t*)data();
466 mem::move_element<T, false>(ptr, ptr, idxDst, idxSrc, m_cap, m_cap);
467 auto* ptr2 = &data()[idxSrc];
468 core::call_dtor(ptr2);
472 auto* ptr = &data()[idxSrc];
473 core::call_dtor(ptr);
480 GAIA_MEM_SANI_POP_N(value_size, data(), m_cap, m_cnt, erased);
486 GAIA_NODISCARD size_type size() const noexcept {
490 GAIA_NODISCARD
bool empty() const noexcept {
494 GAIA_NODISCARD size_type capacity() const noexcept {
498 GAIA_NODISCARD size_type max_size() const noexcept {
502 GAIA_NODISCARD
decltype(
auto) front() noexcept {
503 GAIA_ASSERT(!empty());
504 return (reference)*begin();
507 GAIA_NODISCARD
decltype(
auto) front() const noexcept {
508 GAIA_ASSERT(!empty());
509 return (const_reference)*begin();
512 GAIA_NODISCARD
decltype(
auto) back() noexcept {
513 GAIA_ASSERT(!empty());
514 return (reference) operator[](m_cnt - 1);
517 GAIA_NODISCARD
decltype(
auto) back() const noexcept {
518 GAIA_ASSERT(!empty());
519 return (const_reference) operator[](m_cnt - 1);
522 GAIA_NODISCARD
auto begin() noexcept {
523 return iterator(data());
526 GAIA_NODISCARD
auto begin() const noexcept {
527 return const_iterator(data());
530 GAIA_NODISCARD
auto cbegin() const noexcept {
531 return const_iterator(data());
534 GAIA_NODISCARD
auto rbegin() noexcept {
535 return iterator((pointer)&back());
538 GAIA_NODISCARD
auto rbegin() const noexcept {
539 return const_iterator((const_pointer)&back());
542 GAIA_NODISCARD
auto crbegin() const noexcept {
543 return const_iterator((const_pointer)&back());
546 GAIA_NODISCARD
auto end() noexcept {
547 return iterator(data() + size());
550 GAIA_NODISCARD
auto end() const noexcept {
551 return const_iterator(data() + size());
554 GAIA_NODISCARD
auto cend() const noexcept {
555 return const_iterator(data() + size());
558 GAIA_NODISCARD
auto rend() noexcept {
559 return iterator(data() - 1);
562 GAIA_NODISCARD
auto rend() const noexcept {
563 return const_iterator(data() - 1);
566 GAIA_NODISCARD
auto crend() const noexcept {
567 return const_iterator(data() - 1);
570 GAIA_NODISCARD
bool operator==(
const darr_ext& other)
const noexcept {
571 if (m_cnt != other.m_cnt)
573 const size_type n = size();
574 for (size_type i = 0; i < n; ++i)
575 if (!(
operator[](i) == other[i]))
580 GAIA_NODISCARD
constexpr bool operator!=(
const darr_ext& other)
const noexcept {
581 return !operator==(other);