QtBase  v6.3.1
tst_qtconcurrentmap.cpp
Go to the documentation of this file.
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 #include <qtconcurrentmap.h>
29 #include <qexception.h>
30 #include <qdebug.h>
31 
32 #include <QThread>
33 #include <QMutex>
34 #include <QTest>
35 #include <QRandomGenerator>
36 
37 #include "../testhelper_functions.h"
38 
39 class tst_QtConcurrentMap : public QObject
40 {
41  Q_OBJECT
42 private slots:
43  void map();
44  void blockingMap();
45  void mapOnRvalue();
46  void mapped();
47  void mappedThreadPool();
48  void mappedWithMoveOnlyCallable();
49  void mappedReduced();
50  void mappedReducedThreadPool();
51  void mappedReducedWithMoveOnlyCallable();
52  void mappedReducedDifferentType();
53  void mappedReducedInitialValue();
54  void mappedReducedInitialValueThreadPool();
55  void mappedReducedInitialValueWithMoveOnlyCallable();
56  void mappedReducedDifferentTypeInitialValue();
57  void mappedReduceOptionConvertableToResultType();
58  void assignResult();
59  void functionOverloads();
60  void noExceptFunctionOverloads();
61 #ifndef QT_NO_EXCEPTIONS
62  void exceptions();
63 #endif
64  void incrementalResults();
65  void noDetach();
66  void stlContainers();
67  void stlContainersLambda();
68  void qFutureAssignmentLeak();
69  void stressTest();
70  void persistentResultTest();
71 public slots:
72  void throttling();
73 };
74 
75 using namespace QtConcurrent;
76 
78 {
79  x *= 2;
80 }
81 
83 {
84 public:
85  void operator()(int x)
86  {
87  x *= 2;
88  }
89 };
90 
92 {
93  x *= 2;
94 }
95 
97 {
98 public:
99  void operator()(int &x)
100  {
101  x *= 2;
102  }
103 };
104 
106 {
107 public:
111 
114 
115  void operator()(int &x) { x *= 2; }
116 };
117 
119 
120 void tst_QtConcurrentMap::map()
121 {
122  // functors take arguments by reference, modifying the sequence in place
123  {
125  list << 1 << 2 << 3;
126 
127  // functor
129  QCOMPARE(list, QList<int>() << 2 << 4 << 6);
131  QCOMPARE(list, QList<int>() << 4 << 8 << 12);
132 
133  // function
135  QCOMPARE(list, QList<int>() << 8 << 16 << 24);
137  QCOMPARE(list, QList<int>() << 16 << 32 << 48);
138 
139  // bound function
141  QCOMPARE(list, QList<int>() << 32 << 64 << 96);
143  QCOMPARE(list, QList<int>() << 64 << 128 << 192);
144 
145  // member function
146  QList<Number> numberList;
147  numberList << 1 << 2 << 3;
149  QCOMPARE(numberList, QList<Number>() << 2 << 4 << 6);
150  QtConcurrent::map(numberList.begin(), numberList.end(), &Number::multiplyBy2).waitForFinished();
151  QCOMPARE(numberList, QList<Number>() << 4 << 8 << 12);
152 
153  // lambda
154  QtConcurrent::map(list, [](int &x){x *= 2;}).waitForFinished();
155  QCOMPARE(list, QList<int>() << 128 << 256 << 384);
156  QtConcurrent::map(list.begin(), list.end(), [](int &x){x *= 2;}).waitForFinished();
157  QCOMPARE(list, QList<int>() << 256 << 512 << 768);
158 
159  // move-only functor
161  QCOMPARE(list, QList<int>() << 512 << 1024 << 1536);
163  QCOMPARE(list, QList<int>() << 1024 << 2048 << 3072);
164  }
165 
166  // functors don't take arguments by reference, making these no-ops
167  {
169  list << 1 << 2 << 3;
170 
171  // functor
173  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
175  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
176 
177  // function
179  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
181  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
182 
183  // bound function
185  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
187  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
188 
189  // lambda
190  QtConcurrent::map(list, [](int x){x *= 2;}).waitForFinished();
191  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
192  QtConcurrent::map(list.begin(), list.end(), [](int x){x *= 2;}).waitForFinished();
193  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
194  }
195 
196  // functors take arguments by reference, modifying the move-only sequence in place
197  {
198  MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 });
199 
200  // functor
202  QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 }));
203  }
204 
205  // non-template sequences
206  {
207  NonTemplateSequence list { 1, 2, 3 };
209  QCOMPARE(list, NonTemplateSequence({ 2, 4, 6 }));
210  }
211 
212 #if 0
213  // not allowed: map() with immutable sequences makes no sense
214  {
215  const QList<int> list = QList<int>() << 1 << 2 << 3;
216 
220  }
221 #endif
222 
223 #if 0
224  // not allowed: in place modification of a temp copy (since temp copy goes out of scope)
225  {
227  list << 1 << 2 << 3;
228 
232 
233  QList<Number> numberList;
234  numberList << 1 << 2 << 3;
236  }
237 #endif
238 
239 #if 0
240  // not allowed: map() on a const list, where functors try to modify the items in the list
241  {
242  const QList<int> list = QList<int>() << 1 << 2 << 3;;
243 
247 
248  const QList<Number> numberList = QList<Number>() << 1 << 2 << 3;
250  }
251 #endif
252 }
253 
254 void tst_QtConcurrentMap::blockingMap()
255 {
256  // functors take arguments by reference, modifying the sequence in place
257  {
259  list << 1 << 2 << 3;
260 
261  // functor
263  QCOMPARE(list, QList<int>() << 2 << 4 << 6);
265  QCOMPARE(list, QList<int>() << 4 << 8 << 12);
266 
267  // function
269  QCOMPARE(list, QList<int>() << 8 << 16 << 24);
271  QCOMPARE(list, QList<int>() << 16 << 32 << 48);
272 
273  // bound function
275  QCOMPARE(list, QList<int>() << 32 << 64 << 96);
277  QCOMPARE(list, QList<int>() << 64 << 128 << 192);
278 
279  // member function
280  QList<Number> numberList;
281  numberList << 1 << 2 << 3;
283  QCOMPARE(numberList, QList<Number>() << 2 << 4 << 6);
284  QtConcurrent::blockingMap(numberList.begin(), numberList.end(), &Number::multiplyBy2);
285  QCOMPARE(numberList, QList<Number>() << 4 << 8 << 12);
286 
287  // lambda
288  QtConcurrent::blockingMap(list, [](int &x) { x *= 2; });
289  QCOMPARE(list, QList<int>() << 128 << 256 << 384);
290  QtConcurrent::blockingMap(list.begin(), list.end(), [](int &x) { x *= 2; });
291  QCOMPARE(list, QList<int>() << 256 << 512 << 768);
292 
293  // move-only functor
295  QCOMPARE(list, QList<int>() << 512 << 1024 << 1536);
297  QCOMPARE(list, QList<int>() << 1024 << 2048 << 3072);
298  }
299 
300  // functors take arguments by reference, modifying the move-only sequence in place
301  {
302  MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 });
303 
304  // functor
306  QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 }));
307  QtConcurrent::blockingMap(moveOnlyVector.begin(), moveOnlyVector.end(),
309  QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 4, 8, 12 }));
310  }
311 
312  // functors don't take arguments by reference, making these no-ops
313  {
315  list << 1 << 2 << 3;
316 
317  // functor
319  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
321  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
322 
323  // function
325  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
327  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
328 
329  // bound function
331  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
333  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
334 
335  // lambda
336  QtConcurrent::blockingMap(list, [](int x) { x *= 2; });
337  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
338  QtConcurrent::blockingMap(list.begin(), list.end(), [](int x) { x *= 2; });
339  QCOMPARE(list, QList<int>() << 1 << 2 << 3);
340  }
341 
342  // non-template sequences
343  {
344  NonTemplateSequence list { 1, 2, 3 };
346  QCOMPARE(list, NonTemplateSequence({ 2, 4, 6 }));
347  }
348 
349 #if 0
350  // not allowed: map() with immutable sequences makes no sense
351  {
352  const QList<int> list = QList<int>() << 1 << 2 << 3;
353 
357  }
358 #endif
359 
360 #if 0
361  // not allowed: in place modification of a temp copy (since temp copy goes out of scope)
362  {
364  list << 1 << 2 << 3;
365 
369 
370  QList<Number> numberList;
371  numberList << 1 << 2 << 3;
373  }
374 #endif
375 
376 #if 0
377  // not allowed: map() on a const list, where functors try to modify the items in the list
378  {
379  const QList<int> list = QList<int>() << 1 << 2 << 3;;
380 
384 
385  const QList<Number> numberList = QList<Number>() << 1 << 2 << 3;
387  }
388 #endif
389 }
390 
391 void tst_QtConcurrentMap::mapOnRvalue()
392 {
393  struct ListRange
394  {
396  ListRange(iterator b, iterator e) : m_begin(b), m_end(e) { }
397 
398  iterator begin() const { return m_begin; }
399  iterator end() const { return m_end; }
400 
401  private:
402  iterator m_begin;
403  iterator m_end;
404  };
405 
406  const QList expected { 1, 4, 6, 4 };
407  {
408  QList list { 1, 2, 3, 4 };
409  auto future =
410  QtConcurrent::map(ListRange(list.begin() + 1, list.end() - 1), multiplyBy2InPlace);
412  QCOMPARE(list, expected);
413  }
414 
415  {
416  QList list { 1, 2, 3, 4 };
418  auto future = QtConcurrent::map(&pool, ListRange(list.begin() + 1, list.end() - 1),
421  QCOMPARE(list, expected);
422  }
423 
424  {
425  QList list { 1, 2, 3, 4 };
426  QtConcurrent::blockingMap(ListRange(list.begin() + 1, list.end() - 1), multiplyBy2InPlace);
427  QCOMPARE(list, expected);
428  }
429 
430  {
431  QList list { 1, 2, 3, 4 };
433  QtConcurrent::blockingMap(&pool, ListRange(list.begin() + 1, list.end() - 1),
435  QCOMPARE(list, expected);
436  }
437 }
438 
439 int multiplyBy2(int x)
440 {
441  int y = x * 2;
442  return y;
443 }
444 
446 {
447 public:
448  int operator()(int x) const
449  {
450  int y = x * 2;
451  return y;
452  }
453 };
454 
456 {
457 public:
458  MultiplyBy2MoveOnly() = default;
461 
464 
465  int operator()(int x) const
466  {
467  int y = x * 2;
468  return y;
469  }
470 };
471 
472 double intToDouble(int x)
473 {
474  return double(x);
475 }
476 
478 {
479 public:
480  double operator()(int x) const
481  {
482  return double(x);
483  }
484 };
485 
486 int stringToInt(const QString &string)
487 {
488  return string.toInt();
489 }
490 
492 {
493 public:
494  int operator()(const QString &string) const
495  {
496  return string.toInt();
497  }
498 };
499 
500 #define CHECK_FAIL(message) \
501 do {\
502  if (QTest::currentTestFailed())\
503  QFAIL("failed one line above on " message);\
504 } while (false)
505 
506 template <typename SourceObject, typename ResultObject, typename MapObject>
507 void testMapped(const QList<SourceObject> &sourceObjectList, const QList<ResultObject> &expectedResult, MapObject mapObject)
508 {
510  sourceObjectList, mapObject).results();
511  QCOMPARE(result1, expectedResult);
512 
514  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject).results();
515  QCOMPARE(result2, expectedResult);
516 
518  sourceObjectList, mapObject);
519  QCOMPARE(result3, expectedResult);
520 
521  const QList<ResultObject> result4 = QtConcurrent::blockingMapped<QList<ResultObject>>(
522  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject);
523  QCOMPARE(result4, expectedResult);
524 }
525 
526 void tst_QtConcurrentMap::mapped()
527 {
528  const QList<int> intList {1, 2, 3};
529  const QList<Number> numberList {1, 2, 3};
530  const QList<QString> stringList {"1", "2", "3"};
531  const QList<double> doubleList {1.0, 2.0, 3.0};
532 
533  const QList<int> intListMultipiedBy2 {2, 4, 6};
534  const QList<Number> numberListMultipiedBy2 {2, 4, 6};
535 
536  auto lambdaMultiplyBy2 = [](int x) {
537  return 2 * x;
538  };
539  auto lambdaIntToDouble = [](int x) {
540  return double(x);
541  };
542  auto lambdaStringToInt = [](const QString &string) {
543  return string.toInt();
544  };
545 
546  testMapped(intList, intListMultipiedBy2, MultiplyBy2());
547  CHECK_FAIL("functor");
548  testMapped(intList, intListMultipiedBy2, multiplyBy2);
549  CHECK_FAIL("function");
550  testMapped(numberList, numberListMultipiedBy2, &Number::multipliedBy2);
551  CHECK_FAIL("member");
552  testMapped(intList, intListMultipiedBy2, lambdaMultiplyBy2);
553  CHECK_FAIL("lambda");
554 
555  // change the value_type, same container
556  testMapped(intList, doubleList, IntToDouble());
557  CHECK_FAIL("functor");
558  testMapped(intList, doubleList, intToDouble);
559  CHECK_FAIL("function");
560  testMapped(numberList, stringList, &Number::toString);
561  CHECK_FAIL("member");
562  testMapped(intList, doubleList, lambdaIntToDouble);
563  CHECK_FAIL("lambda");
564 
565  // change the value_type
567  CHECK_FAIL("functor");
569  CHECK_FAIL("function");
570  testMapped(numberList, intList, &Number::toInt);
571  CHECK_FAIL("member");
572  testMapped(stringList, intList, lambdaStringToInt);
573  CHECK_FAIL("lambda");
574 
575  // not allowed: const member function where all arguments have default values
576 #if 0
578  CHECK_FAIL("member");
579 #endif
580 
581  {
582  // non-template sequences
583  NonTemplateSequence list { 1, 2, 3 };
584 
586  QCOMPARE(future.results(), QList({ 2, 4, 6 }));
587 
589  QCOMPARE(result, NonTemplateSequence({ 2, 4, 6 }));
590  }
591 
592  {
593  // rvalue sequences
594  auto future = QtConcurrent::mapped(std::vector { 1, 2, 3 }, multiplyBy2);
595  QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
596 
598  QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
599  }
600 
601  {
602  // move only sequences
604  QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
605 
606  auto result = QtConcurrent::blockingMapped<std::vector<int>>(
607  MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
608  QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
609  }
610 }
611 
612 static QSemaphore semaphore(1);
613 static QSet<QThread *> workingThreads;
614 
616 {
617  semaphore.acquire();
618  workingThreads.insert(QThread::currentThread());
619  semaphore.release();
620 }
621 
623 {
624  semaphore.acquire();
625  const int count = workingThreads.size();
626  semaphore.release();
627  return count;
628 }
629 
630 template <typename SourceObject, typename ResultObject, typename MapObject>
632  const QList<SourceObject> &sourceObjectList,
633  const QList<ResultObject> &expectedResult,
634  MapObject mapObject)
635 {
637  sourceObjectList, mapObject).results();
638  QCOMPARE(result1, expectedResult);
639  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
640 
642  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject).results();
643  QCOMPARE(result2, expectedResult);
644  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
645 
647  sourceObjectList, mapObject);
648  QCOMPARE(result3, expectedResult);
649  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
650 
651  const QList<ResultObject> result4 = QtConcurrent::blockingMapped<QList<ResultObject>>(pool,
652  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject);
653  QCOMPARE(result4, expectedResult);
654  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
655 }
656 
657 int multiplyBy3(int x)
658 {
660  return x * 3;
661 }
662 
664 {
665 public:
666  int operator()(int x) const
667  {
669  return x * 3;
670  }
671 };
672 
673 void tst_QtConcurrentMap::mappedThreadPool()
674 {
675  const QList<int> intList {1, 2, 3};
676  const QList<int> intListMultipiedBy3 {3, 6, 9};
677 
678  auto lambdaMultiplyBy3 = [](int x) {
680  return x * 3;
681  };
682 
685  QCOMPARE(semaphore.available(), 1);
686  workingThreads.clear();
687 
688  testMappedThreadPool(&pool, intList, intListMultipiedBy3, MultiplyBy3());
689  CHECK_FAIL("functor");
690  testMappedThreadPool(&pool, intList, intListMultipiedBy3, multiplyBy3);
691  CHECK_FAIL("function");
692  testMappedThreadPool(&pool, intList, intListMultipiedBy3, lambdaMultiplyBy3);
693  CHECK_FAIL("lambda");
694 
695  {
696  // non-template sequences
697  NonTemplateSequence list { 1, 2, 3 };
698 
700  QCOMPARE(future.results(), QList({ 2, 4, 6 }));
701 
703  QCOMPARE(result, NonTemplateSequence({ 2, 4, 6 }));
704  }
705 
706  {
707  // rvalue sequences
708  auto future = QtConcurrent::mapped(&pool, std::vector { 1, 2, 3 }, multiplyBy2);
709  QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
710 
711  auto result = QtConcurrent::blockingMapped<std::vector<int>>(&pool, std::vector { 1, 2, 3 },
712  multiplyBy2);
713  QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
714  }
715  {
716  // move only sequences
718  QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
719 
720  auto result = QtConcurrent::blockingMapped<std::vector<int>>(
721  &pool, MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
722  QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
723  }
724 }
725 
726 void tst_QtConcurrentMap::mappedWithMoveOnlyCallable()
727 {
728  const QList<int> intList { 1, 2, 3 };
729  const QList<int> intListMultipiedBy2 { 2, 4, 6 };
730  {
731  const auto result = QtConcurrent::mapped(intList, MultiplyBy2()).results();
732  QCOMPARE(result, intListMultipiedBy2);
733  }
734  {
735  const auto result =
737  QCOMPARE(result, intListMultipiedBy2);
738  }
739  {
741  QCOMPARE(result, intListMultipiedBy2);
742  }
743  {
744  const auto result = QtConcurrent::blockingMapped<QList<int>>(intList.begin(), intList.end(),
745  MultiplyBy2());
746  QCOMPARE(result, intListMultipiedBy2);
747  }
748 
750  {
751  const auto result = QtConcurrent::mapped(&pool, intList, MultiplyBy2()).results();
752  QCOMPARE(result, intListMultipiedBy2);
753  }
754  {
755  const auto result = QtConcurrent::mapped(
756  &pool, intList.begin(), intList.end(), MultiplyBy2()).results();
757  QCOMPARE(result, intListMultipiedBy2);
758  }
759  {
761  QCOMPARE(result, intListMultipiedBy2);
762  }
763  {
764  const auto result = QtConcurrent::blockingMapped<QList<int>>(&pool, intList.begin(),
765  intList.end(), MultiplyBy2());
766  QCOMPARE(result, intListMultipiedBy2);
767  }
768 }
769 
770 int intSquare(int x)
771 {
772  return x * x;
773 }
774 
776 {
777 public:
778  int operator()(int x)
779  {
780  return x * x;
781  }
782 };
783 
785 {
786  return Number(x.toInt() * x.toInt());
787 }
788 
790 {
791 public:
793  {
794  return Number(x.toInt() * x.toInt());
795  }
796 };
797 
798 template <typename SourceObject, typename ResultObject, typename MapObject, typename ReduceObject>
799 void testMappedReduced(const QList<SourceObject> &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject)
800 {
801  // Result type is passed explicitly
802  {
803  const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
804  sourceObjectList, mapObject, reduceObject).result();
805  QCOMPARE(result1, expectedResult);
806 
807  const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(
808  sourceObjectList.constBegin(), sourceObjectList.constEnd(),
809  mapObject, reduceObject).result();
810  QCOMPARE(result2, expectedResult);
811 
812  const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(
813  sourceObjectList, mapObject, reduceObject);
814  QCOMPARE(result3, expectedResult);
815 
816  const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>(
817  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject);
818  QCOMPARE(result4, expectedResult);
819  }
820 
821  // Result type is deduced
822  {
824  sourceObjectList, mapObject, reduceObject).result();
825  QCOMPARE(result1, expectedResult);
826 
828  sourceObjectList.constBegin(), sourceObjectList.constEnd(),
829  mapObject, reduceObject).result();
830  QCOMPARE(result2, expectedResult);
831 
833  sourceObjectList, mapObject, reduceObject);
834  QCOMPARE(result3, expectedResult);
835 
837  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject);
838  QCOMPARE(result4, expectedResult);
839  }
840 }
841 
842 template <typename SourceObject, typename ResultObject, typename MapObject, typename ReduceObject>
843 void testMappedReduced(const QList<SourceObject> &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject, QtConcurrent::ReduceOptions options)
844 {
846  sourceObjectList, mapObject, reduceObject, options).result();
847  QCOMPARE(result1, expectedResult);
848 
849  const ResultObject result2 =
850  QtConcurrent::mappedReduced(sourceObjectList.constBegin(), sourceObjectList.constEnd(),
851  mapObject, reduceObject, options).result();
852  QCOMPARE(result2, expectedResult);
853 
855  sourceObjectList, mapObject, reduceObject, options);
856  QCOMPARE(result3, expectedResult);
857 
859  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, options);
860  QCOMPARE(result4, expectedResult);
861 }
862 
863 void tst_QtConcurrentMap::mappedReduced()
864 {
865  const QList<int> intList {1, 2, 3};
866  const QList<int> intListOfSquares {1, 4, 9};
867  const QList<Number> numberList {1, 2, 3};
868  const int sum = 6;
869  const int sumOfSquares = 14;
870 
872 
873  auto lambdaSquare = [](int x) {
874  return x * x;
875  };
876  auto lambdaSumReduce = [](int &sum, int x) {
877  sum += x;
878  };
879 
880  // FUNCTOR-other
881  testMappedReduced(intList, sumOfSquares, IntSquare(), IntSumReduce());
882  CHECK_FAIL("functor-functor");
883  testMappedReduced(intList, sumOfSquares, IntSquare(), intSumReduce);
884  CHECK_FAIL("functor-function");
885  testMappedReduced(intList, intListOfSquares, IntSquare(), push_back, OrderedReduce);
886  CHECK_FAIL("functor-member");
887  testMappedReduced(intList, sumOfSquares, IntSquare(), lambdaSumReduce);
888  CHECK_FAIL("functor-lambda");
889 
890  // FUNCTION-other
891  testMappedReduced(intList, sumOfSquares, intSquare, IntSumReduce());
892  CHECK_FAIL("function-functor");
894  CHECK_FAIL("function-function");
895  testMappedReduced(intList, intListOfSquares, intSquare, push_back, OrderedReduce);
896  CHECK_FAIL("function-member");
897  testMappedReduced(intList, sumOfSquares, intSquare, lambdaSumReduce);
898  CHECK_FAIL("function-lambda");
899 
900  // MEMBER-other
902  CHECK_FAIL("member-functor");
904  CHECK_FAIL("member-function");
905  testMappedReduced(numberList, intList, &Number::toInt, push_back, OrderedReduce);
906  CHECK_FAIL("member-member");
907  testMappedReduced(numberList, sum, &Number::toInt, lambdaSumReduce);
908  CHECK_FAIL("member-lambda");
909 
910  // LAMBDA-other
911  testMappedReduced(intList, sumOfSquares, lambdaSquare, IntSumReduce());
912  CHECK_FAIL("lambda-functor");
913  testMappedReduced(intList, sumOfSquares, lambdaSquare, intSumReduce);
914  CHECK_FAIL("lambda-function");
915  testMappedReduced(intList, intListOfSquares, lambdaSquare, push_back, OrderedReduce);
916  CHECK_FAIL("lambda-member");
917  testMappedReduced(intList, sumOfSquares, lambdaSquare, lambdaSumReduce);
918  CHECK_FAIL("lambda-lambda");
919 
920  {
921  // non-template sequences
922  NonTemplateSequence list { 1, 2, 3 };
923 
925  QCOMPARE(future.result(), 12);
926 
928  QCOMPARE(result, 12);
929  }
930 
931  {
932  // rvalue sequences
934  QCOMPARE(future.result(), sumOfSquares);
935 
937  intSumReduce);
938  QCOMPARE(result, sumOfSquares);
939  }
940 
941  {
942  // move only sequences
943  auto future =
945  QCOMPARE(future.result(), sumOfSquares);
946 
949  QCOMPARE(result, sumOfSquares);
950  }
951 }
952 
953 template <typename SourceObject, typename ResultObject, typename MapObject, typename ReduceObject>
955  const QList<SourceObject> &sourceObjectList,
956  const ResultObject &expectedResult,
957  MapObject mapObject,
958  ReduceObject reduceObject)
959 {
960  // Result type is passed explicitly
961  {
962  const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
963  pool, sourceObjectList, mapObject, reduceObject).result();
964  QCOMPARE(result1, expectedResult);
965  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
966 
967  const ResultObject result2 =
968  QtConcurrent::mappedReduced<ResultObject>(pool, sourceObjectList.constBegin(),
969  sourceObjectList.constEnd(), mapObject,
970  reduceObject).result();
971  QCOMPARE(result2, expectedResult);
972  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
973 
974  const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(
975  pool, sourceObjectList, mapObject, reduceObject);
976  QCOMPARE(result3, expectedResult);
977  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
978 
979  const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>(
980  pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
981  mapObject, reduceObject);
982  QCOMPARE(result4, expectedResult);
983  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
984  }
985 
986  // Result type is deduced
987  {
989  pool, sourceObjectList, mapObject, reduceObject).result();
990  QCOMPARE(result1, expectedResult);
991  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
992 
993  const ResultObject result2 =
994  QtConcurrent::mappedReduced(pool, sourceObjectList.constBegin(),
995  sourceObjectList.constEnd(), mapObject,
996  reduceObject).result();
997  QCOMPARE(result2, expectedResult);
998  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
999 
1001  pool, sourceObjectList, mapObject, reduceObject);
1002  QCOMPARE(result3, expectedResult);
1003  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1004 
1006  pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1007  mapObject, reduceObject);
1008  QCOMPARE(result4, expectedResult);
1009  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1010  }
1011 }
1012 
1013 int intCube(int x)
1014 {
1016  return x * x * x;
1017 }
1018 
1019 class IntCube
1020 {
1021 public:
1022  int operator()(int x)
1023  {
1025  return x * x * x;
1026  }
1027 };
1028 
1029 void tst_QtConcurrentMap::mappedReducedThreadPool()
1030 {
1031  const QList<int> intList {1, 2, 3};
1032  const int sumOfCubes = 36;
1033 
1034  auto lambdaCube = [](int x) {
1035  return x * x * x;
1036  };
1037  auto lambdaSumReduce = [](int &sum, int x) {
1038  sum += x;
1039  };
1040 
1041  QThreadPool pool;
1043  QCOMPARE(semaphore.available(), 1);
1044  workingThreads.clear();
1045 
1046  // FUNCTOR-other
1048  CHECK_FAIL("functor-functor");
1050  CHECK_FAIL("functor-function");
1051  testMappedReducedThreadPool(&pool, intList, sumOfCubes, IntCube(), lambdaSumReduce);
1052  CHECK_FAIL("functor-lambda");
1053 
1054  // FUNCTION-other
1056  CHECK_FAIL("function-functor");
1058  CHECK_FAIL("function-function");
1059  testMappedReducedThreadPool(&pool, intList, sumOfCubes, intCube, lambdaSumReduce);
1060  CHECK_FAIL("function-lambda");
1061 
1062  // LAMBDA-other
1063  testMappedReducedThreadPool(&pool, intList, sumOfCubes, lambdaCube, IntSumReduce());
1064  CHECK_FAIL("lambda-functor");
1065  testMappedReducedThreadPool(&pool, intList, sumOfCubes, lambdaCube, intSumReduce);
1066  CHECK_FAIL("lambda-function");
1067  testMappedReducedThreadPool(&pool, intList, sumOfCubes, lambdaCube, lambdaSumReduce);
1068  CHECK_FAIL("lambda-lambda");
1069 
1070  {
1071  // non-template sequences
1072  NonTemplateSequence list { 1, 2, 3 };
1073 
1075  QCOMPARE(future.result(), 12);
1076 
1078  QCOMPARE(result, 12);
1079  }
1080 
1081  {
1082  // rvalue sequences
1083  auto future =
1085  QCOMPARE(future.result(), sumOfCubes);
1086 
1088  intSumReduce);
1089  QCOMPARE(result, sumOfCubes);
1090  }
1091 
1092  {
1093  // move only sequences
1095  intSumReduce);
1096  QCOMPARE(future.result(), sumOfCubes);
1097 
1100  QCOMPARE(result, sumOfCubes);
1101  }
1102 }
1103 
1104 void tst_QtConcurrentMap::mappedReducedWithMoveOnlyCallable()
1105 {
1106  const QList<int> intList { 1, 2, 3 };
1107  const auto sum = 12;
1108  {
1109  const auto result = QtConcurrent::mappedReduced(
1111  QCOMPARE(result, sum);
1112  }
1113  {
1114  const auto result =
1117  QCOMPARE(result, sum);
1118  }
1119  {
1122  QCOMPARE(result, sum);
1123  }
1124  {
1127  QCOMPARE(result, sum);
1128  }
1129 
1130  QThreadPool pool;
1131  {
1134  QCOMPARE(result, sum);
1135  }
1136  {
1137  const auto result =
1140  QCOMPARE(result, sum);
1141  }
1142  {
1145  QCOMPARE(result, sum);
1146  }
1147  {
1150  QCOMPARE(result, sum);
1151  }
1152 }
1153 
1154 void tst_QtConcurrentMap::mappedReducedDifferentType()
1155 {
1156  const QList<int> intList {1, 2, 3};
1157  const QList<Number> numberList {1, 2, 3};
1158  const int sumOfSquares = 14;
1159 
1160  auto lambdaSquare = [](Number x) {
1161  return Number(x.toInt() * x.toInt());
1162  };
1163  auto lambdaSumReduce = [](int &sum, Number x) {
1164  sum += x.toInt();
1165  };
1166 
1167  // Test the case where reduce function of the form:
1168  // V function(T &result, const U &intermediate)
1169  // has T and U types different.
1170 
1171  // FUNCTOR-other
1173  CHECK_FAIL("functor-functor");
1175  CHECK_FAIL("functor-function");
1176  testMappedReduced(intList, sumOfSquares, NumberSquare(), lambdaSumReduce);
1177  CHECK_FAIL("functor-lambda");
1178 
1179  // FUNCTION-other
1181  CHECK_FAIL("function-functor");
1183  CHECK_FAIL("function-function");
1184  testMappedReduced(intList, sumOfSquares, numberSquare, lambdaSumReduce);
1185  CHECK_FAIL("function-lambda");
1186 
1187  // MEMBER-other
1188  testMappedReduced(numberList, sumOfSquares, &Number::squared, NumberSumReduce());
1189  CHECK_FAIL("member-functor");
1190  testMappedReduced(numberList, sumOfSquares, &Number::squared, numberSumReduce);
1191  CHECK_FAIL("member-function");
1192  testMappedReduced(numberList, sumOfSquares, &Number::squared, lambdaSumReduce);
1193  CHECK_FAIL("member-lambda");
1194 
1195  // LAMBDA-other
1196  testMappedReduced(intList, sumOfSquares, lambdaSquare, NumberSumReduce());
1197  CHECK_FAIL("lambda-functor");
1198  testMappedReduced(intList, sumOfSquares, lambdaSquare, numberSumReduce);
1199  CHECK_FAIL("lambda-function");
1200  testMappedReduced(intList, sumOfSquares, lambdaSquare, lambdaSumReduce);
1201  CHECK_FAIL("lambda-lambda");
1202 }
1203 
1204 template <typename SourceObject, typename ResultObject, typename InitialObject, typename MapObject, typename ReduceObject>
1206  const ResultObject &expectedResult,
1207  MapObject mapObject,
1208  ReduceObject reduceObject,
1209  InitialObject &&initialObject)
1210 {
1211  // Result type is passed explicitly
1212  {
1213  const ResultObject result1 =
1214  QtConcurrent::mappedReduced<ResultObject>(sourceObjectList, mapObject, reduceObject,
1215  initialObject).result();
1216  QCOMPARE(result1, expectedResult);
1217 
1218  const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(
1219  sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1220  mapObject, reduceObject, initialObject).result();
1221  QCOMPARE(result2, expectedResult);
1222 
1223  const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(
1224  sourceObjectList, mapObject, reduceObject, initialObject);
1225  QCOMPARE(result3, expectedResult);
1226 
1227  const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>(
1228  sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1229  mapObject, reduceObject, initialObject);
1230  QCOMPARE(result4, expectedResult);
1231  }
1232 
1233  // Result type is deduced
1234  {
1235  const ResultObject result1 =
1236  QtConcurrent::mappedReduced(sourceObjectList, mapObject, reduceObject,
1237  initialObject).result();
1238  QCOMPARE(result1, expectedResult);
1239 
1240  const ResultObject result2 = QtConcurrent::mappedReduced(
1241  sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1242  mapObject, reduceObject, initialObject).result();
1243  QCOMPARE(result2, expectedResult);
1244 
1246  sourceObjectList, mapObject, reduceObject, initialObject);
1247  QCOMPARE(result3, expectedResult);
1248 
1250  sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1251  mapObject, reduceObject, initialObject);
1252  QCOMPARE(result4, expectedResult);
1253  }
1254 }
1255 
1256 template <typename SourceObject, typename ResultObject, typename InitialObject, typename MapObject, typename ReduceObject>
1258  const ResultObject &expectedResult,
1259  MapObject mapObject,
1260  ReduceObject reduceObject,
1261  InitialObject &&initialObject,
1262  QtConcurrent::ReduceOptions options)
1263 {
1264  const ResultObject result1 = QtConcurrent::mappedReduced(
1265  sourceObjectList, mapObject, reduceObject, initialObject, options).result();
1266  QCOMPARE(result1, expectedResult);
1267 
1268  const ResultObject result2 =
1269  QtConcurrent::mappedReduced(sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1270  mapObject, reduceObject, initialObject, options).result();
1271  QCOMPARE(result2, expectedResult);
1272 
1274  sourceObjectList, mapObject, reduceObject, initialObject, options);
1275  QCOMPARE(result3, expectedResult);
1276 
1278  sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, initialObject, options);
1279  QCOMPARE(result4, expectedResult);
1280 }
1281 
1282 void tst_QtConcurrentMap::mappedReducedInitialValue()
1283 {
1284  // This is a copy of tst_QtConcurrentMap::mappedReduced with the initial value parameter added
1285 
1286  const QList<int> intList {1, 2, 3};
1287  const QList<int> intListInitial {10};
1288  const QList<int> intListAppended {10, 1, 2, 3};
1289  const QList<int> intListSquaresAppended {10, 1, 4, 9};
1290  const QList<Number> numberList {1, 2, 3};
1291  const int sum = 16;
1292  const int sumOfSquares = 24;
1293  const int intInitial = 10;
1294 
1296 
1297  auto lambdaSquare = [](int x) {
1298  return x * x;
1299  };
1300  auto lambdaSumReduce = [](int &sum, int x) {
1301  sum += x;
1302  };
1303 
1304  // FUNCTOR-other
1305  testMappedReducedInitialValue(intList, sumOfSquares, IntSquare(), IntSumReduce(), intInitial);
1306  CHECK_FAIL("functor-functor");
1307  testMappedReducedInitialValue(intList, sumOfSquares, IntSquare(), intSumReduce, intInitial);
1308  CHECK_FAIL("functor-function");
1309  testMappedReducedInitialValue(intList, intListSquaresAppended, IntSquare(), push_back, intListInitial, OrderedReduce);
1310  CHECK_FAIL("functor-member");
1311  testMappedReducedInitialValue(intList, sumOfSquares, IntSquare(), lambdaSumReduce, intInitial);
1312  CHECK_FAIL("functor-lambda");
1313 
1314  // FUNCTION-other
1315  testMappedReducedInitialValue(intList, sumOfSquares, intSquare, IntSumReduce(), intInitial);
1316  CHECK_FAIL("function-functor");
1317  testMappedReducedInitialValue(intList, sumOfSquares, intSquare, intSumReduce, intInitial);
1318  CHECK_FAIL("function-function");
1319  testMappedReducedInitialValue(intList, intListSquaresAppended, intSquare, push_back, intListInitial, OrderedReduce);
1320  CHECK_FAIL("function-member");
1321  testMappedReducedInitialValue(intList, sumOfSquares, intSquare, lambdaSumReduce, intInitial);
1322  CHECK_FAIL("function-lambda");
1323 
1324  // MEMBER-other
1325  testMappedReducedInitialValue(numberList, sum, &Number::toInt, IntSumReduce(), intInitial);
1326  CHECK_FAIL("member-functor");
1327  testMappedReducedInitialValue(numberList, sum, &Number::toInt, intSumReduce, intInitial);
1328  CHECK_FAIL("member-function");
1329  testMappedReducedInitialValue(numberList, intListAppended, &Number::toInt, push_back, intListInitial, OrderedReduce);
1330  CHECK_FAIL("member-member");
1331  testMappedReducedInitialValue(numberList, sum, &Number::toInt, lambdaSumReduce, intInitial);
1332  CHECK_FAIL("member-lambda");
1333 
1334  // LAMBDA-other
1335  testMappedReducedInitialValue(intList, sumOfSquares, lambdaSquare, IntSumReduce(), intInitial);
1336  CHECK_FAIL("lambda-functor");
1337  testMappedReducedInitialValue(intList, sumOfSquares, lambdaSquare, intSumReduce, intInitial);
1338  CHECK_FAIL("lambda-function");
1339  testMappedReducedInitialValue(intList, intListSquaresAppended, lambdaSquare, push_back, intListInitial, OrderedReduce);
1340  CHECK_FAIL("lambda-member");
1341  testMappedReducedInitialValue(intList, sumOfSquares, lambdaSquare, lambdaSumReduce, intInitial);
1342  CHECK_FAIL("lambda-lambda");
1343 
1344  {
1345  // non-template sequences
1346  NonTemplateSequence list { 1, 2, 3 };
1347 
1349  QCOMPARE(future.result(), intInitial + 12);
1350 
1351  auto result =
1353  QCOMPARE(result, intInitial + 12);
1354  }
1355 
1356  {
1357  // rvalue sequences
1359  intInitial);
1360  QCOMPARE(future.result(), sumOfSquares);
1361 
1363  intSumReduce, intInitial);
1364  QCOMPARE(result, sumOfSquares);
1365  }
1366 
1367  {
1368  // move only sequences
1370  intSumReduce, intInitial);
1371  QCOMPARE(future.result(), sumOfSquares);
1372 
1374  intSquare, intSumReduce, intInitial);
1375  QCOMPARE(result, sumOfSquares);
1376  }
1377 }
1378 
1379 template <typename SourceObject, typename ResultObject, typename InitialObject, typename MapObject, typename ReduceObject>
1381  const QList<SourceObject> &sourceObjectList,
1382  const ResultObject &expectedResult,
1383  MapObject mapObject,
1384  ReduceObject reduceObject,
1385  InitialObject &&initialObject)
1386 {
1387  // Result type is passed explicitly
1388  {
1389  const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(
1390  pool, sourceObjectList, mapObject, reduceObject, initialObject).result();
1391  QCOMPARE(result1, expectedResult);
1392  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1393 
1394  const ResultObject result2 =
1395  QtConcurrent::mappedReduced<ResultObject>(pool, sourceObjectList.constBegin(),
1396  sourceObjectList.constEnd(), mapObject,
1397  reduceObject, initialObject).result();
1398  QCOMPARE(result2, expectedResult);
1399  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1400 
1401  const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(
1402  pool, sourceObjectList, mapObject, reduceObject, initialObject);
1403  QCOMPARE(result3, expectedResult);
1404  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1405 
1406  const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>(
1407  pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1408  mapObject, reduceObject, initialObject);
1409  QCOMPARE(result4, expectedResult);
1410  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1411  }
1412 
1413  // Result type is deduced
1414  {
1415  const ResultObject result1 = QtConcurrent::mappedReduced(
1416  pool, sourceObjectList, mapObject, reduceObject, initialObject).result();
1417  QCOMPARE(result1, expectedResult);
1418  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1419 
1420  const ResultObject result2 =
1421  QtConcurrent::mappedReduced(pool, sourceObjectList.constBegin(),
1422  sourceObjectList.constEnd(), mapObject,
1423  reduceObject, initialObject).result();
1424  QCOMPARE(result2, expectedResult);
1425  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1426 
1428  pool, sourceObjectList, mapObject, reduceObject, initialObject);
1429  QCOMPARE(result3, expectedResult);
1430  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1431 
1433  pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
1434  mapObject, reduceObject, initialObject);
1435  QCOMPARE(result4, expectedResult);
1436  QCOMPARE(threadCount(), 1); // ensure the only one thread was working
1437  }
1438 }
1439 
1440 void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool()
1441 {
1442  // This is a copy of tst_QtConcurrentMap::mappedReduced with the initial value parameter added
1443 
1444  const QList<int> intList {1, 2, 3};
1445  const int sumOfCubes = 46;
1446  const int intInitial = 10;
1447 
1448  auto lambdaCube = [](int x) {
1449  return x * x * x;
1450  };
1451  auto lambdaSumReduce = [](int &sum, int x) {
1452  sum += x;
1453  };
1454 
1455  QThreadPool pool;
1457  QCOMPARE(semaphore.available(), 1);
1458  workingThreads.clear();
1459 
1460  // FUNCTOR-other
1462  IntSumReduce(), intInitial);
1463  CHECK_FAIL("functor-functor");
1465  intSumReduce, intInitial);
1466  CHECK_FAIL("functor-function");
1468  lambdaSumReduce, intInitial);
1469  CHECK_FAIL("functor-lambda");
1470 
1471  // FUNCTION-other
1473  IntSumReduce(), intInitial);
1474  CHECK_FAIL("function-functor");
1476  intSumReduce, intInitial);
1477  CHECK_FAIL("function-function");
1479  lambdaSumReduce, intInitial);
1480  CHECK_FAIL("function-lambda");
1481 
1482  // LAMBDA-other
1483  testMappedReducedInitialValueThreadPool(&pool, intList, sumOfCubes, lambdaCube,
1484  IntSumReduce(), intInitial);
1485  CHECK_FAIL("lambda-functor");
1486  testMappedReducedInitialValueThreadPool(&pool, intList, sumOfCubes, lambdaCube,
1487  intSumReduce, intInitial);
1488  CHECK_FAIL("lambda-function");
1489  testMappedReducedInitialValueThreadPool(&pool, intList, sumOfCubes, lambdaCube,
1490  lambdaSumReduce, intInitial);
1491  CHECK_FAIL("lambda-lambda");
1492 
1493  {
1494  // non-template sequences
1495  NonTemplateSequence list { 1, 2, 3 };
1496 
1497  auto future =
1499  QCOMPARE(future.result(), intInitial + 12);
1500 
1502  intInitial);
1503  QCOMPARE(result, intInitial + 12);
1504  }
1505 
1506  {
1507  // rvalue sequences
1509  intSumReduce, intInitial);
1510  QCOMPARE(future.result(), sumOfCubes);
1511 
1513  intSumReduce, intInitial);
1514  QCOMPARE(result, sumOfCubes);
1515  }
1516 
1517  {
1518  // move only sequences
1520  intSumReduce, intInitial);
1521  QCOMPARE(future.result(), sumOfCubes);
1522 
1524  intCube, intSumReduce, intInitial);
1525  QCOMPARE(result, sumOfCubes);
1526  }
1527 }
1528 
1529 void tst_QtConcurrentMap::mappedReducedInitialValueWithMoveOnlyCallable()
1530 {
1531  const QList<int> intList { 1, 2, 3 };
1532  const auto initialValue = 10;
1533  const auto sum = 22;
1534  {
1535  const auto result =
1537  IntSumReduceMoveOnly(), initialValue).result();
1538  QCOMPARE(result, sum);
1539  }
1540  {
1541  const auto result =
1543  IntSumReduceMoveOnly(), initialValue).result();
1544  QCOMPARE(result, sum);
1545  }
1546  {
1548  intList, MultiplyBy2(), IntSumReduceMoveOnly(), initialValue);
1549  QCOMPARE(result, sum);
1550  }
1551  {
1554  initialValue);
1555  QCOMPARE(result, sum);
1556  }
1557 
1558  QThreadPool pool;
1559  {
1560  const auto result =
1562  IntSumReduceMoveOnly(), initialValue).result();
1563  QCOMPARE(result, sum);
1564  }
1565  {
1568  initialValue).result();
1569  QCOMPARE(result, sum);
1570  }
1571  {
1573  &pool, intList, MultiplyBy2(), IntSumReduceMoveOnly(), initialValue);
1574  QCOMPARE(result, sum);
1575  }
1576  {
1579  initialValue);
1580  QCOMPARE(result, sum);
1581  }
1582 }
1583 
1584 void tst_QtConcurrentMap::mappedReducedDifferentTypeInitialValue()
1585 {
1586  // This is a copy of tst_QtConcurrentMap::mappedReducedDifferentType
1587  // with the initial value parameter added
1588 
1589  const QList<Number> numberList {1, 2, 3};
1590  const int sumOfSquares = 24;
1591  const int intInitial = 10;
1592 
1593  auto lambdaSquare = [](Number x) {
1594  return Number(x.toInt() * x.toInt());
1595  };
1596  auto lambdaSumReduce = [](int &sum, Number x) {
1597  sum += x.toInt();
1598  };
1599 
1600  // FUNCTOR-other
1601  testMappedReducedInitialValue(numberList, sumOfSquares, NumberSquare(), NumberSumReduce(), intInitial);
1602  CHECK_FAIL("functor-functor");
1603  testMappedReducedInitialValue(numberList, sumOfSquares, NumberSquare(), numberSumReduce, intInitial);
1604  CHECK_FAIL("functor-function");
1605  testMappedReducedInitialValue(numberList, sumOfSquares, NumberSquare(), lambdaSumReduce, intInitial);
1606  CHECK_FAIL("functor-lambda");
1607 
1608  // FUNCTION-other
1609  testMappedReducedInitialValue(numberList, sumOfSquares, numberSquare, NumberSumReduce(), intInitial);
1610  CHECK_FAIL("function-functor");
1611  testMappedReducedInitialValue(numberList, sumOfSquares, numberSquare, numberSumReduce, intInitial);
1612  CHECK_FAIL("function-function");
1613  testMappedReducedInitialValue(numberList, sumOfSquares, numberSquare, lambdaSumReduce, intInitial);
1614  CHECK_FAIL("function-lambda");
1615 
1616  // MEMBER-other
1617  testMappedReducedInitialValue(numberList, sumOfSquares, &Number::squared, NumberSumReduce(), intInitial);
1618  CHECK_FAIL("member-functor");
1619  testMappedReducedInitialValue(numberList, sumOfSquares, &Number::squared, numberSumReduce, intInitial);
1620  CHECK_FAIL("member-function");
1621  testMappedReducedInitialValue(numberList, sumOfSquares, &Number::squared, lambdaSumReduce, intInitial);
1622  CHECK_FAIL("member-lambda");
1623 
1624  // LAMBDA-other
1625  testMappedReducedInitialValue(numberList, sumOfSquares, lambdaSquare, NumberSumReduce(), intInitial);
1626  CHECK_FAIL("lambda-functor");
1627  testMappedReducedInitialValue(numberList, sumOfSquares, lambdaSquare, numberSumReduce, intInitial);
1628  CHECK_FAIL("lambda-function");
1629  testMappedReducedInitialValue(numberList, sumOfSquares, lambdaSquare, lambdaSumReduce, intInitial);
1630  CHECK_FAIL("lambda-lambda");
1631 }
1632 
1633 void tst_QtConcurrentMap::mappedReduceOptionConvertableToResultType()
1634 {
1635  const QList<int> intList { 1, 2, 3 };
1636  const int sum = 12;
1637  QThreadPool p;
1639 
1640  // With container
1643 
1644  // With iterators
1646  ro).result(), sum);
1648  intSumReduce, ro), sum);
1649 
1650  // With custom QThreadPool;
1654  intSumReduce, ro).result(), sum);
1656  intSumReduce, ro), sum);
1657 
1658  // The same as above, but specify the result type explicitly (this invokes different overloads)
1659  QCOMPARE(QtConcurrent::mappedReduced<int>(intList, multiplyBy2, intSumReduce, ro).result(),
1660  sum);
1661  QCOMPARE(QtConcurrent::blockingMappedReduced<int>(intList, multiplyBy2, intSumReduce, ro), sum);
1662 
1663  QCOMPARE(QtConcurrent::mappedReduced<int>(intList.begin(), intList.end(), multiplyBy2,
1664  intSumReduce, ro).result(), sum);
1665  QCOMPARE(QtConcurrent::blockingMappedReduced<int>(intList.begin(), intList.end(), multiplyBy2,
1666  intSumReduce, ro), sum);
1667 
1668  QCOMPARE(QtConcurrent::mappedReduced<int>(&p, intList, multiplyBy2, intSumReduce, ro).result(),
1669  sum);
1670  QCOMPARE(QtConcurrent::blockingMappedReduced<int>(&p, intList, multiplyBy2, intSumReduce, ro),
1671  sum);
1672  QCOMPARE(QtConcurrent::mappedReduced<int>(&p, intList.begin(), intList.end(), multiplyBy2,
1673  intSumReduce, ro).result(), sum);
1674  QCOMPARE(QtConcurrent::blockingMappedReduced<int>(&p, intList.begin(), intList.end(),
1675  multiplyBy2, intSumReduce, ro), sum);
1676 }
1677 
1678 int sleeper(int val)
1679 {
1680  QTest::qSleep(100);
1681  return val;
1682 }
1683 
1684 void tst_QtConcurrentMap::assignResult()
1685 {
1686  const QList<int> startList = QList<int>() << 0 << 1 << 2;
1688  QCOMPARE(list.at(0), 0);
1689  QCOMPARE(list.at(1), 1);
1690 }
1691 
1692 int fnConst(const int &i)
1693 {
1694  return i;
1695 }
1696 
1697 int fn(int &i)
1698 {
1699  return i;
1700 }
1701 
1702 int fnConstNoExcept(const int &i) noexcept
1703 {
1704  return i;
1705 }
1706 
1707 int fnNoExcept(int &i) noexcept
1708 {
1709  return i;
1710 }
1711 
1713 {
1714  return QString();
1715 }
1716 
1718 {
1719  return QString();
1720 }
1721 
1722 QString changeTypeConstNoExcept(const int &) noexcept
1723 {
1724  return QString();
1725 }
1726 
1728 {
1729  return QString();
1730 }
1731 
1733 {
1734  return 0;
1735 }
1736 
1738 {
1739  return 0;
1740 }
1741 
1743 {
1744  return 0;
1745 }
1746 
1748 {
1749  return 0;
1750 }
1751 
1753 {
1754 public:
1756 
1758  {
1759  return MemFnTester();
1760  }
1761 
1763  {
1764  return MemFnTester();
1765  }
1766 
1768  {
1769  return QString();
1770  }
1771 
1773  {
1774  return QString();
1775  }
1776 
1778  {
1779  return MemFnTester();
1780  }
1781 
1783  {
1784  return MemFnTester();
1785  }
1786 
1788  {
1789  return QString();
1790  }
1791 
1793  {
1794  return QString();
1795  }
1796 };
1797 
1799 
1800 void tst_QtConcurrentMap::functionOverloads()
1801 {
1803  const QList<int> constIntList;
1804  QList<MemFnTester> classList;
1805  const QList<MemFnTester> constMemFnTesterList;
1806 
1808  QtConcurrent::mapped(constIntList, fnConst);
1810  QtConcurrent::mapped(constMemFnTesterList, &MemFnTester::fnConst);
1811 
1812  QtConcurrent::blockingMapped<QList<int>>(intList, fnConst);
1813  QtConcurrent::blockingMapped<QList<int>>(constIntList, fnConst);
1814  QtConcurrent::blockingMapped<QList<MemFnTester>>(classList, &MemFnTester::fnConst);
1815  QtConcurrent::blockingMapped<QList<MemFnTester>>(constMemFnTesterList, &MemFnTester::fnConst);
1816 
1817  QtConcurrent::blockingMapped<QList<QString> >(intList, changeTypeConst);
1818  QtConcurrent::blockingMapped<QList<QString> >(constIntList, changeTypeConst);
1819  QtConcurrent::blockingMapped<QList<QString> >(classList, &MemFnTester::changeTypeConst);
1820  QtConcurrent::blockingMapped<QList<QString> >(constMemFnTesterList, &MemFnTester::changeTypeConst);
1821 }
1822 
1823 void tst_QtConcurrentMap::noExceptFunctionOverloads()
1824 {
1826  const QList<int> constIntList;
1827  QList<MemFnTester> classList;
1828  const QList<MemFnTester> constMemFnTesterList;
1829 
1831  QtConcurrent::mapped(constIntList, fnConstNoExcept);
1833  QtConcurrent::mapped(constMemFnTesterList, &MemFnTester::fnConstNoExcept);
1834 
1835  QtConcurrent::blockingMapped<QList<int>>(intList, fnConstNoExcept);
1836  QtConcurrent::blockingMapped<QList<int>>(constIntList, fnConstNoExcept);
1837  QtConcurrent::blockingMapped<QList<MemFnTester>>(classList, &MemFnTester::fnConstNoExcept);
1838  QtConcurrent::blockingMapped<QList<MemFnTester>>(constMemFnTesterList,
1840 
1841  QtConcurrent::blockingMapped<QList<QString> >(intList, changeTypeConstNoExcept);
1842  QtConcurrent::blockingMapped<QList<QString> >(constIntList, changeTypeConstNoExcept);
1843  QtConcurrent::blockingMapped<QList<QString> >(classList, &MemFnTester::changeTypeConstNoExcept);
1844  QtConcurrent::blockingMapped<QList<QString> >(constMemFnTesterList, &MemFnTester::changeTypeConstNoExcept);
1845 }
1846 
1850 {
1851 public:
1853  { currentInstanceCount.fetchAndAddRelaxed(1); updatePeak(); }
1857  { currentInstanceCount.fetchAndAddRelaxed(1); updatePeak(); }
1858  constexpr InstanceCounter &operator=(const InstanceCounter &) noexcept
1859  { return *this; }
1860 
1861  void updatePeak()
1862  {
1863  forever {
1864  const int localPeak = peakInstanceCount.loadRelaxed();
1865  const int localCurrent = currentInstanceCount.loadRelaxed();
1866  if (localCurrent <= localPeak)
1867  break;
1868  if (peakInstanceCount.testAndSetOrdered(localPeak, localCurrent))
1869  break;
1870  }
1871  }
1872 };
1873 
1875 {
1876  QTest::qSleep(2);
1877  return in;
1878 }
1879 
1881 {
1882  QTest::qSleep(QRandomGenerator::global()->bounded(2) + 1);
1883  return in;
1884 }
1885 
1887 {
1888  QTest::qSleep(QRandomGenerator::global()->bounded(4) + 1);
1889  ++result;
1890 }
1891 
1893 {
1894  ++result;
1895 }
1896 
1898 {
1899  const int itemcount = 100;
1900  const int allowedTemporaries = QThread::idealThreadCount() * 40;
1901 
1902  {
1905 
1906  QList<InstanceCounter> instances;
1907  for (int i = 0; i < itemcount; ++i)
1908  instances.append(InstanceCounter());
1909 
1911 
1913  QCOMPARE(results, itemcount);
1915  QVERIFY(peakInstanceCount.loadRelaxed() < itemcount + allowedTemporaries);
1916  }
1917 
1918  {
1921 
1922  QList<InstanceCounter> instances;
1923  for (int i = 0; i < itemcount; ++i)
1924  instances.append(InstanceCounter());
1925 
1928 
1929  QCOMPARE(results, itemcount);
1931  QVERIFY(peakInstanceCount.loadRelaxed() < itemcount + allowedTemporaries);
1932  }
1933 }
1934 
1935 #ifndef QT_NO_EXCEPTIONS
1936 void throwMapper(int &e)
1937 {
1938  Q_UNUSED(e);
1939  throw QException();
1940 }
1941 
1942 void tst_QtConcurrentMap::exceptions()
1943 {
1944  bool caught = false;
1945  try {
1946  QList<int> list = QList<int>() << 1 << 2 << 3;
1948  } catch (const QException &) {
1949  caught = true;
1950  }
1951  if (!caught)
1952  QFAIL("did not get exception");
1953 }
1954 #endif
1955 
1956 int mapper(const int &i)
1957 {
1958  QTest::qWait(1);
1959  return i;
1960 }
1961 
1962 void tst_QtConcurrentMap::incrementalResults()
1963 {
1964  const int count = 200;
1965  QList<int> ints;
1966  for (int i=0; i < count; ++i)
1967  ints << i;
1968 
1970 
1972 
1973  while (future.isFinished() == false) {
1974  for (int i = 0; i < future.resultCount(); ++i) {
1975  results += future.resultAt(i);
1976  }
1977 
1978  QTest::qWait(1);
1979  }
1980 
1981  QCOMPARE(future.isFinished(), true);
1983  QCOMPARE(future.results().count(), count);
1984 }
1985 
1986 /*
1987  Test that mapped does not cause deep copies when holding
1988  references to Qt containers.
1989 */
1990 void tst_QtConcurrentMap::noDetach()
1991 {
1992  {
1993  QList<int> l = QList<int>() << 1;
1994  QVERIFY(l.isDetached());
1995 
1996  QList<int> ll = l;
1997  QVERIFY(!l.isDetached());
1998 
1999  QtConcurrent::mapped(l, mapper).waitForFinished();
2000 
2001  QVERIFY(!l.isDetached());
2002  QVERIFY(!ll.isDetached());
2003 
2005 
2006  QVERIFY(!l.isDetached());
2007  QVERIFY(!ll.isDetached());
2008 
2010  QVERIFY(l.isDetached());
2011  QVERIFY(ll.isDetached());
2012  }
2013  {
2014  const QList<int> l = QList<int>() << 1;
2015  QVERIFY(l.isDetached());
2016 
2017  const QList<int> ll = l;
2018  QVERIFY(!l.isDetached());
2019 
2020  QtConcurrent::mapped(l, mapper).waitForFinished();
2021 
2022  QVERIFY(!l.isDetached());
2023  QVERIFY(!ll.isDetached());
2024 
2026 
2027  QVERIFY(!l.isDetached());
2028  QVERIFY(!ll.isDetached());
2029  }
2030 
2031 }
2032 
2033 void tst_QtConcurrentMap::stlContainers()
2034 {
2035  std::vector<int> vector;
2036  vector.push_back(1);
2037  vector.push_back(2);
2038 
2039  std::vector<int> vector2 = QtConcurrent::blockingMapped(vector, mapper);
2040  QCOMPARE(vector2.size(), 2u);
2041 
2042  std::list<int> list;
2043  list.push_back(1);
2044  list.push_back(2);
2045 
2046  std::list<int> list2 = QtConcurrent::blockingMapped(list, mapper);
2047  QCOMPARE(list2.size(), 2u);
2048 
2049  QtConcurrent::mapped(list, mapper).waitForFinished();
2050 
2052 }
2053 
2054 void tst_QtConcurrentMap::stlContainersLambda()
2055 {
2056  std::vector<int> vector;
2057  vector.push_back(1);
2058  vector.push_back(2);
2059 
2060  std::vector<int> vector2 =
2061  QtConcurrent::blockingMapped(vector, [](const int &i) { return mapper(i); });
2062  QCOMPARE(vector2.size(), 2u);
2063 
2064  std::list<int> list;
2065  list.push_back(1);
2066  list.push_back(2);
2067 
2068  std::list<int> list2 =
2069  QtConcurrent::blockingMapped(list, [](const int &i) { return mapper(i); });
2070  QCOMPARE(list2.size(), 2u);
2071 
2072  QtConcurrent::mapped(list, [](const int &i) { return mapper(i); }).waitForFinished();
2073 
2074  QtConcurrent::blockingMap(list, [](int x) { x *= 2; });
2075 }
2076 
2078 {
2079  return InstanceCounter(ic);
2080 }
2081 
2082 // Verify that held results are deleted when a future is
2083 // assigned over with operator ==
2084 void tst_QtConcurrentMap::qFutureAssignmentLeak()
2085 {
2089  {
2091  for (int i=0;i<1000;++i)
2092  list += InstanceCounter();
2095 
2098 
2101  }
2102 
2103  // Use QTRY_COMPARE because QtConcurrent::ThreadEngine::asynchronousFinish()
2104  // deletes its internals after signaling finished, so it might still be holding
2105  // on to copies of InstanceCounter for a short while.
2109 }
2110 
2111 inline void increment(int &num)
2112 {
2113  ++num;
2114 }
2115 
2116 inline int echo(const int &num)
2117 {
2118  return num;
2119 }
2120 
2121 void add(int &result, const int &sum)
2122 {
2123  result += sum;
2124 }
2125 
2126 void tst_QtConcurrentMap::stressTest()
2127 {
2128  const int listSize = 1000;
2129  const int sum = (listSize - 1) * (listSize / 2);
2130  QList<int> list;
2131 
2132 
2133  for (int i = 0; i < listSize; ++i) {
2134  list.append(i);
2135  }
2136 
2137  for (int i =0 ; i < 100; ++i) {
2139  for (int j = 0; j < listSize; ++j)
2140  QCOMPARE(result.at(j), j);
2141  }
2142 
2143  for (int i = 0 ; i < 100; ++i) {
2145  QCOMPARE(result, sum);
2146  }
2147 
2148  for (int i = 0 ; i < 100; ++i) {
2150  for (int j = 0; j < listSize; ++j)
2151  QCOMPARE(list.at(j), i + j + 1);
2152  }
2153 }
2154 
2156 {
2158  : mtx(mutex),
2159  ref(ai) {}
2160 
2161  int operator()(int x)
2162  {
2163  QMutexLocker locker(mtx);
2164  ref->ref();
2165  return ++x;
2166  }
2167 
2170 };
2171 
2172 // The Thread engine holds the last reference
2173 // to the QFuture, so this should not leak
2174 // or fail.
2175 void tst_QtConcurrentMap::persistentResultTest()
2176 {
2177  QFuture<void> voidFuture;
2178  QMutex mtx;
2179  QAtomicInt ref;
2180  LockedCounter lc(&mtx, &ref);
2181  QList<int> list;
2182  {
2183  list << 1 << 2 << 3;
2184  mtx.lock();
2186  ,lc);
2187  voidFuture = future;
2188  }
2189  QCOMPARE(ref.loadAcquire(), 0);
2190  mtx.unlock(); // Unblock
2191  voidFuture.waitForFinished();
2192  QCOMPARE(ref.loadAcquire(), 3);
2193 }
2194 
2196 #include "tst_qtconcurrentmap.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
InstanceCounter(const InstanceCounter &)
constexpr InstanceCounter & operator=(const InstanceCounter &) noexcept
int operator()(int x)
int operator()(int x)
double operator()(int x) const
QString changeTypeConstNoExcept() const noexcept
QString changeTypeConst() const
MemFnTester fnConst() const
MemFnTester fnNoExcept() noexcept
QString changeTypeNoExcept() noexcept
MemFnTester fnConstNoExcept() const noexcept
int operator()(int x) const
MultiplyBy2InPlaceMoveOnly & operator=(MultiplyBy2InPlaceMoveOnly &&other)=default
MultiplyBy2InPlaceMoveOnly(const MultiplyBy2InPlaceMoveOnly &)=delete
MultiplyBy2InPlaceMoveOnly & operator=(const MultiplyBy2InPlaceMoveOnly &)=delete
MultiplyBy2InPlaceMoveOnly()=default
MultiplyBy2InPlaceMoveOnly(MultiplyBy2InPlaceMoveOnly &&)=default
MultiplyBy2MoveOnly & operator=(MultiplyBy2MoveOnly &&other)=default
MultiplyBy2MoveOnly()=default
int operator()(int x) const
MultiplyBy2MoveOnly(MultiplyBy2MoveOnly &&)=default
MultiplyBy2MoveOnly(const MultiplyBy2MoveOnly &)=delete
MultiplyBy2MoveOnly & operator=(const MultiplyBy2MoveOnly &)=delete
int operator()(int x) const
Number multipliedBy2() const
void multiplyBy2()
QString toString() const
int toInt() const
Number squared() const
Number operator()(Number x)
The QAtomicInt class provides platform-independent atomic operations on int.
Definition: qatomic.h:158
bool testAndSetOrdered(T expectedValue, T newValue) noexcept
Definition: qbasicatomic.h:113
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
T fetchAndAddRelaxed(T valueToAdd) noexcept
Definition: qbasicatomic.h:140
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
The QException class provides a base class for exceptions that can be transferred across threads.
Definition: qexception.h:58
QList< T > results() const
Definition: qfuture.h:150
int resultCount() const
Definition: qfuture.h:133
T result() const
Definition: qfuture.h:331
T resultAt(int index) const
Definition: qfuture.h:339
void waitForFinished()
Definition: qfuture.h:138
bool isFinished() const
Definition: qfuture.h:130
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
bool isDetached() const noexcept
Definition: qlist.h:438
void push_back(parameter_type t)
Definition: qlist.h:687
iterator end()
Definition: qlist.h:624
const_iterator constBegin() const noexcept
Definition: qlist.h:630
iterator begin()
Definition: qlist.h:623
void append(parameter_type t)
Definition: qlist.h:469
const_iterator constEnd() const noexcept
Definition: qlist.h:631
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
void unlock() noexcept
Definition: qmutex.h:293
void lock() noexcept
Definition: qmutex.h:290
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
Definition: qrandom.h:311
The QSemaphore class provides a general counting semaphore.
Definition: qsemaphore.h:55
void acquire(int n=1)
Definition: qsemaphore.cpp:323
void release(int n=1)
Definition: qsemaphore.cpp:351
int available() const
Definition: qsemaphore.cpp:418
Definition: qset.h:54
The QString class provides a Unicode character string.
Definition: qstring.h:388
int toInt(bool *ok=nullptr, int base=10) const
Definition: qstring.h:848
The QStringList class provides a list of strings.
static int idealThreadCount() noexcept
Definition: qthread.cpp:884
static QThread * currentThread()
Definition: qthread.cpp:879
The QThreadPool class manages a collection of QThreads.
Definition: qthreadpool.h:56
void setMaxThreadCount(int maxThreadCount)
int operator()(const QString &string) const
QMap< QString, QString > map
[6]
double e
QCOMPARE(spy.count(), 1)
#define forever
Definition: ftrandom.c:53
auto it unsigned count const
Definition: hb-iter.hh:848
typename C::iterator iterator
Q_CORE_EXPORT void qSleep(int ms)
Q_CORE_EXPORT void qWait(int ms)
The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded pro...
Definition: qtaskbuilder.h:81
void blockingMap(QThreadPool *pool, Sequence &&sequence, MapFunctor map)
QFuture< void > map(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map)
QFuture< QtPrivate::MapResultType< Sequence, MapFunctor > > mapped(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map)
QFuture< ResultType > mappedReduced(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map, ReduceFunctor &&reduce, ReduceOptions options=ReduceOptions(UnorderedReduce|SequentialReduce))
ResultType blockingMappedReduced(QThreadPool *pool, Sequence &&sequence, MapFunctor &&map, ReduceFunctor &&reduce, ReduceOptions options=ReduceOptions(UnorderedReduce|SequentialReduce))
OutputSequence blockingMapped(QThreadPool *pool, InputSequence &&sequence, MapFunctor &&map)
#define QString()
Definition: parse-defines.h:51
void
Definition: png.h:1080
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint ref
GLint y
GLuint GLfloat * val
Definition: qopenglext.h:1513
GLuint in
Definition: qopenglext.h:8870
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLuint num
Definition: qopenglext.h:5654
GLsizei const GLchar *const * string
[0]
Definition: qopenglext.h:694
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QFAIL(message)
Definition: qtestcase.h:70
#define QTRY_COMPARE(expr, expected)
Definition: qtestcase.h:214
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
Q_UNUSED(salary)
[21]
QList< int > results
QFuture< int > sum
void intSumReduce(int &sum, int x)
[15]
QFuture< void > future
[5]
QList< int > vector
[14]
QThreadPool pool
future waitForFinished()
QList< int > intList
[8]
QList< QString > stringList
QSharedPointer< T > other(t)
[5]
QStringList list
[0]
LockedCounter(QMutex *mutex, QAtomicInt *ai)
void numberSumReduce(int &sum, const Number &x)
int intCube(int x)
void multiplyBy2Immutable(int x)
InstanceCounter slowMap(const InstanceCounter &in)
int changeTypeQStringListConstNoExcept(const QStringList &) noexcept
void slowReduce(int &result, const InstanceCounter &)
int multiplyBy2(int x)
int sleeper(int val)
Q_DECLARE_METATYPE(QList< Number >)
QString changeTypeNoExcept(int &) noexcept
int changeTypeQStringListConst(const QStringList &)
int changeTypeQStringListNoExcept(QStringList &) noexcept
void throwMapper(int &e)
int threadCount()
int mapper(const int &i)
QAtomicInt peakInstanceCount
Number numberSquare(Number x)
void increment(int &num)
int multiplyBy3(int x)
int stringToInt(const QString &string)
int fnNoExcept(int &i) noexcept
QString changeTypeConst(const int &)
void testMappedThreadPool(QThreadPool *pool, const QList< SourceObject > &sourceObjectList, const QList< ResultObject > &expectedResult, MapObject mapObject)
double intToDouble(int x)
QString changeType(int &)
int fn(int &i)
#define CHECK_FAIL(message)
QString changeTypeConstNoExcept(const int &) noexcept
void fastReduce(int &result, const InstanceCounter &)
InstanceCounter fastMap(const InstanceCounter &in)
int fnConst(const int &i)
void testMappedReduced(const QList< SourceObject > &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject)
InstanceCounter ic_fn(const InstanceCounter &ic)
void add(int &result, const int &sum)
void storeCurrentThread()
QAtomicInt currentInstanceCount
int intSquare(int x)
void testMappedReducedInitialValue(const QList< SourceObject > &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject, InitialObject &&initialObject)
void testMappedReducedInitialValueThreadPool(QThreadPool *pool, const QList< SourceObject > &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject, InitialObject &&initialObject)
int changeTypeQStringList(QStringList &)
int fnConstNoExcept(const int &i) noexcept
int echo(const int &num)
void multiplyBy2InPlace(int &x)
void testMappedReducedThreadPool(QThreadPool *pool, const QList< SourceObject > &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject)
void testMapped(const QList< SourceObject > &sourceObjectList, const QList< ResultObject > &expectedResult, MapObject mapObject)
QMutex mutex