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