QtBase  v6.3.1
tst_containerapisymmetry.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
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 <QTest>
30 
31 #include "qbytearray.h"
32 #include "qdebug.h"
33 #include "qhash.h"
34 #include "qlist.h"
35 #include "qstring.h"
36 #include "qvarlengtharray.h"
37 
38 #include <algorithm>
39 #include <functional>
40 #include <vector> // for reference
41 #include <iostream>
42 #include <list>
43 #include <set>
44 #include <sstream>
45 #include <map>
46 #include <forward_list>
47 #include <unordered_set>
48 #include <unordered_map>
49 
50 #if defined(__cpp_lib_erase_if) && __cpp_lib_erase_if >= 202002L
51 # define STDLIB_HAS_UNIFORM_ERASURE
52 #endif
53 
55 std::ostream &operator<<(std::ostream &os, const QChar &c)
56 {
58  return os << c.toLatin1();
59 }
60 std::istream &operator>>(std::istream &os, QChar &c)
61 {
62  char cL1;
63  os >> cL1;
64  c = QLatin1Char{cL1};
65  return os;
66 }
68 
69 struct Movable
70 {
71  explicit Movable(int i = 0) noexcept
72  : i(i)
73  {
74  ++instanceCount;
75  }
76 
77  Movable(const Movable &m)
78  : i(m.i)
79  {
80  ++instanceCount;
81  }
82 
84  {
85  --instanceCount;
86  }
87 
88  int i;
89  static int instanceCount;
90 
91  friend std::ostream &operator<<(std::ostream &os, const Movable &m)
92  { return os << m.i; }
93  friend std::istream &operator>>(std::istream &os, Movable &m)
94  { return os >> m.i; }
95 };
96 
98 bool operator==(Movable lhs, Movable rhs) noexcept { return lhs.i == rhs.i; }
99 bool operator!=(Movable lhs, Movable rhs) noexcept { return lhs.i != rhs.i; }
100 bool operator<(Movable lhs, Movable rhs) noexcept { return lhs.i < rhs.i; }
101 
102 size_t qHash(Movable m, size_t seed = 0) noexcept { return qHash(m.i, seed); }
104 {
105  const QDebugStateSaver saver(d);
106  return d.nospace() << "Movable(" << m.i << ")";
107 }
108 
112 
113 struct Complex
114 {
115  explicit Complex(int i = 0) noexcept
116  : i(i)
117  {
118  ++instanceCount;
119  }
120 
121  Complex(const Complex &c)
122  : i(c.i)
123  {
124  ++instanceCount;
125  }
126 
128  {
129  --instanceCount;
130  }
131  constexpr Complex &operator=(const Complex &o) noexcept
132  { i = o.i; return *this; }
133 
134  int i;
135  static int instanceCount;
136 
137  friend std::ostream &operator<<(std::ostream &os, const Complex &c)
138  { return os << c.i; }
139  friend std::istream &operator>>(std::istream &os, Complex &c)
140  { return os >> c.i; }
141 };
142 
143 int Complex::instanceCount = 0;
144 bool operator==(Complex lhs, Complex rhs) noexcept { return lhs.i == rhs.i; }
145 bool operator!=(Complex lhs, Complex rhs) noexcept { return lhs.i != rhs.i; }
146 bool operator<(Complex lhs, Complex rhs) noexcept { return lhs.i < rhs.i; }
147 
148 size_t qHash(Complex c, size_t seed = 0) noexcept { return qHash(c.i, seed); }
150 {
151  const QDebugStateSaver saver(d);
152  return d.nospace() << "Complex(" << c.i << ")";
153 }
154 
155 
157 {
158  explicit DuplicateStrategyTestType(int i = 0) noexcept
159  : i(i),
160  j(++counter)
161  {
162  }
163 
164  int i;
165  int j;
166 
167  static int counter;
168 };
169 
171 
172 // only look at the i member, not j. j allows us to identify which instance
173 // gets inserted in containers that don't allow for duplicates
175 {
176  return lhs.i == rhs.i;
177 }
178 
180 {
181  return lhs.i != rhs.i;
182 }
183 
185 {
186  return lhs.i < rhs.i;
187 }
188 
189 size_t qHash(DuplicateStrategyTestType c, size_t seed = 0) noexcept
190 {
191  return qHash(c.i, seed);
192 }
193 
195 {
196  return lhs.i == rhs.i && lhs.j == rhs.j;
197 }
198 
200 {
201  const QDebugStateSaver saver(d);
202  return d.nospace() << "DuplicateStrategyTestType(" << c.i << "," << c.j << ")";
203 }
204 
205 
206 namespace std {
207 template<>
208 struct hash<Movable>
209 {
210  std::size_t operator()(Movable m) const noexcept
211  {
212  return hash<int>()(m.i);
213  }
214 };
215 
216 template<>
217 struct hash<Complex>
218 {
219  std::size_t operator()(Complex m) const noexcept
220  {
221  return hash<int>()(m.i);
222  }
223 };
224 
225 template<>
227 {
228  std::size_t operator()(DuplicateStrategyTestType m) const noexcept
229  {
230  return hash<int>()(m.i);
231  }
232 };
233 }
234 
235 // work around the fact that QVarLengthArray has a non-type
236 // template parameter, and that breaks non_associative_container_duplicates_strategy
237 template<typename T>
239 {
240 public:
242 };
243 
245 {
246  Q_OBJECT
247 
248  int m_movableInstanceCount;
249  int m_complexInstanceCount;
250 
251 private Q_SLOTS:
252  void init();
253  void cleanup();
254 
255 private:
256  template <typename Container>
257  void ranged_ctor_non_associative_impl() const;
258 
259  template<template<typename ... T> class Container>
260  void non_associative_container_duplicates_strategy() const;
261 
262  template <typename Container>
263  void ranged_ctor_associative_impl() const;
264 
265 private Q_SLOTS:
266  // non associative
267  void ranged_ctor_std_vector_int() { ranged_ctor_non_associative_impl<std::vector<int>>(); }
268  void ranged_ctor_std_vector_char() { ranged_ctor_non_associative_impl<std::vector<char>>(); }
269  void ranged_ctor_std_vector_QChar() { ranged_ctor_non_associative_impl<std::vector<QChar>>(); }
270  void ranged_ctor_std_vector_Movable() { ranged_ctor_non_associative_impl<std::vector<Movable>>(); }
271  void ranged_ctor_std_vector_Complex() { ranged_ctor_non_associative_impl<std::vector<Complex>>(); }
272  void ranged_ctor_std_vector_duplicates_strategy() { non_associative_container_duplicates_strategy<std::vector>(); }
273 
274  void ranged_ctor_QVarLengthArray_int() { ranged_ctor_non_associative_impl<QVarLengthArray<int>>(); }
275  void ranged_ctor_QVarLengthArray_Movable() { ranged_ctor_non_associative_impl<QVarLengthArray<Movable>>(); }
276  void ranged_ctor_QVarLengthArray_Complex() { ranged_ctor_non_associative_impl<QVarLengthArray<Complex>>(); }
277  void ranged_ctor_QVarLengthArray_duplicates_strategy() { non_associative_container_duplicates_strategy<VarLengthArray>(); } // note the VarLengthArray passed
278 
279  void ranged_ctor_QList_int() { ranged_ctor_non_associative_impl<QList<int>>(); }
280  void ranged_ctor_QList_char() { ranged_ctor_non_associative_impl<QList<char>>(); }
281  void ranged_ctor_QList_QChar() { ranged_ctor_non_associative_impl<QList<QChar>>(); }
282  void ranged_ctor_QList_Movable() { ranged_ctor_non_associative_impl<QList<Movable>>(); }
283  void ranged_ctor_QList_Complex() { ranged_ctor_non_associative_impl<QList<Complex>>(); }
284  void ranged_ctor_QList_duplicates_strategy() { non_associative_container_duplicates_strategy<QList>(); }
285 
286  void ranged_ctor_std_list_int() { ranged_ctor_non_associative_impl<std::list<int>>(); }
287  void ranged_ctor_std_list_Movable() { ranged_ctor_non_associative_impl<std::list<Movable>>(); }
288  void ranged_ctor_std_list_Complex() { ranged_ctor_non_associative_impl<std::list<Complex>>(); }
289  void ranged_ctor_std_list_duplicates_strategy() { non_associative_container_duplicates_strategy<std::list>(); }
290 
291  void ranged_ctor_std_forward_list_int() { ranged_ctor_non_associative_impl<std::forward_list<int>>(); }
292  void ranged_ctor_std_forward_list_Movable() {ranged_ctor_non_associative_impl<std::forward_list<Movable>>(); }
293  void ranged_ctor_std_forward_list_Complex() { ranged_ctor_non_associative_impl<std::forward_list<Complex>>(); }
294  void ranged_ctor_std_forward_list_duplicates_strategy() { non_associative_container_duplicates_strategy<std::forward_list>(); }
295 
296  void ranged_ctor_std_set_int() { ranged_ctor_non_associative_impl<std::set<int>>(); }
297  void ranged_ctor_std_set_Movable() { ranged_ctor_non_associative_impl<std::set<Movable>>(); }
298  void ranged_ctor_std_set_Complex() { ranged_ctor_non_associative_impl<std::set<Complex>>(); }
299  void ranged_ctor_std_set_duplicates_strategy() { non_associative_container_duplicates_strategy<std::set>(); }
300 
301  void ranged_ctor_std_multiset_int() { ranged_ctor_non_associative_impl<std::multiset<int>>(); }
302  void ranged_ctor_std_multiset_Movable() { ranged_ctor_non_associative_impl<std::multiset<Movable>>(); }
303  void ranged_ctor_std_multiset_Complex() { ranged_ctor_non_associative_impl<std::multiset<Complex>>(); }
304  void ranged_ctor_std_multiset_duplicates_strategy() { non_associative_container_duplicates_strategy<std::multiset>(); }
305 
306  void ranged_ctor_std_unordered_set_int() { ranged_ctor_non_associative_impl<std::unordered_set<int>>(); }
307  void ranged_ctor_std_unordered_set_Movable() { ranged_ctor_non_associative_impl<std::unordered_set<Movable>>(); }
308  void ranged_ctor_std_unordered_set_Complex() { ranged_ctor_non_associative_impl<std::unordered_set<Complex>>(); }
309  void ranged_ctor_std_unordered_set_duplicates_strategy() { non_associative_container_duplicates_strategy<std::unordered_set>(); }
310 
311  void ranged_ctor_std_unordered_multiset_int() { ranged_ctor_non_associative_impl<std::unordered_multiset<int>>(); }
312  void ranged_ctor_std_unordered_multiset_Movable() { ranged_ctor_non_associative_impl<std::unordered_multiset<Movable>>(); }
313  void ranged_ctor_std_unordered_multiset_Complex() { ranged_ctor_non_associative_impl<std::unordered_multiset<Complex>>(); }
314  void ranged_ctor_std_unordered_multiset_duplicates_strategy() { non_associative_container_duplicates_strategy<std::unordered_multiset>(); }
315 
316  void ranged_ctor_QSet_int() { ranged_ctor_non_associative_impl<QSet<int>>(); }
317  void ranged_ctor_QSet_Movable() { ranged_ctor_non_associative_impl<QSet<Movable>>(); }
318  void ranged_ctor_QSet_Complex() { ranged_ctor_non_associative_impl<QSet<Complex>>(); }
319  void ranged_ctor_QSet_duplicates_strategy() { non_associative_container_duplicates_strategy<QSet>(); }
320 
321  // associative
322  void ranged_ctor_std_map_int() { ranged_ctor_associative_impl<std::map<int, int>>(); }
323  void ranged_ctor_std_map_Movable() { ranged_ctor_associative_impl<std::map<Movable, int>>(); }
324  void ranged_ctor_std_map_Complex() { ranged_ctor_associative_impl<std::map<Complex, int>>(); }
325 
326  void ranged_ctor_std_multimap_int() { ranged_ctor_associative_impl<std::multimap<int, int>>(); }
327  void ranged_ctor_std_multimap_Movable() { ranged_ctor_associative_impl<std::multimap<Movable, int>>(); }
328  void ranged_ctor_std_multimap_Complex() { ranged_ctor_associative_impl<std::multimap<Complex, int>>(); }
329 
330  void ranged_ctor_unordered_map_int() { ranged_ctor_associative_impl<std::unordered_map<int, int>>(); }
331  void ranged_ctor_unordered_map_Movable() { ranged_ctor_associative_impl<std::unordered_map<Movable, Movable>>(); }
332  void ranged_ctor_unordered_map_Complex() { ranged_ctor_associative_impl<std::unordered_map<Complex, Complex>>(); }
333 
334  void ranged_ctor_QHash_int() { ranged_ctor_associative_impl<QHash<int, int>>(); }
335  void ranged_ctor_QHash_Movable() { ranged_ctor_associative_impl<QHash<Movable, int>>(); }
336  void ranged_ctor_QHash_Complex() { ranged_ctor_associative_impl<QHash<Complex, int>>(); }
337 
338  void ranged_ctor_unordered_multimap_int() { ranged_ctor_associative_impl<std::unordered_multimap<int, int>>(); }
339  void ranged_ctor_unordered_multimap_Movable() { ranged_ctor_associative_impl<std::unordered_multimap<Movable, Movable>>(); }
340  void ranged_ctor_unordered_multimap_Complex() { ranged_ctor_associative_impl<std::unordered_multimap<Complex, Complex>>(); }
341 
342  void ranged_ctor_QMultiHash_int() { ranged_ctor_associative_impl<QMultiHash<int, int>>(); }
343  void ranged_ctor_QMultiHash_Movable() { ranged_ctor_associative_impl<QMultiHash<Movable, int>>(); }
344  void ranged_ctor_QMultiHash_Complex() { ranged_ctor_associative_impl<QMultiHash<Complex, int>>(); }
345 
346 private:
347  template <typename Container>
348  void front_back_impl() const;
349 
350 private Q_SLOTS:
351  void front_back_std_vector() { front_back_impl<std::vector<int>>(); }
352  void front_back_QList() { front_back_impl<QList<qintptr>>(); }
353  void front_back_QVarLengthArray() { front_back_impl<QVarLengthArray<int>>(); }
354  void front_back_QString() { front_back_impl<QString>(); }
355  void front_back_QStringView() { front_back_impl<QStringView>(); }
356  void front_back_QLatin1String() { front_back_impl<QLatin1String>(); }
357  void front_back_QByteArray() { front_back_impl<QByteArray>(); }
358 
359 private:
360  template <typename Container>
361  void erase_impl() const;
362 
363  template <typename Container>
364  void erase_if_impl() const;
365 
366  template <typename Container>
367  void erase_if_associative_impl() const;
368 
369 private Q_SLOTS:
370  void erase_QList() { erase_impl<QList<int>>(); }
371  void erase_QVarLengthArray() { erase_impl<QVarLengthArray<int>>(); }
372  void erase_QString() { erase_impl<QString>(); }
373  void erase_QByteArray() { erase_impl<QByteArray>(); }
374  void erase_std_vector() {
375 #ifdef STDLIB_HAS_UNIFORM_ERASURE
376  erase_impl<std::vector<int>>();
377 #endif
378  }
379 
380  void erase_if_QList() { erase_if_impl<QList<int>>(); }
381  void erase_if_QVarLengthArray() { erase_if_impl<QVarLengthArray<int>>(); }
382  void erase_if_QSet() { erase_if_impl<QSet<int>>(); }
383  void erase_if_QString() { erase_if_impl<QString>(); }
384  void erase_if_QByteArray() { erase_if_impl<QByteArray>(); }
385  void erase_if_std_vector() {
386 #ifdef STDLIB_HAS_UNIFORM_ERASURE
387  erase_if_impl<std::vector<int>>();
388 #endif
389  }
390  void erase_if_QMap() { erase_if_associative_impl<QMap<int, int>>(); }
391  void erase_if_QMultiMap() {erase_if_associative_impl<QMultiMap<int, int>>(); }
392  void erase_if_QHash() { erase_if_associative_impl<QHash<int, int>>(); }
393  void erase_if_QMultiHash() { erase_if_associative_impl<QMultiHash<int, int>>(); }
394 };
395 
396 void tst_ContainerApiSymmetry::init()
397 {
398  m_movableInstanceCount = Movable::instanceCount;
399  m_complexInstanceCount = Complex::instanceCount;
400 }
401 
402 void tst_ContainerApiSymmetry::cleanup()
403 {
404  // very simple leak check
405  QCOMPARE(Movable::instanceCount, m_movableInstanceCount);
406  QCOMPARE(Complex::instanceCount, m_complexInstanceCount);
407 }
408 
409 template <typename Container>
411 {
412  using V = typename Container::value_type;
413 
414  return {V(0), V(1), V(2), V(0)};
415 }
416 
417 template <typename Container>
418 void tst_ContainerApiSymmetry::ranged_ctor_non_associative_impl() const
419 {
420  using V = typename Container::value_type;
421 
422  // the double V(0) is deliberate
423  const auto reference = createContainerReference<Container>();
424 
425  // plain array
426  const V values1[] = { V(0), V(1), V(2), V(0) };
427 
428  const Container c1(values1, values1 + sizeof(values1)/sizeof(values1[0]));
429 
430  // from QList
431  QList<V> l2;
432  l2 << V(0) << V(1) << V(2) << V(0);
433 
434  const Container c2a(l2.begin(), l2.end());
435  const Container c2b(l2.cbegin(), l2.cend());
436 
437  // from std::list
438  std::list<V> l3;
439  l3.push_back(V(0));
440  l3.push_back(V(1));
441  l3.push_back(V(2));
442  l3.push_back(V(0));
443  const Container c3a(l3.begin(), l3.end());
444 
445  // from const std::list
446  const std::list<V> l3c = l3;
447  const Container c3b(l3c.begin(), l3c.end());
448 
449  // from itself
450  const Container c4(reference.begin(), reference.end());
451 
452  // from stringsteam (= pure input_iterator)
453  const Container c5 = [&] {
454  {
455  std::stringstream ss;
456  for (auto &v : values1)
457  ss << v << ' ';
458  ss.seekg(0);
459  return Container(std::istream_iterator<V>{ss},
460  std::istream_iterator<V>{});
461  }
462  }();
463 
464  QCOMPARE(c1, reference);
465  QCOMPARE(c2a, reference);
466  QCOMPARE(c2b, reference);
467  QCOMPARE(c3a, reference);
468  QCOMPARE(c3b, reference);
469  QCOMPARE(c4, reference);
470  QCOMPARE(c5, reference);
471 }
472 
473 
474 // type traits for detecting whether a non-associative container
475 // accepts duplicated values, and if it doesn't, whether construction/insertion
476 // prefer the new values (overwriting) or the old values (rejecting)
477 
481 
482 template<typename Container>
484 
485 template<typename ... T>
487 
488 template<typename ... T>
490 
491 template<typename ... T>
493 
494 template<typename ... T>
496 
497 template<typename ... T>
499 
500 template<typename ... T>
502 
503 // assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution
504 template<typename ... T>
506 
507 template<typename ... T>
509 
510 // assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution
511 template<typename ... T>
513 
514 template<typename ... T>
516 
517 template<typename ... T>
519 
520 template<typename Container>
521 void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerAcceptsDuplicateValues)
522 {
523  // do a deep check for equality, not ordering
524  QVERIFY(std::distance(reference.begin(), reference.end()) == std::distance(c.begin(), c.end()));
525  QVERIFY(std::is_permutation(reference.begin(), reference.end(), c.begin(), &reallyEqual));
526 }
527 
529 {
532 };
533 
534 template<typename Container>
535 void non_associative_container_check_duplicates_impl_no_duplicates(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, IterationOnReference ior)
536 {
537  std::vector<DuplicateStrategyTestType> valuesAlreadySeen;
538 
539  // iterate on reference forward or backwards, depending on ior. this will give
540  // us the expected semantics when checking for duplicated values into c
541  auto it = [&reference, ior]() {
542  switch (ior) {
544  case IterationOnReference::ReverseIteration: return reference.end() - 1;
545  };
547  }();
548 
549  const auto &end = [&reference, ior]() {
550  switch (ior) {
552  case IterationOnReference::ReverseIteration: return reference.begin() - 1;
553  };
555  }();
556 
557  while (it != end) {
558  const auto &value = *it;
559 
560  // check that there is indeed the same value in the container (using operator==)
561  const auto &valueInContainerIterator = std::find(c.begin(), c.end(), value);
562  QVERIFY(valueInContainerIterator != c.end());
563  QVERIFY(value == *valueInContainerIterator);
564 
565  // if the value is a duplicate, we don't expect to find it in the container
566  // (when doing a deep comparison). otherwise it should be there
567 
568  const auto &valuesAlreadySeenIterator = std::find(valuesAlreadySeen.cbegin(), valuesAlreadySeen.cend(), value);
569  const bool valueIsDuplicated = (valuesAlreadySeenIterator != valuesAlreadySeen.cend());
570 
571  const auto &reallyEqualCheck = [&value](const DuplicateStrategyTestType &v) { return reallyEqual(value, v); };
572  QCOMPARE(std::find_if(c.begin(), c.end(), reallyEqualCheck) == c.end(), valueIsDuplicated);
573 
574  valuesAlreadySeen.push_back(value);
575 
576  switch (ior) {
578  ++it;
579  break;
581  --it;
582  break;
583  };
584  }
585 
586 }
587 
588 template<typename Container>
589 void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerRejectsDuplicateValues)
590 {
592 }
593 
594 template<typename Container>
595 void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerOverwritesDuplicateValues)
596 {
598 }
599 
600 template<typename Container>
601 void non_associative_container_check_duplicates(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c)
602 {
604 }
605 
606 template<template<class ... T> class Container>
607 void tst_ContainerApiSymmetry::non_associative_container_duplicates_strategy() const
608 {
609  // first and last are "duplicates" -- they compare equal for operator==,
610  // but they differ when using reallyEqual
611  const std::initializer_list<DuplicateStrategyTestType> reference{ DuplicateStrategyTestType{0},
617 
620 }
621 
622 template <typename Container>
623 void tst_ContainerApiSymmetry::ranged_ctor_associative_impl() const
624 {
625  using K = typename Container::key_type;
626  using V = typename Container::mapped_type;
627 
628  // The double K(0) is deliberate. The order of the elements matters:
629  // * for unique-key STL containers, the first one should be the one inserted (cf. LWG 2844)
630  // * for unique-key Qt containers, the last one should be the one inserted
631  // * for multi-key sorted containers, the order of insertion of identical keys is also the
632  // iteration order (which establishes the equality of the containers)
633  // (although nothing of this is being tested here, that deserves its own testing)
634  const Container reference{
635  { K(0), V(1000) },
636  { K(1), V(1001) },
637  { K(2), V(1002) },
638  { K(0), V(1003) }
639  };
640 
641  // Note that using anything not convertible to std::pair doesn't work for
642  // std containers. Their ranged construction is defined in terms of
643  // insert(value_type), which for std associative containers is
644  // std::pair<const K, T>.
645 
646  // plain array
647  const std::pair<K, V> values1[] = {
648  std::make_pair(K(0), V(1000)),
649  std::make_pair(K(1), V(1001)),
650  std::make_pair(K(2), V(1002)),
651  std::make_pair(K(0), V(1003))
652  };
653 
654  const Container c1(values1, values1 + sizeof(values1)/sizeof(values1[0]));
655 
656  // from QList
658  l2 << std::make_pair(K(0), V(1000))
659  << std::make_pair(K(1), V(1001))
660  << std::make_pair(K(2), V(1002))
661  << std::make_pair(K(0), V(1003));
662 
663  const Container c2a(l2.begin(), l2.end());
664  const Container c2b(l2.cbegin(), l2.cend());
665 
666  // from std::list
667  std::list<std::pair<K, V>> l3;
668  l3.push_back(std::make_pair(K(0), V(1000)));
669  l3.push_back(std::make_pair(K(1), V(1001)));
670  l3.push_back(std::make_pair(K(2), V(1002)));
671  l3.push_back(std::make_pair(K(0), V(1003)));
672  const Container c3a(l3.begin(), l3.end());
673 
674  // from const std::list
675  const std::list<std::pair<K, V>> l3c = l3;
676  const Container c3b(l3c.begin(), l3c.end());
677 
678  // from itself
679  const Container c4(reference.begin(), reference.end());
680 
681  QCOMPARE(c1, reference);
682  QCOMPARE(c2a, reference);
683  QCOMPARE(c2b, reference);
684  QCOMPARE(c3a, reference);
685  QCOMPARE(c3b, reference);
686  QCOMPARE(c4, reference);
687 }
688 
689 template <typename Container>
691 {
692  Container c;
693  c.reserve(size);
694  using V = typename Container::value_type;
695  std::generate_n(std::inserter(c, c.end()), size, [i = 1]() mutable { return V(i++); });
696  return c;
697 }
698 
699 template <typename Container>
701 {
702  using K = typename Container::key_type;
703  using V = typename Container::mapped_type;
704  Container c;
705  for (int i = 1; i <= size; ++i)
706  c.insert(K(i), V(i));
707  return c;
708 }
709 
710 static QString s_string = QStringLiteral("\1\2\3\4\5\6\7");
711 
712 template <> QString make(int size) { return s_string.left(size); }
713 template <> QStringView make(int size) { return QStringView(s_string).left(size); }
714 template <> QLatin1String make(int size) { return QLatin1String("\1\2\3\4\5\6\7", size); }
715 template <> QByteArray make(int size) { return QByteArray("\1\2\3\4\5\6\7", size); }
716 
717 template <typename T> T clean(T &&t) { return std::forward<T>(t); }
718 inline char clean(QLatin1Char ch) { return ch.toLatin1(); }
719 
720 template <typename Container>
721 void tst_ContainerApiSymmetry::front_back_impl() const
722 {
723  using V = typename Container::value_type;
724  auto c1 = make<Container>(1);
725  QCOMPARE(clean(c1.front()), V(1));
726  QCOMPARE(clean(c1.back()), V(1));
727  QCOMPARE(clean(qAsConst(c1).front()), V(1));
728  QCOMPARE(clean(qAsConst(c1).back()), V(1));
729 
730  auto c2 = make<Container>(2);
731  QCOMPARE(clean(c2.front()), V(1));
732  QCOMPARE(clean(c2.back()), V(2));
733  QCOMPARE(clean(qAsConst(c2).front()), V(1));
734  QCOMPARE(clean(qAsConst(c2).back()), V(2));
735 }
736 
737 namespace {
738 struct Conv {
739  template <typename T>
740  static int toInt(T i) { return i; }
741  static int toInt(QChar ch) { return ch.unicode(); }
742 };
743 }
744 
745 template <typename Container>
746 void tst_ContainerApiSymmetry::erase_impl() const
747 {
748  using S = typename Container::size_type;
749  using V = typename Container::value_type;
750  auto c = make<Container>(7); // {1, 2, 3, 4, 5, 6, 7}
751  QCOMPARE(c.size(), S(7));
752 
753  auto result = erase(c, V(1));
754  QCOMPARE(result, S(1));
755  QCOMPARE(c.size(), S(6));
756 
757  result = erase(c, V(5));
758  QCOMPARE(result, S(1));
759  QCOMPARE(c.size(), S(5));
760 
761  result = erase(c, V(123));
762  QCOMPARE(result, S(0));
763  QCOMPARE(c.size(), S(5));
764 }
765 
766 template <typename Container>
767 void tst_ContainerApiSymmetry::erase_if_impl() const
768 {
769  using S = typename Container::size_type;
770  using V = typename Container::value_type;
771  auto c = make<Container>(7); // {1, 2, 3, 4, 5, 6, 7}
772  QCOMPARE(c.size(), S(7));
773 
774  decltype(c.size()) oldSize, count;
775 
776  oldSize = c.size();
777  count = 0;
778  auto result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 2 == 0; });
779  QCOMPARE(result, S(3));
780  QCOMPARE(c.size(), S(4));
781  QCOMPARE(count, oldSize);
782 
783  oldSize = c.size();
784  count = 0;
785  result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 123 == 0; });
786  QCOMPARE(result, S(0));
787  QCOMPARE(c.size(), S(4));
788  QCOMPARE(count, oldSize);
789 
790  oldSize = c.size();
791  count = 0;
792  result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 3 == 0; });
793  QCOMPARE(result, S(1));
794  QCOMPARE(c.size(), S(3));
795  QCOMPARE(count, oldSize);
796 
797  oldSize = c.size();
798  count = 0;
799  result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 2 == 1; });
800  QCOMPARE(result, S(3));
801  QCOMPARE(c.size(), S(0));
802  QCOMPARE(count, oldSize);
803 }
804 
805 template <typename Container>
806 void tst_ContainerApiSymmetry::erase_if_associative_impl() const
807 {
808  using S = typename Container::size_type;
809  using K = typename Container::key_type;
810  using V = typename Container::mapped_type;
811  using I = typename Container::iterator;
812  using P = std::pair<const K &, V &>;
813 
814  auto c = makeAssociative<Container>(20);
815  QCOMPARE(c.size(), S(20));
816 
817  auto result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 2 == 0; });
818  QCOMPARE(result, S(10));
819  QCOMPARE(c.size(), S(10));
820 
821  result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 3 == 0; });
822  QCOMPARE(result, S(3));
823  QCOMPARE(c.size(), S(7));
824 
825  result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 42 == 0; });
826  QCOMPARE(result, S(0));
827  QCOMPARE(c.size(), S(7));
828 
829  result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 2 == 1; });
830  QCOMPARE(result, S(7));
831  QCOMPARE(c.size(), S(0));
832 
833  // same, but with a predicate taking a Qt iterator
834  c = makeAssociative<Container>(20);
835  QCOMPARE(c.size(), S(20));
836 
837  result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 2 == 0; });
838  QCOMPARE(result, S(10));
839  QCOMPARE(c.size(), S(10));
840 
841  result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 3 == 0; });
842  QCOMPARE(result, S(3));
843  QCOMPARE(c.size(), S(7));
844 
845  result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 42 == 0; });
846  QCOMPARE(result, S(0));
847  QCOMPARE(c.size(), S(7));
848 
849  result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 2 == 1; });
850  QCOMPARE(result, S(7));
851  QCOMPARE(c.size(), S(0));
852 }
853 
855 #include "tst_containerapisymmetry.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
#define value
[5]
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
operator>>(QDataStream &ds, qfloat16 &f)
Definition: qfloat16.cpp:344
operator<<(QDataStream &ds, qfloat16 f)
Definition: qfloat16.cpp:327
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
Convenience class for custom QDebug operators.
Definition: qdebug.h:176
bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
template< typename Enum > bool operator!=(Enum lhs, QFlags< Enum > rhs)
template< typename Enum > size_t qHash(QFlags< Enum > flags, size_t seed=0) noexcept
template< typename Enum > bool operator==(Enum lhs, QFlags< Enum > rhs)
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
Definition: qlist.h:108
iterator end()
Definition: qlist.h:624
iterator begin()
Definition: qlist.h:623
const_iterator cend() const noexcept
Definition: qlist.h:629
const_iterator cbegin() const noexcept
Definition: qlist.h:628
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
Definition: qset.h:54
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString left(qsizetype n) const
Definition: qstring.cpp:4951
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
constexpr QStringView left(qsizetype n) const noexcept
Definition: qstringview.h:267
QHash< int, QWidget * > hash
[35multi]
QCOMPARE(spy.count(), 1)
auto V(a, v))) struct
Definition: hb-algs.hh:317
auto it unsigned count const
Definition: hb-iter.hh:848
#define S(cp)
#define I(x, y, z)
Definition: md5.c:55
typename C::value_type value_type
typename C::const_iterator const_iterator
typename C::key_type key_type
typename C::mapped_type mapped_type
typename C::iterator iterator
Definition: qfloat16.h:381
int distance(TestIterator &a, TestIterator &b)
void
Definition: png.h:1080
qsizetype erase_if(QByteArray &ba, Predicate pred)
Definition: qbytearray.h:676
qsizetype erase(QByteArray &ba, const T &t)
Definition: qbytearray.h:670
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint reference
GLuint counter
const GLubyte * c
Definition: qopenglext.h:12701
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define QStringLiteral(str)
#define QTEST_APPLESS_MAIN(TestObject)
Definition: qtest.h:632
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define Q_SLOTS
Definition: qtmetamacros.h:80
@ Q_RELOCATABLE_TYPE
Definition: qtypeinfo.h:156
QFuture< QSet< QChar > > set
[10]
QList< int > vector
[14]
MyCustomStruct c2
QStringList::Iterator it
QStringList list
[0]
friend std::istream & operator>>(std::istream &os, Complex &c)
static int instanceCount
Complex(int i=0) noexcept
constexpr Complex & operator=(const Complex &o) noexcept
Complex(const Complex &c)
friend std::ostream & operator<<(std::ostream &os, const Complex &c)
Movable(const Movable &m)
Movable(int i=0) noexcept
friend std::ostream & operator<<(std::ostream &os, const Movable &m)
friend std::istream & operator>>(std::istream &os, Movable &m)
static int instanceCount
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
constexpr char toLatin1() const noexcept
Definition: qchar.h:56
Definition: main.cpp:38
std::size_t operator()(Complex m) const noexcept
std::size_t operator()(DuplicateStrategyTestType m) const noexcept
std::size_t operator()(Movable m) const noexcept
T clean(T &&t)
void non_associative_container_check_duplicates_impl_no_duplicates(const std::initializer_list< DuplicateStrategyTestType > &reference, const Container &c, IterationOnReference ior)
Container makeAssociative(int size)
Container createContainerReference()
Container make(int size)
QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(Movable, Q_RELOCATABLE_TYPE)
bool reallyEqual(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) noexcept
void non_associative_container_check_duplicates(const std::initializer_list< DuplicateStrategyTestType > &reference, const Container &c)
void non_associative_container_check_duplicates_impl(const std::initializer_list< DuplicateStrategyTestType > &reference, const Container &c, ContainerAcceptsDuplicateValues)
#define rhs
QDomElement find(const QString &tagName, const QDomElement &e)
Definition: main.cpp:39