openat: don’t close (-1)
[gnulib.git] / lib / count-leading-zeros.h
bloba4b68c210645361d0e478768e04816334d374b5a
1 /* count-leading-zeros.h -- counts the number of leading 0 bits in a word.
2 Copyright (C) 2012-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Eric Blake. */
19 #ifndef COUNT_LEADING_ZEROS_H
20 #define COUNT_LEADING_ZEROS_H 1
22 /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */
23 #if !_GL_CONFIG_H_INCLUDED
24 #error "Please include config.h first."
25 #endif
27 #include <limits.h>
28 #include <stdlib.h>
30 _GL_INLINE_HEADER_BEGIN
31 #ifndef COUNT_LEADING_ZEROS_INLINE
32 # define COUNT_LEADING_ZEROS_INLINE _GL_INLINE
33 #endif
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
39 /* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN,
40 expand to code that computes the number of leading zeros of the local
41 variable 'x' of type TYPE (an unsigned integer type) and return it
42 from the current function. */
43 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \
44 || (__clang_major__ >= 4)
45 # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
46 return x ? BUILTIN (x) : CHAR_BIT * sizeof x;
47 #elif _MSC_VER
48 extern unsigned char _BitScanReverse (unsigned long *, unsigned long);
49 # pragma intrinsic (_BitScanReverse)
50 # if defined _M_X64
51 extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long);
52 # pragma intrinsic (_BitScanReverse64)
53 # endif
54 # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
55 do \
56 { \
57 unsigned long result; \
58 if (MSC_BUILTIN (&result, x)) \
59 return CHAR_BIT * sizeof x - 1 - result; \
60 return CHAR_BIT * sizeof x; \
61 } \
62 while (0)
63 #else
64 # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
65 do \
66 { \
67 int count; \
68 unsigned int leading_32; \
69 if (! x) \
70 return CHAR_BIT * sizeof x; \
71 for (count = 0; \
72 (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32)) \
73 & 0xffffffffU), \
74 count < CHAR_BIT * sizeof x - 32 && !leading_32); \
75 count += 32) \
76 x = x << 31 << 1; \
77 return count + count_leading_zeros_32 (leading_32); \
78 } \
79 while (0)
81 /* Compute and return the number of leading zeros in X,
82 where 0 < X < 2**32. */
83 COUNT_LEADING_ZEROS_INLINE int
84 count_leading_zeros_32 (unsigned int x)
86 /* <https://github.com/gibsjose/BitHacks>
87 <https://www.fit.vutbr.cz/~ibarina/pub/bithacks.pdf> */
88 static const char de_Bruijn_lookup[32] = {
89 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
90 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
93 x |= x >> 1;
94 x |= x >> 2;
95 x |= x >> 4;
96 x |= x >> 8;
97 x |= x >> 16;
98 return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27];
100 #endif
102 /* Compute and return the number of leading zeros in X. */
103 COUNT_LEADING_ZEROS_INLINE int
104 count_leading_zeros (unsigned int x)
106 COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int);
109 /* Compute and return the number of leading zeros in X. */
110 COUNT_LEADING_ZEROS_INLINE int
111 count_leading_zeros_l (unsigned long int x)
113 COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int);
116 /* Compute and return the number of leading zeros in X. */
117 COUNT_LEADING_ZEROS_INLINE int
118 count_leading_zeros_ll (unsigned long long int x)
120 #if (defined _MSC_VER && !defined __clang__) && !defined _M_X64
121 /* 32-bit MSVC does not have _BitScanReverse64, only _BitScanReverse. */
122 unsigned long result;
123 if (_BitScanReverse (&result, (unsigned long) (x >> 32)))
124 return CHAR_BIT * sizeof x - 1 - 32 - result;
125 if (_BitScanReverse (&result, (unsigned long) x))
126 return CHAR_BIT * sizeof x - 1 - result;
127 return CHAR_BIT * sizeof x;
128 #else
129 COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64,
130 unsigned long long int);
131 #endif
134 #ifdef __cplusplus
136 #endif
138 _GL_INLINE_HEADER_END
140 #endif /* COUNT_LEADING_ZEROS_H */