1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QTest>
30#include <qvarlengtharray.h>
31#include <qvariant.h>
32#include <qscopedvaluerollback.h>
33
34#include <memory>
35
36class tst_QVarLengthArray : public QObject
37{
38 Q_OBJECT
39private slots:
40 void defaultConstructor_int() { defaultConstructor<int>(); }
41 void defaultConstructor_QString() { defaultConstructor<QString>(); }
42 void append();
43 void removeLast();
44 void oldTests();
45 void appendCausingRealloc();
46 void appendIsStronglyExceptionSafe();
47 void resize();
48 void realloc();
49 void reverseIterators();
50 void count();
51 void cpp17ctad();
52 void first();
53 void last();
54 void squeeze();
55 void operators();
56 void indexOf();
57 void lastIndexOf();
58 void contains();
59 void clear();
60 void initializeListInt();
61 void initializeListMovable();
62 void initializeListComplex();
63 void insertMove();
64 void nonCopyable();
65 void implicitDefaultCtor();
66
67private:
68 template <typename T>
69 void defaultConstructor();
70 template<typename T>
71 void initializeList();
72};
73
74struct Tracker
75{
76 static int count;
77 Tracker() { ++count; }
78 Tracker(const Tracker &) { ++count; }
79 Tracker(Tracker &&) { ++count; }
80
81 Tracker &operator=(const Tracker &) = default;
82 Tracker &operator=(Tracker &&) = default;
83
84 ~Tracker() { --count; }
85};
86
87int Tracker::count = 0;
88
89template <typename T>
90void tst_QVarLengthArray::defaultConstructor()
91{
92 {
93 QVarLengthArray<T, 123> vla;
94 QCOMPARE(vla.size(), 0);
95 QVERIFY(vla.empty());
96 QVERIFY(vla.isEmpty());
97 QCOMPARE(vla.begin(), vla.end());
98 QCOMPARE(vla.capacity(), 123);
99 }
100 {
101 QVarLengthArray<T> vla;
102 QCOMPARE(vla.capacity(), 256); // notice, should we change the default
103 }
104}
105
106void tst_QVarLengthArray::append()
107{
108 QVarLengthArray<QString, 2> v;
109 v.append(t: QString("1"));
110 v.append(t: v.front());
111 QCOMPARE(v.capacity(), 2);
112 // transition from prealloc to heap:
113 v.append(t: v.front());
114 QVERIFY(v.capacity() > 2);
115 QCOMPARE(v.front(), v.back());
116 while (v.size() < v.capacity())
117 v.push_back(t: v[0]);
118 QCOMPARE(v.back(), v.front());
119 QCOMPARE(v.size(), v.capacity());
120 // transition from heap to larger heap:
121 v.push_back(t: v.front());
122 QCOMPARE(v.back(), v.front());
123
124 QVarLengthArray<int> v2; // rocket!
125 v2.append(t: 5);
126}
127
128void tst_QVarLengthArray::removeLast()
129{
130 {
131 QVarLengthArray<char, 2> v;
132 v.append(t: 0);
133 v.append(t: 1);
134 QCOMPARE(v.size(), 2);
135 v.append(t: 2);
136 v.append(t: 3);
137 QCOMPARE(v.size(), 4);
138 v.removeLast();
139 QCOMPARE(v.size(), 3);
140 v.removeLast();
141 QCOMPARE(v.size(), 2);
142 }
143
144 {
145 QVarLengthArray<QString, 2> v;
146 v.append(t: "0");
147 v.append(t: "1");
148 QCOMPARE(v.size(), 2);
149 v.append(t: "2");
150 v.append(t: "3");
151 QCOMPARE(v.size(), 4);
152 v.removeLast();
153 QCOMPARE(v.size(), 3);
154 v.removeLast();
155 QCOMPARE(v.size(), 2);
156 }
157
158 {
159 Tracker t;
160 QCOMPARE(Tracker::count, 1);
161 QVarLengthArray<Tracker, 2> v;
162 v.append(t);
163 v.append(t: {});
164 QCOMPARE(Tracker::count, 3);
165 v.removeLast();
166 QCOMPARE(Tracker::count, 2);
167 v.append(t);
168 v.append(t: {});
169 QCOMPARE(Tracker::count, 4);
170 v.removeLast();
171 QCOMPARE(Tracker::count, 3);
172 }
173 QCOMPARE(Tracker::count, 0);
174}
175
176void tst_QVarLengthArray::oldTests()
177{
178 {
179 QVarLengthArray<int, 256> sa(128);
180 QVERIFY(sa.data() == &sa[0]);
181 sa[0] = 0xfee;
182 sa[10] = 0xff;
183 QVERIFY(sa[0] == 0xfee);
184 QVERIFY(sa[10] == 0xff);
185 sa.resize(asize: 512);
186 QVERIFY(sa.data() == &sa[0]);
187 QVERIFY(sa[0] == 0xfee);
188 QVERIFY(sa[10] == 0xff);
189 QVERIFY(sa.at(0) == 0xfee);
190 QVERIFY(sa.at(10) == 0xff);
191 QVERIFY(sa.value(0) == 0xfee);
192 QVERIFY(sa.value(10) == 0xff);
193 QVERIFY(sa.value(1000) == 0);
194 QVERIFY(sa.value(1000, 12) == 12);
195 QVERIFY(sa.size() == 512);
196 sa.reserve(asize: 1024);
197 QVERIFY(sa.capacity() == 1024);
198 QVERIFY(sa.size() == 512);
199 }
200 {
201 QVarLengthArray<QString> sa(10);
202 sa[0] = "Hello";
203 sa[9] = "World";
204 QCOMPARE(*sa.data(), QLatin1String("Hello"));
205 QCOMPARE(sa[9], QLatin1String("World"));
206 sa.reserve(asize: 512);
207 QCOMPARE(*sa.data(), QLatin1String("Hello"));
208 QCOMPARE(sa[9], QLatin1String("World"));
209 sa.resize(asize: 512);
210 QCOMPARE(*sa.data(), QLatin1String("Hello"));
211 QCOMPARE(sa[9], QLatin1String("World"));
212 }
213 {
214 int arr[2] = {1, 2};
215 QVarLengthArray<int> sa(10);
216 QCOMPARE(sa.size(), 10);
217 sa.append(abuf: arr, increment: 2);
218 QCOMPARE(sa.size(), 12);
219 QCOMPARE(sa[10], 1);
220 QCOMPARE(sa[11], 2);
221 }
222 {
223 QString arr[2] = { QString("hello"), QString("world") };
224 QVarLengthArray<QString> sa(10);
225 QCOMPARE(sa.size(), 10);
226 sa.append(abuf: arr, increment: 2);
227 QCOMPARE(sa.size(), 12);
228 QCOMPARE(sa[10], QString("hello"));
229 QCOMPARE(sa[11], QString("world"));
230 QCOMPARE(sa.at(10), QString("hello"));
231 QCOMPARE(sa.at(11), QString("world"));
232 QCOMPARE(sa.value(10), QString("hello"));
233 QCOMPARE(sa.value(11), QString("world"));
234 QCOMPARE(sa.value(10000), QString());
235 QCOMPARE(sa.value(1212112, QString("none")), QString("none"));
236 QCOMPARE(sa.value(-12, QString("neg")), QString("neg"));
237
238 sa.append(abuf: arr, increment: 1);
239 QCOMPARE(sa.size(), 13);
240 QCOMPARE(sa[12], QString("hello"));
241
242 sa.append(abuf: arr, increment: 0);
243 QCOMPARE(sa.size(), 13);
244 }
245 {
246 // assignment operator and copy constructor
247
248 QVarLengthArray<int> sa(10);
249 sa[5] = 5;
250
251 QVarLengthArray<int> sa2(10);
252 sa2[5] = 6;
253 sa2 = sa;
254 QCOMPARE(sa2[5], 5);
255
256 QVarLengthArray<int> sa3(sa);
257 QCOMPARE(sa3[5], 5);
258 }
259}
260
261void tst_QVarLengthArray::appendCausingRealloc()
262{
263 // This is a regression test for an old bug where creating a
264 // QVarLengthArray of the same size as the prealloc size would make
265 // the next call to append(const T&) corrupt the memory.
266 QVarLengthArray<float, 1> d(1);
267 for (int i=0; i<30; i++)
268 d.append(t: i);
269}
270
271void tst_QVarLengthArray::appendIsStronglyExceptionSafe()
272{
273#ifdef QT_NO_EXCEPTIONS
274 QSKIP("This test requires exception support enabled in the compiler.");
275#else
276 static bool throwOnCopyNow = false;
277 static bool throwOnMoveNow = false;
278 struct Thrower {
279 Thrower() = default;
280 Thrower(const Thrower &)
281 {
282 if (throwOnCopyNow)
283 throw 1;
284 }
285 Thrower &operator=(const Thrower &) = default;
286 Thrower(Thrower &&)
287 {
288 if (throwOnMoveNow)
289 throw 1;
290 }
291 Thrower &operator=(Thrower &&) = default;
292 ~Thrower() = default;
293 };
294
295 {
296 // ### TODO: QVLA isn't exception-safe when throwing during reallocation,
297 // ### so check with size() < capacity() for now
298 QVarLengthArray<Thrower, 2> vla(1);
299 {
300 Thrower t;
301 const QScopedValueRollback<bool> rb(throwOnCopyNow, true);
302 QVERIFY_EXCEPTION_THROWN(vla.push_back(t), int);
303 QCOMPARE(vla.size(), 1);
304 }
305 {
306 const QScopedValueRollback<bool> rb(throwOnMoveNow, true);
307 QVERIFY_EXCEPTION_THROWN(vla.push_back({}), int);
308 QCOMPARE(vla.size(), 1);
309 }
310 }
311#endif
312}
313
314void tst_QVarLengthArray::resize()
315{
316 //MOVABLE
317 {
318 QVarLengthArray<QVariant,1> values(1);
319 QCOMPARE(values.size(), 1);
320 values[0] = 1;
321 values.resize(asize: 2);
322 QCOMPARE(values[1], QVariant());
323 QCOMPARE(values[0], QVariant(1));
324 values[1] = 2;
325 QCOMPARE(values[1], QVariant(2));
326 QCOMPARE(values.size(), 2);
327 }
328
329 //POD
330 {
331 QVarLengthArray<int,1> values(1);
332 QCOMPARE(values.size(), 1);
333 values[0] = 1;
334 values.resize(asize: 2);
335 QCOMPARE(values[0], 1);
336 values[1] = 2;
337 QCOMPARE(values[1], 2);
338 QCOMPARE(values.size(), 2);
339 }
340
341 //COMPLEX
342 {
343 QVarLengthArray<QVarLengthArray<QString, 15>,1> values(1);
344 QCOMPARE(values.size(), 1);
345 values[0].resize(asize: 10);
346 values.resize(asize: 2);
347 QCOMPARE(values[1].size(), 0);
348 QCOMPARE(values[0].size(), 10);
349 values[1].resize(asize: 20);
350 QCOMPARE(values[1].size(), 20);
351 QCOMPARE(values.size(), 2);
352 }
353}
354
355struct MyBase
356{
357 MyBase()
358 : data(this)
359 , isCopy(false)
360 {
361 ++liveCount;
362 }
363
364 MyBase(MyBase const &)
365 : data(this)
366 , isCopy(true)
367 {
368 ++copyCount;
369 ++liveCount;
370 }
371
372 MyBase & operator=(MyBase const &)
373 {
374 if (!isCopy) {
375 isCopy = true;
376 ++copyCount;
377 } else {
378 ++errorCount;
379 }
380 if (!data) {
381 --movedCount;
382 ++liveCount;
383 }
384 data = this;
385
386 return *this;
387 }
388
389 ~MyBase()
390 {
391 if (isCopy) {
392 if (!copyCount || !data)
393 ++errorCount;
394 else
395 --copyCount;
396 }
397
398 if (data) {
399 if (!liveCount)
400 ++errorCount;
401 else
402 --liveCount;
403 } else
404 --movedCount;
405 }
406
407 bool wasConstructedAt(const MyBase *that) const
408 {
409 return that == data;
410 }
411
412 bool hasMoved() const { return !wasConstructedAt(that: this); }
413
414protected:
415 MyBase(const MyBase *data, bool isCopy)
416 : data(data), isCopy(isCopy) {}
417
418 const MyBase *data;
419 bool isCopy;
420
421public:
422 static int errorCount;
423 static int liveCount;
424 static int copyCount;
425 static int movedCount;
426};
427
428int MyBase::errorCount = 0;
429int MyBase::liveCount = 0;
430int MyBase::copyCount = 0;
431int MyBase::movedCount = 0;
432
433struct MyPrimitive
434 : MyBase
435{
436 MyPrimitive()
437 {
438 ++errorCount;
439 }
440
441 ~MyPrimitive()
442 {
443 ++errorCount;
444 }
445
446 MyPrimitive(MyPrimitive const &other)
447 : MyBase(other)
448 {
449 ++errorCount;
450 }
451};
452
453struct MyMovable
454 : MyBase
455{
456 MyMovable(char input = 'j') : MyBase(), i(input) {}
457
458 MyMovable(MyMovable const &other) : MyBase(other), i(other.i) {}
459
460 MyMovable(MyMovable &&other) : MyBase(other.data, other.isCopy), i(other.i)
461 {
462 ++movedCount;
463 other.isCopy = false;
464 other.data = nullptr;
465 }
466
467 MyMovable & operator=(const MyMovable &other)
468 {
469 MyBase::operator=(other);
470 i = other.i;
471 return *this;
472 }
473
474 MyMovable & operator=(MyMovable &&other)
475 {
476 if (isCopy)
477 --copyCount;
478 ++movedCount;
479 if (other.data)
480 --liveCount;
481 isCopy = other.isCopy;
482 data = other.data;
483 other.isCopy = false;
484 other.data = nullptr;
485
486 return *this;
487 }
488
489 bool operator==(const MyMovable &other) const
490 {
491 return i == other.i;
492 }
493 char i;
494};
495
496struct MyComplex
497 : MyBase
498{
499 MyComplex(char input = 'j') : i(input) {}
500 bool operator==(const MyComplex &other) const
501 {
502 return i == other.i;
503 }
504 char i;
505};
506
507QT_BEGIN_NAMESPACE
508
509Q_DECLARE_TYPEINFO(MyPrimitive, Q_PRIMITIVE_TYPE);
510Q_DECLARE_TYPEINFO(MyMovable, Q_MOVABLE_TYPE);
511Q_DECLARE_TYPEINFO(MyComplex, Q_COMPLEX_TYPE);
512
513QT_END_NAMESPACE
514
515bool reallocTestProceed = true;
516
517template <class T, int PreAlloc>
518int countMoved(QVarLengthArray<T, PreAlloc> const &c)
519{
520 int result = 0;
521 for (int i = 0; i < c.size(); ++i)
522 if (c[i].hasMoved())
523 ++result;
524
525 return result;
526}
527
528template <class T>
529void reallocTest()
530{
531 reallocTestProceed = false;
532
533 typedef QVarLengthArray<T, 16> Container;
534 enum {
535 isStatic = QTypeInfo<T>::isStatic,
536 isComplex = QTypeInfo<T>::isComplex,
537
538 isPrimitive = !isComplex && !isStatic,
539 isMovable = !isStatic
540 };
541
542 // Constructors
543 Container a;
544 QCOMPARE( MyBase::liveCount, 0 );
545 QCOMPARE( MyBase::copyCount, 0 );
546
547 QVERIFY( a.capacity() >= 16 );
548 QCOMPARE( a.size(), 0 );
549
550 Container b_real(8);
551 Container const &b = b_real;
552 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 8 );
553 QCOMPARE( MyBase::copyCount, 0 );
554
555 QVERIFY( b.capacity() >= 16 );
556 QCOMPARE( b.size(), 8 );
557
558 // Assignment
559 a = b;
560 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 16 );
561 QCOMPARE( MyBase::copyCount, isComplex ? 8 : 0 );
562 QVERIFY( a.capacity() >= 16 );
563 QCOMPARE( a.size(), 8 );
564
565 QVERIFY( b.capacity() >= 16 );
566 QCOMPARE( b.size(), 8 );
567
568 // append
569 a.append(b.data(), b.size());
570 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 24 );
571 QCOMPARE( MyBase::copyCount, isComplex ? 16 : 0 );
572
573 QVERIFY( a.capacity() >= 16 );
574 QCOMPARE( a.size(), 16 );
575
576 QVERIFY( b.capacity() >= 16 );
577 QCOMPARE( b.size(), 8 );
578
579 // removeLast
580 a.removeLast();
581 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 23 );
582 QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
583
584 QVERIFY( a.capacity() >= 16 );
585 QCOMPARE( a.size(), 15 );
586
587 QVERIFY( b.capacity() >= 16 );
588 QCOMPARE( b.size(), 8 );
589
590 // Movable types
591 const int capacity = a.capacity();
592 if (!isPrimitive)
593 QCOMPARE( countMoved(a), 0 );
594
595 // Reserve, no re-allocation
596 a.reserve(capacity);
597 if (!isPrimitive)
598 QCOMPARE( countMoved(a), 0 );
599 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 23 );
600 QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
601
602 QCOMPARE( a.capacity(), capacity );
603 QCOMPARE( a.size(), 15 );
604
605 QVERIFY( b.capacity() >= 16 );
606 QCOMPARE( b.size(), 8 );
607
608 // Reserve, force re-allocation
609 a.reserve(capacity * 2);
610 if (!isPrimitive)
611 QCOMPARE( countMoved(a), isMovable ? 15 : 0 );
612 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 23 );
613 QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
614
615 QVERIFY( a.capacity() >= capacity * 2 );
616 QCOMPARE( a.size(), 15 );
617
618 QVERIFY( b.capacity() >= 16 );
619 QCOMPARE( b.size(), 8 );
620
621 // resize, grow
622 a.resize(40);
623 if (!isPrimitive)
624 QCOMPARE( countMoved(a), isMovable ? 15 : 0 );
625 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 48 );
626 QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
627
628 QVERIFY( a.capacity() >= a.size() );
629 QCOMPARE( a.size(), 40 );
630
631 QVERIFY( b.capacity() >= 16 );
632 QCOMPARE( b.size(), 8 );
633
634 // Copy constructor, allocate
635 {
636 Container c(a);
637 if (!isPrimitive)
638 QCOMPARE( countMoved(c), 0 );
639 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 88 );
640 QCOMPARE( MyBase::copyCount, isComplex ? 55 : 0 );
641
642 QVERIFY( a.capacity() >= a.size() );
643 QCOMPARE( a.size(), 40 );
644
645 QVERIFY( b.capacity() >= 16 );
646 QCOMPARE( b.size(), 8 );
647
648 QVERIFY( c.capacity() >= 40 );
649 QCOMPARE( c.size(), 40 );
650 }
651
652 // resize, shrink
653 a.resize(10);
654 if (!isPrimitive)
655 QCOMPARE( countMoved(a), isMovable ? 10 : 0 );
656 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 18 );
657 QCOMPARE( MyBase::copyCount, isComplex ? 10 : 0 );
658
659 QVERIFY( a.capacity() >= a.size() );
660 QCOMPARE( a.size(), 10 );
661
662 QVERIFY( b.capacity() >= 16 );
663 QCOMPARE( b.size(), 8 );
664
665 // Copy constructor, don't allocate
666 {
667 Container c(a);
668 if (!isPrimitive)
669 QCOMPARE( countMoved(c), 0 );
670 QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 28 );
671 QCOMPARE( MyBase::copyCount, isComplex ? 20 : 0 );
672
673 QVERIFY( a.capacity() >= a.size() );
674 QCOMPARE( a.size(), 10 );
675
676 QVERIFY( b.capacity() >= 16 );
677 QCOMPARE( b.size(), 8 );
678
679 QVERIFY( c.capacity() >= 16 );
680 QCOMPARE( c.size(), 10 );
681 }
682
683 a.clear();
684 QCOMPARE( a.size(), 0 );
685
686 b_real.clear();
687 QCOMPARE( b.size(), 0 );
688
689 QCOMPARE(MyBase::errorCount, 0);
690 QCOMPARE(MyBase::liveCount, 0);
691
692 // All done
693 reallocTestProceed = true;
694}
695
696void tst_QVarLengthArray::realloc()
697{
698 reallocTest<MyBase>();
699 QVERIFY(reallocTestProceed);
700
701 reallocTest<MyPrimitive>();
702 QVERIFY(reallocTestProceed);
703
704 reallocTest<MyMovable>();
705 QVERIFY(reallocTestProceed);
706
707 reallocTest<MyComplex>();
708 QVERIFY(reallocTestProceed);
709}
710
711void tst_QVarLengthArray::reverseIterators()
712{
713 QVarLengthArray<int> v;
714 v << 1 << 2 << 3 << 4;
715 QVarLengthArray<int> vr = v;
716 std::reverse(first: vr.begin(), last: vr.end());
717 const QVarLengthArray<int> &cvr = vr;
718 QVERIFY(std::equal(v.begin(), v.end(), vr.rbegin()));
719 QVERIFY(std::equal(v.begin(), v.end(), vr.crbegin()));
720 QVERIFY(std::equal(v.begin(), v.end(), cvr.rbegin()));
721 QVERIFY(std::equal(vr.rbegin(), vr.rend(), v.begin()));
722 QVERIFY(std::equal(vr.crbegin(), vr.crend(), v.begin()));
723 QVERIFY(std::equal(cvr.rbegin(), cvr.rend(), v.begin()));
724}
725
726void tst_QVarLengthArray::count()
727{
728 // tests size(), count() and length(), since they're the same thing
729 {
730 const QVarLengthArray<int> list;
731 QCOMPARE(list.length(), 0);
732 QCOMPARE(list.count(), 0);
733 QCOMPARE(list.size(), 0);
734 }
735
736 {
737 QVarLengthArray<int> list;
738 list.append(t: 0);
739 QCOMPARE(list.length(), 1);
740 QCOMPARE(list.count(), 1);
741 QCOMPARE(list.size(), 1);
742 }
743
744 {
745 QVarLengthArray<int> list;
746 list.append(t: 0);
747 list.append(t: 1);
748 QCOMPARE(list.length(), 2);
749 QCOMPARE(list.count(), 2);
750 QCOMPARE(list.size(), 2);
751 }
752
753 {
754 QVarLengthArray<int> list;
755 list.append(t: 0);
756 list.append(t: 0);
757 list.append(t: 0);
758 QCOMPARE(list.length(), 3);
759 QCOMPARE(list.count(), 3);
760 QCOMPARE(list.size(), 3);
761 }
762
763 // test removals too
764 {
765 QVarLengthArray<int> list;
766 list.append(t: 0);
767 list.append(t: 0);
768 list.append(t: 0);
769 QCOMPARE(list.length(), 3);
770 QCOMPARE(list.count(), 3);
771 QCOMPARE(list.size(), 3);
772 list.removeLast();
773 QCOMPARE(list.length(), 2);
774 QCOMPARE(list.count(), 2);
775 QCOMPARE(list.size(), 2);
776 list.removeLast();
777 QCOMPARE(list.length(), 1);
778 QCOMPARE(list.count(), 1);
779 QCOMPARE(list.size(), 1);
780 list.removeLast();
781 QCOMPARE(list.length(), 0);
782 QCOMPARE(list.count(), 0);
783 QCOMPARE(list.size(), 0);
784 }
785}
786
787void tst_QVarLengthArray::cpp17ctad()
788{
789#ifdef __cpp_deduction_guides
790#define QVERIFY_IS_VLA_OF(obj, Type) \
791 QVERIFY2((std::is_same<decltype(obj), QVarLengthArray<Type>>::value), \
792 QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>()))
793#define CHECK(Type, One, Two, Three) \
794 do { \
795 const Type v[] = {One, Two, Three}; \
796 QVarLengthArray v1 = {One, Two, Three}; \
797 QVERIFY_IS_VLA_OF(v1, Type); \
798 QVarLengthArray v2(v1.begin(), v1.end()); \
799 QVERIFY_IS_VLA_OF(v2, Type); \
800 QVarLengthArray v3(std::begin(v), std::end(v)); \
801 QVERIFY_IS_VLA_OF(v3, Type); \
802 } while (false) \
803 /*end*/
804 CHECK(int, 1, 2, 3);
805 CHECK(double, 1.0, 2.0, 3.0);
806 CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three"));
807#undef QVERIFY_IS_VLA_OF
808#undef CHECK
809#else
810 QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler.");
811#endif
812
813}
814
815void tst_QVarLengthArray::first()
816{
817 // append some items, make sure it stays sane
818 QVarLengthArray<int> list;
819 list.append(t: 27);
820 QCOMPARE(list.first(), 27);
821 list.append(t: 4);
822 QCOMPARE(list.first(), 27);
823 list.append(t: 1987);
824 QCOMPARE(list.first(), 27);
825 QCOMPARE(list.length(), 3);
826
827 // remove some, make sure it stays sane
828 list.removeLast();
829 QCOMPARE(list.first(), 27);
830 QCOMPARE(list.length(), 2);
831
832 list.removeLast();
833 QCOMPARE(list.first(), 27);
834 QCOMPARE(list.length(), 1);
835}
836
837void tst_QVarLengthArray::last()
838{
839 // append some items, make sure it stays sane
840 QVarLengthArray<int> list;
841 list.append(t: 27);
842 QCOMPARE(list.last(), 27);
843 list.append(t: 4);
844 QCOMPARE(list.last(), 4);
845 list.append(t: 1987);
846 QCOMPARE(list.last(), 1987);
847 QCOMPARE(list.length(), 3);
848
849 // remove some, make sure it stays sane
850 list.removeLast();
851 QCOMPARE(list.last(), 4);
852 QCOMPARE(list.length(), 2);
853
854 list.removeLast();
855 QCOMPARE(list.last(), 27);
856 QCOMPARE(list.length(), 1);
857}
858
859void tst_QVarLengthArray::squeeze()
860{
861 QVarLengthArray<int> list;
862 int sizeOnStack = list.capacity();
863 int sizeOnHeap = sizeOnStack * 2;
864 list.resize(asize: 0);
865 QCOMPARE(list.capacity(), sizeOnStack);
866 list.resize(asize: sizeOnHeap);
867 QCOMPARE(list.capacity(), sizeOnHeap);
868 list.resize(asize: sizeOnStack);
869 QCOMPARE(list.capacity(), sizeOnHeap);
870 list.resize(asize: 0);
871 QCOMPARE(list.capacity(), sizeOnHeap);
872 list.squeeze();
873 QCOMPARE(list.capacity(), sizeOnStack);
874 list.resize(asize: sizeOnStack);
875 list.squeeze();
876 QCOMPARE(list.capacity(), sizeOnStack);
877 list.resize(asize: sizeOnHeap);
878 list.squeeze();
879 QCOMPARE(list.capacity(), sizeOnHeap);
880}
881
882void tst_QVarLengthArray::operators()
883{
884 QVarLengthArray<QString> myvla;
885 myvla << "A" << "B" << "C";
886 QVarLengthArray<QString> myvlatwo;
887 myvlatwo << "D" << "E" << "F";
888 QVarLengthArray<QString> combined;
889 combined << "A" << "B" << "C" << "D" << "E" << "F";
890
891 // !=
892 QVERIFY(myvla != myvlatwo);
893
894 // +=: not provided, emulate
895 //myvla += myvlatwo;
896 Q_FOREACH (const QString &s, myvlatwo)
897 myvla.push_back(t: s);
898 QCOMPARE(myvla, combined);
899
900 // ==
901 QVERIFY(myvla == combined);
902
903 // <, >, <=, >=
904 QVERIFY(!(myvla < combined));
905 QVERIFY(!(myvla > combined));
906 QVERIFY( myvla <= combined);
907 QVERIFY( myvla >= combined);
908 combined.push_back(t: "G");
909 QVERIFY( myvla < combined);
910 QVERIFY(!(myvla > combined));
911 QVERIFY( myvla <= combined);
912 QVERIFY(!(myvla >= combined));
913 QVERIFY(combined > myvla);
914 QVERIFY(combined >= myvla);
915
916 // []
917 QCOMPARE(myvla[0], QLatin1String("A"));
918 QCOMPARE(myvla[1], QLatin1String("B"));
919 QCOMPARE(myvla[2], QLatin1String("C"));
920 QCOMPARE(myvla[3], QLatin1String("D"));
921 QCOMPARE(myvla[4], QLatin1String("E"));
922 QCOMPARE(myvla[5], QLatin1String("F"));
923}
924
925void tst_QVarLengthArray::indexOf()
926{
927 QVarLengthArray<QString> myvec;
928 myvec << "A" << "B" << "C" << "B" << "A";
929
930 QVERIFY(myvec.indexOf("B") == 1);
931 QVERIFY(myvec.indexOf("B", 1) == 1);
932 QVERIFY(myvec.indexOf("B", 2) == 3);
933 QVERIFY(myvec.indexOf("X") == -1);
934 QVERIFY(myvec.indexOf("X", 2) == -1);
935
936 // add an X
937 myvec << "X";
938 QVERIFY(myvec.indexOf("X") == 5);
939 QVERIFY(myvec.indexOf("X", 5) == 5);
940 QVERIFY(myvec.indexOf("X", 6) == -1);
941
942 // remove first A
943 myvec.remove(i: 0);
944 QVERIFY(myvec.indexOf("A") == 3);
945 QVERIFY(myvec.indexOf("A", 3) == 3);
946 QVERIFY(myvec.indexOf("A", 4) == -1);
947}
948
949void tst_QVarLengthArray::lastIndexOf()
950{
951 QVarLengthArray<QString> myvec;
952 myvec << "A" << "B" << "C" << "B" << "A";
953
954 QVERIFY(myvec.lastIndexOf("B") == 3);
955 QVERIFY(myvec.lastIndexOf("B", 2) == 1);
956 QVERIFY(myvec.lastIndexOf("X") == -1);
957 QVERIFY(myvec.lastIndexOf("X", 2) == -1);
958
959 // add an X
960 myvec << "X";
961 QVERIFY(myvec.lastIndexOf("X") == 5);
962 QVERIFY(myvec.lastIndexOf("X", 5) == 5);
963 QVERIFY(myvec.lastIndexOf("X", 3) == -1);
964
965 // remove first A
966 myvec.remove(i: 0);
967 QVERIFY(myvec.lastIndexOf("A") == 3);
968 QVERIFY(myvec.lastIndexOf("A", 3) == 3);
969 QVERIFY(myvec.lastIndexOf("A", 2) == -1);
970}
971
972void tst_QVarLengthArray::contains()
973{
974 QVarLengthArray<QString> myvec;
975 myvec << "aaa" << "bbb" << "ccc";
976
977 QVERIFY(myvec.contains(QLatin1String("aaa")));
978 QVERIFY(myvec.contains(QLatin1String("bbb")));
979 QVERIFY(myvec.contains(QLatin1String("ccc")));
980 QVERIFY(!myvec.contains(QLatin1String("I don't exist")));
981
982 // add it and make sure it does :)
983 myvec.append(t: QLatin1String("I don't exist"));
984 QVERIFY(myvec.contains(QLatin1String("I don't exist")));
985}
986
987void tst_QVarLengthArray::clear()
988{
989 QVarLengthArray<QString, 5> myvec;
990
991 for (int i = 0; i < 10; ++i)
992 myvec << "aaa";
993
994 QCOMPARE(myvec.size(), 10);
995 QVERIFY(myvec.capacity() >= myvec.size());
996 const int oldCapacity = myvec.capacity();
997 myvec.clear();
998 QCOMPARE(myvec.size(), 0);
999 QCOMPARE(myvec.capacity(), oldCapacity);
1000}
1001
1002void tst_QVarLengthArray::initializeListInt()
1003{
1004 initializeList<int>();
1005}
1006
1007void tst_QVarLengthArray::initializeListMovable()
1008{
1009 const int instancesCount = MyMovable::liveCount;
1010 initializeList<MyMovable>();
1011 QCOMPARE(MyMovable::liveCount, instancesCount);
1012}
1013
1014void tst_QVarLengthArray::initializeListComplex()
1015{
1016 const int instancesCount = MyComplex::liveCount;
1017 initializeList<MyComplex>();
1018 QCOMPARE(MyComplex::liveCount, instancesCount);
1019}
1020
1021template<typename T>
1022void tst_QVarLengthArray::initializeList()
1023{
1024 T val1(110);
1025 T val2(105);
1026 T val3(101);
1027 T val4(114);
1028
1029 // QVarLengthArray(std::initializer_list<>)
1030 QVarLengthArray<T> v1 {val1, val2, val3};
1031 QCOMPARE(v1, QVarLengthArray<T>() << val1 << val2 << val3);
1032 QCOMPARE(v1, (QVarLengthArray<T> {val1, val2, val3}));
1033
1034 QVarLengthArray<QVarLengthArray<T>, 4> v2{ v1, {val4}, QVarLengthArray<T>(), {val1, val2, val3} };
1035 QVarLengthArray<QVarLengthArray<T>, 4> v3;
1036 v3 << v1 << (QVarLengthArray<T>() << val4) << QVarLengthArray<T>() << v1;
1037 QCOMPARE(v3, v2);
1038
1039 QVarLengthArray<T> v4({});
1040 QCOMPARE(v4.size(), 0);
1041
1042 // operator=(std::initializer_list<>)
1043
1044 QVarLengthArray<T> v5({val2, val1});
1045 v1 = { val1, val2 }; // make array smaller
1046 v4 = { val1, val2 }; // make array bigger
1047 v5 = { val1, val2 }; // same size
1048 QCOMPARE(v1, QVarLengthArray<T>() << val1 << val2);
1049 QCOMPARE(v4, v1);
1050 QCOMPARE(v5, v1);
1051
1052 QVarLengthArray<T, 1> v6 = { val1 };
1053 v6 = { val1, val2 }; // force allocation on heap
1054 QCOMPARE(v6.size(), 2);
1055 QCOMPARE(v6.first(), val1);
1056 QCOMPARE(v6.last(), val2);
1057
1058 v6 = {}; // assign empty
1059 QCOMPARE(v6.size(), 0);
1060}
1061
1062void tst_QVarLengthArray::insertMove()
1063{
1064 MyBase::errorCount = 0;
1065 QCOMPARE(MyBase::liveCount, 0);
1066 QCOMPARE(MyBase::copyCount, 0);
1067
1068 {
1069 QVarLengthArray<MyMovable, 6> vec;
1070 MyMovable m1;
1071 MyMovable m2;
1072 MyMovable m3;
1073 MyMovable m4;
1074 MyMovable m5;
1075 MyMovable m6;
1076 QCOMPARE(MyBase::copyCount, 0);
1077 QCOMPARE(MyBase::liveCount, 6);
1078
1079 vec.append(t: std::move(m3));
1080 QVERIFY(m3.wasConstructedAt(nullptr));
1081 QVERIFY(vec.at(0).wasConstructedAt(&m3));
1082 QCOMPARE(MyBase::errorCount, 0);
1083 QCOMPARE(MyBase::liveCount, 6);
1084 QCOMPARE(MyBase::movedCount, 1);
1085
1086 vec.push_back(t: std::move(m4));
1087 QVERIFY(m4.wasConstructedAt(nullptr));
1088 QVERIFY(vec.at(0).wasConstructedAt(&m3));
1089 QVERIFY(vec.at(1).wasConstructedAt(&m4));
1090 QCOMPARE(MyBase::errorCount, 0);
1091 QCOMPARE(MyBase::liveCount, 6);
1092 QCOMPARE(MyBase::movedCount, 2);
1093
1094 vec.prepend(t: std::move(m1));
1095 QVERIFY(m1.wasConstructedAt(nullptr));
1096 QVERIFY(vec.at(0).wasConstructedAt(&m1));
1097 QVERIFY(vec.at(1).wasConstructedAt(&m3));
1098 QVERIFY(vec.at(2).wasConstructedAt(&m4));
1099 QCOMPARE(MyBase::errorCount, 0);
1100 QCOMPARE(MyBase::liveCount, 6);
1101 QCOMPARE(MyBase::movedCount, 3);
1102
1103 vec.insert(i: 1, t: std::move(m2));
1104 QVERIFY(m2.wasConstructedAt(nullptr));
1105 QVERIFY(vec.at(0).wasConstructedAt(&m1));
1106 QVERIFY(vec.at(1).wasConstructedAt(&m2));
1107 QVERIFY(vec.at(2).wasConstructedAt(&m3));
1108 QVERIFY(vec.at(3).wasConstructedAt(&m4));
1109 QCOMPARE(MyBase::errorCount, 0);
1110 QCOMPARE(MyBase::liveCount, 6);
1111 QCOMPARE(MyBase::movedCount, 4);
1112
1113 vec += std::move(m5);
1114 QVERIFY(m5.wasConstructedAt(nullptr));
1115 QVERIFY(vec.at(0).wasConstructedAt(&m1));
1116 QVERIFY(vec.at(1).wasConstructedAt(&m2));
1117 QVERIFY(vec.at(2).wasConstructedAt(&m3));
1118 QVERIFY(vec.at(3).wasConstructedAt(&m4));
1119 QVERIFY(vec.at(4).wasConstructedAt(&m5));
1120 QCOMPARE(MyBase::errorCount, 0);
1121 QCOMPARE(MyBase::liveCount, 6);
1122 QCOMPARE(MyBase::movedCount, 5);
1123
1124 vec << std::move(m6);
1125 QVERIFY(m6.wasConstructedAt(nullptr));
1126 QVERIFY(vec.at(0).wasConstructedAt(&m1));
1127 QVERIFY(vec.at(1).wasConstructedAt(&m2));
1128 QVERIFY(vec.at(2).wasConstructedAt(&m3));
1129 QVERIFY(vec.at(3).wasConstructedAt(&m4));
1130 QVERIFY(vec.at(4).wasConstructedAt(&m5));
1131 QVERIFY(vec.at(5).wasConstructedAt(&m6));
1132
1133 QCOMPARE(MyBase::copyCount, 0);
1134 QCOMPARE(MyBase::liveCount, 6);
1135 QCOMPARE(MyBase::errorCount, 0);
1136 QCOMPARE(MyBase::movedCount, 6);
1137 }
1138 QCOMPARE(MyBase::liveCount, 0);
1139 QCOMPARE(MyBase::errorCount, 0);
1140 QCOMPARE(MyBase::movedCount, 0);
1141}
1142
1143void tst_QVarLengthArray::nonCopyable()
1144{
1145 QVarLengthArray<std::unique_ptr<int>> vec;
1146 std::unique_ptr<int> val1(new int(1));
1147 std::unique_ptr<int> val2(new int(2));
1148 std::unique_ptr<int> val3(new int(3));
1149 std::unique_ptr<int> val4(new int(4));
1150 std::unique_ptr<int> val5(new int(5));
1151 std::unique_ptr<int> val6(new int(6));
1152 int *const ptr1 = val1.get();
1153 int *const ptr2 = val2.get();
1154 int *const ptr3 = val3.get();
1155 int *const ptr4 = val4.get();
1156 int *const ptr5 = val5.get();
1157 int *const ptr6 = val6.get();
1158
1159 vec.append(t: std::move(val3));
1160 QVERIFY(!val3);
1161 QVERIFY(ptr3 == vec.at(0).get());
1162 vec.append(t: std::move(val4));
1163 QVERIFY(!val4);
1164 QVERIFY(ptr3 == vec.at(0).get());
1165 QVERIFY(ptr4 == vec.at(1).get());
1166 vec.prepend(t: std::move(val1));
1167 QVERIFY(!val1);
1168 QVERIFY(ptr1 == vec.at(0).get());
1169 QVERIFY(ptr3 == vec.at(1).get());
1170 QVERIFY(ptr4 == vec.at(2).get());
1171 vec.insert(i: 1, t: std::move(val2));
1172 QVERIFY(!val2);
1173 QVERIFY(ptr1 == vec.at(0).get());
1174 QVERIFY(ptr2 == vec.at(1).get());
1175 QVERIFY(ptr3 == vec.at(2).get());
1176 QVERIFY(ptr4 == vec.at(3).get());
1177 vec += std::move(val5);
1178 QVERIFY(!val5);
1179 QVERIFY(ptr1 == vec.at(0).get());
1180 QVERIFY(ptr2 == vec.at(1).get());
1181 QVERIFY(ptr3 == vec.at(2).get());
1182 QVERIFY(ptr4 == vec.at(3).get());
1183 QVERIFY(ptr5 == vec.at(4).get());
1184 vec << std::move(val6);
1185 QVERIFY(!val6);
1186 QVERIFY(ptr1 == vec.at(0).get());
1187 QVERIFY(ptr2 == vec.at(1).get());
1188 QVERIFY(ptr3 == vec.at(2).get());
1189 QVERIFY(ptr4 == vec.at(3).get());
1190 QVERIFY(ptr5 == vec.at(4).get());
1191 QVERIFY(ptr6 == vec.at(5).get());
1192}
1193
1194void tst_QVarLengthArray::implicitDefaultCtor()
1195{
1196 QVarLengthArray<int> def = {};
1197 QCOMPARE(def.size(), 0);
1198}
1199
1200QTEST_APPLESS_MAIN(tst_QVarLengthArray)
1201#include "tst_qvarlengtharray.moc"
1202

source code of qtbase/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp