Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
q20bit.h
Go to the documentation of this file.
1// Copyright (C) 2025 Intel Corporation.
2// Copyright (C) 2020 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#ifndef Q20BIT_H
7#define Q20BIT_H
8
9#include <QtCore/q20type_traits.h>
10
11#if defined(__cpp_lib_bitops) || defined(__cpp_lib_int_pow2)
12# include <bit>
13#else
14# include <QtCore/qtypes.h>
15# include <limits>
16
17# ifdef Q_CC_MSVC
18// avoiding qsimd.h -> immintrin.h unless necessary, because it increases
19// compilation time
20# include <QtCore/qsimd.h>
21# include <intrin.h>
22# endif
23#endif
24
25//
26// W A R N I N G
27// -------------
28//
29// This file is not part of the Qt API. Types and functions defined in this
30// file can reliably be replaced by their std counterparts, once available.
31// You may use these definitions in your own code, but be aware that we
32// will remove them once Qt depends on the C++ version that supports
33// them in namespace std. There will be NO deprecation warning, the
34// definitions will JUST go away.
35//
36// If you can't agree to these terms, don't use these definitions!
37//
38// We mean it.
39//
40
41QT_BEGIN_NAMESPACE
42
43namespace q20 {
44#if defined(__cpp_lib_bitops)
45using std::countl_zero;
46using std::countr_zero;
47using std::popcount;
48using std::rotl;
49using std::rotr;
50#else
51namespace detail {
52template <typename T> /*non-constexpr*/ inline auto hw_popcount(T v) noexcept
53{
54#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_ARM_64)
55 if constexpr (sizeof(T) == sizeof(quint64))
56 return int(_CountOneBits64(v));
57 return int(_CountOneBits(v));
58#endif
59#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) && defined(__POPCNT__)
60 // Note: __POPCNT__ comes from qsimd.h, not the compiler.
61# ifdef Q_PROCESSOR_X86_64
62 if constexpr (sizeof(T) == sizeof(quint64))
63 return int(__popcnt64(v));
64# endif
65 if constexpr (sizeof(T) == sizeof(quint64))
66 return int(__popcnt(quint32(v)) + __popcnt(quint32(v >> 32)));
67 if constexpr (sizeof(T) == sizeof(quint32))
68 return int(__popcnt(v));
69 return int(__popcnt16(v));
70#else
71 Q_UNUSED(v);
72#endif
73}
74
75template <typename T> /*non-constexpr*/ inline auto hw_countl_zero(T v) noexcept
76{
77#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_ARM_64)
78 if constexpr (sizeof(T) == sizeof(quint64))
79 return int(_CountLeadingZeros64(v));
80 return int(_CountLeadingZeros(v)) - (32 - std::numeric_limits<T>::digits);
81#endif
82#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) && defined(__LZCNT__)
83 // Note: __LZCNT__ comes from qsimd.h, not the compiler
84# if defined(Q_PROCESSOR_X86_64)
85 if constexpr (sizeof(T) == sizeof(quint64))
86 return int(__lzcnt64(v));
87# endif
88 if constexpr (sizeof(T) == sizeof(quint32))
89 return int(__lzcnt(v));
90 if constexpr (sizeof(T) == sizeof(quint16))
91 return int(__lzcnt16(v));
92 if constexpr (sizeof(T) == sizeof(quint8))
93 return int(__lzcnt(v)) - 24;
94#endif
95#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
96 constexpr int Digits = std::numeric_limits<T>::digits;
97 unsigned long result;
98
99 if constexpr (sizeof(T) == sizeof(quint64)) {
100# ifdef Q_PROCESSOR_X86_64
101 if (_BitScanReverse64(&result, v) == 0)
102 return Digits;
103# else
104 if (quint32 h = quint32(v >> 32))
105 return hw_countl_zero(h);
106 return hw_countl_zero(quint32(v)) + 32;
107# endif
108 } else {
109 if (_BitScanReverse(&result, v) == 0)
110 return Digits;
111 }
112
113 // Now Invert the result: clz will count *down* from the msb to the lsb, so the msb index is 31
114 // and the lsb index is 0. The result for the index when counting up: msb index is 0 (because it
115 // starts there), and the lsb index is 31.
116 result ^= sizeof(T) * 8 - 1;
117 return int(result);
118#else
119 Q_UNUSED(v);
120#endif
121}
122
123template <typename T> /*non-constexpr*/ inline auto hw_countr_zero(T v) noexcept
124{
125#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_ARM_64)
126 if constexpr (sizeof(T) == sizeof(quint64))
127 return int(_CountTrailingZeros64(v));
128 constexpr int Digits = std::numeric_limits<T>::digits;
129 const int result = int(_CountTrailingZeros(v));
130 return result > Digits ? Digits : result;
131#endif
132#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) && defined(__BMI__)
133 // Note: __BMI__ comes from qsimd.h, not the compiler
134# if defined(Q_PROCESSOR_X86_64)
135 if constexpr (sizeof(T) == sizeof(quint64))
136 return int(_tzcnt_u64(v));
137# endif
138 if constexpr (sizeof(T) == sizeof(quint32))
139 return int(_tzcnt_u32(v));
140 // No _tzcnt_u16 or u8 intrinsics
141#endif
142#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
143 constexpr int Digits = std::numeric_limits<T>::digits;
144 unsigned long result;
145 if constexpr (sizeof(T) <= sizeof(quint32))
146 return _BitScanForward(&result, v) ? int(result) : Digits;
147# ifdef Q_PROCESSOR_X86_64
148 return _BitScanForward64(&result, v) ? int(result) : Digits;
149# endif
150#else
151 Q_UNUSED(v);
152#endif
153}
154} // namespace q20::detail
155
156template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, int>
157popcount(T v) noexcept
158{
159#if __has_builtin(__builtin_popcountg)
160 return __builtin_popcountg(v);
161#endif
162
163 if constexpr (sizeof(T) > sizeof(quint64)) {
164 static_assert(sizeof(T) == 16, "Unsupported integer size");
165 return popcount(quint64(v)) + popcount(quint64(v >> 64));
166 }
167
168# if __has_builtin(__builtin_popcount)
169 // These GCC/Clang intrinsics are constexpr and use the HW instructions
170 // where available. Note: no runtime detection.
171 if constexpr (sizeof(T) > sizeof(quint32))
172 return __builtin_popcountll(v);
173 return __builtin_popcount(v);
174# endif
175
176# ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
177 // Try hardware functions if not constexpr. Note: no runtime detection.
178 if (!is_constant_evaluated()) {
179 if constexpr (std::is_integral_v<decltype(detail::hw_popcount(v))>)
180 return detail::hw_popcount(v);
181 }
182# endif
183
184 constexpr int Digits = std::numeric_limits<T>::digits;
185 int r = (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
186 if constexpr (Digits > 12)
187 r += (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
188 if constexpr (Digits > 24)
189 r += (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
190 if constexpr (Digits > 36) {
191 r += (((v >> 36) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f +
192 (((v >> 48) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f +
193 (((v >> 60) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
194 }
195 return r;
196}
197
198template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, int>
199countl_zero(T v) noexcept
200{
201#if __has_builtin(__builtin_clzg)
202 // "If two arguments are specified, and first argument is 0, the result is
203 // the second argument."
204 return __builtin_clzg(v, std::numeric_limits<T>::digits);
205#endif
206
207 if constexpr (sizeof(T) > sizeof(quint64)) {
208 static_assert(sizeof(T) == 16, "Unsupported integer size");
209 if (quint64 h = quint64(v >> 64))
210 return countl_zero(h);
211 return countl_zero(quint64(v)) + 64;
212 }
213
214#if __has_builtin(__builtin_clz)
215 // These GCC/Clang intrinsics are constexpr and use the HW instructions
216 // where available.
217 if (!v)
218 return std::numeric_limits<T>::digits;
219 if constexpr (sizeof(T) == sizeof(quint64))
220 return __builtin_clzll(v);
221# if __has_builtin(__builtin_clzs)
222 if constexpr (sizeof(T) == sizeof(quint16))
223 return __builtin_clzs(v);
224# endif
225 return __builtin_clz(v) - (32 - std::numeric_limits<T>::digits);
226#endif
227
228#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
229 // Try hardware functions if not constexpr. Note: no runtime detection.
230 if (!is_constant_evaluated()) {
231 if constexpr (std::is_integral_v<decltype(detail::hw_countl_zero(v))>)
232 return detail::hw_countl_zero(v);
233 }
234#endif
235
236 // Hacker's Delight, 2nd ed. Fig 5-16, p. 102
237 v = v | (v >> 1);
238 v = v | (v >> 2);
239 v = v | (v >> 4);
240 if constexpr (sizeof(T) > sizeof(quint8))
241 v = v | (v >> 8);
242 if constexpr (sizeof(T) > sizeof(quint16))
243 v = v | (v >> 16);
244 if constexpr (sizeof(T) > sizeof(quint32))
245 v = v | (v >> 32);
246 return popcount(T(~v));
247}
248
249template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, int>
250countr_zero(T v) noexcept
251{
252#if __has_builtin(__builtin_ctzg)
253 // "If two arguments are specified, and first argument is 0, the result is
254 // the second argument."
255 return __builtin_ctzg(v, std::numeric_limits<T>::digits);
256#endif
257
258 if constexpr (sizeof(T) > sizeof(quint64)) {
259 static_assert(sizeof(T) == 16, "Unsupported integer size");
260 quint64 l = quint64(v);
261 return l ? countr_zero(l) : 64 + countr_zero(quint64(v >> 64));
262 }
263
264#if __has_builtin(__builtin_ctz)
265 // These GCC/Clang intrinsics are constexpr and use the HW instructions
266 // where available.
267 if (!v)
268 return std::numeric_limits<T>::digits;
269 if constexpr (sizeof(T) == sizeof(quint64))
270 return __builtin_ctzll(v);
271# if __has_builtin(__builtin_ctzs)
272 if constexpr (sizeof(T) == sizeof(quint16))
273 return __builtin_ctzs(v);
274# endif
275 return __builtin_ctz(v);
276#endif
277
278#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
279 // Try hardware functions if not constexpr. Note: no runtime detection.
280 if (!is_constant_evaluated()) {
281 if constexpr (std::is_integral_v<decltype(detail::hw_countr_zero(v))>)
282 return detail::hw_countr_zero(v);
283 }
284#endif
285
286 if constexpr (sizeof(T) > sizeof(quint32)) {
287 quint32 l = quint32(v);
288 return l ? countr_zero(l) : 32 + countr_zero(quint32(v >> 32));
289 }
290
291 // see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel
292 int c = std::numeric_limits<T>::digits; // c will be the number of zero bits on the right
293QT_WARNING_PUSH
294QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
295 v &= T(-v);
296QT_WARNING_POP
297 if (v) c--;
298 if constexpr (sizeof(T) == sizeof(quint32)) {
299 if (v & 0x0000FFFF) c -= 16;
300 if (v & 0x00FF00FF) c -= 8;
301 if (v & 0x0F0F0F0F) c -= 4;
302 if (v & 0x33333333) c -= 2;
303 if (v & 0x55555555) c -= 1;
304 } else if constexpr (sizeof(T) == sizeof(quint16)) {
305 if (v & 0x000000FF) c -= 8;
306 if (v & 0x00000F0F) c -= 4;
307 if (v & 0x00003333) c -= 2;
308 if (v & 0x00005555) c -= 1;
309 } else /*if constexpr (sizeof(T) == sizeof(quint8))*/ {
310 if (v & 0x0000000F) c -= 4;
311 if (v & 0x00000033) c -= 2;
312 if (v & 0x00000055) c -= 1;
313 }
314 return c;
315}
316
317template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
318rotl(T v, int s) noexcept
319{
320 constexpr int Digits = std::numeric_limits<T>::digits;
321 unsigned n = unsigned(s) % Digits;
322 return (v << n) | (v >> (Digits - n));
323}
324
325template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
326rotr(T v, int s) noexcept
327{
328 constexpr int Digits = std::numeric_limits<T>::digits;
329 unsigned n = unsigned(s) % Digits;
330 return (v >> n) | (v << (Digits - n));
331}
332#endif // __cpp_lib_bitops
333
334#if defined(__cpp_lib_int_pow2)
335using std::bit_ceil;
336using std::bit_floor;
337using std::bit_width;
338#else
339template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
340bit_ceil(T v) noexcept
341{
342 // Difference from standard: we do not enforce UB
343 constexpr int Digits = std::numeric_limits<T>::digits;
344 if (v <= 1)
345 return 1;
346 return T(1) << (Digits - countl_zero(T(v - 1)));
347}
348
349template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
350bit_width(T v) noexcept
351{
352 return std::numeric_limits<T>::digits - countl_zero(v);
353}
354
355template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
356bit_floor(T v) noexcept
357{
358 return v ? T(1) << (bit_width(v) - 1) : 0;
359}
360#endif // __cpp_lib_int_pow2
361} // namespace q20
362
363QT_END_NAMESPACE
364
365#endif // Q20BIT_H
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:56
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
Definition qnumeric.h:592
constexpr bool HasLargerInt
Definition qnumeric.h:227
constexpr int qSaturateRound(FP value)
Definition qnumeric.h:557
constexpr std::enable_if_t<(std::is_unsigned_v< T >||std::is_signed_v< T >), bool > qMulOverflowGeneric(T v1, T v2, T *r)
Definition qnumeric.h:234
constexpr auto qUnsignedAbs(T t)
Definition qnumeric.h:494
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflowGeneric(T v1, T v2, T *r)
Definition qnumeric.h:112
constexpr std::enable_if_t< std::is_same_v< T, decltype(+T{})>, bool > qMulOverflowWideMultiplication(T v1, T v2, T *r)
Definition qnumeric.h:126
constexpr bool fuzzyCompare(const T &lhs, const S &rhs) noexcept
Definition qnumeric.h:641
constexpr Result qCheckedFPConversionToInteger(FP value)
Definition qnumeric.h:504
auto hw_popcount(T v) noexcept
Definition q20bit.h:52
auto hw_countl_zero(T v) noexcept
Definition q20bit.h:75
auto hw_countr_zero(T v) noexcept
Definition q20bit.h:123
constexpr std::enable_if_t< std::is_unsigned_v< T >, int > popcount(T v) noexcept
Definition q20bit.h:157
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > bit_floor(T v) noexcept
Definition q20bit.h:356
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > rotl(T v, int s) noexcept
Definition q20bit.h:318
constexpr std::enable_if_t< std::is_unsigned_v< T >, int > countl_zero(T v) noexcept
Definition q20bit.h:199
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > bit_width(T v) noexcept
Definition q20bit.h:350
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > bit_ceil(T v) noexcept
Definition q20bit.h:340
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > rotr(T v, int s) noexcept
Definition q20bit.h:326
constexpr std::enable_if_t< std::is_unsigned_v< T >, int > countr_zero(T v) noexcept
Definition q20bit.h:250
static Q_DECL_CONST_FUNCTION bool isinf(double d)
Definition qnumeric_p.h:75
static Q_DECL_CONST_FUNCTION bool isnan(float f)
Definition qnumeric_p.h:78
static Q_DECL_CONST_FUNCTION bool isinf(float f)
Definition qnumeric_p.h:79
static Q_DECL_CONST_FUNCTION int fpclassify(float f)
Definition qnumeric_p.h:81
static Q_DECL_CONST_FUNCTION int fpclassify(double d)
Definition qnumeric_p.h:77
static Q_DECL_CONST_FUNCTION bool isfinite(double d)
Definition qnumeric_p.h:76
static Q_DECL_CONST_FUNCTION bool isnan(double d)
Definition qnumeric_p.h:74
static Q_DECL_CONST_FUNCTION bool isfinite(float f)
Definition qnumeric_p.h:80
#define __has_builtin(x)
static quint64 d2i(double d)
Definition qnumeric.cpp:181
Q_CORE_EXPORT int qFpClassify(float val)
Definition qnumeric.cpp:102
Q_CORE_EXPORT int qFpClassify(double val)
Definition qnumeric.cpp:101
static quint32 f2i(float f)
Definition qnumeric.cpp:108
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(float f)
int qIntCast(double f)
Definition qnumeric.h:651
constexpr T qAbs(const T &t)
Definition qnumeric.h:484
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsFinite(T)
Definition qnumeric.h:61
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d)
constexpr bool qSubOverflow(T v1, T *r)
Definition qnumeric.h:422
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf()
constexpr bool qMulOverflow(T v1, T *r)
Definition qnumeric.h:476
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f)
constexpr bool qFuzzyIsNull(double d) noexcept
Definition qnumeric.h:605
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(double d)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsInf(float f)
constexpr bool qFuzzyCompare(float p1, float p2) noexcept
Definition qnumeric.h:600
constexpr bool qSubOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:417
constexpr bool qAddOverflow(T v1, T *r)
Definition qnumeric.h:412
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsNaN(T)
Definition qnumeric.h:58
constexpr std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
Definition qnumeric.h:360
constexpr qint64 qRound64(double d)
Definition qnumeric.h:580
constexpr int qRound(float f)
Definition qnumeric.h:575
int qIntCast(float f)
Definition qnumeric.h:652
constexpr int qRound(double d)
Definition qnumeric.h:570
constexpr bool qIsNull(float f) noexcept
Definition qnumeric.h:623
constexpr bool qFuzzyIsNull(float f) noexcept
Definition qnumeric.h:610
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qSubOverflow(T v1, T v2, T *r)
Definition qnumeric.h:325
constexpr bool qFuzzyCompare(double p1, double p2) noexcept
Definition qnumeric.h:595
constexpr qint64 qRound64(float f)
Definition qnumeric.h:585
constexpr bool qMulOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:427
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN()
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflow(T v1, T v2, T *r)
Definition qnumeric.h:264
constexpr bool qAddOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:407
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(double d)
QT_WARNING_PUSH QT_WARNING_DISABLE_FLOAT_COMPARE constexpr bool qIsNull(double d) noexcept
Definition qnumeric.h:618
static constexpr auto qt_saturate(From x)
Definition qnumeric_p.h:437
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:114
#define __has_extension(X)
Definition qnumeric_p.h:29
static Q_DECL_CONST_FUNCTION int qt_fpclassify(float f)
Definition qnumeric_p.h:144
constexpr static Q_DECL_CONST_FUNCTION double qt_qnan() noexcept
Definition qnumeric_p.h:102
constexpr static Q_DECL_CONST_FUNCTION double qt_inf() noexcept
Definition qnumeric_p.h:85
static Q_DECL_CONST_FUNCTION int qt_fpclassify(double d)
Definition qnumeric_p.h:124
static Q_DECL_CONST_FUNCTION bool qt_is_inf(double d)
Definition qnumeric_p.h:109
static Q_DECL_CONST_FUNCTION bool qt_is_finite(double d)
Definition qnumeric_p.h:119
static Q_DECL_CONST_FUNCTION bool qt_is_finite(float f)
Definition qnumeric_p.h:139
static Q_DECL_CONST_FUNCTION bool qt_is_nan(float f)
Definition qnumeric_p.h:134
static Q_DECL_CONST_FUNCTION bool qt_is_inf(float f)
Definition qnumeric_p.h:129