Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qarraydataops.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QARRAYDATAOPS_H
6#define QARRAYDATAOPS_H
7
8#include <QtCore/qarraydata.h>
9#include <QtCore/qcontainertools_impl.h>
10#include <QtCore/qnamespace.h>
11
12#include <memory>
13#include <new>
14#include <string.h>
15#include <utility>
16#include <iterator>
17#include <tuple>
18#include <type_traits>
19
21
22template <class T> struct QArrayDataPointer;
23
24namespace QtPrivate {
25
26template <class T>
28 : public QArrayDataPointer<T>
29{
30 static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
31
32protected:
33 typedef QTypedArrayData<T> Data;
34 using DataPointer = QArrayDataPointer<T>;
35
36public:
38
40
41 void appendInitialize(qsizetype newSize) noexcept
42 {
43 Q_ASSERT(this->isMutable());
44 Q_ASSERT(!this->isShared());
45 Q_ASSERT(newSize > this->size);
46 Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
47
48 T *where = this->end();
49 this->size = newSize;
50 const T *e = this->end();
51 while (where != e)
52 *where++ = T();
53 }
54
55 void copyAppend(const T *b, const T *e) noexcept
56 {
57 Q_ASSERT(this->isMutable() || b == e);
58 Q_ASSERT(!this->isShared() || b == e);
59 Q_ASSERT(b <= e);
60 Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
61
62 if (b == e)
63 return;
64
65 ::memcpy(static_cast<void *>(this->end()), static_cast<const void *>(b), (e - b) * sizeof(T));
66 this->size += (e - b);
67 }
68
70 {
71 Q_ASSERT(!this->isShared() || n == 0);
72 Q_ASSERT(this->freeSpaceAtEnd() >= n);
73 if (!n)
74 return;
75
76 T *where = this->end();
77 this->size += qsizetype(n);
78 while (n--)
79 *where++ = t;
80 }
81
82 void moveAppend(T *b, T *e) noexcept
83 {
84 copyAppend(b, e);
85 }
86
87 void truncate(size_t newSize) noexcept
88 {
89 Q_ASSERT(this->isMutable());
90 Q_ASSERT(!this->isShared());
91 Q_ASSERT(newSize < size_t(this->size));
92
93 this->size = qsizetype(newSize);
94 }
95
96 void destroyAll() noexcept // Call from destructors, ONLY!
97 {
98 Q_ASSERT(this->d);
99 Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
100
101 // As this is to be called only from destructor, it doesn't need to be
102 // exception safe; size not updated.
103 }
104
106 {
108 (pos == QArrayData::GrowsAtEnd && n <= this->freeSpaceAtEnd()));
109
110 T *insertionPoint = this->ptr + where;
112 if (where < this->size)
113 ::memmove(static_cast<void *>(insertionPoint + n), static_cast<void *>(insertionPoint), (this->size - where) * sizeof(T));
114 } else {
115 Q_ASSERT(where == 0);
116 this->ptr -= n;
117 insertionPoint -= n;
118 }
119 this->size += n;
120 return insertionPoint;
121 }
122
123 void insert(qsizetype i, const T *data, qsizetype n)
124 {
125 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
126 if (this->size != 0 && i == 0)
127 pos = Data::GrowsAtBeginning;
128
129 DataPointer oldData;
130 this->detachAndGrow(pos, n, &data, &oldData);
131 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
132 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
133
134 T *where = createHole(pos, i, n);
135 ::memcpy(static_cast<void *>(where), static_cast<const void *>(data), n * sizeof(T));
136 }
137
139 {
140 T copy(t);
141
142 typename Data::GrowthPosition pos = Data::GrowsAtEnd;
143 if (this->size != 0 && i == 0)
144 pos = Data::GrowsAtBeginning;
145
146 this->detachAndGrow(pos, n, nullptr, nullptr);
147 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
148 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
149
150 T *where = createHole(pos, i, n);
151 while (n--)
152 *where++ = copy;
153 }
154
155 template<typename... Args>
156 void emplace(qsizetype i, Args &&... args)
157 {
158 bool detach = this->needsDetach();
159 if (!detach) {
160 if (i == this->size && this->freeSpaceAtEnd()) {
161 new (this->end()) T(std::forward<Args>(args)...);
162 ++this->size;
163 return;
164 }
165 if (i == 0 && this->freeSpaceAtBegin()) {
166 new (this->begin() - 1) T(std::forward<Args>(args)...);
167 --this->ptr;
168 ++this->size;
169 return;
170 }
171 }
172 T tmp(std::forward<Args>(args)...);
174 if (this->size != 0 && i == 0)
176
177 this->detachAndGrow(pos, 1, nullptr, nullptr);
178
179 T *where = createHole(pos, i, 1);
180 new (where) T(std::move(tmp));
181 }
182
183 void erase(T *b, qsizetype n)
184 {
185 T *e = b + n;
186 Q_ASSERT(this->isMutable());
187 Q_ASSERT(b < e);
188 Q_ASSERT(b >= this->begin() && b < this->end());
189 Q_ASSERT(e > this->begin() && e <= this->end());
190
191 // Comply with std::vector::erase(): erased elements and all after them
192 // are invalidated. However, erasing from the beginning effectively
193 // means that all iterators are invalidated. We can use this freedom to
194 // erase by moving towards the end.
195 if (b == this->begin() && e != this->end()) {
196 this->ptr = e;
197 } else if (e != this->end()) {
198 ::memmove(static_cast<void *>(b), static_cast<void *>(e),
199 (static_cast<T *>(this->end()) - e) * sizeof(T));
200 }
201 this->size -= n;
202 }
203
204 void eraseFirst() noexcept
205 {
206 Q_ASSERT(this->isMutable());
207 Q_ASSERT(this->size);
208 ++this->ptr;
209 --this->size;
210 }
211
212 void eraseLast() noexcept
213 {
214 Q_ASSERT(this->isMutable());
215 Q_ASSERT(this->size);
216 --this->size;
217 }
218
219 template <typename Predicate>
220 qsizetype eraseIf(Predicate pred)
221 {
222 qsizetype result = 0;
223 if (this->size == 0)
224 return result;
225
226 if (!this->needsDetach()) {
227 auto end = this->end();
228 auto it = std::remove_if(this->begin(), end, pred);
229 if (it != end) {
230 result = std::distance(it, end);
231 erase(it, result);
232 }
233 } else {
234 const auto begin = this->begin();
235 const auto end = this->end();
236 auto it = std::find_if(begin, end, pred);
237 if (it == end)
238 return result;
239
240 QPodArrayOps<T> other(this->size);
241 Q_CHECK_PTR(other.data());
242 auto dest = other.begin();
243 // std::uninitialized_copy will fallback to ::memcpy/memmove()
244 dest = std::uninitialized_copy(begin, it, dest);
245 dest = q_uninitialized_remove_copy_if(std::next(it), end, dest, pred);
246 other.size = std::distance(other.data(), dest);
247 result = this->size - other.size;
248 this->swap(other);
249 }
250 return result;
251 }
252
253 struct Span { T *begin; T *end; };
254
255 void copyRanges(std::initializer_list<Span> ranges)
256 {
257 auto it = this->begin();
258 std::for_each(ranges.begin(), ranges.end(), [&it](const auto &span) {
259 it = std::copy(span.begin, span.end, it);
260 });
261 this->size = std::distance(this->begin(), it);
262 }
263
264 void assign(T *b, T *e, parameter_type t) noexcept
265 {
266 Q_ASSERT(b <= e);
267 Q_ASSERT(b >= this->begin() && e <= this->end());
268
269 while (b != e)
270 ::memcpy(static_cast<void *>(b++), static_cast<const void *>(&t), sizeof(T));
271 }
272
273 bool compare(const T *begin1, const T *begin2, size_t n) const
274 {
275 // only use memcmp for fundamental types or pointers.
276 // Other types could have padding in the data structure or custom comparison
277 // operators that would break the comparison using memcmp
279 return ::memcmp(begin1, begin2, n * sizeof(T)) == 0;
280 } else {
281 const T *end1 = begin1 + n;
282 while (begin1 != end1) {
283 if (*begin1 == *begin2) {
284 ++begin1;
285 ++begin2;
286 } else {
287 return false;
288 }
289 }
290 return true;
291 }
292 }
293
295 {
296 auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
297 Q_CHECK_PTR(pair.second);
298 Q_ASSERT(pair.first != nullptr);
299 this->d = pair.first;
300 this->ptr = pair.second;
301 }
302};
303
304template <class T>
306 : public QArrayDataPointer<T>
307{
308 static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
309
310protected:
311 typedef QTypedArrayData<T> Data;
312 using DataPointer = QArrayDataPointer<T>;
313
314public:
316
318 {
319 Q_ASSERT(this->isMutable());
320 Q_ASSERT(!this->isShared());
321 Q_ASSERT(newSize > this->size);
322 Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
323
324 T *const b = this->begin();
325 do {
326 new (b + this->size) T;
327 } while (++this->size != newSize);
328 }
329
330 void copyAppend(const T *b, const T *e)
331 {
332 Q_ASSERT(this->isMutable() || b == e);
333 Q_ASSERT(!this->isShared() || b == e);
334 Q_ASSERT(b <= e);
335 Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
336
337 if (b == e) // short-cut and handling the case b and e == nullptr
338 return;
339
340 T *data = this->begin();
341 while (b < e) {
342 new (data + this->size) T(*b);
343 ++b;
344 ++this->size;
345 }
346 }
347
349 {
350 Q_ASSERT(!this->isShared() || n == 0);
351 Q_ASSERT(this->freeSpaceAtEnd() >= n);
352 if (!n)
353 return;
354
355 T *data = this->begin();
356 while (n--) {
357 new (data + this->size) T(t);
358 ++this->size;
359 }
360 }
361
362 void moveAppend(T *b, T *e)
363 {
364 Q_ASSERT(this->isMutable() || b == e);
365 Q_ASSERT(!this->isShared() || b == e);
366 Q_ASSERT(b <= e);
367 Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
368
369 if (b == e)
370 return;
371
372 T *data = this->begin();
373 while (b < e) {
374 new (data + this->size) T(std::move(*b));
375 ++b;
376 ++this->size;
377 }
378 }
379
380 void truncate(size_t newSize)
381 {
382 Q_ASSERT(this->isMutable());
383 Q_ASSERT(!this->isShared());
384 Q_ASSERT(newSize < size_t(this->size));
385
386 std::destroy(this->begin() + newSize, this->end());
387 this->size = newSize;
388 }
389
390 void destroyAll() // Call from destructors, ONLY
391 {
392 Q_ASSERT(this->d);
393 // As this is to be called only from destructor, it doesn't need to be
394 // exception safe; size not updated.
395
396 Q_ASSERT(this->d->ref_.loadRelaxed() == 0);
397
398 std::destroy(this->begin(), this->end());
399 }
400
401 struct Inserter
402 {
403 QArrayDataPointer<T> *data;
406
408 T *end = nullptr, *last = nullptr, *where = nullptr;
409
410 Inserter(QArrayDataPointer<T> *d) : data(d)
411 {
412 begin = d->ptr;
413 size = d->size;
414 }
416 data->ptr = begin;
417 data->size = size;
418 }
419 Q_DISABLE_COPY(Inserter)
420
422 {
423 end = begin + size;
424 last = end - 1;
425 where = begin + pos;
428 nSource = n;
429 move = n - dist; // smaller 0
431 if (n > dist) {
433 move = 0;
435 }
436 }
437
439 {
440 qsizetype oldSize = size;
441 Q_UNUSED(oldSize);
442
443 setup(pos, n);
444
445 // first create new elements at the end, by copying from elements
446 // to be inserted (if they extend past the current end of the array)
447 for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
448 new (end + i) T(source[nSource - sourceCopyConstruct + i]);
449 ++size;
450 }
451 Q_ASSERT(size <= oldSize + n);
452
453 // now move construct new elements at the end from existing elements inside
454 // the array.
455 for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
456 new (end + i) T(std::move(*(end + i - nSource)));
457 ++size;
458 }
459 // array has the new size now!
460 Q_ASSERT(size == oldSize + n);
461
462 // now move assign existing elements towards the end
463 for (qsizetype i = 0; i != move; --i)
464 last[i] = std::move(last[i - nSource]);
465
466 // finally copy the remaining elements from source over
467 for (qsizetype i = 0; i != sourceCopyAssign; ++i)
468 where[i] = source[i];
469 }
470
471 void insert(qsizetype pos, const T &t, qsizetype n)
472 {
473 const qsizetype oldSize = size;
474 Q_UNUSED(oldSize);
475
476 setup(pos, n);
477
478 // first create new elements at the end, by copying from elements
479 // to be inserted (if they extend past the current end of the array)
480 for (qsizetype i = 0; i != sourceCopyConstruct; ++i) {
481 new (end + i) T(t);
482 ++size;
483 }
484 Q_ASSERT(size <= oldSize + n);
485
486 // now move construct new elements at the end from existing elements inside
487 // the array.
488 for (qsizetype i = sourceCopyConstruct; i != nSource; ++i) {
489 new (end + i) T(std::move(*(end + i - nSource)));
490 ++size;
491 }
492 // array has the new size now!
493 Q_ASSERT(size == oldSize + n);
494
495 // now move assign existing elements towards the end
496 for (qsizetype i = 0; i != move; --i)
497 last[i] = std::move(last[i - nSource]);
498
499 // finally copy the remaining elements from source over
500 for (qsizetype i = 0; i != sourceCopyAssign; ++i)
501 where[i] = t;
502 }
503
505 {
506 setup(pos, 1);
507
510 new (end) T(std::move(t));
511 ++size;
512 } else {
513 // create a new element at the end by move constructing one existing element
514 // inside the array.
515 new (end) T(std::move(*(end - 1)));
516 ++size;
517
518 // now move assign existing elements towards the end
519 for (qsizetype i = 0; i != move; --i)
520 last[i] = std::move(last[i - 1]);
521
522 // and move the new item into place
523 *where = std::move(t);
524 }
525 }
526 };
527
528 void insert(qsizetype i, const T *data, qsizetype n)
529 {
530 const bool growsAtBegin = this->size != 0 && i == 0;
531 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
532
533 DataPointer oldData;
534 this->detachAndGrow(pos, n, &data, &oldData);
535 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
536 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
537
538 if (growsAtBegin) {
539 // copy construct items in reverse order at the begin
540 Q_ASSERT(this->freeSpaceAtBegin() >= n);
541 while (n) {
542 --n;
543 new (this->begin() - 1) T(data[n]);
544 --this->ptr;
545 ++this->size;
546 }
547 } else {
548 Inserter(this).insert(i, data, n);
549 }
550 }
551
553 {
554 T copy(t);
555
556 const bool growsAtBegin = this->size != 0 && i == 0;
557 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
558
559 this->detachAndGrow(pos, n, nullptr, nullptr);
560 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
561 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
562
563 if (growsAtBegin) {
564 // copy construct items in reverse order at the begin
565 Q_ASSERT(this->freeSpaceAtBegin() >= n);
566 while (n--) {
567 new (this->begin() - 1) T(copy);
568 --this->ptr;
569 ++this->size;
570 }
571 } else {
572 Inserter(this).insert(i, copy, n);
573 }
574 }
575
576 template<typename... Args>
577 void emplace(qsizetype i, Args &&... args)
578 {
579 bool detach = this->needsDetach();
580 if (!detach) {
581 if (i == this->size && this->freeSpaceAtEnd()) {
582 new (this->end()) T(std::forward<Args>(args)...);
583 ++this->size;
584 return;
585 }
586 if (i == 0 && this->freeSpaceAtBegin()) {
587 new (this->begin() - 1) T(std::forward<Args>(args)...);
588 --this->ptr;
589 ++this->size;
590 return;
591 }
592 }
593 T tmp(std::forward<Args>(args)...);
594 const bool growsAtBegin = this->size != 0 && i == 0;
595 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
596
597 this->detachAndGrow(pos, 1, nullptr, nullptr);
598
599 if (growsAtBegin) {
600 Q_ASSERT(this->freeSpaceAtBegin());
601 new (this->begin() - 1) T(std::move(tmp));
602 --this->ptr;
603 ++this->size;
604 } else {
605 Inserter(this).insertOne(i, std::move(tmp));
606 }
607 }
608
609 void erase(T *b, qsizetype n)
610 {
611 T *e = b + n;
612 Q_ASSERT(this->isMutable());
613 Q_ASSERT(b < e);
614 Q_ASSERT(b >= this->begin() && b < this->end());
615 Q_ASSERT(e > this->begin() && e <= this->end());
616
617 // Comply with std::vector::erase(): erased elements and all after them
618 // are invalidated. However, erasing from the beginning effectively
619 // means that all iterators are invalidated. We can use this freedom to
620 // erase by moving towards the end.
621 if (b == this->begin() && e != this->end()) {
622 this->ptr = e;
623 } else {
624 const T *const end = this->end();
625
626 // move (by assignment) the elements from e to end
627 // onto b to the new end
628 while (e != end) {
629 *b = std::move(*e);
630 ++b;
631 ++e;
632 }
633 }
634 this->size -= n;
635 std::destroy(b, e);
636 }
637
638 void eraseFirst() noexcept
639 {
640 Q_ASSERT(this->isMutable());
641 Q_ASSERT(this->size);
642 this->begin()->~T();
643 ++this->ptr;
644 --this->size;
645 }
646
647 void eraseLast() noexcept
648 {
649 Q_ASSERT(this->isMutable());
650 Q_ASSERT(this->size);
651 (this->end() - 1)->~T();
652 --this->size;
653 }
654
655
656 void assign(T *b, T *e, parameter_type t)
657 {
658 Q_ASSERT(b <= e);
659 Q_ASSERT(b >= this->begin() && e <= this->end());
660
661 while (b != e)
662 *b++ = t;
663 }
664
665 bool compare(const T *begin1, const T *begin2, size_t n) const
666 {
667 const T *end1 = begin1 + n;
668 while (begin1 != end1) {
669 if (*begin1 == *begin2) {
670 ++begin1;
671 ++begin2;
672 } else {
673 return false;
674 }
675 }
676 return true;
677 }
678};
679
680template <class T>
683{
684 static_assert (std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
685
686protected:
687 typedef QTypedArrayData<T> Data;
688 using DataPointer = QArrayDataPointer<T>;
689
690public:
691 // using QGenericArrayOps<T>::copyAppend;
692 // using QGenericArrayOps<T>::moveAppend;
693 // using QGenericArrayOps<T>::truncate;
694 // using QGenericArrayOps<T>::destroyAll;
696
697 struct Inserter
698 {
699 QArrayDataPointer<T> *data;
704
705 Inserter(QArrayDataPointer<T> *d) : data(d) { }
707 if constexpr (!std::is_nothrow_copy_constructible_v<T>) {
708 if (displaceFrom != displaceTo) {
709 ::memmove(static_cast<void *>(displaceFrom), static_cast<void *>(displaceTo), bytes);
711 }
712 }
713 data->size += nInserts;
714 }
715 Q_DISABLE_COPY(Inserter)
716
718 {
719 nInserts = n;
720 T *insertionPoint = data->ptr + pos;
721 displaceFrom = data->ptr + pos;
723 bytes = data->size - pos;
724 bytes *= sizeof(T);
725 ::memmove(static_cast<void *>(displaceTo), static_cast<void *>(displaceFrom), bytes);
726 return insertionPoint;
727 }
728
730 {
731 T *where = displace(pos, n);
732
733 while (n--) {
734 new (where) T(*source);
735 ++where;
736 ++source;
737 ++displaceFrom;
738 }
739 }
740
741 void insert(qsizetype pos, const T &t, qsizetype n)
742 {
743 T *where = displace(pos, n);
744
745 while (n--) {
746 new (where) T(t);
747 ++where;
748 ++displaceFrom;
749 }
750 }
751
753 {
754 T *where = displace(pos, 1);
755 new (where) T(std::move(t));
756 ++displaceFrom;
758 }
759
760 };
761
762
763 void insert(qsizetype i, const T *data, qsizetype n)
764 {
765 const bool growsAtBegin = this->size != 0 && i == 0;
766 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
767
768 DataPointer oldData;
769 this->detachAndGrow(pos, n, &data, &oldData);
770 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
771 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
772
773 if (growsAtBegin) {
774 // copy construct items in reverse order at the begin
775 Q_ASSERT(this->freeSpaceAtBegin() >= n);
776 while (n) {
777 --n;
778 new (this->begin() - 1) T(data[n]);
779 --this->ptr;
780 ++this->size;
781 }
782 } else {
783 Inserter(this).insert(i, data, n);
784 }
785 }
786
788 {
789 T copy(t);
790
791 const bool growsAtBegin = this->size != 0 && i == 0;
792 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
793
794 this->detachAndGrow(pos, n, nullptr, nullptr);
795 Q_ASSERT((pos == Data::GrowsAtBeginning && this->freeSpaceAtBegin() >= n) ||
796 (pos == Data::GrowsAtEnd && this->freeSpaceAtEnd() >= n));
797
798 if (growsAtBegin) {
799 // copy construct items in reverse order at the begin
800 Q_ASSERT(this->freeSpaceAtBegin() >= n);
801 while (n--) {
802 new (this->begin() - 1) T(copy);
803 --this->ptr;
804 ++this->size;
805 }
806 } else {
807 Inserter(this).insert(i, copy, n);
808 }
809 }
810
811 template<typename... Args>
812 void emplace(qsizetype i, Args &&... args)
813 {
814 bool detach = this->needsDetach();
815 if (!detach) {
816 if (i == this->size && this->freeSpaceAtEnd()) {
817 new (this->end()) T(std::forward<Args>(args)...);
818 ++this->size;
819 return;
820 }
821 if (i == 0 && this->freeSpaceAtBegin()) {
822 new (this->begin() - 1) T(std::forward<Args>(args)...);
823 --this->ptr;
824 ++this->size;
825 return;
826 }
827 }
828 T tmp(std::forward<Args>(args)...);
829 const bool growsAtBegin = this->size != 0 && i == 0;
830 const auto pos = growsAtBegin ? Data::GrowsAtBeginning : Data::GrowsAtEnd;
831
832 this->detachAndGrow(pos, 1, nullptr, nullptr);
833 if (growsAtBegin) {
834 Q_ASSERT(this->freeSpaceAtBegin());
835 new (this->begin() - 1) T(std::move(tmp));
836 --this->ptr;
837 ++this->size;
838 } else {
839 Inserter(this).insertOne(i, std::move(tmp));
840 }
841 }
842
843 void erase(T *b, qsizetype n)
844 {
845 T *e = b + n;
846
847 Q_ASSERT(this->isMutable());
848 Q_ASSERT(b < e);
849 Q_ASSERT(b >= this->begin() && b < this->end());
850 Q_ASSERT(e > this->begin() && e <= this->end());
851
852 // Comply with std::vector::erase(): erased elements and all after them
853 // are invalidated. However, erasing from the beginning effectively
854 // means that all iterators are invalidated. We can use this freedom to
855 // erase by moving towards the end.
856
857 std::destroy(b, e);
858 if (b == this->begin() && e != this->end()) {
859 this->ptr = e;
860 } else if (e != this->end()) {
861 memmove(static_cast<void *>(b), static_cast<const void *>(e), (static_cast<const T *>(this->end()) - e)*sizeof(T));
862 }
863 this->size -= n;
864 }
865
867 {
868 auto pair = Data::reallocateUnaligned(this->d, this->ptr, alloc, option);
869 Q_CHECK_PTR(pair.second);
870 Q_ASSERT(pair.first != nullptr);
871 this->d = pair.first;
872 this->ptr = pair.second;
873 }
874};
875
876template <class T, class = void>
878{
879 typedef QGenericArrayOps<T> Type;
880};
881
882template <class T>
884 typename std::enable_if<
885 !QTypeInfo<T>::isComplex && QTypeInfo<T>::isRelocatable
886 >::type>
887{
888 typedef QPodArrayOps<T> Type;
889};
890
891template <class T>
893 typename std::enable_if<
894 QTypeInfo<T>::isComplex && QTypeInfo<T>::isRelocatable
895 >::type>
896{
897 typedef QMovableArrayOps<T> Type;
898};
899
900template <class T>
902{
904 using Data = QTypedArrayData<T>;
905 using DataPointer = QArrayDataPointer<T>;
906 using parameter_type = typename Base::parameter_type;
907
908protected:
909 using Self = QCommonArrayOps<T>;
910
911public:
912 // using Base::truncate;
913 // using Base::destroyAll;
914 // using Base::assign;
915 // using Base::compare;
916
917 template<typename It>
919 {
920 Q_ASSERT(this->isMutable() || b == e);
921 Q_ASSERT(!this->isShared() || b == e);
922 const qsizetype distance = std::distance(b, e);
923 Q_ASSERT(distance >= 0 && distance <= this->allocatedCapacity() - this->size);
925
926#if __cplusplus >= 202002L && defined(__cpp_concepts) && defined(__cpp_lib_concepts)
927 constexpr bool canUseCopyAppend =
928 std::contiguous_iterator<It> &&
929 std::is_same_v<
930 std::remove_cv_t<typename std::iterator_traits<It>::value_type>,
931 T
932 >;
933 if constexpr (canUseCopyAppend) {
934 this->copyAppend(std::to_address(b), std::to_address(e));
935 } else
936#endif
937 {
938 T *iter = this->end();
939 for (; b != e; ++iter, ++b) {
940 new (iter) T(*b);
941 ++this->size;
942 }
943 }
944 }
945
946 // slightly higher level API than copyAppend() that also preallocates space
947 void growAppend(const T *b, const T *e)
948 {
949 if (b == e)
950 return;
951 Q_ASSERT(b < e);
952 const qsizetype n = e - b;
953 DataPointer old;
954
955 // points into range:
957 this->detachAndGrow(QArrayData::GrowsAtEnd, n, &b, &old);
958 else
959 this->detachAndGrow(QArrayData::GrowsAtEnd, n, nullptr, nullptr);
960 Q_ASSERT(this->freeSpaceAtEnd() >= n);
961 // b might be updated so use [b, n)
962 this->copyAppend(b, b + n);
963 }
964
966 {
967 Q_ASSERT(this->isMutable());
968 Q_ASSERT(!this->isShared());
969 Q_ASSERT(newSize > this->size);
970 Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
971
972 T *const b = this->begin();
973 do {
974 auto ptr = b + this->size;
975
976 if constexpr (std::is_constructible_v<T, Qt::Initialization>)
977 new (ptr) T(Qt::Uninitialized);
978 else
979 new (ptr) T; // not T() -- default-construct
980 } while (++this->size != newSize);
981 }
982};
983
984} // namespace QtPrivate
985
986template <class T>
989{
990};
991
993
994#endif // include guard
QSet< QString >::iterator it
Combined button and popup list for selecting options.
\macro QT_NO_KEYWORDS >
static constexpr bool q_points_into_range(const T *p, const T *b, const T *e, Cmp less={}) noexcept
typename std::enable_if< std::is_convertible< typename std::iterator_traits< Iterator >::iterator_category, std::forward_iterator_tag >::value, bool >::type IfIsForwardIterator
T * q_uninitialized_remove_copy_if(T *first, T *last, T *out, Predicate &pred)
SlotObjUniquePtr copy(const SlotObjUniquePtr &other) noexcept
constexpr Initialization Uninitialized
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLboolean GLboolean GLboolean b
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLfloat distance
GLenum type
GLfloat n
GLsizei GLsizei GLchar * source
GLdouble GLdouble t
Definition qopenglext.h:243
GLenum GLenum GLsizei void GLsizei void void * span
GLuint64EXT * result
[6]
GLuint GLenum option
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
Q_CHECK_PTR(a=new int[80])
std::uniform_real_distribution dist(1, 2.5)
[2]
QSharedPointer< T > other(t)
[5]
QJSValueList args
void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, const T **data, QArrayDataPointer *old)
bool isShared() const noexcept
qsizetype freeSpaceAtBegin() const noexcept
void detach(QArrayDataPointer *old=nullptr)
bool needsDetach() const noexcept
qsizetype allocatedCapacity() noexcept
std::conditional< pass_parameter_by_value, T, constT & >::type parameter_type
Q_NODISCARD_CTOR constexpr QArrayDataPointer() noexcept
qsizetype freeSpaceAtEnd() const noexcept
void swap(QArrayDataPointer &other) noexcept
bool isMutable() const noexcept
@ GrowsAtBeginning
Definition qarraydata.h:33
QGenericArrayOps< T > Type
void appendUninitialized(qsizetype newSize)
QArrayDataPointer< T > DataPointer
typename QArrayOpsSelector< T >::Type Base
QTypedArrayData< T > Data
QCommonArrayOps< T > Self
void appendIteratorRange(It b, It e, QtPrivate::IfIsForwardIterator< It >=true)
void growAppend(const T *b, const T *e)
typename Base::parameter_type parameter_type
void insert(qsizetype pos, const T &t, qsizetype n)
Inserter(QArrayDataPointer< T > *d)
void insertOne(qsizetype pos, T &&t)
void setup(qsizetype pos, qsizetype n)
void insert(qsizetype pos, const T *source, qsizetype n)
void truncate(size_t newSize)
void appendInitialize(qsizetype newSize)
void insert(qsizetype i, qsizetype n, parameter_type t)
QArrayDataPointer< T >::parameter_type parameter_type
QTypedArrayData< T > Data
void emplace(qsizetype i, Args &&... args)
void copyAppend(const T *b, const T *e)
QArrayDataPointer< T > DataPointer
void assign(T *b, T *e, parameter_type t)
void erase(T *b, qsizetype n)
bool compare(const T *begin1, const T *begin2, size_t n) const
void insert(qsizetype i, const T *data, qsizetype n)
void copyAppend(qsizetype n, parameter_type t)
void insertOne(qsizetype pos, T &&t)
void insert(qsizetype pos, const T &t, qsizetype n)
T * displace(qsizetype pos, qsizetype n)
void insert(qsizetype pos, const T *source, qsizetype n)
Inserter(QArrayDataPointer< T > *d)
QTypedArrayData< T > Data
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
void insert(qsizetype i, const T *data, qsizetype n)
void emplace(qsizetype i, Args &&... args)
QGenericArrayOps< T >::parameter_type parameter_type
QArrayDataPointer< T > DataPointer
void erase(T *b, qsizetype n)
void insert(qsizetype i, qsizetype n, parameter_type t)
void moveAppend(T *b, T *e) noexcept
void eraseFirst() noexcept
void appendInitialize(qsizetype newSize) noexcept
QArrayDataPointer< T >::parameter_type parameter_type
void copyRanges(std::initializer_list< Span > ranges)
void erase(T *b, qsizetype n)
void eraseLast() noexcept
T * createHole(QArrayData::GrowthPosition pos, qsizetype where, qsizetype n)
void insert(qsizetype i, const T *data, qsizetype n)
void truncate(size_t newSize) noexcept
void emplace(qsizetype i, Args &&... args)
qsizetype eraseIf(Predicate pred)
void assign(T *b, T *e, parameter_type t) noexcept
void copyAppend(const T *b, const T *e) noexcept
void copyAppend(qsizetype n, parameter_type t) noexcept
bool compare(const T *begin1, const T *begin2, size_t n) const
void reallocate(qsizetype alloc, QArrayData::AllocationOption option)
void insert(qsizetype i, qsizetype n, parameter_type t)
QArrayDataPointer< T > DataPointer
QTypedArrayData< T > Data
void destroyAll() noexcept
Definition moc.h:23