|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 #include <QtTest/QtTest> |
|
44 |
|
45 #include <iostream> |
|
46 #include <iomanip> |
|
47 #include <sstream> |
|
48 #include <algorithm> |
|
49 #include <qalgorithms.h> |
|
50 #include "../../../src/qt3support/tools/q3tl.h" |
|
51 #include <QStringList> |
|
52 #include <QString> |
|
53 #include <QVector> |
|
54 |
|
55 #define Q_TEST_PERFORMANCE 0 |
|
56 |
|
57 using namespace std; |
|
58 |
|
59 //TESTED_FILES= |
|
60 |
|
61 class tst_QAlgorithms : public QObject |
|
62 { |
|
63 Q_OBJECT |
|
64 |
|
65 public: |
|
66 tst_QAlgorithms(); |
|
67 ~tst_QAlgorithms(); |
|
68 |
|
69 public slots: |
|
70 void init(); |
|
71 void cleanup(); |
|
72 |
|
73 private slots: |
|
74 void qBubbleSort(); |
|
75 void qHeapSort(); |
|
76 void test_qLowerBound_data(); |
|
77 void test_qLowerBound(); |
|
78 void test_qUpperBound_data(); |
|
79 void test_qUpperBound(); |
|
80 void test_qBinaryFind_data(); |
|
81 void test_qBinaryFind(); |
|
82 void qBinaryFindOneEntry(); |
|
83 void swap(); |
|
84 void sortEmptyList(); |
|
85 void sortedList(); |
|
86 void sortAPItest(); |
|
87 void stableSortTest(); |
|
88 void stableSortCorrectnessTest_data(); |
|
89 void stableSortCorrectnessTest(); |
|
90 void convenienceAPI(); |
|
91 void qCountIterators() const; |
|
92 void qCountContainer() const; |
|
93 void binaryFindOnLargeContainer() const; |
|
94 |
|
95 #if Q_TEST_PERFORMANCE |
|
96 private: |
|
97 void performance(); |
|
98 #endif |
|
99 }; |
|
100 |
|
101 tst_QAlgorithms::tst_QAlgorithms() |
|
102 |
|
103 { |
|
104 } |
|
105 |
|
106 tst_QAlgorithms::~tst_QAlgorithms() |
|
107 { |
|
108 |
|
109 } |
|
110 |
|
111 void tst_QAlgorithms::init() |
|
112 { |
|
113 } |
|
114 |
|
115 void tst_QAlgorithms::cleanup() |
|
116 { |
|
117 } |
|
118 |
|
119 |
|
120 class TestInt |
|
121 { |
|
122 public: |
|
123 TestInt(int number) :m_number(number) {} ; |
|
124 TestInt() : m_number(0) {}; |
|
125 bool operator<(const TestInt &other) const { ++TestInt::lessThanRefCount; return (m_number < other.m_number); } |
|
126 int m_number; |
|
127 static long int lessThanRefCount; |
|
128 }; |
|
129 |
|
130 long int TestInt::lessThanRefCount; |
|
131 |
|
132 |
|
133 QStringList dataSetTypes = QStringList() << "Random" << "Ascending" |
|
134 << "Descending" << "Equal" << "Duplicates" << "Almost Sorted" ; |
|
135 |
|
136 template <typename DataType> |
|
137 QVector<DataType> generateData(QString dataSetType, const int length) |
|
138 { |
|
139 QVector<DataType> container; |
|
140 if (dataSetType == "Random") { |
|
141 for(int i=0; i < length; ++i) |
|
142 container.append(rand()); |
|
143 } |
|
144 else if (dataSetType == "Ascending") { |
|
145 for (int i=0; i < length; ++i) |
|
146 container.append(i); |
|
147 } |
|
148 else if (dataSetType == "Descending") { |
|
149 for (int i=0; i < length; ++i) |
|
150 container.append(length - i); |
|
151 } |
|
152 else if (dataSetType == "Equal") { |
|
153 for (int i=0; i < length; ++i) |
|
154 container.append(43); |
|
155 } |
|
156 else if (dataSetType == "Duplicates") { |
|
157 for (int i=0; i < length; ++i) |
|
158 container.append(i % 10); |
|
159 } |
|
160 else if (dataSetType == "Almost Sorted") { |
|
161 for (int i=0; i < length; ++i) |
|
162 container.append(i); |
|
163 for(int i = 0; i<= length / 10; ++i) { |
|
164 const int iswap = i * 9; |
|
165 DataType tmp = container.at(iswap); |
|
166 container[iswap] = container.at(iswap + 1); |
|
167 container[iswap + 1] = tmp; |
|
168 } |
|
169 } |
|
170 return container; |
|
171 } |
|
172 |
|
173 struct ResultSet |
|
174 { |
|
175 int numSorts; |
|
176 long int lessThanRefCount; |
|
177 }; |
|
178 |
|
179 |
|
180 template <typename ContainerType, typename Algorithm> |
|
181 ResultSet testRun(ContainerType &container, Algorithm &algorithm, int millisecs) |
|
182 { |
|
183 TestInt::lessThanRefCount = 0; |
|
184 int count = 0; |
|
185 QTime t; |
|
186 t.start(); |
|
187 while(t.elapsed() < millisecs) { |
|
188 ++count; |
|
189 algorithm(container); |
|
190 } |
|
191 ResultSet result; |
|
192 result.numSorts = count; |
|
193 result.lessThanRefCount = TestInt::lessThanRefCount; |
|
194 return result; |
|
195 } |
|
196 |
|
197 template <typename ContainerType, typename LessThan> |
|
198 bool isSorted(ContainerType &container, LessThan lessThan) |
|
199 { |
|
200 for (int i=0; i < container.count() - 1; ++i) |
|
201 if (lessThan(container.at(i+1), container.at(i))) { |
|
202 return false; |
|
203 } |
|
204 return true; |
|
205 } |
|
206 |
|
207 template <typename ContainerType> |
|
208 bool isSorted(ContainerType &container) |
|
209 { |
|
210 return isSorted(container, qLess<Q_TYPENAME ContainerType::value_type>()); |
|
211 } |
|
212 |
|
213 |
|
214 #if Q_TEST_PERFORMANCE |
|
215 void printHeader(QStringList &headers) |
|
216 { |
|
217 cout << setw(10) << setiosflags(ios_base::left) << " "; |
|
218 for (int h = 0; h < headers.count(); ++h) { |
|
219 cout << setw(20) << setiosflags(ios_base::left) << headers.at(h).toLatin1().constData(); |
|
220 } |
|
221 cout << endl; |
|
222 } |
|
223 |
|
224 template <typename ContainerType> |
|
225 void print(ContainerType testContainer) |
|
226 { |
|
227 typedef typename ContainerType::value_type T; |
|
228 |
|
229 foreach(T value, testContainer) { |
|
230 cout << value << " "; |
|
231 } |
|
232 |
|
233 cout << endl; |
|
234 } |
|
235 |
|
236 template <typename Algorithm, typename DataType> |
|
237 QList<ResultSet> testAlgorithm(Algorithm &algorithm, QStringList dataSetTypes, int size, int time) |
|
238 { |
|
239 QList<ResultSet> results; |
|
240 foreach(QString dataSetType, dataSetTypes) { |
|
241 QVector<DataType> container = generateData<DataType>(dataSetType, size); |
|
242 results.append(testRun(container, algorithm, time)); |
|
243 Q_ASSERT(isSorted(container)); |
|
244 } |
|
245 return results; |
|
246 } |
|
247 |
|
248 template <typename Algorithm, typename DataType> |
|
249 void testAlgorithm(Algorithm algorithm, QStringList &dataSetTypes) |
|
250 { |
|
251 QList<int> sizes = QList<int>() << 5 << 15 << 35 << 70 << 200 << 1000 << 10000; |
|
252 printHeader(dataSetTypes); |
|
253 for (int s = 0; s < sizes.count(); ++s){ |
|
254 cout << setw(10) << setiosflags(ios_base::left)<< sizes.at(s); |
|
255 QList<ResultSet> results = |
|
256 testAlgorithm<Algorithm, DataType>(algorithm, dataSetTypes, sizes.at(s), 100); |
|
257 foreach(ResultSet result, results) { |
|
258 stringstream numSorts; |
|
259 numSorts << setiosflags(ios_base::left) << setw(10) << result.numSorts; |
|
260 stringstream lessThan; |
|
261 lessThan << setiosflags(ios_base::left) << setw(10) << result.lessThanRefCount / result.numSorts; |
|
262 cout << numSorts.str() << lessThan.str(); |
|
263 } |
|
264 cout << endl; |
|
265 } |
|
266 } |
|
267 #endif |
|
268 static bool userFunction1(char ch1, char ch2) |
|
269 { |
|
270 return (ch1 ^ 1) < (ch2 ^ 1); |
|
271 } |
|
272 |
|
273 bool userFunction2(const char &ch1, char ch2) |
|
274 { |
|
275 return (ch1 ^ 1) < (ch2 ^ 1); |
|
276 } |
|
277 |
|
278 static inline bool userFunction3(char ch1, const char &ch2) |
|
279 { |
|
280 return (ch1 ^ 1) < (ch2 ^ 1); |
|
281 } |
|
282 |
|
283 inline bool userFunction4(const char &ch1, const char &ch2) |
|
284 { |
|
285 return (ch1 ^ 1) < (ch2 ^ 1); |
|
286 } |
|
287 |
|
288 class UserFunctor1 |
|
289 { |
|
290 public: |
|
291 UserFunctor1(int x = 1) : y(x) {} |
|
292 |
|
293 bool operator()(char ch1, char ch2) |
|
294 { |
|
295 return (ch1 ^ y) < (ch2 ^ y); |
|
296 } |
|
297 |
|
298 char y; |
|
299 }; |
|
300 |
|
301 void tst_QAlgorithms::qHeapSort() |
|
302 { |
|
303 char array1[] = "3141592"; |
|
304 ::qHeapSort((char *)array1, array1 + strlen(array1)); |
|
305 QVERIFY(strcmp(array1, "1123459") == 0); |
|
306 |
|
307 ::qHeapSort((char *)array1, array1 + strlen(array1), qGreater<char>()); |
|
308 QVERIFY(strcmp(array1, "9543211") == 0); |
|
309 |
|
310 ::qHeapSort((char *)array1, array1 + strlen(array1), qLess<char>()); |
|
311 QVERIFY(strcmp(array1, "1123459") == 0); |
|
312 { |
|
313 char array2[] = "0123456789@ABCDE"; |
|
314 ::qHeapSort((char *)array2, array2 + strlen(array2), userFunction1); |
|
315 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
316 } |
|
317 |
|
318 { |
|
319 char array2[] = "0123456789@ABCDE"; |
|
320 ::qHeapSort((char *)array2, array2 + strlen(array2), userFunction2); |
|
321 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
322 } |
|
323 |
|
324 { |
|
325 char array2[] = "0123456789@ABCDE"; |
|
326 ::qHeapSort((char *)array2, array2 + strlen(array2), userFunction3); |
|
327 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
328 } |
|
329 |
|
330 { |
|
331 char array2[] = "0123456789@ABCDE"; |
|
332 ::qHeapSort((char *)array2, array2 + strlen(array2), userFunction4); |
|
333 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
334 } |
|
335 |
|
336 { |
|
337 UserFunctor1 userFunctor1; |
|
338 char array2[] = "0123456789@ABCDE"; |
|
339 ::qHeapSort((char *)array2, array2 + strlen(array2), userFunctor1); |
|
340 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
341 } |
|
342 |
|
343 { |
|
344 char array2[] = "0123456789@ABCDE"; |
|
345 ::qHeapSort((char *)array2, array2 + strlen(array2), UserFunctor1()); |
|
346 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
347 ::qHeapSort((char *)array2, array2 + strlen(array2), UserFunctor1(1)); |
|
348 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
349 ::qHeapSort((char *)array2, array2 + strlen(array2), UserFunctor1(3)); |
|
350 QVERIFY(strcmp(array2, "3210765498CBA@ED") == 0); |
|
351 ::qHeapSort((char *)array2, array2 + strlen(array2), UserFunctor1(0)); |
|
352 QVERIFY(strcmp(array2, "0123456789@ABCDE") == 0); |
|
353 } |
|
354 } |
|
355 |
|
356 void tst_QAlgorithms::qBubbleSort() |
|
357 { |
|
358 char array1[] = "3141592"; |
|
359 ::qBubbleSort((char *)array1, array1 + strlen(array1)); |
|
360 QVERIFY(strcmp(array1, "1123459") == 0); |
|
361 |
|
362 ::qBubbleSort((char *)array1, array1 + strlen(array1), qGreater<char>()); |
|
363 QVERIFY(strcmp(array1, "9543211") == 0); |
|
364 |
|
365 ::qBubbleSort((char *)array1, array1 + strlen(array1), qLess<char>()); |
|
366 QVERIFY(strcmp(array1, "1123459") == 0); |
|
367 |
|
368 { |
|
369 char array2[] = "0123456789@ABCDE"; |
|
370 ::qBubbleSort((char *)array2, array2 + strlen(array2), userFunction1); |
|
371 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
372 } |
|
373 |
|
374 { |
|
375 char array2[] = "0123456789@ABCDE"; |
|
376 ::qBubbleSort((char *)array2, array2 + strlen(array2), userFunction2); |
|
377 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
378 } |
|
379 |
|
380 { |
|
381 char array2[] = "0123456789@ABCDE"; |
|
382 ::qBubbleSort((char *)array2, array2 + strlen(array2), userFunction3); |
|
383 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
384 } |
|
385 |
|
386 { |
|
387 char array2[] = "0123456789@ABCDE"; |
|
388 ::qBubbleSort((char *)array2, array2 + strlen(array2), userFunction4); |
|
389 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
390 } |
|
391 |
|
392 { |
|
393 UserFunctor1 userFunctor1; |
|
394 char array2[] = "0123456789@ABCDE"; |
|
395 ::qBubbleSort((char *)array2, array2 + strlen(array2), userFunctor1); |
|
396 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
397 } |
|
398 |
|
399 { |
|
400 char array2[] = "0123456789@ABCDE"; |
|
401 ::qBubbleSort((char *)array2, array2 + strlen(array2), UserFunctor1()); |
|
402 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
403 ::qBubbleSort((char *)array2, array2 + strlen(array2), UserFunctor1(1)); |
|
404 QVERIFY(strcmp(array2, "1032547698A@CBED") == 0); |
|
405 ::qBubbleSort((char *)array2, array2 + strlen(array2), UserFunctor1(3)); |
|
406 QVERIFY(strcmp(array2, "3210765498CBA@ED") == 0); |
|
407 ::qBubbleSort((char *)array2, array2 + strlen(array2), UserFunctor1(0)); |
|
408 QVERIFY(strcmp(array2, "0123456789@ABCDE") == 0); |
|
409 } |
|
410 } |
|
411 |
|
412 void tst_QAlgorithms::swap() |
|
413 { |
|
414 { |
|
415 int a = 1, b = 2; |
|
416 qSwap(a, b); |
|
417 QVERIFY(a == 2); |
|
418 QVERIFY(b == 1); |
|
419 |
|
420 qSwap(a, a); |
|
421 QVERIFY(a == 2); |
|
422 QVERIFY(b == 1); |
|
423 |
|
424 qSwap(b, b); |
|
425 QVERIFY(a == 2); |
|
426 QVERIFY(b == 1); |
|
427 |
|
428 qSwap(a, b); |
|
429 QVERIFY(a == 1); |
|
430 QVERIFY(b == 2); |
|
431 |
|
432 qSwap(b, a); |
|
433 QVERIFY(a == 2); |
|
434 QVERIFY(b == 1); |
|
435 } |
|
436 |
|
437 { |
|
438 double a = 1.0, b = 2.0; |
|
439 qSwap(a, b); |
|
440 QVERIFY(a == 2.0); |
|
441 QVERIFY(b == 1.0); |
|
442 |
|
443 qSwap(a, a); |
|
444 QVERIFY(a == 2.0); |
|
445 QVERIFY(b == 1.0); |
|
446 |
|
447 qSwap(b, b); |
|
448 QVERIFY(a == 2.0); |
|
449 QVERIFY(b == 1.0); |
|
450 |
|
451 qSwap(a, b); |
|
452 QVERIFY(a == 1.0); |
|
453 QVERIFY(b == 2.0); |
|
454 |
|
455 qSwap(b, a); |
|
456 QVERIFY(a == 2.0); |
|
457 QVERIFY(b == 1.0); |
|
458 } |
|
459 |
|
460 { |
|
461 QString a = "1", b = "2"; |
|
462 qSwap(a, b); |
|
463 QVERIFY(a == "2"); |
|
464 QVERIFY(b == "1"); |
|
465 |
|
466 qSwap(a, a); |
|
467 QVERIFY(a == "2"); |
|
468 QVERIFY(b == "1"); |
|
469 |
|
470 qSwap(b, b); |
|
471 QVERIFY(a == "2"); |
|
472 QVERIFY(b == "1"); |
|
473 |
|
474 qSwap(a, b); |
|
475 QVERIFY(a == "1"); |
|
476 QVERIFY(b == "2"); |
|
477 |
|
478 qSwap(b, a); |
|
479 QVERIFY(a == "2"); |
|
480 QVERIFY(b == "1"); |
|
481 } |
|
482 |
|
483 { |
|
484 void *a = 0, *b = 0; |
|
485 qSwap(a, b); |
|
486 } |
|
487 |
|
488 { |
|
489 const void *a = 0, *b = 0; |
|
490 qSwap(a, b); |
|
491 } |
|
492 |
|
493 { |
|
494 QString *a = 0, *b = 0; |
|
495 qSwap(a, b); |
|
496 } |
|
497 |
|
498 { |
|
499 const QString *a = 0, *b = 0; |
|
500 qSwap(a, b); |
|
501 } |
|
502 |
|
503 { |
|
504 QString **a = 0, **b = 0; |
|
505 qSwap(a, b); |
|
506 } |
|
507 |
|
508 { |
|
509 const QString **a = 0, **b = 0; |
|
510 qSwap(a, b); |
|
511 } |
|
512 |
|
513 { |
|
514 QString * const *a = 0, * const *b = 0; |
|
515 qSwap(a, b); |
|
516 } |
|
517 |
|
518 { |
|
519 const QString * const *a = 0, * const *b = 0; |
|
520 qSwap(a, b); |
|
521 } |
|
522 } |
|
523 |
|
524 void tst_QAlgorithms::sortEmptyList() |
|
525 { |
|
526 // Only test if it crashes |
|
527 QStringList stringList; |
|
528 stringList.sort(); |
|
529 QVERIFY(true); |
|
530 } |
|
531 |
|
532 void tst_QAlgorithms::sortedList() |
|
533 { |
|
534 QList<int> list; |
|
535 list << 4 << 3 << 6; |
|
536 |
|
537 ::qHeapSort(list.begin(), list.end()); |
|
538 |
|
539 QCOMPARE(list.count(), 3); |
|
540 QCOMPARE(list.at(0), 3); |
|
541 QCOMPARE(list.at(1), 4); |
|
542 QCOMPARE(list.at(2), 6); |
|
543 |
|
544 list.insert(qUpperBound(list.begin(), list.end(), 5), 5); |
|
545 list.insert(qUpperBound(list.begin(), list.end(), 1), 1); |
|
546 list.insert(qUpperBound(list.begin(), list.end(), 8), 8); |
|
547 |
|
548 QCOMPARE(list.count(), 6); |
|
549 QCOMPARE(list.at(0), 1); |
|
550 QCOMPARE(list.at(1), 3); |
|
551 QCOMPARE(list.at(2), 4); |
|
552 QCOMPARE(list.at(3), 5); |
|
553 QCOMPARE(list.at(4), 6); |
|
554 QCOMPARE(list.at(5), 8); |
|
555 } |
|
556 |
|
557 Q_DECLARE_METATYPE(QList<int>) |
|
558 |
|
559 void tst_QAlgorithms::test_qLowerBound_data() |
|
560 { |
|
561 QTest::addColumn<QList<int> >("data"); |
|
562 QTest::addColumn<int>("resultValue"); |
|
563 QTest::addColumn<int>("resultIndex"); |
|
564 |
|
565 QTest::newRow("sorted-duplicate") << (QList<int>() << 1 << 2 << 2 << 3) << 2 << 1; |
|
566 } |
|
567 |
|
568 void tst_QAlgorithms::test_qLowerBound() |
|
569 { |
|
570 QFETCH(QList<int>, data); |
|
571 QFETCH(int, resultValue); |
|
572 QFETCH(int, resultIndex); |
|
573 |
|
574 |
|
575 QCOMPARE(qLowerBound(data.constBegin(), data.constEnd(), resultValue), data.constBegin() + resultIndex); |
|
576 QCOMPARE(qLowerBound(data.begin(), data.end(), resultValue), data.begin() + resultIndex); |
|
577 QCOMPARE(qLowerBound(data, resultValue), data.constBegin() + resultIndex); |
|
578 QCOMPARE(qLowerBound(data.constBegin(), data.constEnd(), resultValue, qLess<int>()), data.constBegin() + resultIndex); |
|
579 } |
|
580 |
|
581 void tst_QAlgorithms::test_qUpperBound_data() |
|
582 { |
|
583 QTest::addColumn<QList<int> >("data"); |
|
584 QTest::addColumn<int>("resultValue"); |
|
585 QTest::addColumn<int>("resultIndex"); |
|
586 |
|
587 QTest::newRow("sorted-duplicate") << (QList<int>() << 1 << 2 << 2 << 3) << 2 << 3; |
|
588 } |
|
589 |
|
590 void tst_QAlgorithms::test_qUpperBound() |
|
591 { |
|
592 QFETCH(QList<int>, data); |
|
593 QFETCH(int, resultValue); |
|
594 QFETCH(int, resultIndex); |
|
595 |
|
596 QCOMPARE(qUpperBound(data.constBegin(), data.constEnd(), resultValue), data.constBegin() + resultIndex); |
|
597 QCOMPARE(qUpperBound(data.begin(), data.end(), resultValue), data.begin() + resultIndex); |
|
598 QCOMPARE(qUpperBound(data, resultValue), data.constBegin() + resultIndex); |
|
599 QCOMPARE(qUpperBound(data.constBegin(), data.constEnd(), resultValue, qLess<int>()), data.constBegin() + resultIndex); |
|
600 } |
|
601 |
|
602 void tst_QAlgorithms::test_qBinaryFind_data() |
|
603 { |
|
604 QTest::addColumn<QList<int> >("data"); |
|
605 QTest::addColumn<int>("resultValue"); |
|
606 |
|
607 QTest::newRow("sorted-duplicate") << (QList<int>() << 1 << 2 << 2 << 3) << 2; |
|
608 } |
|
609 |
|
610 void tst_QAlgorithms::test_qBinaryFind() |
|
611 { |
|
612 QFETCH(QList<int>, data); |
|
613 QFETCH(int, resultValue); |
|
614 |
|
615 QCOMPARE(*qBinaryFind(data.constBegin(), data.constEnd(), resultValue), resultValue); |
|
616 QCOMPARE(*qBinaryFind(data.begin(), data.end(), resultValue), resultValue); |
|
617 QCOMPARE(*qBinaryFind(data, resultValue), resultValue); |
|
618 QCOMPARE(*qBinaryFind(data.constBegin(), data.constEnd(), resultValue, qLess<int>()), resultValue); |
|
619 } |
|
620 |
|
621 void tst_QAlgorithms::qBinaryFindOneEntry() |
|
622 { |
|
623 QList<int> list; |
|
624 list << 2; |
|
625 |
|
626 QVERIFY(::qBinaryFind(list.constBegin(), list.constEnd(), 2) != list.constEnd()); |
|
627 } |
|
628 |
|
629 |
|
630 void tst_QAlgorithms::sortAPItest() |
|
631 { |
|
632 QVector<int> testVector = generateData<int>("Random", 101); |
|
633 qSort(testVector); |
|
634 QVERIFY(isSorted(testVector)); |
|
635 qSort(testVector.begin(), testVector.end()); |
|
636 QVERIFY(isSorted(testVector)); |
|
637 qSort(testVector.begin(), testVector.end(), qLess<int>()); |
|
638 QVERIFY(isSorted(testVector)); |
|
639 |
|
640 testVector = generateData<int>("Random", 71); |
|
641 qStableSort(testVector); |
|
642 QVERIFY(isSorted(testVector)); |
|
643 qStableSort(testVector.begin(), testVector.end()); |
|
644 QVERIFY(isSorted(testVector)); |
|
645 qStableSort(testVector.begin(), testVector.end(), qLess<int>()); |
|
646 QVERIFY(isSorted(testVector)); |
|
647 |
|
648 QList<int> testList = generateData<int>("Random", 101).toList(); |
|
649 qSort(testList); |
|
650 QVERIFY(isSorted(testList)); |
|
651 qSort(testList.begin(), testList.end()); |
|
652 QVERIFY(isSorted(testList)); |
|
653 qSort(testList.begin(), testList.end(), qLess<int>()); |
|
654 QVERIFY(isSorted(testList)); |
|
655 |
|
656 testList = generateData<int>("Random", 71).toList(); |
|
657 qStableSort(testList); |
|
658 QVERIFY(isSorted(testList)); |
|
659 qStableSort(testList.begin(), testList.end()); |
|
660 QVERIFY(isSorted(testList)); |
|
661 qStableSort(testList.begin(), testList.end(), qLess<int>()); |
|
662 QVERIFY(isSorted(testList)); |
|
663 } |
|
664 |
|
665 |
|
666 class StableSortTest |
|
667 { |
|
668 public: |
|
669 StableSortTest(){}; |
|
670 StableSortTest(int Major, int Minor) : Major(Major), Minor(Minor) {} |
|
671 bool operator<(const StableSortTest &other) const {return (Major < other.Major); } |
|
672 bool testMinor(const StableSortTest &other) const {return Minor < other.Minor; } |
|
673 |
|
674 int Major; |
|
675 int Minor; |
|
676 }; |
|
677 |
|
678 ostream &operator<<(ostream &out, const StableSortTest& obj) { out << obj.Major << "-" << obj.Minor; return out; } |
|
679 |
|
680 QVector<StableSortTest> createStableTestVector() |
|
681 { |
|
682 QVector<StableSortTest> stableTestVector; |
|
683 for (int i=500; i>=0; --i) { |
|
684 for (int j=0; j<10; ++j) { |
|
685 stableTestVector.append(StableSortTest(i, j)); |
|
686 } |
|
687 } |
|
688 return stableTestVector; |
|
689 } |
|
690 |
|
691 template <typename ContainerType, typename LessThan> |
|
692 bool isStableSorted(ContainerType &container, LessThan lessThan) |
|
693 { |
|
694 for (int i=0; i < container.count() - 1; ++i) { |
|
695 //not sorted? |
|
696 if (lessThan(container.at(i + 1), container.at(i))) |
|
697 return false; |
|
698 // equal? |
|
699 if (lessThan(container.at(i), container.at(i + 1))) |
|
700 continue; |
|
701 // minor version? |
|
702 if(container.at(i + 1).testMinor(container.at(i))) |
|
703 return false; |
|
704 } |
|
705 return true; |
|
706 } |
|
707 |
|
708 void tst_QAlgorithms::stableSortTest() |
|
709 { |
|
710 // Selftests: |
|
711 { |
|
712 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
713 qSort(stableTestVector.begin(), stableTestVector.end(), qLess<StableSortTest>()); |
|
714 QVERIFY(isSorted(stableTestVector, qLess<StableSortTest>())); |
|
715 QVERIFY(!isStableSorted(stableTestVector, qLess<StableSortTest>())); |
|
716 } |
|
717 { |
|
718 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
719 qSort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>()); |
|
720 QVERIFY(isSorted(stableTestVector, qGreater<StableSortTest>())); |
|
721 QVERIFY(!isStableSorted(stableTestVector, qGreater<StableSortTest>())); |
|
722 } |
|
723 { |
|
724 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
725 qSort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>()); |
|
726 QVERIFY(!isSorted(stableTestVector, qLess<StableSortTest>())); |
|
727 QVERIFY(!isStableSorted(stableTestVector, qGreater<StableSortTest>())); |
|
728 } |
|
729 |
|
730 |
|
731 // Stable sort with qLess |
|
732 { |
|
733 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
734 std::stable_sort(stableTestVector.begin(), stableTestVector.end(), qLess<StableSortTest>()); |
|
735 QVERIFY(isSorted(stableTestVector, qLess<StableSortTest>())); |
|
736 QVERIFY(isStableSorted(stableTestVector, qLess<StableSortTest>())); |
|
737 } |
|
738 { |
|
739 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
740 qStableSort(stableTestVector.begin(), stableTestVector.end(), qLess<StableSortTest>()); |
|
741 QVERIFY(isSorted(stableTestVector, qLess<StableSortTest>())); |
|
742 QVERIFY(isStableSorted(stableTestVector, qLess<StableSortTest>())); |
|
743 } |
|
744 |
|
745 // Stable sort with qGreater |
|
746 { |
|
747 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
748 std::stable_sort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>()); |
|
749 QVERIFY(isSorted(stableTestVector, qGreater<StableSortTest>())); |
|
750 QVERIFY(isStableSorted(stableTestVector, qGreater<StableSortTest>())); |
|
751 } |
|
752 |
|
753 { |
|
754 QVector<StableSortTest> stableTestVector = createStableTestVector(); |
|
755 qStableSort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>()); |
|
756 QVERIFY(isSorted(stableTestVector, qGreater<StableSortTest>())); |
|
757 QVERIFY(isStableSorted(stableTestVector, qGreater<StableSortTest>())); |
|
758 } |
|
759 } |
|
760 |
|
761 Q_DECLARE_METATYPE(QVector<int>) |
|
762 |
|
763 void tst_QAlgorithms::stableSortCorrectnessTest_data() |
|
764 { |
|
765 const int dataSize = 1000; |
|
766 QTest::addColumn<QVector<int> >("unsorted"); |
|
767 QTest::newRow("From documentation") << (QVector<int>() << 33 << 12 << 68 << 6 << 12); |
|
768 QTest::newRow("Equal") << (generateData<int>("Equal", dataSize)); |
|
769 QTest::newRow("Ascending") << (generateData<int>("Ascending", dataSize)); |
|
770 QTest::newRow("Descending") << (generateData<int>("Descending", dataSize)); |
|
771 QTest::newRow("Duplicates") << (generateData<int>("Duplicates", dataSize)); |
|
772 QTest::newRow("Almost Sorted") << (generateData<int>("Almost Sorted", dataSize)); |
|
773 QTest::newRow("Random") << (generateData<int>("Random", dataSize)); |
|
774 } |
|
775 |
|
776 void tst_QAlgorithms::stableSortCorrectnessTest() |
|
777 { |
|
778 QFETCH(QVector<int>, unsorted); |
|
779 |
|
780 QVector<int> sorted = unsorted; |
|
781 qStableSort(sorted.begin(), sorted.end()); |
|
782 |
|
783 // Verify that sorted contains the same numbers as unsorted. |
|
784 foreach(int value, unsorted) { |
|
785 QVERIFY(sorted.contains(value)); |
|
786 int unsortedCount = 0; |
|
787 qCount(unsorted.begin(), unsorted.end(), value, unsortedCount); |
|
788 int sortedCount = 0; |
|
789 qCount(sorted.begin(), sorted.end(), value, sortedCount); |
|
790 QCOMPARE(sortedCount, unsortedCount); |
|
791 } |
|
792 |
|
793 QVERIFY(isSorted(sorted)); |
|
794 } |
|
795 |
|
796 void tst_QAlgorithms::convenienceAPI() |
|
797 { |
|
798 // Compile-test for QAlgorithm convenience functions. |
|
799 QList<int> list, list2; |
|
800 |
|
801 qCopy(list.begin(), list.end(), list2.begin()); |
|
802 qCopyBackward(list.begin(), list.end(), list2.begin()); |
|
803 qEqual(list.begin(), list.end(), list2.begin()); |
|
804 |
|
805 qFill(list, 1); |
|
806 qFill(list.begin(), list.end(), 1); |
|
807 |
|
808 qFind(list, 1); |
|
809 qFind(list.begin(), list.end(), 1); |
|
810 |
|
811 int count1 = 0 , count2 = 0, count3 = 0; |
|
812 qCount(list, 1, count1); |
|
813 qCount(list.begin(), list.end(), 1, count2); |
|
814 QCOMPARE(count1, count2); |
|
815 QCOMPARE(count2, count3); |
|
816 |
|
817 qSort(list); |
|
818 qSort(list.begin(), list.end()); |
|
819 qSort(list.begin(), list.end(), qLess<int>()); |
|
820 |
|
821 qStableSort(list); |
|
822 qStableSort(list.begin(), list.end()); |
|
823 qStableSort(list.begin(), list.end(), qLess<int>()); |
|
824 |
|
825 qLowerBound(list, 1);; |
|
826 qLowerBound(list.begin(), list.end(), 1); |
|
827 qLowerBound(list.begin(), list.end(), 1, qLess<int>()); |
|
828 |
|
829 qUpperBound(list, 1); |
|
830 qUpperBound(list.begin(), list.end(), 1); |
|
831 qUpperBound(list.begin(), list.end(), 1, qLess<int>()); |
|
832 |
|
833 qBinaryFind(list, 1); |
|
834 qBinaryFind(list.begin(), list.end(), 1); |
|
835 qBinaryFind(list.begin(), list.end(), 1, qLess<int>()); |
|
836 |
|
837 QList<int *> pointerList; |
|
838 qDeleteAll(pointerList); |
|
839 qDeleteAll(pointerList.begin(), pointerList.end()); |
|
840 } |
|
841 |
|
842 template <typename DataType> |
|
843 class HeapSortHelper |
|
844 { |
|
845 public: |
|
846 void operator()(QVector<DataType> list) |
|
847 { |
|
848 ::qHeapSort(list); |
|
849 } |
|
850 }; |
|
851 |
|
852 template <typename DataType> |
|
853 class BubbleSortHelper |
|
854 { |
|
855 public: |
|
856 void operator()(QVector<DataType> list) |
|
857 { |
|
858 ::qBubbleSort(list); |
|
859 } |
|
860 }; |
|
861 |
|
862 template <typename DataType> |
|
863 class QuickSortHelper |
|
864 { |
|
865 public: |
|
866 void operator()(QVector<DataType> list) |
|
867 { |
|
868 ::qSort(list); |
|
869 } |
|
870 }; |
|
871 |
|
872 template <typename DataType> |
|
873 class StableSortHelper |
|
874 { |
|
875 public: |
|
876 void operator()(QVector<DataType> list) |
|
877 { |
|
878 ::qStableSort(list); |
|
879 } |
|
880 }; |
|
881 |
|
882 template <typename DataType> |
|
883 class StlSortHelper |
|
884 { |
|
885 public: |
|
886 void operator()(QVector<DataType> list) |
|
887 { |
|
888 std::sort(list.begin(), list.end()); |
|
889 } |
|
890 }; |
|
891 |
|
892 template <typename DataType> |
|
893 class StlStableSortHelper |
|
894 { |
|
895 public: |
|
896 void operator()(QVector<DataType> list) |
|
897 { |
|
898 std::stable_sort(list.begin(), list.end()); |
|
899 } |
|
900 }; |
|
901 |
|
902 #if Q_TEST_PERFORMANCE |
|
903 void tst_QAlgorithms::performance() |
|
904 { |
|
905 cout << endl << "Quick sort" << endl; |
|
906 testAlgorithm<QuickSortHelper<TestInt>, TestInt>(QuickSortHelper<TestInt>(), dataSetTypes); |
|
907 cout << endl << "stable sort" << endl; |
|
908 testAlgorithm<StableSortHelper<TestInt>, TestInt>(StableSortHelper<TestInt>(), dataSetTypes); |
|
909 cout << endl << "std::sort" << endl; |
|
910 testAlgorithm<StlSortHelper<TestInt>, TestInt>(StlSortHelper<TestInt>(), dataSetTypes); |
|
911 cout << endl << "std::stable_sort" << endl; |
|
912 testAlgorithm<StlStableSortHelper<TestInt>, TestInt>(StlStableSortHelper<TestInt>(), dataSetTypes); |
|
913 cout << "Heap sort" << endl; |
|
914 testAlgorithm<HeapSortHelper<TestInt>, TestInt>(HeapSortHelper<TestInt>(), dataSetTypes); |
|
915 cout << endl << "Bubble sort" << endl; |
|
916 testAlgorithm<BubbleSortHelper<TestInt>, TestInt>(BubbleSortHelper<TestInt>(), dataSetTypes); |
|
917 /* |
|
918 cout << endl << "Sorting lists of ints" << endl; |
|
919 cout << "Heap sort" << endl; |
|
920 testAlgorithm<HeapSortHelper<int>, int>(HeapSortHelper<int>(), dataSetTypes); |
|
921 cout << endl << "Quick sort" << endl; |
|
922 testAlgorithm<QuickSortHelper<int>, int>(QuickSortHelper<int>(), dataSetTypes); |
|
923 cout << endl << "std::sort" << endl; |
|
924 testAlgorithm<StlSortHelper<int>, int>(StlSortHelper<int>(), dataSetTypes); |
|
925 cout << endl << "std::stable_sort" << endl; |
|
926 testAlgorithm<StlStableSortHelper<int>, int>(StlStableSortHelper<int>(), dataSetTypes); |
|
927 cout << endl << "Bubble sort" << endl; |
|
928 testAlgorithm<BubbleSortHelper<int>, int>(BubbleSortHelper<int>(), dataSetTypes); |
|
929 */ |
|
930 } |
|
931 #endif |
|
932 |
|
933 void tst_QAlgorithms::qCountIterators() const |
|
934 { |
|
935 QList<int> list; |
|
936 list << 3 << 3 << 6 << 6 << 6 << 8; |
|
937 |
|
938 { |
|
939 int countOf7 = 0; |
|
940 ::qCount(list.begin(), list.end(), 7, countOf7); |
|
941 QCOMPARE(countOf7, 0); |
|
942 } |
|
943 |
|
944 { |
|
945 int countOf3 = 0; |
|
946 ::qCount(list.begin(), list.end(), 3, countOf3); |
|
947 QCOMPARE(countOf3, 2); |
|
948 } |
|
949 |
|
950 { |
|
951 int countOf6 = 0; |
|
952 ::qCount(list.begin(), list.end(), 6, countOf6); |
|
953 QCOMPARE(countOf6, 3); |
|
954 } |
|
955 |
|
956 { |
|
957 int countOf8 = 0; |
|
958 ::qCount(list.begin(), list.end(), 8, countOf8); |
|
959 QCOMPARE(countOf8, 1); |
|
960 } |
|
961 |
|
962 /* Check that we add to the count, not set it. */ |
|
963 { |
|
964 int countOf8 = 5; |
|
965 ::qCount(list.begin(), list.end(), 8, countOf8); |
|
966 QCOMPARE(countOf8, 6); |
|
967 } |
|
968 } |
|
969 |
|
970 void tst_QAlgorithms::qCountContainer() const |
|
971 { |
|
972 QList<int> list; |
|
973 list << 3 << 3 << 6 << 6 << 6 << 8; |
|
974 |
|
975 { |
|
976 int countOf7 = 0; |
|
977 ::qCount(list, 7, countOf7); |
|
978 QCOMPARE(countOf7, 0); |
|
979 } |
|
980 |
|
981 { |
|
982 int countOf3 = 0; |
|
983 ::qCount(list, 3, countOf3); |
|
984 QCOMPARE(countOf3, 2); |
|
985 } |
|
986 |
|
987 { |
|
988 int countOf6 = 0; |
|
989 ::qCount(list, 6, countOf6); |
|
990 QCOMPARE(countOf6, 3); |
|
991 } |
|
992 |
|
993 { |
|
994 int countOf8 = 0; |
|
995 ::qCount(list, 8, countOf8); |
|
996 QCOMPARE(countOf8, 1); |
|
997 } |
|
998 |
|
999 /* Check that we add to the count, not set it. */ |
|
1000 { |
|
1001 int countOf8 = 5; |
|
1002 ::qCount(list, 8, countOf8); |
|
1003 QCOMPARE(countOf8, 6); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 class RAI |
|
1008 { |
|
1009 public: |
|
1010 RAI(int searched = 5, int hidePos = 4, int len = 10) |
|
1011 : curPos_(0) |
|
1012 , length_(len) |
|
1013 , searchedVal_(searched) |
|
1014 , searchedValPos_(hidePos) |
|
1015 { |
|
1016 } |
|
1017 |
|
1018 int at(int pos) const |
|
1019 { |
|
1020 if (pos == searchedValPos_) { |
|
1021 return searchedVal_; |
|
1022 } |
|
1023 else if (pos < searchedValPos_) { |
|
1024 return searchedVal_ - 1; |
|
1025 } |
|
1026 |
|
1027 return searchedVal_ + 1; |
|
1028 } |
|
1029 |
|
1030 RAI begin() const |
|
1031 { |
|
1032 RAI rai = *this; |
|
1033 rai.setCurPos(0); |
|
1034 return rai; |
|
1035 } |
|
1036 |
|
1037 RAI end() const |
|
1038 { |
|
1039 RAI rai = *this; |
|
1040 rai.setCurPos(length_); |
|
1041 return rai; |
|
1042 } |
|
1043 |
|
1044 int pos() const |
|
1045 { |
|
1046 return curPos(); |
|
1047 } |
|
1048 |
|
1049 int size() const |
|
1050 { |
|
1051 return length_; |
|
1052 } |
|
1053 |
|
1054 RAI operator+(int i) const |
|
1055 { |
|
1056 RAI rai = *this; |
|
1057 rai.setCurPos( rai.curPos() + i ); |
|
1058 if (rai.curPos() > length_) { |
|
1059 rai.setCurPos(length_); |
|
1060 } |
|
1061 return rai; |
|
1062 } |
|
1063 |
|
1064 RAI operator-(int i) const |
|
1065 { |
|
1066 RAI rai = *this; |
|
1067 rai.setCurPos( rai.curPos() - i ); |
|
1068 if (rai.curPos() < 0) { |
|
1069 rai.setCurPos(0); |
|
1070 } |
|
1071 return rai; |
|
1072 } |
|
1073 |
|
1074 int operator-(const RAI& it) const |
|
1075 { |
|
1076 return curPos() - it.curPos(); |
|
1077 } |
|
1078 |
|
1079 RAI& operator+=(int i) |
|
1080 { |
|
1081 setCurPos( curPos() + i ); |
|
1082 if (curPos() > length_) { |
|
1083 setCurPos(length_); |
|
1084 } |
|
1085 return *this; |
|
1086 } |
|
1087 |
|
1088 RAI& operator-=(int i) |
|
1089 { |
|
1090 setCurPos( curPos() - i); |
|
1091 if (curPos() < 0) { |
|
1092 setCurPos(0); |
|
1093 } |
|
1094 return *this; |
|
1095 } |
|
1096 |
|
1097 RAI& operator++() |
|
1098 { |
|
1099 if (curPos() < length_) { |
|
1100 setCurPos( curPos() + 1 ); |
|
1101 } |
|
1102 return *this; |
|
1103 } |
|
1104 |
|
1105 RAI operator++(int) |
|
1106 { |
|
1107 RAI rai = *this; |
|
1108 |
|
1109 if (curPos() < length_) { |
|
1110 setCurPos( curPos() + 1 ); |
|
1111 } |
|
1112 |
|
1113 return rai; |
|
1114 } |
|
1115 |
|
1116 RAI& operator--() |
|
1117 { |
|
1118 if (curPos() > 0) { |
|
1119 setCurPos( curPos() - 1 ); |
|
1120 } |
|
1121 return *this; |
|
1122 } |
|
1123 |
|
1124 RAI operator--(int) |
|
1125 { |
|
1126 RAI rai = *this; |
|
1127 |
|
1128 if (curPos() > 0) { |
|
1129 setCurPos( curPos() - 1 ); |
|
1130 } |
|
1131 |
|
1132 return rai; |
|
1133 } |
|
1134 |
|
1135 bool operator==(const RAI& rai) const |
|
1136 { |
|
1137 return rai.curPos() == curPos(); |
|
1138 } |
|
1139 |
|
1140 bool operator!=(const RAI& rai) const |
|
1141 { |
|
1142 return !operator==(rai); |
|
1143 } |
|
1144 |
|
1145 int operator*() const |
|
1146 { |
|
1147 return at(curPos()); |
|
1148 } |
|
1149 |
|
1150 int operator[](int i) const |
|
1151 { |
|
1152 return at(i); |
|
1153 } |
|
1154 |
|
1155 private: |
|
1156 |
|
1157 int curPos() const |
|
1158 { |
|
1159 return curPos_; |
|
1160 } |
|
1161 |
|
1162 void setCurPos(int pos) |
|
1163 { |
|
1164 curPos_ = pos; |
|
1165 } |
|
1166 |
|
1167 int curPos_; |
|
1168 int length_; |
|
1169 int searchedVal_; |
|
1170 int searchedValPos_; |
|
1171 }; |
|
1172 |
|
1173 void tst_QAlgorithms::binaryFindOnLargeContainer() const |
|
1174 { |
|
1175 const int len = 2 * 1000 * 1000 * 537; |
|
1176 const int pos = len - 12345; |
|
1177 RAI rai(5, pos, len); |
|
1178 |
|
1179 RAI foundIt = qBinaryFind(rai.begin(), rai.end(), 5); |
|
1180 QCOMPARE(foundIt.pos(), 1073987655); |
|
1181 } |
|
1182 |
|
1183 QTEST_APPLESS_MAIN(tst_QAlgorithms) |
|
1184 #include "tst_qalgorithms.moc" |
|
1185 |