1 /****************************************************************************
2 **
3 ** DQt - D bindings for the Qt Toolkit
4 **
5 ** GNU Lesser General Public License Usage
6 ** This file may be used under the terms of the GNU Lesser
7 ** General Public License version 3 as published by the Free Software
8 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
9 ** packaging of this file. Please review the following information to
10 ** ensure the GNU Lesser General Public License version 3 requirements
11 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
12 **
13 ****************************************************************************/
14 module qt.core.vector;
15 extern(C++):
16 
17 import qt.config;
18 import qt.core.arraydata;
19 import qt.core.global;
20 import qt.core.list;
21 import qt.core.typeinfo;
22 import qt.helpers;
23 
24 /+ #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
25 #endif +/
26 
27 extern(C++, class) struct QVector(T)
28 {
29 private:
30     alias Data = QTypedArrayData!(T);
31     version(Windows)
32         Data* d;
33     else
34     {
35         union
36         {
37             const(QArrayData)* d2 = QArrayData.shared_null.ptr;
38             Data* d;
39         }
40     }
41 
42 public:
43     version(Windows)
44     {
45         @disable this();
46         pragma(inline, true) void rawConstructor()/+ noexcept+/
47         {
48             this.d = Data.sharedNull();
49         }
50         static typeof(this) create()
51         {
52             typeof(this) r = typeof(this).init;
53             r.rawConstructor();
54             return r;
55         }
56     }
57     else
58     {
59         static typeof(this) create()
60         {
61             return typeof(this).init;
62         }
63     }
64 
65     /+ explicit +/this(int asize)
66     {
67         (mixin(Q_ASSERT_X(q{asize >= 0},q{ "QVector::QVector"},q{ "Size must be greater than or equal to 0."})));
68         if (/+ Q_LIKELY +/(asize > 0)) {
69             d = cast(Data*)(Data.allocate(asize));
70             //mixin(Q_CHECK_PTR(q{QVector.d}));
71             d.size = asize;
72             defaultConstruct(cast(T*)(d.begin()), cast(T*)(d.end()));
73         } else {
74             d = cast(Data*)(Data.sharedNull());
75         }
76     }
77     this(int asize, ref const(T) t)
78     {
79         import core.lifetime;
80 
81         (mixin(Q_ASSERT_X(q{asize >= 0},q{ "QVector::QVector"},q{ "Size must be greater than or equal to 0."})));
82         if (asize > 0) {
83             d = cast(Data*)(Data.allocate(asize));
84             mixin(Q_CHECK_PTR(q{QVector.d}));
85             d.size = asize;
86             T* i = cast(T*)(d.end());
87             while (i != d.begin())
88                 copyEmplace!T(*--i, t);
89         } else {
90             d = cast(Data*)(Data.sharedNull());
91         }
92     }
93     /+@disable this(this);
94     pragma(inline, true) this()(ref const(QVector!(T)) v)
95     {
96         if ((cast(Data*)v.d).ref_.ref_()) {
97             d = cast(Data*)v.d;
98         } else {
99             if (v.d.capacityReserved) {
100                 d = cast(Data*)(Data.allocate(v.d.alloc));
101                 mixin(Q_CHECK_PTR(q{QVector.d}));
102                 d.capacityReserved = true;
103             } else {
104                 d = cast(Data*)(Data.allocate(v.d.size));
105                 mixin(Q_CHECK_PTR(q{QVector.d}));
106             }
107             if (d.alloc) {
108                 copyConstruct(cast(const(T)*)(v.d.begin()), cast(const(T)*)(v.d.end()), cast(T*)(d.begin()));
109                 d.size = v.d.size;
110             }
111         }
112     }+/
113     this(this)
114     {
115         if (!d.ref_.ref_()) {
116             auto orig = d;
117             if (d.capacityReserved) {
118                 d = cast(Data*)(Data.allocate(d.alloc));
119                 mixin(Q_CHECK_PTR(/*p*/q{    QVector.d}));
120                 d.capacityReserved = true;
121             } else {
122                 d = cast(Data*)(Data.allocate(d.size));
123                 mixin(Q_CHECK_PTR(/*p*/q{    QVector.d}));
124             }
125             if (d.alloc) {
126                 copyConstruct(cast(const(T)*)(orig.begin()), cast(const(T)*)(orig.end()), cast(T*)(d.begin()));
127                 d.size = orig.size;
128             }
129         }
130     }
131     pragma(inline, true) ~this() { if (!d.base0.ref_.deref()) freeData(d); }
132     /+ref QVector!(T) operator =(ref const(QVector!(T)) v)
133     {
134         if (v.d != d) {
135             QVector<T> tmp(v);
136             tmp.swap(this);
137         }
138         return this;
139     }+/
140     /+ QVector(QVector<T> &&other) noexcept : d(other.d) { other.d = Data::sharedNull(); } +/
141     /+ QVector<T> &operator=(QVector<T> &&other) noexcept
142     { QVector moved(std::move(other)); swap(moved); return *this; } +/
143     /+ void swap(QVector<T> &other) noexcept { qSwap(d, other.d); } +/
144     /+ inline QVector(std::initializer_list<T> args); +/
145     /+ QVector<T> &operator=(std::initializer_list<T> args); +/
146     /+ template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> +/
147     /+ inline QVector(InputIterator first, InputIterator last); +/
148     /+ explicit +/this(QArrayDataPointerRef!(T) ref_)/+ noexcept+/
149     {
150         this.d = ref_.ptr;
151     }
152 
153     /+bool operator ==(ref const(QVector!(T)) v) const
154     {
155         if (d == v.d)
156             return true;
157         if (d.size != v.d.size)
158             return false;
159         const(T)* vb = cast(const(T)*)(v.d.begin());
160         const(T)* b  = cast(const(T)*)(d.begin());
161         const(T)* e  = cast(const(T)*)(d.end());
162         return /+ std:: +/equal(b, e, mixin(QT_MAKE_CHECKED_ARRAY_ITERATOR(q{vb},q{ v.d->size})));
163     }+/
164     /+pragma(inline, true) bool operator !=(ref const(QVector!(T)) v) const { return !(this == v); }+/
165 
166     pragma(inline, true) int size() const { return d.base0.size; }
167 
168     pragma(inline, true) bool isEmpty() const { return d.base0.size == 0; }
169 
170     void resize()(int asize)
171     {
172         if (asize == d.size)
173             return detach();
174         if (asize > int(d.alloc) || !isDetached()) { // there is not enough space
175             QArrayData.AllocationOptions opt = asize > int(d.alloc) ? QArrayData.AllocationOption.Grow : QArrayData.AllocationOption.Default;
176             realloc(qMax(int(d.alloc), asize), opt);
177         }
178         if (asize < d.size)
179             destruct(cast(T*)(begin() + asize), cast(T*)(end()));
180         else
181             defaultConstruct(cast(T*)(end()), cast(T*)(begin() + asize));
182         d.size = asize;
183     }
184 
185     pragma(inline, true) int capacity() const { return int(d.base0.alloc); }
186     void reserve(int asize)
187     {
188         if (asize > int(d.alloc))
189             realloc(asize);
190         if ( mixin((!versionIsSet!("QT_NO_UNSHARABLE_CONTAINERS")) ? q{
191                     isDetached()
192             /+ #if !defined(QT_NO_UNSHARABLE_CONTAINERS) +/
193                         && d != Data.unsharableEmpty()
194             } : q{
195             isDetached()
196             })/+ #endif +/
197                 )
198             d.capacityReserved = 1;
199         (mixin(Q_ASSERT(q{QVector.capacity() >= asize})));
200     }
201     pragma(inline, true) void squeeze()
202     {
203         if (d.size < int(d.alloc)) {
204             if (!d.size) {
205                 this = QVector!(T).create();
206                 return;
207             }
208             realloc(d.size);
209         }
210         if (d.capacityReserved) {
211             // capacity reserved in a read only memory would be useless
212             // this checks avoid writing to such memory.
213             d.capacityReserved = 0;
214         }
215     }
216 
217     pragma(inline, true) void detach()
218     {
219         if (!isDetached()) {
220     /+ #if !defined(QT_NO_UNSHARABLE_CONTAINERS) +/
221             static if(!versionIsSet!("QT_NO_UNSHARABLE_CONTAINERS"))
222             {
223                     if (!d.alloc)
224                     d = cast(Data*)(Data.unsharableEmpty());
225                 else
226         /+ #endif +/
227                     realloc(int(d.alloc));
228             }
229             else
230             {
231         realloc(int(d.alloc));
232             }
233         }
234         (mixin(Q_ASSERT(q{QVector.isDetached()})));
235     }
236     pragma(inline, true) bool isDetached() const { return !d.ref_.isShared(); }
237     version(QT_NO_UNSHARABLE_CONTAINERS){}else
238     {
239         pragma(inline, true) void setSharable(bool sharable)
240         {
241             if (sharable == d.ref_.isSharable())
242                 return;
243             if (!sharable)
244                 detach();
245 
246             if (d == Data.unsharableEmpty()) {
247                 if (sharable)
248                     d = cast(Data*)(Data.sharedNull());
249             } else {
250                 d.ref_.setSharable(sharable);
251             }
252             (mixin(Q_ASSERT(q{QVector.d.ref_.isSharable() == sharable})));
253         }
254     }
255 
256     pragma(inline, true) bool isSharedWith(ref const(QVector!(T)) other) const { return d == other.d; }
257 
258     pragma(inline, true) T* data() { detach(); return cast(T*)(d.begin()); }
259     pragma(inline, true) const(T)* data() const { return cast(const(T)*)(d.begin()); }
260     pragma(inline, true) const(T)* constData() const { return cast(const(T)*)(d.begin()); }
261     pragma(inline, true) void clear()
262     {
263         if (!d.size)
264             return;
265         destruct(cast(T*)(begin()), cast(T*)(end()));
266         d.size = 0;
267     }
268 
269     pragma(inline, true) ref const(T) at(int i) const
270     { (mixin(Q_ASSERT_X(q{i >= 0 && i < QVector.d.size},q{ "QVector<T>::at"},q{ "index out of range"})));
271       return d.begin()[i]; }
272     pragma(inline, true) ref T opIndex(int i)
273     { (mixin(Q_ASSERT_X(q{i >= 0 && i < QVector.d.size},q{ "QVector<T>::operator[]"},q{ "index out of range"})));
274       return data()[i]; }
275     pragma(inline, true) ref const(T) opIndex(int i) const
276     { (mixin(Q_ASSERT_X(q{i >= 0 && i < QVector.d.size},q{ "QVector<T>::operator[]"},q{ "index out of range"})));
277       return d.begin()[i]; }
278     void append(ref const(T) t)
279     {
280         import core.lifetime;
281 
282         const(bool) isTooSmall = uint(d.size + 1) > d.alloc;
283         if (!isDetached() || isTooSmall) {
284             auto copy = *cast(T*)&t;
285             auto opt = QArrayData.AllocationOptions(isTooSmall ? QArrayData.AllocationOption.Grow : QArrayData.AllocationOption.Default);
286             realloc(isTooSmall ? d.size + 1 : d.alloc, opt);
287 
288             if (QTypeInfo!(T).isComplex)
289                 moveEmplace!T(copy, *d.end());
290             else
291                 moveEmplace!T(copy, *d.end());
292 
293         } else {
294             if (QTypeInfo!(T).isComplex)
295             {
296                 auto copy = *cast(T*)&t;
297                 emplace(d.end(), copy);
298             }
299             else
300             {
301                 auto copy = *cast(T*)&t;
302                 *d.end() = copy;
303             }
304         }
305         ++d.size;
306     }
307     void append(const(T)  t)
308     {
309         append(t);
310     }
311 
312     /+ void append(T &&t); +/
313     pragma(inline, true) void append()(ref const(QVector!(T)) l) { this += l; }
314     /+ void prepend(T &&t); +/
315     pragma(inline, true) void prepend()(ref const(T) t)
316     { insert(begin(), 1, t); }
317     /+ void insert(int i, T &&t); +/
318     pragma(inline, true) void insert()(int i, ref const(T) t)
319     { (mixin(Q_ASSERT_X(q{i >= 0 && i <= QVector.d.size},q{ "QVector<T>::insert"},q{ "index out of range"})));
320       insert(begin() + i, 1, t); }
321     pragma(inline, true) void insert()(int i, int n, ref const(T) t)
322     { (mixin(Q_ASSERT_X(q{i >= 0 && i <= QVector.d.size},q{ "QVector<T>::insert"},q{ "index out of range"})));
323       insert(begin() + i, n, t); }
324     pragma(inline, true) void replace(int i, ref const(T) t)
325     {
326         (mixin(Q_ASSERT_X(q{i >= 0 && i < QVector.d.size},q{ "QVector<T>::replace"},q{ "index out of range"})));
327         auto copy = *cast(T*)&t;
328         data()[i] = copy;
329     }
330     pragma(inline, true) void remove(int i)
331     { (mixin(Q_ASSERT_X(q{i >= 0 && i < QVector.d.size},q{ "QVector<T>::remove"},q{ "index out of range"})));
332       erase(d.begin() + i, d.begin() + i + 1); }
333     pragma(inline, true) void remove(int i, int n)
334     { (mixin(Q_ASSERT_X(q{i >= 0 && n >= 0 && i + n <= QVector.d.size},q{ "QVector<T>::remove"},q{ "index out of range"})));
335       erase(d.begin() + i, d.begin() + i + n); }
336     pragma(inline, true) void removeFirst() { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); erase(d.begin()); }
337     pragma(inline, true) void removeLast()
338     {
339         (mixin(Q_ASSERT(q{!QVector.isEmpty()})));
340         (mixin(Q_ASSERT(q{QVector.d.alloc})));
341 
342         if (d.ref_.isShared())
343             detach();
344         --d.size;
345         if (QTypeInfo!(T).isComplex)
346             destroy!false(*(d.data() + d.size));
347     }
348 /+    T takeFirst() { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); T r = /+ std:: +/move(first()); removeFirst(); return r; }
349     T takeLast() { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); T r = /+ std:: +/move(last()); removeLast(); return r; }
350 +/
351     ref QVector!(T) fill()(ref const(T) from, int asize = -1)
352     {
353         auto copy = const(T)(from);
354         resize(asize < 0 ? d.size : asize);
355         if (d.size) {
356             T* i = cast(T*)(d.end());
357             T* b = cast(T*)(d.begin());
358             while (i != b)
359                 *--i = copy;
360         }
361         return this;
362     }
363 
364     int indexOf(ref const(T) t, int from = 0) const
365     {
366         if (from < 0)
367         {
368             //from = qMax(from + d.size, 0);
369             from = from + d.size;
370             if(from < 0)
371                 from = 0;
372         }
373         if (from < d.size) {
374             T* n = cast(T*)(d.begin() + from - 1);
375             T* e = cast(T*)(d.end());
376             while (++n != e)
377                 if (*n == t)
378                     return cast(int)(n - d.begin());
379         }
380         return -1;
381     }
382     int indexOf(const(T)  t, int from = 0) const
383     {
384         return indexOf(t, from);
385     }
386     int lastIndexOf(ref const(T) t, int from = -1) const
387     {
388         if (from < 0)
389             from += d.size;
390         else if (from >= d.size)
391             from = d.size-1;
392         if (from >= 0) {
393             T* b = cast(T*)(d.begin());
394             T* n = cast(T*)(d.begin() + from + 1);
395             while (n != b) {
396                 if (*--n == t)
397                     return cast(int)(n - b);
398             }
399         }
400         return -1;
401     }
402 /+    bool contains(ref const(T) t) const
403     {
404         const(T)* b = cast(const(T)*)(d.begin());
405         const(T)* e = cast(const(T)*)(d.end());
406         return /+ std:: +/find(b, e, t) != e;
407     }+/
408 /+    int count(ref const(T) t) const
409     {
410         const(T)* b = cast(const(T)*)(d.begin());
411         const(T)* e = cast(const(T)*)(d.end());
412         return int(/+ std:: +/count(b, e, t));
413     }
414 +/
415 
416     // QList compatibility
417 //    void removeAt(int i) { remove(i); }
418 /+    int removeAll(ref const(T) t)
419     {
420         const(const_iterator) ce = this.cend(); const(const_iterator) cit = /+ std:: +/find(this.cbegin(), ce, t);
421         if (cit == ce)
422             return 0;
423         // next operation detaches, so ce, cit, t may become invalidated:
424         const(T) tCopy = t;
425         const(int) firstFoundIdx = /+ std:: +/distance(this.cbegin(), cit);
426         const(iterator) e = end(); const(iterator) it = /+ std:: +/remove(begin() + firstFoundIdx, e, tCopy);
427         const(int) result = /+ std:: +/distance(it, e);
428         erase(cast(iterator)(it), cast(iterator)(e));
429         return result;
430     }+/
431     bool removeOne(ref const(T) t)
432     {
433         const(int) i = indexOf(t);
434         if (i < 0)
435             return false;
436         remove(i);
437         return true;
438     }
439     int length() const { return size(); }
440     T takeAt(int i) { 
441     T t = /+ std:: +//*move*/cast(T)((this)[i]); remove(i); return t; }
442 /+    void move(int from, int to)
443     {
444         (mixin(Q_ASSERT_X(q{from >= 0 && from < QVector.size()},q{ "QVector::move(int,int)"},q{ "'from' is out-of-range"})));
445         (mixin(Q_ASSERT_X(q{to >= 0 && to < QVector.size()},q{ "QVector::move(int,int)"},q{ "'to' is out-of-range"})));
446         if (from == to) // don't detach when no-op
447             return;
448         detach();
449         T* /+ const +/  b = cast(T*)(d.begin());
450         if (from < to)
451             /+ std:: +/rotate(b + from, b + from + 1, b + to + 1);
452         else
453             /+ std:: +/rotate(b + to, b + from, b + from + 1);
454     }+/
455 
456     // STL-style
457     /+ typename Data::iterator +/alias iterator = Data.iterator;
458     /+ typename Data::const_iterator +/alias const_iterator = Data.const_iterator;
459     /+ typedef std::reverse_iterator<iterator> reverse_iterator; +/
460     /+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator; +/
461 /+ #if !defined(QT_STRICT_ITERATORS) || defined(Q_CLANG_QDOC) +/
462     pragma(inline, true) iterator begin() { detach(); return iterator(d.begin()); }
463     pragma(inline, true) const_iterator begin() const/+ noexcept+/ { return d.constBegin(); }
464     pragma(inline, true) const_iterator cbegin() const/+ noexcept+/ { return d.constBegin(); }
465     pragma(inline, true) const_iterator constBegin() const/+ noexcept+/ { return d.constBegin(); }
466     pragma(inline, true) iterator end() { detach(); return iterator(d.end()); }
467 
468     auto opSlice()const
469     {
470         struct R
471         {
472             iterator i;
473             iterator end;
474             ref T front()
475             {
476                 return *i;
477             }
478             bool empty()
479             {
480                 return i == end;
481             }
482             void popFront()
483             {
484                 i++;
485             }
486         }
487         auto this_ = cast(QVector*)&this;
488         return R(this_.begin(), this_.end());
489     }
490 
491     pragma(inline, true) const_iterator end() const/+ noexcept+/ { return d.constEnd(); }
492     pragma(inline, true) const_iterator cend() const/+ noexcept+/ { return d.constEnd(); }
493     pragma(inline, true) const_iterator constEnd() const/+ noexcept+/ { return d.constEnd(); }
494 /+ #else
495     inline iterator begin(iterator = iterator()) { detach(); return d->begin(); }
496     inline const_iterator begin(const_iterator = const_iterator()) const noexcept { return d->constBegin(); }
497     inline const_iterator cbegin(const_iterator = const_iterator()) const noexcept { return d->constBegin(); }
498     inline const_iterator constBegin(const_iterator = const_iterator()) const noexcept { return d->constBegin(); }
499     inline iterator end(iterator = iterator()) { detach(); return d->end(); }
500     inline const_iterator end(const_iterator = const_iterator()) const noexcept { return d->constEnd(); }
501     inline const_iterator cend(const_iterator = const_iterator()) const noexcept { return d->constEnd(); }
502     inline const_iterator constEnd(const_iterator = const_iterator()) const noexcept { return d->constEnd(); }
503 #endif +/
504     /+ reverse_iterator rbegin() { return reverse_iterator(end()); } +/
505     /+ reverse_iterator rend() { return reverse_iterator(begin()); } +/
506     /+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } +/
507     /+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } +/
508     /+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } +/
509     /+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } +/
510     iterator insert()(iterator before, int n, ref const(T) t)
511     /+/+ typename QVector<T>::iterator +/iterator insert(iterator before, size_type n, ref const(T) t)+/
512     {
513         import core.lifetime;
514         import core.stdc.string;
515 
516         (mixin(Q_ASSERT_X(q{QVector.isValidIterator(before)},q{  "QVector::insert"},q{ "The specified iterator argument 'before' is invalid"})));
517 
518         const offset = before - d.begin(); // /+ std:: +/distance(d.begin(), before);
519         if (n != 0) {
520             T copy = *cast(T*)&t;
521             if (!isDetached() || d.size + n > int(d.alloc))
522                 realloc(d.size + n, /+ QArrayData:: +/QArrayData.AllocationOptions.Grow);
523             static if (!QTypeInfoQuery!T.isRelocatable) {
524                 T* b = cast(T*)(d.end());
525                 T* i = cast(T*)(d.end() + n);
526                 while (i != b)
527                     emplace!T(--i);
528                 i = cast(T*)(d.end());
529                 T* j = i + n;
530                 b = cast(T*)(d.begin() + offset);
531                 while (i != b)
532                     *--j = *--i;
533                 i = b+n;
534                 while (i != b)
535                     *--i = copy;
536             } else {
537                 T* b = cast(T*)(d.begin() + offset);
538                 T* i = b + n;
539                 memmove(static_cast!(void*)(i), static_cast!(const(void)*)(b), (d.size - offset) * T.sizeof);
540                 while (i != b)
541                     copyEmplace!T(copy, *--i);
542             }
543             d.size += n;
544         }
545         return d.begin() + offset;
546     }
547     pragma(inline, true) iterator insert()(iterator before, ref const(T) x) { return insert(before, 1, x); }
548     /+ inline iterator insert(iterator before, T &&x); +/
549     iterator erase(iterator abegin, iterator aend)
550     /+/+ typename QVector<T>::iterator +/iterator erase(iterator abegin, iterator aend)+/
551     {
552         import core.lifetime;
553         import core.stdc.string;
554 
555         (mixin(Q_ASSERT_X(q{QVector.isValidIterator(abegin)},q{ "QVector::erase"},q{ "The specified iterator argument 'abegin' is invalid"})));
556         (mixin(Q_ASSERT_X(q{QVector.isValidIterator(aend)},q{ "QVector::erase"},q{ "The specified iterator argument 'aend' is invalid"})));
557 
558         const itemsToErase = aend - abegin;
559 
560         if (!itemsToErase)
561             return abegin;
562 
563         (mixin(Q_ASSERT(q{abegin >= QVector.d.begin()})));
564         (mixin(Q_ASSERT(q{aend <= QVector.d.end()})));
565         (mixin(Q_ASSERT(q{abegin <= aend})));
566 
567         const itemsUntouched = abegin - d.begin();
568 
569         // FIXME we could do a proper realloc, which copy constructs only needed data.
570         // FIXME we are about to delete data - maybe it is good time to shrink?
571         // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this.
572         if (d.alloc) {
573             detach();
574             abegin = d.begin() + itemsUntouched;
575             aend = abegin + itemsToErase;
576             if (!QTypeInfoQuery!T.isRelocatable) {
577                 iterator moveBegin = abegin + itemsToErase;
578                 iterator moveEnd = d.end();
579                 while (moveBegin != moveEnd) {
580                     if (QTypeInfo!(T).isComplex)
581                         destroy!false(*static_cast!(T*)(abegin));
582                     emplace!T(abegin++, *moveBegin++);
583                 }
584                 if (abegin < d.end()) {
585                     // destroy rest of instances
586                     destruct(cast(T*)(abegin), cast(T*)(d.end()));
587                 }
588             } else {
589                 destruct(cast(T*)(abegin), cast(T*)(aend));
590                 // QTBUG-53605: static_cast<void *> masks clang errors of the form
591                 // error: destination for this 'memmove' call is a pointer to class containing a dynamic class
592                 // FIXME maybe use std::is_polymorphic (as soon as allowed) to avoid the memmove
593                 memmove(static_cast!(void*)(abegin), static_cast!(void*)(aend),
594                         (d.size - itemsToErase - itemsUntouched) * T.sizeof);
595             }
596             d.size -= cast(int)(itemsToErase);
597         }
598         return d.begin() + itemsUntouched;
599     }
600     pragma(inline, true) iterator erase(iterator pos) { return erase(pos, pos+1); }
601 
602     // more Qt
603     pragma(inline, true) int count() const { return d.size; }
604     pragma(inline, true) ref T first() { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); return *begin(); }
605     pragma(inline, true) ref const(T) first() const { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); return *begin(); }
606     pragma(inline, true) ref const(T) constFirst() const { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); return *begin(); }
607     pragma(inline, true) ref T last() { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); return *(end()-1); }
608     pragma(inline, true) ref const(T) last() const { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); return *(end()-1); }
609     pragma(inline, true) ref const(T) constLast() const { (mixin(Q_ASSERT(q{!QVector.isEmpty()}))); return *(end()-1); }
610     pragma(inline, true) bool startsWith(ref const(T) t) const { return !isEmpty() && first() == t; }
611     pragma(inline, true) bool endsWith(ref const(T) t) const { return !isEmpty() && last() == t; }
612 /+    QVector!(T) mid(int pos, int len = -1) const
613     {
614         //using namespace QtPrivate;
615         switch (QContainerImplHelper.mid(d.size, &pos, &len)) {
616         case QContainerImplHelper.Null:
617         case QContainerImplHelper.Empty:
618             return QVector!(T)();
619         case QContainerImplHelper.Full:
620             return this;
621         case QContainerImplHelper.Subset:
622             break;default:
623 
624         }
625 
626         QVector!T midResult;
627         midResult.realloc(len);
628         T* srcFrom = cast(T*)(d.begin() + pos);
629         T* srcTo = cast(T*)(d.begin() + pos + len);
630         midResult.copyConstruct(srcFrom, srcTo, midResult.data());
631         midResult.d.size = len;
632         return midResult;
633     }+/
634 
635     T value(int i) const
636     {
637         if (uint(i) >= uint(d.size)) {
638             return T.init;
639         }
640         return *cast(T*)&d.begin()[i];
641     }
642     T value(int i, ref const(T) defaultValue) const
643     {
644         return *cast(T*)&(uint(i) >= uint(d.size) ? defaultValue : d.begin()[i]);
645     }
646 
647 /+    void swapItemsAt(int i, int j) {
648         (mixin(Q_ASSERT_X(q{i >= 0 && i < QVector.size() && j >= 0 && j < QVector.size()},q{
649                     "QVector<T>::swap"},q{ "index out of range"})));
650         detach();
651         auto tmp = d.begin()[i]; auto tmp__1 = d.begin()[j]; qSwap(tmp, tmp__1);
652     }
653 +/
654     // STL compatibility
655     alias value_type = T;
656     alias pointer = value_type*;
657     alias const_pointer = const(value_type)*;
658     /+ typedef value_type& reference; +/
659     /+ typedef const value_type& const_reference; +/
660     alias difference_type = qptrdiff;
661     alias Iterator = iterator;
662     alias ConstIterator = const_iterator;
663     alias size_type = int;
664     pragma(inline, true) void push_back()(ref const(T) t) { append(t); }
665     /+ void push_back(T &&t) { append(std::move(t)); } +/
666     /+ void push_front(T &&t) { prepend(std::move(t)); } +/
667     pragma(inline, true) void push_front()(ref const(T) t) { prepend(t); }
668     void pop_back() { removeLast(); }
669     void pop_front() { removeFirst(); }
670     pragma(inline, true) bool empty() const
671     { return d.base0.size == 0; }
672     pragma(inline, true) ref T front() { return first(); }
673     pragma(inline, true) /*const_reference*/ref const(value_type) front() const { return first(); }
674     pragma(inline, true) /*reference*/ref value_type back() { return last(); }
675     pragma(inline, true) /*const_reference*/ ref const(value_type) back() const { return last(); }
676     void shrink_to_fit() { squeeze(); }
677 
678     // comfort
679     extern(D) ref QVector!(T) opOpAssign(string op)(ref const(QVector!(T)) l) if(op == "~");
680     extern(D) pragma(inline, true) QVector!(T) opBinary(string op)(ref const(QVector!(T)) l) const if(op == "~")
681     { QVector n = this; n ~= l; return n; }
682     extern(D) pragma(inline, true) ref QVector!(T) opOpAssign(string op)(ref const(T) t) if(op == "~")
683     { append(t); return this; }
684     /+pragma(inline, true) ref QVector!(T) operator << (ref const(T) t)
685     { append(t); return this; }+/
686     /+pragma(inline, true) ref QVector!(T) operator <<(ref const(QVector!(T)) l)
687     { this += l; return this; }+/
688     extern(D) void opOpAssign(string op, T2)(ref const T2 t) if(op == "~" && !is(const(T2) == const(T)))
689     {
690         auto tmp = T(t);
691         append(tmp);
692     }
693     extern(D) void opOpAssign(string op)(const T t) if(op == "~")
694     {
695         append(t);
696     }
697     /+ inline QVector<T> &operator+=(T &&t)
698     { append(std::move(t)); return *this; } +/
699     /+ inline QVector<T> &operator<<(T &&t)
700     { append(std::move(t)); return *this; } +/
701 
702 /+    static QVector!(T) fromList(ref const(QList!(T)) list)
703     {
704         return list.toVector();
705     }+/
706 /+    QList!(T) toList() const
707     {
708         return QList!(T)(begin(), end());
709     }+/
710 
711 /+ #if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0) +/
712     /+ QT_DEPRECATED_X("Use QVector<T>(vector.begin(), vector.end()) instead.")
713     static inline QVector<T> fromStdVector(const std::vector<T> &vector)
714     { return QVector<T>(vector.begin(), vector.end()); } +/
715     /+ QT_DEPRECATED_X("Use std::vector<T>(vector.begin(), vector.end()) instead.")
716     inline std::vector<T> toStdVector() const
717     { return std::vector<T>(d->begin(), d->end()); } +/
718 /+ #endif +/
719 private:
720     // ### Qt6: remove methods, they are unused
721     void reallocData()(const(int) asize, const(int) aalloc, QArrayData.AllocationOptions options = QArrayData.AllocationOption.Default)
722     {
723         import core.lifetime;
724         import core.stdc.string;
725 
726         (mixin(Q_ASSERT(q{asize >= 0 && asize <= aalloc})));
727         Data* x = d;
728 
729         const(bool) isShared = d.ref_.isShared();
730 
731         if (aalloc != 0) {
732             if (aalloc != int(d.alloc) || isShared) {
733                 /+ QT_TRY +/ {
734                      /+ QT_CATCH (...) +/scope(failure) {
735                         Data.deallocate(x);
736                     }
737                     import core.stdc.string;
738                     // allocate memory
739                     x = cast(Data*)(Data.allocate(aalloc, options));
740                     //mixin(Q_CHECK_PTR(q{x}));
741                     // aalloc is bigger then 0 so it is not [un]sharedEmpty
742                     version(QT_NO_UNSHARABLE_CONTAINERS){}else
743                     {
744                         (mixin(Q_ASSERT(q{x.ref_.isSharable() || options.testFlag(QArrayData.AllocationOption.Unsharable)})));
745                     }
746                     //(mixin(Q_ASSERT(q{!x.ref_.isStatic()})));
747                     x.size = asize;
748 
749                     T* srcBegin = cast(T*)(d.begin());
750                     T* srcEnd = asize > d.size ? cast(T*)(d.end()) : cast(T*)(d.begin() + asize);
751                     T* dst = cast(T*)(x.begin());
752 
753                     if (!QTypeInfoQuery!T.isRelocatable || (isShared && QTypeInfo!T.isComplex)) {
754                         /+ QT_TRY +/ {
755                              /+ QT_CATCH (...) +/scope(failure) {
756                                 // destruct already copied objects
757                                 destruct(cast(T*)(x.begin()), dst);
758                             }
759                             if (true/+isShared || !std.is_nothrow_move_constructible<T>.value+/) {
760                                 // we can not move the data, we need to copy construct it
761                                 while (srcBegin != srcEnd)
762                                     emplace!T(dst++, *srcBegin++);
763                             } /+else {
764                                 while (srcBegin != srcEnd)
765                                     emplace!T(dst++, /+ std:: +/move(*srcBegin++));
766                             }+/
767                         }
768                     } else {
769                         memcpy(static_cast!(void*)(dst), static_cast!(void*)(srcBegin), (srcEnd - srcBegin) * T.sizeof);
770                         dst += srcEnd - srcBegin;
771 
772                         // destruct unused / not moved data
773                         if (asize < d.size)
774                             destruct(cast(T*)(d.begin() + asize), cast(T*)(d.end()));
775                     }
776 
777                     if (asize > d.size) {
778                         // construct all new objects when growing
779                         if (!QTypeInfo!(T).isComplex) {
780                             .memset(static_cast!(void*)(dst), 0, (static_cast!(T*)(x.end()) - dst) * T.sizeof);
781                         } else {
782                             /+ QT_TRY +/ {
783                                  /+ QT_CATCH (...) +/scope(failure) {
784                                     // destruct already copied objects
785                                     destruct(cast(T*)(x.begin()), dst);
786                                 }
787                                 while (dst != x.end())
788                                     emplace!T(dst++);
789                             }
790                         }
791                     }
792                 }
793                 x.capacityReserved = d.capacityReserved;
794             } else {
795                 (mixin(Q_ASSERT(q{int(QVector.d.alloc) == aalloc}))); // resize, without changing allocation size
796                 (mixin(Q_ASSERT(q{QVector.isDetached()})));       // can be done only on detached d
797                 (mixin(Q_ASSERT(q{x == QVector.d})));             // in this case we do not need to allocate anything
798                 if (asize <= d.size) {
799                     destruct(cast(T*)(x.begin() + asize), cast(T*)(x.end())); // from future end to current end
800                 } else {
801                     defaultConstruct(cast(T*)(x.end()), cast(T*)(x.begin() + asize)); // from current end to future end
802                 }
803                 x.size = asize;
804             }
805         } else {
806             x = cast(Data*)(Data.sharedNull());
807         }
808         if (d != x) {
809             if (!d.ref_.deref()) {
810                 if (!QTypeInfoQuery!T.isRelocatable || !aalloc || (isShared && QTypeInfo!T.isComplex)) {
811                     // data was copy constructed, we need to call destructors
812                     // or if !alloc we did nothing to the old 'd'.
813                     freeData(d);
814                 } else {
815                     Data.deallocate(d);
816                 }
817             }
818             d = x;
819         }
820 
821         (mixin(Q_ASSERT(q{QVector.d.data()})));
822         (mixin(Q_ASSERT(q{uint(QVector.d.size) <= QVector.d.alloc})));
823         version(QT_NO_UNSHARABLE_CONTAINERS){}else
824         {
825             (mixin(Q_ASSERT(q{QVector.d != Data.unsharableEmpty()})));
826         }
827         (mixin(Q_ASSERT(q{aalloc ? QVector.d != Data.sharedNull() : QVector.d == Data.sharedNull()})));
828         (mixin(Q_ASSERT(q{QVector.d.alloc >= uint(aalloc)})));
829         (mixin(Q_ASSERT(q{QVector.d.size == asize})));
830     }
831     void reallocData()(const(int) sz) { reallocData(sz, d.alloc); }
832     void realloc()(int aalloc, QArrayData.AllocationOptions options = QArrayData.AllocationOption.Default)
833     {
834         import core.lifetime;
835         import core.stdc.string;
836 
837         (mixin(Q_ASSERT(q{aalloc >= QVector.d.size})));
838         Data* x = d;
839 
840         const(bool) isShared = d.ref_.isShared();
841 
842         /+ QT_TRY +/ {
843              /+ QT_CATCH (...) +/scope(failure) {
844                 Data.deallocate(x);
845             }
846             // allocate memory
847             x = cast(Data*)(Data.allocate(aalloc, options));
848             //mixin(Q_CHECK_PTR(q{x}));
849             // aalloc is bigger then 0 so it is not [un]sharedEmpty
850             version(QT_NO_UNSHARABLE_CONTAINERS){}else
851             {
852                 (mixin(Q_ASSERT(q{x.ref_.isSharable() || options.testFlag(QArrayData.AllocationOption.Unsharable)})));
853             }
854     //        (mixin(Q_ASSERT(q{!x.ref_.isStatic()})));
855             x.size = d.size;
856 
857             T* srcBegin = cast(T*)(d.begin());
858             T* srcEnd = cast(T*)(d.end());
859             T* dst = cast(T*)(x.begin());
860 
861             if (!QTypeInfoQuery!T.isRelocatable || (isShared && QTypeInfo!T.isComplex)) {
862                 /+ QT_TRY +/ {
863                      /+ QT_CATCH (...) +/scope(failure) {
864                         // destruct already copied objects
865                         destruct(cast(T*)(x.begin()), dst);
866                     }
867                     /+if (isShared || !std::is_nothrow_move_constructible<T>::value)+/ {
868                         // we can not move the data, we need to copy construct it
869                         while (srcBegin != srcEnd)
870                             emplace!T(dst++, *srcBegin++);
871                     } /+else {
872                         while (srcBegin != srcEnd)
873                             emplace!T(dst++, /+ std:: +/move(*srcBegin++));
874                     }+/
875                 }
876             } else {
877                 memcpy(static_cast!(void*)(dst), static_cast!(void*)(srcBegin), (srcEnd - srcBegin) * T.sizeof);
878                 dst += srcEnd - srcBegin;
879             }
880 
881         }
882         x.capacityReserved = d.capacityReserved;
883 
884         (mixin(Q_ASSERT(q{QVector.d != x})));
885         if (!d.ref_.deref()) {
886             if (!QTypeInfoQuery!T.isRelocatable || !aalloc || (isShared && QTypeInfo!T.isComplex)) {
887                 // data was copy constructed, we need to call destructors
888                 // or if !alloc we did nothing to the old 'd'.
889                 freeData(d);
890             } else {
891                 Data.deallocate(d);
892             }
893         }
894         d = x;
895 
896         (mixin(Q_ASSERT(q{QVector.d.data()})));
897         (mixin(Q_ASSERT(q{uint(QVector.d.size) <= QVector.d.alloc})));
898         version(QT_NO_UNSHARABLE_CONTAINERS){}else
899         {
900             (mixin(Q_ASSERT(q{QVector.d != Data.unsharableEmpty()})));
901         }
902         (mixin(Q_ASSERT(q{QVector.d != Data.sharedNull()})));
903         (mixin(Q_ASSERT(q{QVector.d.alloc >= uint(aalloc)})));
904     }
905     void freeData(Data* x)
906     {
907         destruct(cast(T*)(x.begin()), cast(T*)(x.end()));
908         Data.deallocate(x);
909     }
910     void defaultConstruct()(T* from, T* to)
911     {
912         import core.lifetime;
913         import core.stdc.string;
914 
915         while (from != to)
916         {
917             static if(__traits(hasMember, T, "rawConstructor"))
918                 (*from++).rawConstructor();
919             else
920                 emplace!T(from++);
921         }
922     }
923     void copyConstruct()(const(T)* srcFrom, const(T)* srcTo, T* dstFrom)
924     {
925         import core.lifetime;
926         import core.stdc.string;
927 
928         if (QTypeInfo!(T).isComplex) {
929             while (srcFrom != srcTo)
930                 copyEmplace!T(*cast(T*)srcFrom++, *dstFrom++);
931         } else {
932             memcpy(static_cast!(void*)(dstFrom), static_cast!(const(void)*)(srcFrom), (srcTo - srcFrom) * T.sizeof);
933         }
934     }
935     void destruct(T* from, T* to)
936     {
937         if (QTypeInfo!T.isComplex) {
938             while (from != to) {
939                 destroy!false(*from++);
940             }
941         }
942     }
943     bool isValidIterator(ref const(iterator) i) const
944     {
945         return !(d.end() < i) && !(i < d.begin());
946     }
947     extern(C++, class) struct AlignmentDummy {
948     private:
949  Data header; T[1] array; }
950 }
951 
952 /+ #if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
953 template <typename InputIterator,
954           typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
955           QtPrivate::IfIsInputIterator<InputIterator> = true>
956 QVector(InputIterator, InputIterator) -> QVector<ValueType>;
957 #endif
958 
959 #ifdef Q_CC_MSVC
960 // behavior change: an object of POD type constructed with an initializer of the form ()
961 // will be default-initialized
962 #   pragma warning ( push )
963 #   pragma warning(disable : 4127) // conditional expression is constant
964 #endif
965 
966 #if defined(Q_CC_MSVC)
967 #pragma warning( pop )
968 #endif
969 template <typename T>
970 inline void QVector<T>::insert(int i, T &&t)
971 { Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range");
972   insert(begin() + i, std::move(t)); }template <typename T>
973 inline void QVector<T>::prepend(T &&t)
974 { insert(begin(), std::move(t)); }
975 
976 #if defined(Q_CC_MSVC)
977 QT_WARNING_PUSH
978 QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
979 #endif // Q_CC_MSVC
980 
981 template <typename T>
982 QVector<T>::QVector(std::initializer_list<T> args)
983 {
984     if (args.size() > 0) {
985         d = Data::allocate(args.size());
986         Q_CHECK_PTR(d);
987         // std::initializer_list<T>::iterator is guaranteed to be
988         // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct
989         copyConstruct(args.begin(), args.end(), d->begin());
990         d->size = int(args.size());
991     } else {
992         d = Data::sharedNull();
993     }
994 }
995 
996 template <typename T>
997 QVector<T> &QVector<T>::operator=(std::initializer_list<T> args)
998 {
999     QVector<T> tmp(args);
1000     tmp.swap(*this);
1001     return *this;
1002 }
1003 
1004 #if defined(Q_CC_MSVC)
1005 QT_WARNING_POP
1006 #endif // Q_CC_MSVC
1007 
1008 #if defined(Q_CC_MSVC)
1009 QT_WARNING_PUSH
1010 QT_WARNING_DISABLE_MSVC(4127) // conditional expression is constant
1011 #endif
1012 
1013 #if defined(Q_CC_MSVC)
1014 QT_WARNING_POP
1015 #endif
1016 
1017 template <typename T>
1018 void QVector<T>::append(T &&t)
1019 {
1020     const bool isTooSmall = uint(d->size + 1) > d->alloc;
1021     if (!isDetached() || isTooSmall) {
1022         QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default);
1023         realloc(isTooSmall ? d->size + 1 : d->alloc, opt);
1024     }
1025 
1026     new (d->end()) T(std::move(t));
1027 
1028     ++d->size;
1029 }
1030 
1031 template <typename T>
1032 typename QVector<T>::iterator QVector<T>::insert(iterator before, T &&t)
1033 {
1034     Q_ASSERT_X(isValidIterator(before),  "QVector::insert", "The specified iterator argument 'before' is invalid");
1035 
1036     const auto offset = std::distance(d->begin(), before);
1037     if (!isDetached() || d->size + 1 > int(d->alloc))
1038         realloc(d->size + 1, QArrayData::Grow);
1039     if (!QTypeInfoQuery<T>::isRelocatable) {
1040         T *i = d->end();
1041         T *j = i + 1;
1042         T *b = d->begin() + offset;
1043         // The new end-element needs to be constructed, the rest must be move assigned
1044         if (i != b) {
1045             new (--j) T(std::move(*--i));
1046             while (i != b)
1047                 *--j = std::move(*--i);
1048             *b = std::move(t);
1049         } else {
1050             new (b) T(std::move(t));
1051         }
1052     } else {
1053         T *b = d->begin() + offset;
1054         memmove(static_cast<void *>(b + 1), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
1055         new (b) T(std::move(t));
1056     }
1057     d->size += 1;
1058     return d->begin() + offset;
1059 }
1060 
1061 Q_DECLARE_SEQUENTIAL_ITERATOR(Vector)
1062 Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(Vector)
1063 
1064 template <typename T>
1065 uint qHash(const QVector<T> &key, uint seed = 0)
1066     noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
1067 {
1068     return qHashRange(key.cbegin(), key.cend(), seed);
1069 } +/
1070 
1071 /+bool operator <(T)(ref const(QVector!(T)) lhs, ref const(QVector!(T)) rhs)
1072     /+ noexcept(noexcept(std::lexicographical_compare(lhs.begin(), lhs.end(),
1073                                                                rhs.begin(), rhs.end()))) +/
1074 {
1075     return /+ std:: +/lexicographical_compare(lhs.begin(), lhs.end(),
1076                                         rhs.begin(), rhs.end());
1077 }+/
1078 
1079 /+pragma(inline, true) bool operator >(T)(ref const(QVector!(T)) lhs, ref const(QVector!(T)) rhs)
1080     /+ noexcept(noexcept(lhs < rhs)) +/
1081 {
1082     return rhs < lhs;
1083 }+/
1084 
1085 /+pragma(inline, true) bool operator <=(T)(ref const(QVector!(T)) lhs, ref const(QVector!(T)) rhs)
1086     /+ noexcept(noexcept(lhs < rhs)) +/
1087 {
1088     return !(lhs > rhs);
1089 }+/
1090 
1091 /+pragma(inline, true) bool operator >=(T)(ref const(QVector!(T)) lhs, ref const(QVector!(T)) rhs)
1092     /+ noexcept(noexcept(lhs < rhs)) +/
1093 {
1094     return !(lhs < rhs);
1095 }+/
1096 
1097 /*
1098    ### Qt 5:
1099    ### This needs to be removed for next releases of Qt. It is a workaround for vc++ because
1100    ### Qt exports QPolygon and QPolygonF that inherit QVector<QPoint> and
1101    ### QVector<QPointF> respectively.
1102 */
1103 
1104 /+ #if defined(Q_CC_MSVC) && !defined(QT_BUILD_CORE_LIB)
1105 QT_BEGIN_INCLUDE_NAMESPACE
1106 QT_END_INCLUDE_NAMESPACE
1107 extern template class Q_CORE_EXPORT QVector<QPointF>;
1108 extern template class Q_CORE_EXPORT QVector<QPoint>;
1109 #endif +/
1110