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_X86) && defined(__POPCNT__)
55 // Note: __POPCNT__ comes from qsimd.h, not the compiler.
56# ifdef Q_PROCESSOR_X86_64
57 if constexpr (sizeof(T) == sizeof(quint64))
58 return int(__popcnt64(v));
59# endif
60 if constexpr (sizeof(T) == sizeof(quint64))
61 return int(__popcnt(quint32(v)) + __popcnt(quint32(v >> 32)));
62 if constexpr (sizeof(T) == sizeof(quint32))
63 return int(__popcnt(v));
64 return int(__popcnt16(v));
65#else
66 Q_UNUSED(v);
67#endif
68}
69
70template <typename T> /*non-constexpr*/ inline auto hw_countl_zero(T v) noexcept
71{
72#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) && defined(__LZCNT__)
73 // Note: __LZCNT__ comes from qsimd.h, not the compiler
74# if defined(Q_PROCESSOR_X86_64)
75 if constexpr (sizeof(T) == sizeof(quint64))
76 return int(__lzcnt64(v));
77# endif
78 if constexpr (sizeof(T) == sizeof(quint32))
79 return int(__lzcnt(v));
80 if constexpr (sizeof(T) == sizeof(quint16))
81 return int(__lzcnt16(v));
82 if constexpr (sizeof(T) == sizeof(quint8))
83 return int(__lzcnt(v)) - 24;
84#endif
85#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
86 constexpr int Digits = std::numeric_limits<T>::digits;
87 unsigned long result;
88
89 if constexpr (sizeof(T) == sizeof(quint64)) {
90# ifdef Q_PROCESSOR_X86_64
91 if (_BitScanReverse64(&result, v) == 0)
92 return Digits;
93# else
94 if (quint32 h = quint32(v >> 32))
95 return hw_countl_zero(h);
96 return hw_countl_zero(quint32(v)) + 32;
97# endif
98 } else {
99 if (_BitScanReverse(&result, v) == 0)
100 return Digits;
101 }
102
103 // Now Invert the result: clz will count *down* from the msb to the lsb, so the msb index is 31
104 // and the lsb index is 0. The result for the index when counting up: msb index is 0 (because it
105 // starts there), and the lsb index is 31.
106 result ^= sizeof(T) * 8 - 1;
107 return int(result);
108#else
109 Q_UNUSED(v);
110#endif
111}
112
113template <typename T> /*non-constexpr*/ inline auto hw_countr_zero(T v) noexcept
114{
115#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) && defined(__BMI__)
116 // Note: __BMI__ comes from qsimd.h, not the compiler
117# if defined(Q_PROCESSOR_X86_64)
118 if constexpr (sizeof(T) == sizeof(quint64))
119 return int(_tzcnt_u64(v));
120# endif
121 if constexpr (sizeof(T) == sizeof(quint32))
122 return int(_tzcnt_u32(v));
123 // No _tzcnt_u16 or u8 intrinsics
124#endif
125#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
126 constexpr int Digits = std::numeric_limits<T>::digits;
127 unsigned long result;
128 if constexpr (sizeof(T) <= sizeof(quint32))
129 return _BitScanForward(&result, v) ? int(result) : Digits;
130# ifdef Q_PROCESSOR_X86_64
131 return _BitScanForward64(&result, v) ? int(result) : Digits;
132# endif
133#else
134 Q_UNUSED(v);
135#endif
136}
137} // namespace q20::detail
138
139template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, int>
140popcount(T v) noexcept
141{
142#if __has_builtin(__builtin_popcountg)
143 return __builtin_popcountg(v);
144#endif
145
146 if constexpr (sizeof(T) > sizeof(quint64)) {
147 static_assert(sizeof(T) == 16, "Unsupported integer size");
148 return popcount(quint64(v)) + popcount(quint64(v >> 64));
149 }
150
151# if __has_builtin(__builtin_popcount)
152 // These GCC/Clang intrinsics are constexpr and use the HW instructions
153 // where available. Note: no runtime detection.
154 if constexpr (sizeof(T) > sizeof(quint32))
155 return __builtin_popcountll(v);
156 return __builtin_popcount(v);
157# endif
158
159# ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
160 // Try hardware functions if not constexpr. Note: no runtime detection.
161 if (!is_constant_evaluated()) {
162 if constexpr (std::is_integral_v<decltype(detail::hw_popcount(v))>)
163 return detail::hw_popcount(v);
164 }
165# endif
166
167 constexpr int Digits = std::numeric_limits<T>::digits;
168 int r = (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
169 if constexpr (Digits > 12)
170 r += (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
171 if constexpr (Digits > 24)
172 r += (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
173 if constexpr (Digits > 36) {
174 r += (((v >> 36) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f +
175 (((v >> 48) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f +
176 (((v >> 60) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f;
177 }
178 return r;
179}
180
181template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, int>
182countl_zero(T v) noexcept
183{
184#if __has_builtin(__builtin_clzg)
185 // "If two arguments are specified, and first argument is 0, the result is
186 // the second argument."
187 return __builtin_clzg(v, std::numeric_limits<T>::digits);
188#endif
189
190 if constexpr (sizeof(T) > sizeof(quint64)) {
191 static_assert(sizeof(T) == 16, "Unsupported integer size");
192 if (quint64 h = quint64(v >> 64))
193 return countl_zero(h);
194 return countl_zero(quint64(v)) + 64;
195 }
196
197#if __has_builtin(__builtin_clz)
198 // These GCC/Clang intrinsics are constexpr and use the HW instructions
199 // where available.
200 if (!v)
201 return std::numeric_limits<T>::digits;
202 if constexpr (sizeof(T) == sizeof(quint64))
203 return __builtin_clzll(v);
204# if __has_builtin(__builtin_clzs)
205 if constexpr (sizeof(T) == sizeof(quint16))
206 return __builtin_clzs(v);
207# endif
208 return __builtin_clz(v) - (32 - std::numeric_limits<T>::digits);
209#endif
210
211#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
212 // Try hardware functions if not constexpr. Note: no runtime detection.
213 if (!is_constant_evaluated()) {
214 if constexpr (std::is_integral_v<decltype(detail::hw_countl_zero(v))>)
215 return detail::hw_countl_zero(v);
216 }
217#endif
218
219 // Hacker's Delight, 2nd ed. Fig 5-16, p. 102
220 v = v | (v >> 1);
221 v = v | (v >> 2);
222 v = v | (v >> 4);
223 if constexpr (sizeof(T) > sizeof(quint8))
224 v = v | (v >> 8);
225 if constexpr (sizeof(T) > sizeof(quint16))
226 v = v | (v >> 16);
227 if constexpr (sizeof(T) > sizeof(quint32))
228 v = v | (v >> 32);
229 return popcount(T(~v));
230}
231
232template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, int>
233countr_zero(T v) noexcept
234{
235#if __has_builtin(__builtin_ctzg)
236 // "If two arguments are specified, and first argument is 0, the result is
237 // the second argument."
238 return __builtin_ctzg(v, std::numeric_limits<T>::digits);
239#endif
240
241 if constexpr (sizeof(T) > sizeof(quint64)) {
242 static_assert(sizeof(T) == 16, "Unsupported integer size");
243 quint64 l = quint64(v);
244 return l ? countr_zero(l) : 64 + countr_zero(quint64(v >> 64));
245 }
246
247#if __has_builtin(__builtin_ctz)
248 // These GCC/Clang intrinsics are constexpr and use the HW instructions
249 // where available.
250 if (!v)
251 return std::numeric_limits<T>::digits;
252 if constexpr (sizeof(T) == sizeof(quint64))
253 return __builtin_ctzll(v);
254# if __has_builtin(__builtin_ctzs)
255 if constexpr (sizeof(T) == sizeof(quint16))
256 return __builtin_ctzs(v);
257# endif
258 return __builtin_ctz(v);
259#endif
260
261#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
262 // Try hardware functions if not constexpr. Note: no runtime detection.
263 if (!is_constant_evaluated()) {
264 if constexpr (std::is_integral_v<decltype(detail::hw_countr_zero(v))>)
265 return detail::hw_countr_zero(v);
266 }
267#endif
268
269 if constexpr (sizeof(T) > sizeof(quint32)) {
270 quint32 l = quint32(v);
271 return l ? countr_zero(l) : 32 + countr_zero(quint32(v >> 32));
272 }
273
274 // see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel
275 int c = std::numeric_limits<T>::digits; // c will be the number of zero bits on the right
276QT_WARNING_PUSH
277QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
278 v &= T(-v);
279QT_WARNING_POP
280 if (v) c--;
281 if constexpr (sizeof(T) == sizeof(quint32)) {
282 if (v & 0x0000FFFF) c -= 16;
283 if (v & 0x00FF00FF) c -= 8;
284 if (v & 0x0F0F0F0F) c -= 4;
285 if (v & 0x33333333) c -= 2;
286 if (v & 0x55555555) c -= 1;
287 } else if constexpr (sizeof(T) == sizeof(quint16)) {
288 if (v & 0x000000FF) c -= 8;
289 if (v & 0x00000F0F) c -= 4;
290 if (v & 0x00003333) c -= 2;
291 if (v & 0x00005555) c -= 1;
292 } else /*if constexpr (sizeof(T) == sizeof(quint8))*/ {
293 if (v & 0x0000000F) c -= 4;
294 if (v & 0x00000033) c -= 2;
295 if (v & 0x00000055) c -= 1;
296 }
297 return c;
298}
299
300template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
301rotl(T v, int s) noexcept
302{
303 constexpr int Digits = std::numeric_limits<T>::digits;
304 unsigned n = unsigned(s) % Digits;
305 return (v << n) | (v >> (Digits - n));
306}
307
308template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
309rotr(T v, int s) noexcept
310{
311 constexpr int Digits = std::numeric_limits<T>::digits;
312 unsigned n = unsigned(s) % Digits;
313 return (v >> n) | (v << (Digits - n));
314}
315#endif // __cpp_lib_bitops
316
317#if defined(__cpp_lib_int_pow2)
318using std::bit_ceil;
319using std::bit_floor;
320using std::bit_width;
321#else
322template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
323bit_ceil(T v) noexcept
324{
325 // Difference from standard: we do not enforce UB
326 constexpr int Digits = std::numeric_limits<T>::digits;
327 if (v <= 1)
328 return 1;
329 return T(1) << (Digits - countl_zero(T(v - 1)));
330}
331
332template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
333bit_width(T v) noexcept
334{
335 return std::numeric_limits<T>::digits - countl_zero(v);
336}
337
338template <typename T> constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
339bit_floor(T v) noexcept
340{
341 return v ? T(1) << (bit_width(v) - 1) : 0;
342}
343#endif // __cpp_lib_int_pow2
344} // namespace q20
345
346QT_END_NAMESPACE
347
348#endif // Q20BIT_H
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:48
constexpr const T & min(const T &a, const T &b)
Definition qnumeric.h:614
constexpr bool HasLargerInt
Definition qnumeric.h:239
constexpr int qSaturateRound(FP value)
Definition qnumeric.h:579
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:246
constexpr auto qUnsignedAbs(T t)
Definition qnumeric.h:516
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflowGeneric(T v1, T v2, T *r)
Definition qnumeric.h:124
constexpr std::enable_if_t< std::is_same_v< T, decltype(+T{})>, bool > qMulOverflowWideMultiplication(T v1, T v2, T *r)
Definition qnumeric.h:138
constexpr Result qCheckedFPConversionToInteger(FP value)
Definition qnumeric.h:526
auto hw_popcount(T v) noexcept
Definition q20bit.h:52
auto hw_countl_zero(T v) noexcept
Definition q20bit.h:70
auto hw_countr_zero(T v) noexcept
Definition q20bit.h:113
constexpr std::enable_if_t< std::is_unsigned_v< T >, int > popcount(T v) noexcept
Definition q20bit.h:140
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > bit_floor(T v) noexcept
Definition q20bit.h:339
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > rotl(T v, int s) noexcept
Definition q20bit.h:301
constexpr std::enable_if_t< std::is_unsigned_v< T >, int > countl_zero(T v) noexcept
Definition q20bit.h:182
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > bit_width(T v) noexcept
Definition q20bit.h:333
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > bit_ceil(T v) noexcept
Definition q20bit.h:323
constexpr std::enable_if_t< std::is_unsigned_v< T >, T > rotr(T v, int s) noexcept
Definition q20bit.h:309
constexpr std::enable_if_t< std::is_unsigned_v< T >, int > countr_zero(T v) noexcept
Definition q20bit.h:233
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)
#define __has_include(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)
constexpr T qAbs(const T &t)
Definition qnumeric.h:506
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsFinite(T)
Definition qnumeric.h:73
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsFinite(double d)
constexpr bool qSubOverflow(T v1, T *r)
Definition qnumeric.h:444
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qInf()
constexpr bool qMulOverflow(T v1, T *r)
Definition qnumeric.h:498
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qIsNaN(float f)
constexpr bool qFuzzyIsNull(double d) noexcept
Definition qnumeric.h:627
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:622
constexpr bool qSubOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:439
constexpr bool qAddOverflow(T v1, T *r)
Definition qnumeric.h:434
constexpr std::enable_if< std::is_integral< T >::value, bool >::type qIsNaN(T)
Definition qnumeric.h:70
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:380
constexpr qint64 qRound64(double d)
Definition qnumeric.h:602
constexpr int qRound(float f)
Definition qnumeric.h:597
int qIntCast(float f)
Definition qnumeric.h:653
constexpr int qRound(double d)
Definition qnumeric.h:592
constexpr bool qIsNull(float f) noexcept
Definition qnumeric.h:645
constexpr bool qFuzzyIsNull(float f) noexcept
Definition qnumeric.h:632
constexpr std::enable_if_t< std::is_unsigned_v< T >, bool > qSubOverflow(T v1, T v2, T *r)
Definition qnumeric.h:341
constexpr bool qFuzzyCompare(double p1, double p2) noexcept
Definition qnumeric.h:617
constexpr qint64 qRound64(float f)
Definition qnumeric.h:607
constexpr bool qMulOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:449
QT_WARNING_POP int qIntCast(double f)
Definition qnumeric.h:652
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:276
constexpr bool qAddOverflow(T v1, std::integral_constant< T, V2 >, T *r)
Definition qnumeric.h:429
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:640
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