MySQL 8.0.40
Source Code Documentation
bit.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_STDX_BIT_H_
27#define MYSQL_HARNESS_STDX_BIT_H_
28
29#include <climits> // CHAR_BIT
30#include <cstdint> // uint64_t
31#include <limits> // numeric_limits
32#include <type_traits> // enable_if, is_unsigned
33
34namespace stdx {
35
36// implementation 'byteswap()' and 'bitops' from std c++20
37//
38// see:
39// - http://wg21.link/P1272
40// - http://wg21.link/P0553
41
42// bswap() functions translate into
43//
44// - `bswap` on x86 with
45// - clang -O1 since 3.5
46// - gcc -O2 since 5.1
47// - msvc /O1 for all but 8-byte. _byteswap_uint64() exists, but isn't
48// constexpr
49// - `rev` on armv6 and later with -O1
50// - clang
51// - gcc
52// - msvc /O1 for 4 byte
53
54namespace impl {
55// two implementations are provided:
56//
57// 1. std::enable_if_t<> preselects valid int-sizes for impl::bswap() which
58// selects impl::bswap_N() with an 'if'
59// 2. impl::bswap() is automatically selected with std::if_enable_t<>
60//
61// implementation for
62//
63// - gcc [
64// 2 byte: 1x rol
65// 4 byte: 1x bswap
66// 8 byte: 1x bswap
67// ]
68// - clang [
69// 2 byte: 1x rol
70// 4 byte: 1x bswap
71// 8 byte: 1x bswap
72// ]
73// - msvc [
74// 2 byte: 1x rol
75// 4 byte: 1x bswap
76// 8 byte: lots of shifts, or and ands
77// ]
78//
79// the GCC/Clang variant can use __builtin_bswap*() which translates to
80// the right asm instructions on all platforms and optimization levels.
81//
82// The fallback variant with shift-or only gets translated to BSWAP
83// on higher optimization levels.
84//
85// MSVC provides _byteswap_uint64() and friends as instrincts, but they aren't
86// marked as constexpr.
87//
88template <class T>
89constexpr std::enable_if_t<sizeof(T) == 1, T> bswap(T t) noexcept {
90 return t;
91}
92
93template <class T>
94constexpr std::enable_if_t<sizeof(T) == 2, T> bswap(T t) noexcept {
95#if defined(__GNUC__)
96 return __builtin_bswap16(t);
97#else
98 return (t & UINT16_C(0x00ff)) << (1 * 8) | (t & UINT16_C(0xff00)) >> (1 * 8);
99#endif
100}
101
102// for all types that are 4 byte long
103//
104// unsigned long and unsigned int are both 4 byte on windows, but different
105// types
106template <class T>
107constexpr std::enable_if_t<sizeof(T) == 4, T> bswap(T t) noexcept {
108#if defined(__GNUC__)
109 return __builtin_bswap32(t);
110#else
111 return (t & UINT32_C(0x0000'00ff)) << (3 * 8) |
112 (t & UINT32_C(0x0000'ff00)) << (1 * 8) |
113 (t & UINT32_C(0x00ff'0000)) >> (1 * 8) |
114 (t & UINT32_C(0xff00'0000)) >> (3 * 8);
115#endif
116}
117
118// for all types that are 8 byte long
119//
120// unsigned long and unsigned long long are both 8 byte on unixes, but different
121// types
122template <class T>
123constexpr std::enable_if_t<sizeof(T) == 8, T> bswap(T t) noexcept {
124#if defined(__GNUC__)
125 return __builtin_bswap64(t);
126#else
127 return (t & UINT64_C(0x0000'0000'0000'00ff)) << (7 * 8) |
128 (t & UINT64_C(0x0000'0000'0000'ff00)) << (5 * 8) |
129 (t & UINT64_C(0x0000'0000'00ff'0000)) << (3 * 8) |
130 (t & UINT64_C(0x0000'0000'ff00'0000)) << (1 * 8) |
131 (t & UINT64_C(0x0000'00ff'0000'0000)) >> (1 * 8) |
132 (t & UINT64_C(0x0000'ff00'0000'0000)) >> (3 * 8) |
133 (t & UINT64_C(0x00ff'0000'0000'0000)) >> (5 * 8) |
134 (t & UINT64_C(0xff00'0000'0000'0000)) >> (7 * 8);
135#endif
136}
137
138} // namespace impl
139
140template <class IntegerType>
141std::enable_if_t<std::is_integral<IntegerType>::value,
142 IntegerType> constexpr byteswap(IntegerType t) noexcept {
143 return impl::bswap(static_cast<std::make_unsigned_t<IntegerType>>(t));
144}
145
146// [bitops.ret]
147template <class T>
148constexpr std::enable_if_t<std::is_unsigned<T>::value, T> rotl(T x,
149 int s) noexcept {
151 auto r = s % N;
152
153 if (0 == r) return x;
154
155 return r > 0 ? ((x << r) | x >> (N - r)) : rotr(x, -r);
156}
157
158template <class T>
159constexpr std::enable_if_t<std::is_unsigned<T>::value, T> rotr(T x,
160 int s) noexcept {
162 auto r = s % N;
163
164 if (0 == r) return x;
165
166 return r > 0 ? ((x >> r) | x << (N - r)) : rotl(x, -r);
167}
168
169namespace impl {
170template <class T>
171inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int>
172countl_zero_linear(T x) noexcept {
173 // O(N) N = digits
174 //
176
177 if (x == 0) return N;
178
179 int r{};
180 for (; x != 0; ++r) {
181 x >>= 1;
182 }
183
184 return N - r;
185}
186
187template <class T>
188inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int>
190 // O(log(N)) N = digits
191 //
192 // x = 0b0000'0100
193 // mask[0] = 0b1111'1111
194 // shiftr[0] = 1 * 4
195 // r = 0
196 //
197 // -- for-loop 1st round
198 // mask[1] = 0b1111'0000
199 // x[1] = 0b0100'0000
200 // r[1] = 4
201 // shiftr = 2
202 // -- for-loop 2nd round
203 // mask[2] = 0b1100'0000
204 // x[2] = 0b0100'0000
205 // r[2] = 4
206 // shiftr = 1
207 // -- for-loop 3rd round
208 // mask[3] = 0b1000'0000
209 // x[3] = 0b1000'0000
210 // r[3] = 5
211 // shiftr = 0
213
214 if (x == 0) return N;
215
216 int r{};
217 T mask = ~static_cast<T>(0); // all bits
218 int shiftr = sizeof(T) * 4; // (sizeof(T) * 8) / 2
219
220 for (; shiftr; shiftr >>= 1) {
221 mask = mask << shiftr;
222 if ((x & mask) == 0) {
223 x <<= shiftr;
224 r += shiftr;
225 }
226 }
227
228 return r;
229}
230
231template <class T>
232inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int>
233countl_zero_builtin(T x) noexcept {
234#if defined(__GNUC__) || defined(__clang__)
235 // __builtin_clz is undefined for x == 0
236 if (x == 0) return std::numeric_limits<T>::digits;
237
238 // pick the right builtin for the type
239 if (sizeof(T) == sizeof(unsigned long long)) {
240 return __builtin_clzll(x);
241 } else if (sizeof(T) == sizeof(unsigned long)) {
242 return __builtin_clzl(x);
243 } else if (sizeof(T) == sizeof(unsigned int)) {
244 return __builtin_clz(x);
245 }
246 // fallthrough for uint8_t and uint16_t
247#endif
248
250}
251
252template <class T>
253inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int>
254countr_zero_linear(T x) noexcept {
255 // O(N) N = digits
256 //
257 // x[0] = 0b0001'1000
258 // x[1] = 0b0011'0000
259 // x[2] = 0b0110'0000
260 // x[3] = 0b1100'0000
261 // x[4] = 0b1000'0000
262 // x[5] = 0b0000'0000 -> 8 - 5 = 3
263 //
265
266 if (x == 0) return N;
267
268 int r{};
269 for (; x != 0; ++r) {
270 x <<= 1;
271 }
272
273 return N - r;
274}
275
276template <class T>
277inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int>
280
281 // simple case
282 if (x == 0) return N;
283
284 // O(log(N))
285 //
286 // x = 0b0010'0000
287 // mask[0] = 0b1111'1111
288 // shiftr[0] = 1 * 4
289 // r = 0
290 //
291 // -- for-loop 1st round
292 // mask[1] = 0b0000'1111
293 // x[1] = 0b0000'0010
294 // r[1] = 4
295 // shiftr = 2
296 // -- for-loop 2nd round
297 // mask[2] = 0b0000'0011
298 // x[2] = 0b0000'0010
299 // r[2] = 4
300 // shiftr = 1
301 // -- for-loop 3rd round
302 // mask[3] = 0b0000'0001
303 // x[3] = 0b0000'0001
304 // r[3] = 5
305 // shiftr = 0
306 T mask = ~static_cast<T>(0); // all bits
307 int shiftr = sizeof(T) * 4; // (sizeof(T) * 8) / 2
308
309 int r{};
310 for (; shiftr; shiftr >>= 1) {
311 mask = mask >> shiftr;
312 if ((x & mask) == 0) {
313 x >>= shiftr;
314 r += shiftr;
315 }
316 }
317
318 return r;
319}
320
321template <class T>
322inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int>
323countr_zero_builtin(T x) noexcept {
325
326 // simple case, and __builtin_ctz() is undefined for x == 0
327 if (x == 0) return N;
328#if defined(__GNUC__) || defined(__clang__)
329 if (sizeof(T) == sizeof(unsigned long long)) {
330 return __builtin_ctzll(x);
331 } else if (sizeof(T) == sizeof(unsigned long)) {
332 return __builtin_ctzl(x);
333 } else if (sizeof(T) == sizeof(unsigned int)) {
334 return __builtin_ctz(x);
335 }
336#endif
337
339}
340
341#if 0
342// only for reference.
343
344/**
345 * popcount.
346 *
347 * O(N), naive version.
348 */
349template <class T>
350constexpr std::enable_if_t<std::is_unsigned<T>::value, int> popcount_linear(
351 T v) noexcept {
352 int cnt{};
353 for (; v; v >>= 1) {
354 cnt += v & 1;
355 }
356 return cnt;
357}
358
359/**
360 * popcount.
361 *
362 * O(N), K&R version
363 */
364template <class T>
365constexpr std::enable_if_t<std::is_unsigned<T>::value, int> popcount_linear_kr(
366 T v) noexcept {
367 // K&R version of popcount
368 int cnt{};
369 for (; v; ++cnt) {
370 v &= v - 1;
371 }
372 return cnt;
373}
374#endif
375
376/**
377 * popcount.
378 *
379 * O(1) version, as fast as builtin popcount
380 */
381template <class T>
382constexpr std::enable_if_t<std::is_unsigned<T>::value, int> popcount_constant(
383 T v) noexcept {
384 // non-looping, parallel version
385 //
386 // see: https://www.chessprogramming.org/Population_Count#SWAR-Popcount
387 // see: Knuth Art of Computer Programming: Vol 4, Fascicle 1: Bitwise tricks
388 static_assert(sizeof(T) <= 16,
389 "implementation of popcount works for up to 128 bit only");
390
391 // p-adic numbers
392 const T bit_pattern_all = ~(static_cast<T>(0));
393 const T bit_pattern_5555 = bit_pattern_all / 3;
394 const T bit_pattern_3333 = bit_pattern_all / 0x0f * 3;
395 const T bit_pattern_0f0f = bit_pattern_all / 0xff * 0x0f;
396 const T bit_pattern_0101 = bit_pattern_all / 0xff;
397
398 v = v - ((v >> 1) & bit_pattern_5555);
399 v = (v & bit_pattern_3333) + ((v >> 2) & bit_pattern_3333);
400 v = (v + (v >> 4)) & bit_pattern_0f0f;
401 return static_cast<T>(v * bit_pattern_0101) >> (sizeof(T) - 1) * CHAR_BIT;
402}
403
404/*
405 * Other links for faster popcounts:
406 *
407 * - http://0x80.pl/articles/index.html#population-count
408 * - https://news.ycombinator.com/item?id=11277891
409 */
410
411/**
412 * popcount.
413 *
414 * uses builtin's if available, falls back to popcount_constant() if not
415 * available.
416 */
417template <class T>
418constexpr std::enable_if_t<std::is_unsigned<T>::value, int> popcount_builtin(
419 T v) noexcept {
420#if defined(__clang__) || defined(__GNUC__)
421 if (sizeof(T) == sizeof(unsigned long long)) {
422 return __builtin_popcountll(v);
423 } else if (sizeof(T) == sizeof(unsigned long)) {
424 return __builtin_popcountl(v);
425 } else {
426 return __builtin_popcount(v);
427 }
428#endif
429
430 return popcount_constant(v);
431}
432} // namespace impl
433
434template <class T>
435constexpr std::enable_if_t<std::is_unsigned<T>::value, int> popcount(
436 T v) noexcept {
437 return impl::popcount_builtin(v);
438}
439
440/**
441 * consecutive 0-bits starting from MSB.
442 *
443 * 0b0000'0000 = 8
444 * 0b0000'0001 = 7
445 * 0b0000'1110 = 4
446 */
447template <class T>
448inline constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countl_zero(
449 T x) noexcept {
450#if (defined(__clang_major__) && (__clang_major__ >= 9))
451 // clang-9 can translate the linear bitshift version to the right
452 // __builtin_clz*() itself in all optimization levels
453 return impl::countl_zero_linear(x);
454#else
456#endif
457}
458
459/**
460 * consecutive 0-bits starting from LSB (right).
461 */
462template <class T>
463constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countr_zero(
464 T x) noexcept {
465#if (defined(__clang_major__) && (__clang_major__ >= 9))
466 // clang-9 can translate the linear bitshift version to the right
467 // __builtin_clz*() itself in all optimization levels
468 return impl::countr_zero_linear(x);
469#else
471#endif
472} // namespace stdx
473
474/**
475 * consecutive 1-bits starting from LSB (right).
476 */
477template <class T>
478constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countr_one(
479 T x) noexcept {
480 // countr_one(0b0000'0011) == 2
481 // countr_zero(0b1111'1100) == 2
482 return countr_zero(static_cast<T>(~x));
483}
484
485/**
486 * consecutive 1-bits starting from LSB (right).
487 */
488template <class T>
489constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countl_one(
490 T x) noexcept {
491 // countl_one(0b0000'0011) == 6
492 // countl_zero(0b1111'1100) == 6
493 return countl_zero(static_cast<T>(~x));
494}
495
496} // namespace stdx
497#endif
static mi_bit_type mask[]
Definition: mi_packrec.cc:141
std::atomic< Type > N
Definition: ut0counter.h:225
Definition: authentication.cc:36
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countr_zero_linear(T x) noexcept
Definition: bit.h:254
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countl_zero_logarithmic(T x) noexcept
Definition: bit.h:189
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countl_zero_linear(T x) noexcept
Definition: bit.h:172
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > popcount_constant(T v) noexcept
popcount.
Definition: bit.h:382
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > popcount_builtin(T v) noexcept
popcount.
Definition: bit.h:418
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countr_zero_builtin(T x) noexcept
Definition: bit.h:323
constexpr std::enable_if_t< sizeof(T)==1, T > bswap(T t) noexcept
Definition: bit.h:89
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countl_zero_builtin(T x) noexcept
Definition: bit.h:233
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countr_zero_logarithmic(T x) noexcept
Definition: bit.h:278
Definition: bit.h:34
constexpr std::enable_if_t< std::is_unsigned< T >::value, T > rotr(T x, int s) noexcept
Definition: bit.h:159
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countr_zero(T x) noexcept
consecutive 0-bits starting from LSB (right).
Definition: bit.h:463
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countr_one(T x) noexcept
consecutive 1-bits starting from LSB (right).
Definition: bit.h:478
constexpr std::enable_if_t< std::is_unsigned< T >::value, T > rotl(T x, int s) noexcept
Definition: bit.h:148
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countl_one(T x) noexcept
consecutive 1-bits starting from LSB (right).
Definition: bit.h:489
constexpr std::enable_if_t< std::is_integral< IntegerType >::value, IntegerType > byteswap(IntegerType t) noexcept
Definition: bit.h:142
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > countl_zero(T x) noexcept
consecutive 0-bits starting from MSB.
Definition: bit.h:448
constexpr std::enable_if_t< std::is_unsigned< T >::value, int > popcount(T v) noexcept
Definition: bit.h:435
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
static const char digits[]
Definition: stacktrace.cc:598