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