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 QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
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 Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QALGORITHMS_H |
41 | #define QALGORITHMS_H |
42 | |
43 | #include <QtCore/qglobal.h> |
44 | |
45 | #ifdef Q_CC_MSVC |
46 | #include <intrin.h> |
47 | #endif |
48 | |
49 | QT_BEGIN_NAMESPACE |
50 | QT_WARNING_PUSH |
51 | QT_WARNING_DISABLE_DEPRECATED |
52 | |
53 | /* |
54 | Warning: The contents of QAlgorithmsPrivate is not a part of the public Qt API |
55 | and may be changed from version to version or even be completely removed. |
56 | */ |
57 | namespace QAlgorithmsPrivate { |
58 | |
59 | #if QT_DEPRECATED_SINCE(5, 2) |
60 | template <typename RandomAccessIterator, typename T, typename LessThan> |
61 | QT_DEPRECATED_X("Use std::sort" ) Q_OUTOFLINE_TEMPLATE void qSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan); |
62 | template <typename RandomAccessIterator, typename T> |
63 | QT_DEPRECATED_X("Use std::sort" ) inline void qSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy); |
64 | |
65 | template <typename RandomAccessIterator, typename T, typename LessThan> |
66 | QT_DEPRECATED_X("Use std::stable_sort" ) Q_OUTOFLINE_TEMPLATE void qStableSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan); |
67 | template <typename RandomAccessIterator, typename T> |
68 | QT_DEPRECATED_X("Use std::stable_sort" ) inline void qStableSortHelper(RandomAccessIterator, RandomAccessIterator, const T &); |
69 | |
70 | template <typename RandomAccessIterator, typename T, typename LessThan> |
71 | QT_DEPRECATED_X("Use std::lower_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan); |
72 | template <typename RandomAccessIterator, typename T, typename LessThan> |
73 | QT_DEPRECATED_X("Use std::upper_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan); |
74 | template <typename RandomAccessIterator, typename T, typename LessThan> |
75 | QT_DEPRECATED_X("Use std::binary_search" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan); |
76 | #endif // QT_DEPRECATED_SINCE(5, 2) |
77 | |
78 | } |
79 | |
80 | #if QT_DEPRECATED_SINCE(5, 2) |
81 | template <typename InputIterator, typename OutputIterator> |
82 | QT_DEPRECATED_X("Use std::copy" ) inline OutputIterator qCopy(InputIterator begin, InputIterator end, OutputIterator dest) |
83 | { |
84 | while (begin != end) |
85 | *dest++ = *begin++; |
86 | return dest; |
87 | } |
88 | |
89 | template <typename BiIterator1, typename BiIterator2> |
90 | QT_DEPRECATED_X("Use std::copy_backward" ) inline BiIterator2 qCopyBackward(BiIterator1 begin, BiIterator1 end, BiIterator2 dest) |
91 | { |
92 | while (begin != end) |
93 | *--dest = *--end; |
94 | return dest; |
95 | } |
96 | |
97 | template <typename InputIterator1, typename InputIterator2> |
98 | QT_DEPRECATED_X("Use std::equal" ) inline bool qEqual(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) |
99 | { |
100 | for (; first1 != last1; ++first1, ++first2) |
101 | if (!(*first1 == *first2)) |
102 | return false; |
103 | return true; |
104 | } |
105 | |
106 | template <typename ForwardIterator, typename T> |
107 | QT_DEPRECATED_X("Use std::fill" ) inline void qFill(ForwardIterator first, ForwardIterator last, const T &val) |
108 | { |
109 | for (; first != last; ++first) |
110 | *first = val; |
111 | } |
112 | |
113 | template <typename Container, typename T> |
114 | QT_DEPRECATED_X("Use std::fill" ) inline void qFill(Container &container, const T &val) |
115 | { |
116 | qFill(container.begin(), container.end(), val); |
117 | } |
118 | |
119 | template <typename InputIterator, typename T> |
120 | QT_DEPRECATED_X("Use std::find" ) inline InputIterator qFind(InputIterator first, InputIterator last, const T &val) |
121 | { |
122 | while (first != last && !(*first == val)) |
123 | ++first; |
124 | return first; |
125 | } |
126 | |
127 | template <typename Container, typename T> |
128 | QT_DEPRECATED_X("Use std::find" ) inline typename Container::const_iterator qFind(const Container &container, const T &val) |
129 | { |
130 | return qFind(container.constBegin(), container.constEnd(), val); |
131 | } |
132 | |
133 | template <typename InputIterator, typename T, typename Size> |
134 | QT_DEPRECATED_X("Use std::count" ) inline void qCount(InputIterator first, InputIterator last, const T &value, Size &n) |
135 | { |
136 | for (; first != last; ++first) |
137 | if (*first == value) |
138 | ++n; |
139 | } |
140 | |
141 | template <typename Container, typename T, typename Size> |
142 | QT_DEPRECATED_X("Use std::count" ) inline void qCount(const Container &container, const T &value, Size &n) |
143 | { |
144 | qCount(container.constBegin(), container.constEnd(), value, n); |
145 | } |
146 | |
147 | #ifdef Q_QDOC |
148 | typedef void* LessThan; |
149 | template <typename T> LessThan qLess(); |
150 | template <typename T> LessThan qGreater(); |
151 | #else |
152 | template <typename T> |
153 | class QT_DEPRECATED_X("Use std::less" ) qLess |
154 | { |
155 | public: |
156 | inline bool operator()(const T &t1, const T &t2) const |
157 | { |
158 | return (t1 < t2); |
159 | } |
160 | }; |
161 | |
162 | template <typename T> |
163 | class QT_DEPRECATED_X("Use std::greater" ) qGreater |
164 | { |
165 | public: |
166 | inline bool operator()(const T &t1, const T &t2) const |
167 | { |
168 | return (t2 < t1); |
169 | } |
170 | }; |
171 | #endif |
172 | |
173 | template <typename RandomAccessIterator> |
174 | QT_DEPRECATED_X("Use std::sort" ) inline void qSort(RandomAccessIterator start, RandomAccessIterator end) |
175 | { |
176 | if (start != end) |
177 | QAlgorithmsPrivate::qSortHelper(start, end, *start); |
178 | } |
179 | |
180 | template <typename RandomAccessIterator, typename LessThan> |
181 | QT_DEPRECATED_X("Use std::sort" ) inline void qSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan) |
182 | { |
183 | if (start != end) |
184 | QAlgorithmsPrivate::qSortHelper(start, end, *start, lessThan); |
185 | } |
186 | |
187 | template<typename Container> |
188 | QT_DEPRECATED_X("Use std::sort" ) inline void qSort(Container &c) |
189 | { |
190 | #ifdef Q_CC_BOR |
191 | // Work around Borland 5.5 optimizer bug |
192 | c.detach(); |
193 | #endif |
194 | if (!c.empty()) |
195 | QAlgorithmsPrivate::qSortHelper(c.begin(), c.end(), *c.begin()); |
196 | } |
197 | |
198 | template <typename RandomAccessIterator> |
199 | QT_DEPRECATED_X("Use std::stable_sort" ) inline void qStableSort(RandomAccessIterator start, RandomAccessIterator end) |
200 | { |
201 | if (start != end) |
202 | QAlgorithmsPrivate::qStableSortHelper(start, end, *start); |
203 | } |
204 | |
205 | template <typename RandomAccessIterator, typename LessThan> |
206 | QT_DEPRECATED_X("Use std::stable_sort" ) inline void qStableSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan) |
207 | { |
208 | if (start != end) |
209 | QAlgorithmsPrivate::qStableSortHelper(start, end, *start, lessThan); |
210 | } |
211 | |
212 | template<typename Container> |
213 | QT_DEPRECATED_X("Use std::stable_sort" ) inline void qStableSort(Container &c) |
214 | { |
215 | #ifdef Q_CC_BOR |
216 | // Work around Borland 5.5 optimizer bug |
217 | c.detach(); |
218 | #endif |
219 | if (!c.empty()) |
220 | QAlgorithmsPrivate::qStableSortHelper(c.begin(), c.end(), *c.begin()); |
221 | } |
222 | |
223 | template <typename RandomAccessIterator, typename T> |
224 | QT_DEPRECATED_X("Use std::lower_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value) |
225 | { |
226 | // Implementation is duplicated from QAlgorithmsPrivate to keep existing code |
227 | // compiling. We have to allow using *begin and value with different types, |
228 | // and then implementing operator< for those types. |
229 | RandomAccessIterator middle; |
230 | int n = end - begin; |
231 | int half; |
232 | |
233 | while (n > 0) { |
234 | half = n >> 1; |
235 | middle = begin + half; |
236 | if (*middle < value) { |
237 | begin = middle + 1; |
238 | n -= half + 1; |
239 | } else { |
240 | n = half; |
241 | } |
242 | } |
243 | return begin; |
244 | } |
245 | |
246 | template <typename RandomAccessIterator, typename T, typename LessThan> |
247 | QT_DEPRECATED_X("Use std::lower_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) |
248 | { |
249 | return QAlgorithmsPrivate::qLowerBoundHelper(begin, end, value, lessThan); |
250 | } |
251 | |
252 | template <typename Container, typename T> |
253 | QT_DEPRECATED_X("Use std::lower_bound" ) Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qLowerBound(const Container &container, const T &value) |
254 | { |
255 | return QAlgorithmsPrivate::qLowerBoundHelper(container.constBegin(), container.constEnd(), value, qLess<T>()); |
256 | } |
257 | |
258 | template <typename RandomAccessIterator, typename T> |
259 | QT_DEPRECATED_X("Use std::upper_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value) |
260 | { |
261 | // Implementation is duplicated from QAlgorithmsPrivate. |
262 | RandomAccessIterator middle; |
263 | int n = end - begin; |
264 | int half; |
265 | |
266 | while (n > 0) { |
267 | half = n >> 1; |
268 | middle = begin + half; |
269 | if (value < *middle) { |
270 | n = half; |
271 | } else { |
272 | begin = middle + 1; |
273 | n -= half + 1; |
274 | } |
275 | } |
276 | return begin; |
277 | } |
278 | |
279 | template <typename RandomAccessIterator, typename T, typename LessThan> |
280 | QT_DEPRECATED_X("Use std::upper_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) |
281 | { |
282 | return QAlgorithmsPrivate::qUpperBoundHelper(begin, end, value, lessThan); |
283 | } |
284 | |
285 | template <typename Container, typename T> |
286 | QT_DEPRECATED_X("Use std::upper_bound" ) Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qUpperBound(const Container &container, const T &value) |
287 | { |
288 | return QAlgorithmsPrivate::qUpperBoundHelper(container.constBegin(), container.constEnd(), value, qLess<T>()); |
289 | } |
290 | |
291 | template <typename RandomAccessIterator, typename T> |
292 | QT_DEPRECATED_X("Use std::binary_search" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value) |
293 | { |
294 | // Implementation is duplicated from QAlgorithmsPrivate. |
295 | RandomAccessIterator it = qLowerBound(begin, end, value); |
296 | |
297 | if (it == end || value < *it) |
298 | return end; |
299 | |
300 | return it; |
301 | } |
302 | |
303 | template <typename RandomAccessIterator, typename T, typename LessThan> |
304 | QT_DEPRECATED_X("Use std::binary_search" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) |
305 | { |
306 | return QAlgorithmsPrivate::qBinaryFindHelper(begin, end, value, lessThan); |
307 | } |
308 | |
309 | template <typename Container, typename T> |
310 | QT_DEPRECATED_X("Use std::binary_search" ) Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qBinaryFind(const Container &container, const T &value) |
311 | { |
312 | return QAlgorithmsPrivate::qBinaryFindHelper(container.constBegin(), container.constEnd(), value, qLess<T>()); |
313 | } |
314 | #endif // QT_DEPRECATED_SINCE(5, 2) |
315 | |
316 | template <typename ForwardIterator> |
317 | Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end) |
318 | { |
319 | while (begin != end) { |
320 | delete *begin; |
321 | ++begin; |
322 | } |
323 | } |
324 | |
325 | template <typename Container> |
326 | inline void qDeleteAll(const Container &c) |
327 | { |
328 | qDeleteAll(c.begin(), c.end()); |
329 | } |
330 | |
331 | /* |
332 | Warning: The contents of QAlgorithmsPrivate is not a part of the public Qt API |
333 | and may be changed from version to version or even be completely removed. |
334 | */ |
335 | namespace QAlgorithmsPrivate { |
336 | |
337 | #if QT_DEPRECATED_SINCE(5, 2) |
338 | |
339 | template <typename RandomAccessIterator, typename T, typename LessThan> |
340 | QT_DEPRECATED_X("Use std::sort" ) Q_OUTOFLINE_TEMPLATE void qSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan) |
341 | { |
342 | top: |
343 | int span = int(end - start); |
344 | if (span < 2) |
345 | return; |
346 | |
347 | --end; |
348 | RandomAccessIterator low = start, high = end - 1; |
349 | RandomAccessIterator pivot = start + span / 2; |
350 | |
351 | if (lessThan(*end, *start)) |
352 | qSwap(*end, *start); |
353 | if (span == 2) |
354 | return; |
355 | |
356 | if (lessThan(*pivot, *start)) |
357 | qSwap(*pivot, *start); |
358 | if (lessThan(*end, *pivot)) |
359 | qSwap(*end, *pivot); |
360 | if (span == 3) |
361 | return; |
362 | |
363 | qSwap(*pivot, *end); |
364 | |
365 | while (low < high) { |
366 | while (low < high && lessThan(*low, *end)) |
367 | ++low; |
368 | |
369 | while (high > low && lessThan(*end, *high)) |
370 | --high; |
371 | |
372 | if (low < high) { |
373 | qSwap(*low, *high); |
374 | ++low; |
375 | --high; |
376 | } else { |
377 | break; |
378 | } |
379 | } |
380 | |
381 | if (lessThan(*low, *end)) |
382 | ++low; |
383 | |
384 | qSwap(*end, *low); |
385 | qSortHelper(start, low, t, lessThan); |
386 | |
387 | start = low + 1; |
388 | ++end; |
389 | goto top; |
390 | } |
391 | |
392 | template <typename RandomAccessIterator, typename T> |
393 | QT_DEPRECATED_X("Use std::sort" ) inline void qSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy) |
394 | { |
395 | qSortHelper(begin, end, dummy, qLess<T>()); |
396 | } |
397 | |
398 | template <typename RandomAccessIterator> |
399 | QT_DEPRECATED_X("Use std::reverse" ) Q_OUTOFLINE_TEMPLATE void qReverse(RandomAccessIterator begin, RandomAccessIterator end) |
400 | { |
401 | --end; |
402 | while (begin < end) |
403 | qSwap(*begin++, *end--); |
404 | } |
405 | |
406 | template <typename RandomAccessIterator> |
407 | QT_DEPRECATED_X("Use std::rotate" ) Q_OUTOFLINE_TEMPLATE void qRotate(RandomAccessIterator begin, RandomAccessIterator middle, RandomAccessIterator end) |
408 | { |
409 | qReverse(begin, middle); |
410 | qReverse(middle, end); |
411 | qReverse(begin, end); |
412 | } |
413 | |
414 | template <typename RandomAccessIterator, typename T, typename LessThan> |
415 | QT_DEPRECATED_X("Use std::merge" ) Q_OUTOFLINE_TEMPLATE void qMerge(RandomAccessIterator begin, RandomAccessIterator pivot, RandomAccessIterator end, T &t, LessThan lessThan) |
416 | { |
417 | const int len1 = pivot - begin; |
418 | const int len2 = end - pivot; |
419 | |
420 | if (len1 == 0 || len2 == 0) |
421 | return; |
422 | |
423 | if (len1 + len2 == 2) { |
424 | if (lessThan(*(begin + 1), *(begin))) |
425 | qSwap(*begin, *(begin + 1)); |
426 | return; |
427 | } |
428 | |
429 | RandomAccessIterator firstCut; |
430 | RandomAccessIterator secondCut; |
431 | int len2Half; |
432 | if (len1 > len2) { |
433 | const int len1Half = len1 / 2; |
434 | firstCut = begin + len1Half; |
435 | secondCut = qLowerBound(pivot, end, *firstCut, lessThan); |
436 | len2Half = secondCut - pivot; |
437 | } else { |
438 | len2Half = len2 / 2; |
439 | secondCut = pivot + len2Half; |
440 | firstCut = qUpperBound(begin, pivot, *secondCut, lessThan); |
441 | } |
442 | |
443 | qRotate(firstCut, pivot, secondCut); |
444 | const RandomAccessIterator newPivot = firstCut + len2Half; |
445 | qMerge(begin, firstCut, newPivot, t, lessThan); |
446 | qMerge(newPivot, secondCut, end, t, lessThan); |
447 | } |
448 | |
449 | template <typename RandomAccessIterator, typename T, typename LessThan> |
450 | QT_DEPRECATED_X("Use std::stable_sort" ) Q_OUTOFLINE_TEMPLATE void qStableSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &t, LessThan lessThan) |
451 | { |
452 | const int span = end - begin; |
453 | if (span < 2) |
454 | return; |
455 | |
456 | const RandomAccessIterator middle = begin + span / 2; |
457 | qStableSortHelper(begin, middle, t, lessThan); |
458 | qStableSortHelper(middle, end, t, lessThan); |
459 | qMerge(begin, middle, end, t, lessThan); |
460 | } |
461 | |
462 | template <typename RandomAccessIterator, typename T> |
463 | QT_DEPRECATED_X("Use std::stable_sort" ) inline void qStableSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy) |
464 | { |
465 | qStableSortHelper(begin, end, dummy, qLess<T>()); |
466 | } |
467 | |
468 | template <typename RandomAccessIterator, typename T, typename LessThan> |
469 | QT_DEPRECATED_X("Use std::lower_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) |
470 | { |
471 | RandomAccessIterator middle; |
472 | int n = int(end - begin); |
473 | int half; |
474 | |
475 | while (n > 0) { |
476 | half = n >> 1; |
477 | middle = begin + half; |
478 | if (lessThan(*middle, value)) { |
479 | begin = middle + 1; |
480 | n -= half + 1; |
481 | } else { |
482 | n = half; |
483 | } |
484 | } |
485 | return begin; |
486 | } |
487 | |
488 | |
489 | template <typename RandomAccessIterator, typename T, typename LessThan> |
490 | QT_DEPRECATED_X("Use std::upper_bound" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) |
491 | { |
492 | RandomAccessIterator middle; |
493 | int n = end - begin; |
494 | int half; |
495 | |
496 | while (n > 0) { |
497 | half = n >> 1; |
498 | middle = begin + half; |
499 | if (lessThan(value, *middle)) { |
500 | n = half; |
501 | } else { |
502 | begin = middle + 1; |
503 | n -= half + 1; |
504 | } |
505 | } |
506 | return begin; |
507 | } |
508 | |
509 | template <typename RandomAccessIterator, typename T, typename LessThan> |
510 | QT_DEPRECATED_X("Use std::binary_search" ) Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) |
511 | { |
512 | RandomAccessIterator it = qLowerBoundHelper(begin, end, value, lessThan); |
513 | |
514 | if (it == end || lessThan(value, *it)) |
515 | return end; |
516 | |
517 | return it; |
518 | } |
519 | |
520 | #endif // QT_DEPRECATED_SINCE(5, 2) |
521 | |
522 | #ifdef Q_CC_CLANG |
523 | // Clang had a bug where __builtin_ctz/clz/popcount were not marked as constexpr. |
524 | # if (defined __apple_build_version__ && __clang_major__ >= 7) || (Q_CC_CLANG >= 307) |
525 | # define QT_HAS_CONSTEXPR_BUILTINS |
526 | # endif |
527 | #elif defined(Q_CC_MSVC) && !defined(Q_CC_INTEL) && !defined(Q_PROCESSOR_ARM) |
528 | # define QT_HAS_CONSTEXPR_BUILTINS |
529 | #elif defined(Q_CC_GNU) |
530 | # define QT_HAS_CONSTEXPR_BUILTINS |
531 | #endif |
532 | |
533 | #if defined QT_HAS_CONSTEXPR_BUILTINS |
534 | #if defined(Q_CC_GNU) || defined(Q_CC_CLANG) |
535 | # define QT_HAS_BUILTIN_CTZS |
536 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept |
537 | { |
538 | # if __has_builtin(__builtin_ctzs) |
539 | return __builtin_ctzs(v); |
540 | # else |
541 | return __builtin_ctz(v); |
542 | # endif |
543 | } |
544 | #define QT_HAS_BUILTIN_CLZS |
545 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept |
546 | { |
547 | # if __has_builtin(__builtin_clzs) |
548 | return __builtin_clzs(v); |
549 | # else |
550 | return __builtin_clz(v) - 16U; |
551 | # endif |
552 | } |
553 | #define QT_HAS_BUILTIN_CTZ |
554 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctz(quint32 v) noexcept |
555 | { |
556 | return __builtin_ctz(v); |
557 | } |
558 | #define QT_HAS_BUILTIN_CLZ |
559 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clz(quint32 v) noexcept |
560 | { |
561 | return __builtin_clz(v); |
562 | } |
563 | #define QT_HAS_BUILTIN_CTZLL |
564 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzll(quint64 v) noexcept |
565 | { |
566 | return __builtin_ctzll(v); |
567 | } |
568 | #define QT_HAS_BUILTIN_CLZLL |
569 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzll(quint64 v) noexcept |
570 | { |
571 | return __builtin_clzll(v); |
572 | } |
573 | #define QALGORITHMS_USE_BUILTIN_POPCOUNT |
574 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcount(quint32 v) noexcept |
575 | { |
576 | return __builtin_popcount(v); |
577 | } |
578 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcount(quint8 v) noexcept |
579 | { |
580 | return __builtin_popcount(v); |
581 | } |
582 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcount(quint16 v) noexcept |
583 | { |
584 | return __builtin_popcount(v); |
585 | } |
586 | #define QALGORITHMS_USE_BUILTIN_POPCOUNTLL |
587 | Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_popcountll(quint64 v) noexcept |
588 | { |
589 | return __builtin_popcountll(v); |
590 | } |
591 | #elif defined(Q_CC_MSVC) && !defined(Q_PROCESSOR_ARM) |
592 | #define QT_POPCOUNT_CONSTEXPR |
593 | #define QT_POPCOUNT_RELAXED_CONSTEXPR |
594 | #define QT_HAS_BUILTIN_CTZ |
595 | Q_ALWAYS_INLINE unsigned long qt_builtin_ctz(quint32 val) |
596 | { |
597 | unsigned long result; |
598 | _BitScanForward(&result, val); |
599 | return result; |
600 | } |
601 | #define QT_HAS_BUILTIN_CLZ |
602 | Q_ALWAYS_INLINE unsigned long qt_builtin_clz(quint32 val) |
603 | { |
604 | unsigned long result; |
605 | _BitScanReverse(&result, val); |
606 | // Now Invert the result: clz will count *down* from the msb to the lsb, so the msb index is 31 |
607 | // and the lsb index is 0. The result for the index when counting up: msb index is 0 (because it |
608 | // starts there), and the lsb index is 31. |
609 | result ^= sizeof(quint32) * 8 - 1; |
610 | return result; |
611 | } |
612 | #if Q_PROCESSOR_WORDSIZE == 8 |
613 | // These are only defined for 64bit builds. |
614 | #define QT_HAS_BUILTIN_CTZLL |
615 | Q_ALWAYS_INLINE unsigned long qt_builtin_ctzll(quint64 val) |
616 | { |
617 | unsigned long result; |
618 | _BitScanForward64(&result, val); |
619 | return result; |
620 | } |
621 | // MSVC calls it _BitScanReverse and returns the carry flag, which we don't need |
622 | #define QT_HAS_BUILTIN_CLZLL |
623 | Q_ALWAYS_INLINE unsigned long qt_builtin_clzll(quint64 val) |
624 | { |
625 | unsigned long result; |
626 | _BitScanReverse64(&result, val); |
627 | // see qt_builtin_clz |
628 | result ^= sizeof(quint64) * 8 - 1; |
629 | return result; |
630 | } |
631 | #endif // MSVC 64bit |
632 | # define QT_HAS_BUILTIN_CTZS |
633 | Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept |
634 | { |
635 | return qt_builtin_ctz(v); |
636 | } |
637 | #define QT_HAS_BUILTIN_CLZS |
638 | Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept |
639 | { |
640 | return qt_builtin_clz(v) - 16U; |
641 | } |
642 | |
643 | // Neither MSVC nor the Intel compiler define a macro for the POPCNT processor |
644 | // feature, so we're using either the SSE4.2 or the AVX macro as a proxy (Clang |
645 | // does define the macro). It's incorrect for two reasons: |
646 | // 1. It's a separate bit in CPUID, so a processor could implement SSE4.2 and |
647 | // not POPCNT, but that's unlikely to happen. |
648 | // 2. There are processors that support POPCNT but not AVX (Intel Nehalem |
649 | // architecture), but unlike the other compilers, MSVC has no option |
650 | // to generate code for those processors. |
651 | // So it's an acceptable compromise. |
652 | #if defined(__AVX__) || defined(__SSE4_2__) || defined(__POPCNT__) |
653 | #define QALGORITHMS_USE_BUILTIN_POPCOUNT |
654 | #define QALGORITHMS_USE_BUILTIN_POPCOUNTLL |
655 | Q_ALWAYS_INLINE uint qt_builtin_popcount(quint32 v) noexcept |
656 | { |
657 | return __popcnt(v); |
658 | } |
659 | Q_ALWAYS_INLINE uint qt_builtin_popcount(quint8 v) noexcept |
660 | { |
661 | return __popcnt16(v); |
662 | } |
663 | Q_ALWAYS_INLINE uint qt_builtin_popcount(quint16 v) noexcept |
664 | { |
665 | return __popcnt16(v); |
666 | } |
667 | Q_ALWAYS_INLINE uint qt_builtin_popcountll(quint64 v) noexcept |
668 | { |
669 | #if Q_PROCESSOR_WORDSIZE == 8 |
670 | return __popcnt64(v); |
671 | #else |
672 | return __popcnt(quint32(v)) + __popcnt(quint32(v >> 32)); |
673 | #endif // MSVC 64bit |
674 | } |
675 | |
676 | #endif // __AVX__ || __SSE4_2__ || __POPCNT__ |
677 | |
678 | #endif // MSVC |
679 | #endif // QT_HAS_CONSTEXPR_BUILTINS |
680 | |
681 | #ifndef QT_POPCOUNT_CONSTEXPR |
682 | #define QT_POPCOUNT_CONSTEXPR Q_DECL_CONSTEXPR |
683 | #define QT_POPCOUNT_RELAXED_CONSTEXPR Q_DECL_RELAXED_CONSTEXPR |
684 | #endif |
685 | |
686 | } //namespace QAlgorithmsPrivate |
687 | |
688 | Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint32 v) noexcept |
689 | { |
690 | #ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT |
691 | return QAlgorithmsPrivate::qt_builtin_popcount(v); |
692 | #else |
693 | // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel |
694 | return |
695 | (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
696 | (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
697 | (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; |
698 | #endif |
699 | } |
700 | |
701 | Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint8 v) noexcept |
702 | { |
703 | #ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT |
704 | return QAlgorithmsPrivate::qt_builtin_popcount(v); |
705 | #else |
706 | return |
707 | (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; |
708 | #endif |
709 | } |
710 | |
711 | Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint16 v) noexcept |
712 | { |
713 | #ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT |
714 | return QAlgorithmsPrivate::qt_builtin_popcount(v); |
715 | #else |
716 | return |
717 | (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
718 | (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; |
719 | #endif |
720 | } |
721 | |
722 | Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(quint64 v) noexcept |
723 | { |
724 | #ifdef QALGORITHMS_USE_BUILTIN_POPCOUNTLL |
725 | return QAlgorithmsPrivate::qt_builtin_popcountll(v); |
726 | #else |
727 | return |
728 | (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
729 | (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
730 | (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
731 | (((v >> 36) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
732 | (((v >> 48) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + |
733 | (((v >> 60) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; |
734 | #endif |
735 | } |
736 | |
737 | Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR inline uint qPopulationCount(long unsigned int v) noexcept |
738 | { |
739 | return qPopulationCount(static_cast<quint64>(v)); |
740 | } |
741 | |
742 | #if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) |
743 | #undef QALGORITHMS_USE_BUILTIN_POPCOUNT |
744 | #endif |
745 | #undef QT_POPCOUNT_CONSTEXPR |
746 | |
747 | Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint32 v) noexcept |
748 | { |
749 | #if defined(QT_HAS_BUILTIN_CTZ) |
750 | return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 32U; |
751 | #else |
752 | // see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel |
753 | unsigned int c = 32; // c will be the number of zero bits on the right |
754 | v &= -signed(v); |
755 | if (v) c--; |
756 | if (v & 0x0000FFFF) c -= 16; |
757 | if (v & 0x00FF00FF) c -= 8; |
758 | if (v & 0x0F0F0F0F) c -= 4; |
759 | if (v & 0x33333333) c -= 2; |
760 | if (v & 0x55555555) c -= 1; |
761 | return c; |
762 | #endif |
763 | } |
764 | |
765 | Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint8 v) noexcept |
766 | { |
767 | #if defined(QT_HAS_BUILTIN_CTZ) |
768 | return v ? QAlgorithmsPrivate::qt_builtin_ctz(v) : 8U; |
769 | #else |
770 | unsigned int c = 8; // c will be the number of zero bits on the right |
771 | v &= -signed(v); |
772 | if (v) c--; |
773 | if (v & 0x0000000F) c -= 4; |
774 | if (v & 0x00000033) c -= 2; |
775 | if (v & 0x00000055) c -= 1; |
776 | return c; |
777 | #endif |
778 | } |
779 | |
780 | Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint16 v) noexcept |
781 | { |
782 | #if defined(QT_HAS_BUILTIN_CTZS) |
783 | return v ? QAlgorithmsPrivate::qt_builtin_ctzs(v) : 16U; |
784 | #else |
785 | unsigned int c = 16; // c will be the number of zero bits on the right |
786 | v &= -signed(v); |
787 | if (v) c--; |
788 | if (v & 0x000000FF) c -= 8; |
789 | if (v & 0x00000F0F) c -= 4; |
790 | if (v & 0x00003333) c -= 2; |
791 | if (v & 0x00005555) c -= 1; |
792 | return c; |
793 | #endif |
794 | } |
795 | |
796 | Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint64 v) noexcept |
797 | { |
798 | #if defined(QT_HAS_BUILTIN_CTZLL) |
799 | return v ? QAlgorithmsPrivate::qt_builtin_ctzll(v) : 64; |
800 | #else |
801 | quint32 x = static_cast<quint32>(v); |
802 | return x ? qCountTrailingZeroBits(x) |
803 | : 32 + qCountTrailingZeroBits(static_cast<quint32>(v >> 32)); |
804 | #endif |
805 | } |
806 | |
807 | Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(unsigned long v) noexcept |
808 | { |
809 | return qCountTrailingZeroBits(QIntegerForSizeof<long>::Unsigned(v)); |
810 | } |
811 | |
812 | Q_DECL_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint32 v) noexcept |
813 | { |
814 | #if defined(QT_HAS_BUILTIN_CLZ) |
815 | return v ? QAlgorithmsPrivate::qt_builtin_clz(v) : 32U; |
816 | #else |
817 | // Hacker's Delight, 2nd ed. Fig 5-16, p. 102 |
818 | v = v | (v >> 1); |
819 | v = v | (v >> 2); |
820 | v = v | (v >> 4); |
821 | v = v | (v >> 8); |
822 | v = v | (v >> 16); |
823 | return qPopulationCount(~v); |
824 | #endif |
825 | } |
826 | |
827 | QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint8 v) noexcept |
828 | { |
829 | #if defined(QT_HAS_BUILTIN_CLZ) |
830 | return v ? QAlgorithmsPrivate::qt_builtin_clz(v)-24U : 8U; |
831 | #else |
832 | v = v | (v >> 1); |
833 | v = v | (v >> 2); |
834 | v = v | (v >> 4); |
835 | return qPopulationCount(static_cast<quint8>(~v)); |
836 | #endif |
837 | } |
838 | |
839 | QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint16 v) noexcept |
840 | { |
841 | #if defined(QT_HAS_BUILTIN_CLZS) |
842 | return v ? QAlgorithmsPrivate::qt_builtin_clzs(v) : 16U; |
843 | #else |
844 | v = v | (v >> 1); |
845 | v = v | (v >> 2); |
846 | v = v | (v >> 4); |
847 | v = v | (v >> 8); |
848 | return qPopulationCount(static_cast<quint16>(~v)); |
849 | #endif |
850 | } |
851 | |
852 | QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint64 v) noexcept |
853 | { |
854 | #if defined(QT_HAS_BUILTIN_CLZLL) |
855 | return v ? QAlgorithmsPrivate::qt_builtin_clzll(v) : 64U; |
856 | #else |
857 | v = v | (v >> 1); |
858 | v = v | (v >> 2); |
859 | v = v | (v >> 4); |
860 | v = v | (v >> 8); |
861 | v = v | (v >> 16); |
862 | v = v | (v >> 32); |
863 | return qPopulationCount(~v); |
864 | #endif |
865 | } |
866 | |
867 | QT_POPCOUNT_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(unsigned long v) noexcept |
868 | { |
869 | return qCountLeadingZeroBits(QIntegerForSizeof<long>::Unsigned(v)); |
870 | } |
871 | |
872 | QT_WARNING_POP |
873 | QT_END_NAMESPACE |
874 | |
875 | #endif // QALGORITHMS_H |
876 | |