1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.core.list;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.arraydata;
17 import qt.core.arraydataops;
18 import qt.core.arraydatapointer;
19 import qt.core.global;
20 import qt.core.string;
21 import qt.core.typeinfo;
22 import qt.helpers;
23 import std.traits;
24 
25 /+ extern(C++, "QtPrivate") {
26    qsizetype indexOf(V, U)(ref const(QList!(V)) list, ref const(U) u, qsizetype from)/+ noexcept+/;
27    qsizetype lastIndexOf(V, U)(ref const(QList!(V)) list, ref const(U) u, qsizetype from)/+ noexcept+/;
28 } +/
29 
30 /+ struct QListSpecialMethodsBase(T)
31 {
32 protected:
33     /+ ~QListSpecialMethodsBase() = default; +/
34 
35     alias Self = QList!(T);
36     Self* self() { return static_cast!(Self*)(&this); }
37     const(Self)* self() const { return static_cast!(const(Self)*)(&this); }
38 
39 public:
40     /+ template <typename AT = T> +/
41     qsizetype indexOf(AT)(ref const(AT) t, qsizetype from = 0) const/+ noexcept+/
42     {
43         return /+ QtPrivate:: +/.indexOf(*self(), t, from);
44     }
45     /+ template <typename AT = T> +/
46     qsizetype lastIndexOf(AT)(ref const(AT) t, qsizetype from = -1) const/+ noexcept+/
47     {
48         return /+ QtPrivate:: +/.lastIndexOf(*self(), t, from);
49     }
50 
51     /+ template <typename AT = T> +/
52     bool contains(AT)(ref const(AT) t) const/+ noexcept+/
53     {
54         return self().indexOf(t) != -1;
55     }
56 }
57 struct QListSpecialMethods(T)
58 {
59     QListSpecialMethodsBase!(T) base0;
60     alias base0 this;
61 protected:
62     /+ ~QListSpecialMethods() = default; +/
63 public:
64     /+ using QListSpecialMethodsBase<T>::indexOf; +/
65     /+ using QListSpecialMethodsBase<T>::lastIndexOf; +/
66     /+ using QListSpecialMethodsBase<T>::contains; +/
67 } +/
68 /+ template <> struct QListSpecialMethods<QByteArray>;
69 template <> struct QListSpecialMethods<QString>;
70 
71 #ifdef Q_QDOC // define QVector for QDoc
72 template<typename T> class QVector : public QList<T> {};
73 #endif +/
74 
75 /// Binding for C++ class [QList](https://doc.qt.io/qt-6/qlist.html).
76 extern(C++, class) struct QList(T)
77 /+ #ifndef Q_QDOC +/
78 
79 /+ #endif +/
80 {
81 private:
82     alias Data = QTypedArrayData!(T);
83     alias DataOps = QArrayDataOps!(T);
84     alias DataPointer = QArrayDataPointer!(T);
85     extern(C++, class) struct DisableRValueRefs {}
86 
87     DataPointer d;
88 
89     /+ template <typename V, typename U> +/ /+ friend qsizetype QtPrivate::indexOf(const QList<V> &list, const U &u, qsizetype from) noexcept; +/
90     /+ template <typename V, typename U> +/ /+ friend qsizetype QtPrivate::lastIndexOf(const QList<V> &list, const U &u, qsizetype from) noexcept; +/
91 
92 public:
93     alias Type = T;
94     alias value_type = T;
95     alias pointer = T*;
96     alias const_pointer = const(T)*;
97     /+ using reference = T &; +/
98     /+ using const_reference = const T &; +/
99     alias size_type = qsizetype;
100     alias difference_type = qptrdiff;
101 /+ #ifndef Q_QDOC +/
102     //alias parameter_type = DataPointer.parameter_type;
103     alias parameter_type = T;
104     /+ using rvalue_ref = typename std::conditional<DataPointer::pass_parameter_by_value, DisableRValueRefs, T &&>::type; +/
105 /+ #else  // simplified aliases for QDoc
106     using parameter_type = const T &;
107     using rvalue_ref = T &&;
108 #endif +/
109 
110     extern(C++, class) struct iterator {
111     private:
112         T* i = null;
113     public:
114         alias difference_type__1 = qsizetype;
115         alias value_type__1 = T;
116         // libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
117 /+ #if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
118         using iterator_category = std::contiguous_iterator_tag;
119         using element_type = value_type;
120 #else +/
121 //        alias iterator_category = /+ std:: +/random_access_iterator_tag;
122 /+ #endif +/
123 
124         alias pointer__1 = T*;
125         /+ using reference = T &; +/
126 
127         /+ inline constexpr iterator() = default; +/
128         pragma(inline, true) this(T* n)
129         {
130             this.i = n;
131         }
132         pragma(inline, true) ref T opUnary(string op)() const if(op == "*") { return *cast(T*)i; }
133         /+pragma(inline, true) T* operator ->() const { return i; }+/
134         //pragma(inline, true) ref T opIndex(qsizetype j) const { return *(i + j); }
135         /+pragma(inline, true) bool operator ==(iterator o) const { return i == o.i; }+/
136         /+pragma(inline, true) bool operator !=(iterator o) const { return i != o.i; }+/
137         /+pragma(inline, true) bool operator <(iterator other) const { return i < other.i; }+/
138         /+pragma(inline, true) bool operator <=(iterator other) const { return i <= other.i; }+/
139         /+pragma(inline, true) bool operator >(iterator other) const { return i > other.i; }+/
140         /+pragma(inline, true) bool operator >=(iterator other) const { return i >= other.i; }+/
141         /+pragma(inline, true) bool operator ==(pointer p) const { return i == p; }+/
142         /+pragma(inline, true) bool operator !=(pointer p) const { return i != p; }+/
143         pragma(inline, true) ref iterator opUnary(string op)() if(op == "++") { ++i; return this; }
144         /+pragma(inline, true) iterator operator ++(int) { T* n = i; ++i; return cast(iterator)(n); }+/
145         pragma(inline, true) ref iterator opUnary(string op)() if(op == "--") { i--; return this; }
146         /+pragma(inline, true) iterator operator --(int) { T* n = i; i--; return cast(iterator)(n); }+/
147         pragma(inline, true) qsizetype opBinary(string op)(iterator j) const if(op == "-") { return i - j.i; }
148         /+pragma(inline, true) auto opCast(T : T)() const { return i; }+/
149 
150         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, iterator>
151         &operator+=(Int j) { i+=j; return *this; } +/
152         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, iterator>
153         &operator-=(Int j) { i-=j; return *this; } +/
154         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, iterator>
155         operator+(Int j) const { return iterator(i+j); } +/
156         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, iterator>
157         operator-(Int j) const { return iterator(i-j); } +/
158         /+ template <typename Int> +/ /+ friend std::enable_if_t<std::is_integral_v<Int>, iterator>
159         operator+(Int j, iterator k) { return k + j; } +/
160     }
161 
162     extern(C++, class) struct const_iterator {
163     private:
164         const(T)* i = null;
165     public:
166         alias difference_type__1 = qsizetype;
167         alias value_type__1 = T;
168         // libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
169 /+ #if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
170         using iterator_category = std::contiguous_iterator_tag;
171         using element_type = const value_type;
172 #else +/
173 //        alias iterator_category = /+ std:: +/random_access_iterator_tag;
174 /+ #endif +/
175         alias pointer__1 = const(T)*;
176         /+ using reference = const T &; +/
177 
178         /+ inline constexpr const_iterator() = default; +/
179         pragma(inline, true) this(const(T)* n)
180         {
181             this.i = n;
182         }
183         /*pragma(inline, true) this(iterator o)
184         {
185             this.i = o;
186         }*/
187         pragma(inline, true) ref const(T) opUnary(string op)() const if(op == "*") { return *i; }
188         /+pragma(inline, true) const(T)* operator ->() const { return i; }+/
189         pragma(inline, true) ref const(T) opIndex(qsizetype j) const { return *(i + j); }
190         /+pragma(inline, true) bool operator ==(const_iterator o) const { return i == o.i; }+/
191         /+pragma(inline, true) bool operator !=(const_iterator o) const { return i != o.i; }+/
192         /+pragma(inline, true) bool operator <(const_iterator other) const { return i < other.i; }+/
193         /+pragma(inline, true) bool operator <=(const_iterator other) const { return i <= other.i; }+/
194         /+pragma(inline, true) bool operator >(const_iterator other) const { return i > other.i; }+/
195         /+pragma(inline, true) bool operator >=(const_iterator other) const { return i >= other.i; }+/
196         /+pragma(inline, true) bool operator ==(iterator o) const { return i == const_iterator(o).i; }+/
197         /+pragma(inline, true) bool operator !=(iterator o) const { return i != const_iterator(o).i; }+/
198         /+pragma(inline, true) bool operator ==(pointer p) const { return i == p; }+/
199         /+pragma(inline, true) bool operator !=(pointer p) const { return i != p; }+/
200         pragma(inline, true) ref const_iterator opUnary(string op)() if(op == "++") { ++i; return this; }
201         /+pragma(inline, true) const_iterator operator ++(int) { const(T)* n = i; ++i; return cast(const_iterator)(n); }+/
202         pragma(inline, true) ref const_iterator opUnary(string op)() if(op == "--") { i--; return this; }
203         /+pragma(inline, true) const_iterator operator --(int) { const(T)* n = i; i--; return cast(const_iterator)(n); }+/
204         pragma(inline, true) qsizetype opBinary(string op)(const_iterator j) const if(op == "-") { return i - j.i; }
205         /+pragma(inline, true) auto opCast(T : const(T))() const { return i; }+/
206         int opCmp(const const_iterator other) const
207         {
208             if (i < other.i)
209                 return -1;
210             if (i > other.i)
211                 return 1;
212 
213             return 0;
214         }
215 
216         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, const_iterator>
217         &operator+=(Int j) { i+=j; return *this; } +/
218         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, const_iterator>
219         &operator-=(Int j) { i-=j; return *this; } +/
220         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, const_iterator>
221         operator+(Int j) const { return const_iterator(i+j); } +/
222         pragma(inline, true) const_iterator opBinary(string op, Int)(Int j) const if(op == "+" && isIntegral!Int) { return const_iterator(i+j); }
223         /+ template <typename Int> +/ /+ std::enable_if_t<std::is_integral_v<Int>, const_iterator>
224         operator-(Int j) const { return const_iterator(i-j); } +/
225         pragma(inline, true) const_iterator opBinary(string op, Int)(Int j) const if(op == "-" && isIntegral!Int) { return const_iterator(i-j); }
226         /+ template <typename Int> +/ /+ friend std::enable_if_t<std::is_integral_v<Int>, const_iterator>
227         operator+(Int j, const_iterator k) { return k + j; } +/
228     }
229     alias Iterator = iterator;
230     alias ConstIterator = const_iterator;
231     /+ using reverse_iterator = std::reverse_iterator<iterator>; +/
232     /+ using const_reverse_iterator = std::reverse_iterator<const_iterator>; +/
233 
234 private:
235     pragma(inline, true) void resize_internal()(qsizetype newSize)
236     {
237         (mixin(Q_ASSERT(q{newSize >= 0})));
238 
239         if (d.needsDetach() || newSize > capacity() - d.freeSpaceAtBegin()) {
240             d.detachAndGrow(QArrayData.GrowthPosition.GrowsAtEnd, newSize - d.size, null, null);
241         } else if (newSize < size()) {
242             DataOps.truncate(d, newSize);
243         }
244     }
245     bool isValidIterator(const_iterator i) const
246     {
247         return i.i < d.end() && i.i >= d.begin();
248     }
249 public:
250     this(DataPointer dd)/+ noexcept+/
251     {
252         this.d = dd;
253     }
254 
255 public:
256     /+ QList() = default; +/
257     /+ explicit +/this()(qsizetype size)
258     {
259         this.d = Data.allocate(size);
260 
261         if (size)
262             DataOps.appendInitialize(d, size);
263     }
264     this()(qsizetype size, parameter_type t)
265     {
266         this.d = Data.allocate(size);
267 
268         if (size)
269             DataOps.copyAppend(d, size, t);
270     }
271 
272     static QList create()
273     {
274         return QList.init;
275     }
276 
277     /+ inline QList(std::initializer_list<T> args)
278         : d(Data::allocate(args.size()))
279     {
280         if (args.size())
281             d->copyAppend(args.begin(), args.end());
282     } +/
283 
284     /+ QList<T> &operator=(std::initializer_list<T> args)
285     {
286         d = DataPointer(Data::allocate(args.size()));
287         if (args.size())
288             d->copyAppend(args.begin(), args.end());
289         return *this;
290     } +/
291     /+ template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> +/
292     /+ this(InputIterator,)(InputIterator i1, InputIterator i2)
293     {
294         static if (!/+ std:: +/is_convertible_v!(UnknownType!q{/+ std:: +/iterator_traits!(InputIterator).iterator_category}, /+ std:: +/forward_iterator_tag)) {
295             /+ std:: +/copy(i1, i2, /+ std:: +/back_inserter(this));
296         } else {
297             const distance = /+ std:: +/distance(i1, i2);
298             if (distance) {
299                 d = DataPointer(Data.allocate(distance));
300                 static if (/+ std:: +/is_same_v!(/+ std:: +/decay_t!(InputIterator), iterator) ||
301                               /+ std:: +/is_same_v!(/+ std:: +/decay_t!(InputIterator), const_iterator)) {
302                     d.copyAppend(i1, i2);
303                 } else {
304                     d.appendIteratorRange(i1, i2);
305                }
306             }
307         }
308     } +/
309 
310     // This constructor is here for compatibility with QStringList in Qt 5, that has a QStringList(const QString &) constructor
311     /+ template<typename String, typename = std::enable_if_t<std::is_same_v<T, QString> && std::is_convertible_v<String, QString>>> +/
312     /+ /+ explicit +/pragma(inline, true) this(String,)(ref const(String) str)
313     { append(str); } +/
314 
315     // compiler-generated special member functions are fine!
316 
317     /+ void swap(QList<T> &other) noexcept { qSwap(d, other.d); } +/
318 
319 /+ #ifndef Q_CLANG_QDOC +/
320     /+ template <typename U = T> +/
321     /+/+ QTypeTraits:: +/qt.core.typeinfo.compare_eq_result_container!(QList, U) operator ==(U)(ref const(QList) other) const
322     {
323         if (size() != other.size())
324             return cast(qt.core.typeinfo.compare_eq_result_container!(QList, U))(false);
325         if (begin() == other.begin())
326             return cast(qt.core.typeinfo.compare_eq_result_container!(QList, U))(true);
327 
328         // do element-by-element comparison
329         return d.compare(begin(), other.begin(), size());
330     }+/
331     /+ template <typename U = T> +/
332     /+/+ QTypeTraits:: +/qt.core.typeinfo.compare_eq_result_container!(QList, U) operator !=(U)(ref const(QList) other) const
333     {
334         return !(this == other);
335     }+/
336 
337     /+ template <typename U = T> +/
338     /+/+ QTypeTraits:: +/qt.core.typeinfo.compare_lt_result_container!(QList, U) operator <(U)(ref const(QList) other) const
339             /+ noexcept(noexcept(std::lexicographical_compare<typename QList<U>::const_iterator,
340                                                            typename QList::const_iterator>(
341                                 std::declval<QList<U>>().begin(), std::declval<QList<U>>().end(),
342                                 other.begin(), other.end()))) +/
343     {
344         return cast(qt.core.typeinfo.compare_lt_result_container!(QList, U))(/+ std:: +/lexicographical_compare(begin(), end(),
345                                             other.begin(), other.end()));
346     }+/
347 
348     /+ template <typename U = T> +/
349     /+/+ QTypeTraits:: +/qt.core.typeinfo.compare_lt_result_container!(QList, U) operator >(U)(ref const(QList) other) const
350             /+ noexcept(noexcept(other < std::declval<QList<U>>())) +/
351     {
352         return cast(qt.core.typeinfo.compare_lt_result_container!(QList, U))(other < this);
353     }+/
354 
355     /+ template <typename U = T> +/
356     /+/+ QTypeTraits:: +/qt.core.typeinfo.compare_lt_result_container!(QList, U) operator <=(U)(ref const(QList) other) const
357             /+ noexcept(noexcept(other < std::declval<QList<U>>())) +/
358     {
359         return !(other < this);
360     }+/
361 
362     /+ template <typename U = T> +/
363     /+/+ QTypeTraits:: +/qt.core.typeinfo.compare_lt_result_container!(QList, U) operator >=(U)(ref const(QList) other) const
364             /+ noexcept(noexcept(std::declval<QList<U>>() < other)) +/
365     {
366         return !(this < other);
367     }+/
368 /+ #else
369     bool operator==(const QList &other) const;
370     bool operator!=(const QList &other) const;
371     bool operator<(const QList &other) const;
372     bool operator>(const QList &other) const;
373     bool operator<=(const QList &other) const;
374     bool operator>=(const QList &other) const;
375 #endif +/ // Q_CLANG_QDOC
376 
377     qsizetype size() const/+ noexcept+/ { return d.size; }
378     qsizetype count() const/+ noexcept+/ { return size(); }
379     qsizetype length() const/+ noexcept+/ { return size(); }
380 
381     pragma(inline, true) bool isEmpty() const/+ noexcept+/ { return d.size == 0; }
382 
383     void resize()(qsizetype size)
384     {
385         resize_internal(size);
386         if (size > this.size())
387             DataOps.appendInitialize(d, size);
388     }
389     void resize()(qsizetype size, parameter_type c)
390     {
391         resize_internal(size);
392         if (size > this.size())
393             DataOps.copyAppend(d, size - this.size(), c);
394     }
395 
396     pragma(inline, true) qsizetype capacity() const { return qsizetype(d.constAllocatedCapacity()); }
397 /+    void reserve(qsizetype asize)
398     {
399         // capacity() == 0 for immutable data, so this will force a detaching below
400         if (asize <= capacity() - d.freeSpaceAtBegin()) {
401             if (d.flags() & Data.CapacityReserved)
402                 return;  // already reserved, don't shrink
403             if (!d.isShared()) {
404                 // accept current allocation, don't shrink
405                 d.setFlag(Data.CapacityReserved);
406                 return;
407             }
408         }
409 
410         static if(#configValue!"merged")
411         {
412         auto detached = DataPointer(Data.allocate(qMax(asize, size())));
413         }
414     static if(#configValue!"merged")
415     {
416     DataPointer detached__1();
417     }
418         detached__1.copyAppend(constBegin(), constEnd());
419         if (detached__1.d_ptr())
420             detached__1.setFlag(Data.CapacityReserved);
421         d.swap(detached__1);
422     }+/
423 /+    pragma(inline, true) void squeeze()
424     {
425         if (!d.isMutable())
426             return;
427         if (d.needsDetach() || size() < capacity()) {
428             // must allocate memory
429             static if(#configValue!"merged")
430             {
431             auto detached = DataPointer(Data.allocate(size()));
432             }
433     static if(#configValue!"merged")
434     {
435     DataPointer detached__1();
436     }
437             if (size()) {
438                 if (d.needsDetach())
439                     detached__1.copyAppend(constBegin(), constEnd());
440                 else
441                     detached__1.moveAppend(d.data(), d.data() + d.size);
442             }
443             d.swap(detached__1);
444         }
445         // We're detached so this is fine
446         d.clearFlag(Data.CapacityReserved);
447     }+/
448 
449     void detach()() { d.detach(); }
450     bool isDetached() const/+ noexcept+/ { return !d.isShared(); }
451 
452     pragma(inline, true) bool isSharedWith(ref const(QList!(T)) other) const { return d == other.d; }
453 
454     pointer data()() { detach(); return d.data(); }
455     const_pointer data() const/+ noexcept+/ { return d.data(); }
456     const_pointer constData() const/+ noexcept+/ { return d.data(); }
457     void clear() {
458         if (!size())
459             return;
460         if (d.needsDetach()) {
461             // must allocate memory
462             auto detached = DataPointer(Data.allocate(d.allocatedCapacity()));
463             d.swap(detached);
464         } else {
465             DataOps.truncate(d, 0);
466         }
467     }
468 
469     ref const(T) at(qsizetype i) const/+ noexcept+/
470     {
471         (mixin(Q_ASSERT_X(q{size_t(i) < size_t(QList.d.size)},q{ "QList::at"},q{ "index out of range"})));
472         return data()[i];
473     }
474     ref T opIndex()(qsizetype i)
475     {
476         (mixin(Q_ASSERT_X(q{size_t(i) < size_t(QList.d.size)},q{ "QList::operator[]"},q{ "index out of range"})));
477         detach();
478         return data()[i];
479     }
480     ref const(T) opIndex(qsizetype i) const/+ noexcept+/ { return at(i); }
481     void append()(parameter_type t) { emplaceBack(t); }
482     /*pragma(inline, true) void append(const_iterator i1, const_iterator i2)
483     {
484         DataOps.growAppend(d, i1, i2);
485     }*/
486 /+    void append(rvalue_ref t)
487     {
488         static if (DataPointer.pass_parameter_by_value) {
489             /+ Q_UNUSED(t) +/
490         } else {
491             emplaceBack(/+ std:: +/move(t));
492         }
493     }+/
494     /+void append(ref const(QList!(T)) l)
495     {
496         append(l.constBegin(), l.constEnd());
497     }+/
498     /+ void append(QList<T> &&l); +/
499 /+    void prepend(rvalue_ref t) {
500         static if (DataPointer.pass_parameter_by_value) {
501             /+ Q_UNUSED(t) +/
502         } else {
503             emplaceFront(/+ std:: +/move(t));
504         }
505     }+/
506     //void prepend(parameter_type t) { emplaceFront(t); }
507 
508     /+ template<typename... Args> +/
509     pragma(inline, true) ref T emplaceBack(Args...)(auto ref Args /+ && +/ args)
510     {
511         DataOps.emplace(d, d.size, args /*/+ std:: +/forward!(Args)(args)...*/);
512         return *(d.end() - 1);
513     }
514 
515     /+ template <typename ...Args> +/
516     pragma(inline, true) ref T emplaceFront(Args...)(auto ref Args /+ && +/ args)
517     {
518         DataOps.emplace(d, 0, args /*/+ std:: +/forward!(Args)(args)...*/);
519         return *d.begin();
520     }
521 
522     /+iterator insert(qsizetype i, parameter_type t)
523     { return emplace(i, t); }+/
524     /+pragma(inline, true) iterator insert(qsizetype i, qsizetype n, parameter_type t)
525     {
526         (mixin(Q_ASSERT_X(q{size_t(i) <= size_t(QList.d.size)},q{ "QList<T>::insert"},q{ "index out of range"})));
527         (mixin(Q_ASSERT_X(q{n >= 0},q{ "QList::insert"},q{ "invalid count"})));
528         if (/+ Q_LIKELY +/(n))
529             d.insert(i, n, t);
530         return d.begin() + i;
531     }+/
532 /+    iterator insert(const_iterator before, parameter_type t)
533     {
534         (mixin(Q_ASSERT_X(q{QList.isValidIterator(before)},q{  "QList::insert"},q{ "The specified iterator argument 'before' is invalid"})));
535         return insert(before, 1, t);
536     }
537     iterator insert(const_iterator before, qsizetype n, parameter_type t)
538     {
539         (mixin(Q_ASSERT_X(q{QList.isValidIterator(before)},q{  "QList::insert"},q{ "The specified iterator argument 'before' is invalid"})));
540         return insert(/+ std:: +/distance(constBegin(), before), n, t);
541     }+/
542 /+    iterator insert(const_iterator before, rvalue_ref t)
543     {
544         (mixin(Q_ASSERT_X(q{QList.isValidIterator(before)},q{  "QList::insert"},q{ "The specified iterator argument 'before' is invalid"})));
545         return insert(/+ std:: +/distance(constBegin(), before), /+ std:: +/move(t));
546     }
547     iterator insert(qsizetype i, rvalue_ref t) {
548         static if (DataPointer.pass_parameter_by_value) {
549             /+ Q_UNUSED(i) +/
550             /+ Q_UNUSED(t) +/
551             return end();
552         } else {
553             return emplace(i, /+ std:: +/move(t));
554         }
555     }+/
556 
557     /+ template <typename ...Args> +/
558     /+ iterator emplace(Args)(const_iterator before, Args && /+ && +/ args)
559     {
560         (mixin(Q_ASSERT_X(q{QList.isValidIterator(before)},q{  "QList::emplace"},q{ "The specified iterator argument 'before' is invalid"})));
561         return emplace(/+ std:: +/distance(constBegin(), before), /+ std:: +/forward!(Args)(args)...);
562     } +/
563 
564     /+ template <typename ...Args> +/
565     iterator emplace(Args...)(qsizetype i, auto ref Args /+ && +/ args)
566     {
567         mixin(Q_ASSERT_X(q{i >= 0 && i <= d.size},q{ "QList<T>::insert"},q{ "index out of range"}));
568         DataOps.emplace(d, i, args /*std::forward<Args>(args)...*/);
569         return d.begin() + i;
570     }
571 /+ #if 0
572     template< class InputIt >
573     iterator insert( const_iterator pos, InputIt first, InputIt last );
574     iterator insert( const_iterator pos, std::initializer_list<T> ilist );
575 #endif +/
576     void replace()(qsizetype i, parameter_type t)
577     {
578         (mixin(Q_ASSERT_X(q{i >= 0 && i < QList.d.size},q{ "QList<T>::replace"},q{ "index out of range"})));
579         DataPointer oldData;
580         d.detach(&oldData);
581         d.data()[i] = t;
582     }
583 /+    void replace(qsizetype i, rvalue_ref t)
584     {
585         static if (DataPointer.pass_parameter_by_value) {
586             /+ Q_UNUSED(i) +/
587             /+ Q_UNUSED(t) +/
588         } else {
589             (mixin(Q_ASSERT_X(q{i >= 0 && i < QList.d.size},q{ "QList<T>::replace"},q{ "index out of range"})));
590             DataPointer oldData;
591             d.detach(&oldData);
592             d.data()[i] = /+ std:: +/move(t);
593         }
594     }+/
595 
596 /+    pragma(inline, true) void remove(qsizetype i, qsizetype n = 1)
597     {
598         (mixin(Q_ASSERT_X(q{size_t(i) + size_t(n) <= size_t(QList.d.size)},q{ "QList::remove"},q{ "index out of range"})));
599         (mixin(Q_ASSERT_X(q{n >= 0},q{ "QList::remove"},q{ "invalid count"})));
600 
601         if (n == 0)
602             return;
603 
604         d.detach();
605         d.erase(d.begin() + i, n);
606     }+/
607 /+    pragma(inline, true) void removeFirst()/+ noexcept+/
608     {
609         (mixin(Q_ASSERT(q{!QList.isEmpty()})));
610         d.detach();
611         d.eraseFirst();
612     }
613     pragma(inline, true) void removeLast()/+ noexcept+/
614     {
615         (mixin(Q_ASSERT(q{!QList.isEmpty()})));
616         d.detach();
617         d.eraseLast();
618     }
619     value_type takeFirst() { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); value_type v = /+ std:: +/move(first()); d.eraseFirst(); return v; }
620     value_type takeLast() { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); value_type v = /+ std:: +/move(last()); d.eraseLast(); return v; }
621 +/
622     pragma(inline, true) ref QList!(T) fill()(parameter_type t, qsizetype newSize = -1)
623     {
624         if (newSize == -1)
625             newSize = size();
626         if (d.needsDetach() || newSize > capacity()) {
627             // must allocate memory
628             auto detached = DataPointer(Data.allocate(d.detachCapacity(newSize)));
629             DataOps.copyAppend(detached, newSize, t);
630             d.swap(detached);
631         } else {
632             // we're detached
633             auto copy = t;
634             DataOps.assign(d, d.begin(), d.begin() + qMin(size(), newSize), t);
635             if (newSize > size()) {
636                 DataOps.copyAppend(d, newSize - size(), copy);
637             } else if (newSize < size()) {
638                 DataOps.truncate(d, newSize);
639             }
640         }
641         return this;
642     }
643 
644 /+ #ifndef Q_QDOC +/
645     /+ using QListSpecialMethods<T>::contains; +/
646     /+ using QListSpecialMethods<T>::indexOf; +/
647     /+ using QListSpecialMethods<T>::lastIndexOf; +/
648 /+ #else
649     template <typename AT>
650     qsizetype indexOf(const AT &t, qsizetype from = 0) const noexcept;
651     template <typename AT>
652     qsizetype lastIndexOf(const AT &t, qsizetype from = -1) const noexcept;
653     template <typename AT>
654     bool contains(const AT &t) const noexcept;
655 #endif +/
656 
657     /+ template <typename AT = T> +/
658     qsizetype count(AT)(ref const(AT) t) const/+ noexcept+/
659     {
660         return qsizetype(/+ std:: +/count(data(), data() + size(), t));
661     }
662 
663     //void removeAt(qsizetype i) { remove(i); }
664     /+ template <typename AT = T> +/
665     qsizetype removeAll(AT)(ref const(AT) t)
666     {
667         import qt.core.containertools_impl;
668 
669         return /+ QtPrivate:: +/qt.core.containertools_impl.sequential_erase_with_copy(this, t);
670     }
671 
672     /+ template <typename AT = T> +/
673     bool removeOne(AT)(ref const(AT) t)
674     {
675         import qt.core.containertools_impl;
676 
677         return (/+ QtPrivate:: +/qt.core.containertools_impl.sequential_erase_one(this, t)) != 0;
678     }
679 
680     /+ template <typename Predicate> +/
681     qsizetype removeIf(Predicate)(Predicate pred)
682     {
683         import qt.core.containertools_impl;
684 
685         return /+ QtPrivate:: +/qt.core.containertools_impl.sequential_erase_if(this, pred);
686     }
687 
688     //T takeAt(qsizetype i) { T t = /+ std:: +/move((this)[i]); remove(i); return t; }
689     /+void move(qsizetype from, qsizetype to)
690     {
691         (mixin(Q_ASSERT_X(q{from >= 0 && from < QList.size()},q{ "QList::move(qsizetype, qsizetype)"},q{ "'from' is out-of-range"})));
692         (mixin(Q_ASSERT_X(q{to >= 0 && to < QList.size()},q{ "QList::move(qsizetype, qsizetype)"},q{ "'to' is out-of-range"})));
693         if (from == to) // don't detach when no-op
694             return;
695         detach();
696         T* /+ const +/  b = d.begin();
697         if (from < to)
698             /+ std:: +/rotate(b + from, b + from + 1, b + to + 1);
699         else
700             /+ std:: +/rotate(b + to, b + from, b + from + 1);
701     }+/
702 
703     // STL-style
704     iterator begin()() { detach(); return iterator(d.begin()); }
705     iterator end()() { detach(); return iterator(d.end()); }
706 
707     const_iterator begin() const/+ noexcept+/ { return const_iterator(d.constBegin()); }
708     const_iterator end() const/+ noexcept+/ { return const_iterator(d.constEnd()); }
709     const_iterator cbegin() const/+ noexcept+/ { return const_iterator(d.constBegin()); }
710     const_iterator cend() const/+ noexcept+/ { return const_iterator(d.constEnd()); }
711     const_iterator constBegin() const/+ noexcept+/ { return const_iterator(d.constBegin()); }
712     const_iterator constEnd() const/+ noexcept+/ { return const_iterator(d.constEnd()); }
713     /+ reverse_iterator rbegin() { return reverse_iterator(end()); } +/
714     /+ reverse_iterator rend() { return reverse_iterator(begin()); } +/
715     /+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } +/
716     /+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } +/
717     /+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } +/
718     /+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } +/
719 
720     auto opSlice()()const
721     {
722         struct R
723         {
724             iterator i;
725             iterator end;
726             ref T front()
727             {
728                 return *i;
729             }
730             bool empty()
731             {
732                 return i == end;
733             }
734             void popFront()
735             {
736                 ++i;
737             }
738         }
739         auto this_ = cast(QList*)&this;
740         return R(this_.begin(), this_.end());
741     }
742 
743 /+    iterator erase(const_iterator abegin, const_iterator aend)
744     {
745         (mixin(Q_ASSERT_X(q{QList.isValidIterator(abegin)},q{ "QList::erase"},q{ "The specified iterator argument 'abegin' is invalid"})));
746         (mixin(Q_ASSERT_X(q{QList.isValidIterator(aend)},q{ "QList::erase"},q{ "The specified iterator argument 'aend' is invalid"})));
747         (mixin(Q_ASSERT(q{aend >= abegin})));
748 
749         qsizetype i = /+ std:: +/distance(constBegin(), abegin);
750         qsizetype n = /+ std:: +/distance(abegin, aend);
751         remove(i, n);
752 
753         return d.begin() + i;
754     }+/
755 //    pragma(inline, true) iterator erase(const_iterator pos) { return erase(pos, cast(const_iterator)(pos+1)); }
756 
757     // more Qt
758     pragma(inline, true) ref T first()() { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); return *begin(); }
759     pragma(inline, true) ref const(T) first()() const/+ noexcept+/ { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); return *begin(); }
760     pragma(inline, true) ref const(T) constFirst()() const/+ noexcept+/ { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); return *begin(); }
761 //    pragma(inline, true) ref T last() { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); return *(end()-1); }
762 //    pragma(inline, true) ref const(T) last() const/+ noexcept+/ { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); return *(end()-1); }
763 //    pragma(inline, true) ref const(T) constLast() const/+ noexcept+/ { (mixin(Q_ASSERT(q{!QList.isEmpty()}))); return *(end()-1); }
764 //    pragma(inline, true) bool startsWith(parameter_type t) const { return !isEmpty() && first() == t; }
765 //    pragma(inline, true) bool endsWith(parameter_type t) const { return !isEmpty() && last() == t; }
766 /+    pragma(inline, true) QList!(T) mid(qsizetype pos, qsizetype len = -1) const
767     {
768         qsizetype p = pos;
769         qsizetype l = len;
770         //using namespace QtPrivate;
771         switch (QContainerImplHelper.mid(d.size, &p, &l)) {
772         case QContainerImplHelper.Null:
773         case QContainerImplHelper.Empty:
774             return QList();
775         case QContainerImplHelper.Full:
776             return this;
777         case QContainerImplHelper.Subset:
778             break;default:
779 
780         }
781 
782         // Allocate memory
783         static if(#configValue!"merged")
784         {
785         auto copied = DataPointer(Data.allocate(l));
786         }
787     static if(#configValue!"merged")
788     {
789     DataPointer copied__1();
790     }
791         copied__1.copyAppend(constBegin() + p, constBegin() + p + l);
792         return cast(QList!(T))(copied__1);
793     }+/
794 
795 /+    QList!(T) first(qsizetype n) const
796     {
797         (mixin(Q_ASSERT(q{size_t(n) <= size_t(QList.size())})));
798         return QList!(T)(begin(), begin() + n);
799     }
800     QList!(T) last(qsizetype n) const
801     {
802         (mixin(Q_ASSERT(q{size_t(n) <= size_t(QList.size())})));
803         return QList!(T)(end() - n, end());
804     }+/
805 /+    QList!(T) sliced(qsizetype pos) const
806     {
807         (mixin(Q_ASSERT(q{size_t(pos) <= size_t(QList.size())})));
808         return QList!(T)(begin() + pos, end());
809     }
810     QList!(T) sliced(qsizetype pos, qsizetype n) const
811     {
812         (mixin(Q_ASSERT(q{size_t(pos) <= size_t(QList.size())})));
813         (mixin(Q_ASSERT(q{n >= 0})));
814         (mixin(Q_ASSERT(q{pos + n <= QList.size()})));
815         return QList!(T)(begin() + pos, begin() + pos + n);
816     }+/
817 
818 //    T value(qsizetype i) const { return value(i, T()); }
819     /+pragma(inline, true) T value(qsizetype i, parameter_type defaultValue) const
820     {
821         return size_t(i) < size_t(d.size) ? at(i) : defaultValue;
822     }+/
823 
824     void swapItemsAt()(qsizetype i, qsizetype j) {
825         (mixin(Q_ASSERT_X(q{i >= 0 && i < QList.size() && j >= 0 && j < QList.size()},q{
826                     "QList<T>::swap"},q{ "index out of range"})));
827         detach();
828         qt.core.global.qSwap(d.begin()[i], d.begin()[j]);
829     }
830 
831     // STL compatibility
832 //    pragma(inline, true) void push_back(parameter_type t) { append(t); }
833     //void push_back(rvalue_ref t) { append(/+ std:: +/move(t)); }
834     //void push_front(rvalue_ref t) { prepend(/+ std:: +/move(t)); }
835 //    pragma(inline, true) void push_front(parameter_type t) { prepend(t); }
836 //    void pop_back()/+ noexcept+/ { removeLast(); }
837 //    void pop_front()/+ noexcept+/ { removeFirst(); }
838 
839     /+ template <typename ...Args> +/
840     // reference emplace_back(Args)(Args && /+ && +/ args) { return emplaceBack(/+ std:: +/forward!(Args)(args)...); }
841 
842     pragma(inline, true) bool empty() const/+ noexcept+/
843     { return d.size == 0; }
844 //    pragma(inline, true) ref T front() { return first(); }
845 //    pragma(inline, true) ref const(T) front() const/+ noexcept+/ { return first(); }
846 //    pragma(inline, true) ref T back() { return last(); }
847 //    pragma(inline, true) ref const(T) back() const/+ noexcept+/ { return last(); }
848 //    void shrink_to_fit() { squeeze(); }
849 
850     // comfort
851     extern(D) ref QList!(T) opOpAssign(string op)(ref const(QList!(T)) l) if(op == "~") { append(l); return this; }
852     /+ QList<T> &operator+=(QList<T> &&l) { append(std::move(l)); return *this; } +/
853     extern(D) pragma(inline, true) QList!(T) opBinary(string op)(ref const(QList!(T)) l) const if(op == "~")
854     { QList n = this; n ~= l; return n; }
855     /+ inline QList<T> operator+(QList<T> &&l) const
856     { QList n = *this; n += std::move(l); return n; } +/
857     extern(D) pragma(inline, true) ref QList!(T) opOpAssign(string op)(parameter_type t) if(op == "~")
858     { append(t); return this; }
859     /+pragma(inline, true) ref QList!(T) operator << (parameter_type t)
860     { append(t); return this; }+/
861     /+pragma(inline, true) ref QList!(T) operator <<(ref const(QList!(T)) l)
862     { this += l; return this; }+/
863     /+ inline QList<T> &operator<<(QList<T> &&l)
864     { *this += std::move(l); return *this; } +/
865     /+extern(D) pragma(inline, true) ref QList!(T) opOpAssign(string op)(rvalue_ref t) if(op == "~")
866     { append(/+ std:: +/move(t)); return this; }+/
867     /+pragma(inline, true) ref QList!(T) operator <<(rvalue_ref t)
868     { append(/+ std:: +/move(t)); return this; }+/
869 
870     // Consider deprecating in 6.4 or later
871 //    static QList!(T) fromList(ref const(QList!(T)) list)/+ noexcept+/ { return list; }
872 //    QList!(T) toList() const/+ noexcept+/ { return this; }
873 
874 //    pragma(inline, true) static QList!(T) fromVector(ref const(QList!(T)) vector)/+ noexcept+/ { return vector; }
875 //    pragma(inline, true) QList!(T) toVector() const/+ noexcept+/ { return this; }
876 
877     /+ template<qsizetype N> +/
878     /+ static QList!(T) fromReadOnlyData(qsizetype N)(ref const(T)[N] t)/+ noexcept+/
879     {
880         return QList!(T)({ null, const_cast!(T*)(t), N} );
881     } +/
882 
883     /+ template <typename AT = T> +/
884     qsizetype indexOf(AT)(ref const(AT) t, qsizetype from = 0) const/+ noexcept+/
885     {
886         return /+ QtPrivate:: +/.indexOf(this, t, from);
887     }
888     /+ template <typename AT = T> +/
889     qsizetype lastIndexOf(AT)(ref const(AT) t, qsizetype from = -1) const/+ noexcept+/
890     {
891         return /+ QtPrivate:: +/.lastIndexOf(this, t, from);
892     }
893 
894     /+ template <typename AT = T> +/
895     bool contains(AT)(ref const(AT) t) const/+ noexcept+/
896     {
897         return this.indexOf(t) != -1;
898     }
899 }
900 
901 /+ #if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
902 template <typename InputIterator,
903           typename ValueType = typename std::iterator_traits<InputIterator>::value_type,
904           QtPrivate::IfIsInputIterator<InputIterator> = true>
905 QList(InputIterator, InputIterator) -> QList<ValueType>;
906 #endif
907 
908 
909 template <typename T>
910 inline void QList<T>::append(QList<T> &&other)
911 {
912     Q_ASSERT(&other != this);
913     if (other.isEmpty())
914         return;
915     if (other.d->needsDetach() || !std::is_nothrow_move_constructible_v<T>)
916         return append(other);
917 
918     // due to precondition &other != this, we can unconditionally modify 'this'
919     d.detachAndGrow(QArrayData::GrowsAtEnd, other.size(), nullptr, nullptr);
920     Q_ASSERT(d.freeSpaceAtEnd() >= other.size());
921     d->moveAppend(other.begin(), other.end());
922 } +/
923 
924 
925 extern(C++, "QtPrivate") {
926 qsizetype indexOf(T, U)(ref const(QList!(T)) vector, ref const(U) u, qsizetype from)/+ noexcept+/
927 {
928     if (from < 0)
929         from = qMax(from + vector.size(), qsizetype(0));
930     if (from < vector.size()) {
931         auto n = vector.begin() + from - 1;
932         auto e = vector.end();
933         while (++n != e)
934             if (*n == u)
935                 return qsizetype(n - vector.begin());
936     }
937     return -1;
938 }
939 
940 qsizetype lastIndexOf(T, U)(ref const(QList!(T)) vector, ref const(U) u, qsizetype from)/+ noexcept+/
941 {
942     if (from < 0)
943         from += vector.d.size;
944     else if (from >= vector.size())
945         from = vector.size() - 1;
946     if (from >= 0) {
947         auto b = vector.begin();
948         auto n = vector.begin() + from + 1;
949         while (n != b) {
950             if (*--n == u)
951                 return qsizetype(n - b);
952         }
953     }
954     return -1;
955 }
956 }
957 
958 /+ Q_DECLARE_SEQUENTIAL_ITERATOR(List)
959 Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(List)
960 
961 template <typename T>
962 size_t qHash(const QList<T> &key, size_t seed = 0)
963     noexcept(noexcept(qHashRange(key.cbegin(), key.cend(), seed)))
964 {
965     return qHashRange(key.cbegin(), key.cend(), seed);
966 } +/
967 
968 qsizetype erase(T, AT)(ref QList!(T) list, ref const(AT) t)
969 {
970     import qt.core.containertools_impl;
971 
972     return /+ QtPrivate:: +/qt.core.containertools_impl.sequential_erase(list, t);
973 }
974 
975 qsizetype erase_if(T, Predicate)(ref QList!(T) list, Predicate pred)
976 {
977     import qt.core.containertools_impl;
978 
979     return /+ QtPrivate:: +/qt.core.containertools_impl.sequential_erase_if(list, pred);
980 }
981