CNL  2.0.2 (development)
Compositional Numeric Library
bit.h
Go to the documentation of this file.
1 
2 // Copyright John McFarlane 2017.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file ../LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
9 
10 #if !defined(CNL_BIT_H)
11 #define CNL_BIT_H
12 
13 #include "_impl/num_traits/digits.h"
14 #include "_impl/numbers/set_signedness.h"
15 #include "_impl/numbers/signedness.h"
16 
17 #include <limits>
18 
19 namespace cnl {
21  // loosely based on P0553R1
22  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0553r1.html
23 
24  namespace _bit_impl {
25  template<typename T>
26  [[nodiscard]] constexpr auto is_integral_unsigned()
27  {
28  return std::numeric_limits<T>::is_integer && !numbers::signedness<T>::value;
29  }
30 
31  template<typename T>
32  [[nodiscard]] constexpr auto is_integral_signed()
33  {
34  return std::numeric_limits<T>::is_integer && numbers::signedness<T>::value;
35  }
36 
37  template<typename T>
38  [[nodiscard]] constexpr auto rotl(T x, unsigned int s, unsigned int width)
39  {
40  static_assert(is_integral_unsigned<T>(), "T must be unsigned integer");
41 
42  return static_cast<T>((x << (s % width)) | (x >> (width - (s % width))));
43  }
44 
45  template<typename T>
46  [[nodiscard]] constexpr auto rotr(T x, unsigned int s, unsigned int width)
47  {
48  static_assert(is_integral_unsigned<T>(), "T must be unsigned integer");
49 
50  return static_cast<T>((x >> (s % width)) | (x << (width - (s % width))));
51  }
52 
53  template<typename T>
54  [[nodiscard]] constexpr auto countr_zero(T x) -> int
55  {
56  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
57 
58  return (x & 1) ? 0 : countr_zero<T>(static_cast<T>(x >> 1)) + 1;
59  }
60  }
61 
62  // rotl - rotate bits to the left
63  template<typename T>
64  [[nodiscard]] constexpr auto rotl(T x, unsigned int s)
65  {
66  return _bit_impl::rotl(x, s, digits_v<T>);
67  }
68 
69  // rotr - rotate bits to the right
70  template<typename T>
71  [[nodiscard]] constexpr auto rotr(T x, unsigned int s)
72  {
73  return _bit_impl::rotr(x, s, digits_v<T>);
74  }
75 
76  // countl_zero - count 0-bits to the left
77  template<typename T>
78  [[nodiscard]] constexpr auto countl_zero(T x) -> int;
79 
80 #if defined(CNL_GCC_INTRINSICS_ENABLED)
81 
82  template<>
83  [[nodiscard]] constexpr auto countl_zero(unsigned int x) -> int
84  {
85  return x ? __builtin_clz(x) : digits_v<unsigned int>;
86  }
87 
88  template<>
89  [[nodiscard]] constexpr auto countl_zero(unsigned long x) -> int
90  {
91  return x ? __builtin_clzl(x) : digits_v<unsigned long>;
92  }
93 
94  template<>
95  [[nodiscard]] constexpr auto countl_zero(unsigned long long x) -> int
96  {
97  return x ? __builtin_clzll(x) : digits_v<unsigned long long>;
98  }
99 
100 #endif
101 
102  template<typename T>
103  [[nodiscard]] constexpr auto countl_zero(T x) -> int
104  {
105  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
106 
107  return x ? countl_zero<T>(static_cast<T>(x >> 1)) - 1 : digits_v<T>;
108  }
109 
110  // countl_one - count 1-bits to the left
111  template<typename T>
112  [[nodiscard]] constexpr auto countl_one(T x) -> int;
113 
114 #if defined(CNL_GCC_INTRINSICS_ENABLED)
115 
116  template<>
117  [[nodiscard]] constexpr auto countl_one(unsigned int x) -> int
118  {
119  return ~x ? __builtin_clz(~x) : digits_v<unsigned int>;
120  }
121 
122  template<>
123  [[nodiscard]] constexpr auto countl_one(unsigned long x) -> int
124  {
125  return ~x ? __builtin_clzl(~x) : digits_v<unsigned long>;
126  }
127 
128  template<>
129  [[nodiscard]] constexpr auto countl_one(unsigned long long x) -> int
130  {
131  return ~x ? __builtin_clzll(~x) : digits_v<unsigned long long>;
132  }
133 
134 #endif
135 
136  template<typename T>
137  [[nodiscard]] constexpr auto countl_one(T x) -> int
138  {
139  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
140 
141  return (x & (T{1} << (digits_v<T> - 1)))
142  ? countl_one<T>(static_cast<T>(x << 1)) + 1
143  : 0;
144  }
145 
146  // countr_zero - count 0-bits to the right
147  template<typename T>
148  [[nodiscard]] constexpr auto countr_zero(T x);
149 
150 #if defined(CNL_GCC_INTRINSICS_ENABLED) && !defined(__clang__)
151 
152  template<>
153  [[nodiscard]] constexpr auto countr_zero(unsigned int x)
154  {
155  return int{__builtin_ctz(x)};
156  }
157 
158  template<>
159  [[nodiscard]] constexpr auto countr_zero(unsigned long x)
160  {
161  return x ? __builtin_ctzl(x) : digits_v<unsigned long>;
162  }
163 
164  template<>
165  [[nodiscard]] constexpr auto countr_zero(unsigned long long x)
166  {
167  return x ? __builtin_ctzll(x) : digits_v<unsigned long long>;
168  }
169 
170 #endif
171 
172  template<typename T>
173  [[nodiscard]] constexpr auto countr_zero(T x)
174  {
175  return x ? _bit_impl::countr_zero(x) : digits_v<T>;
176  }
177 
178  // countr_one - count 1-bits to the right
179  template<typename T>
180  [[nodiscard]] constexpr auto countr_one(T x) -> int;
181 
182  template<>
183  [[nodiscard]] constexpr auto countr_one(unsigned int x) -> int
184  {
185  return countr_zero(~x);
186  }
187 
188  template<typename T>
189  [[nodiscard]] constexpr auto countr_one(T x) -> int
190  {
191  return (x & T{1}) ? countr_one(x >> 1) + 1 : 0;
192  }
193 
194  // popcount - count total number of 1-bits
195  template<typename T>
196  [[nodiscard]] constexpr auto popcount(T x) -> int;
197 
198 #if defined(CNL_GCC_INTRINSICS_ENABLED)
199 
200  template<>
201  [[nodiscard]] constexpr auto popcount(unsigned int x) -> int
202  {
203  return __builtin_popcount(x);
204  }
205 
206  template<>
207  [[nodiscard]] constexpr auto popcount(unsigned long x) -> int
208  {
209  return __builtin_popcountl(x);
210  }
211 
212  template<>
213  [[nodiscard]] constexpr auto popcount(unsigned long long x) -> int
214  {
215  return __builtin_popcountll(x);
216  }
217 
218 #endif
219 
220  template<typename T>
221  [[nodiscard]] constexpr auto popcount(T x) -> int
222  {
223  return x ? popcount(x & (x - 1)) + 1 : 0;
224  }
225 
227  // loosely based on P0556R1
228  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0556r1.html
229 
230  // ispow2
231  template<class T>
232  [[nodiscard]] constexpr auto ispow2(T x)
233  {
234  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
235 
236  return x && !(x & (x - 1));
237  }
238 
239  // ceil2 - lowest power of 2 no less than x
240  template<class T>
241  [[nodiscard]] constexpr auto ceil2(T x)
242  {
243  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
244 
245  return x ? static_cast<T>(T{1} << (digits_v<T> - countl_zero(T(x - T(1))))) : T{0};
246  }
247 
248  // floor2 - greatest power of 2 no greater than x
249  template<class T>
250  [[nodiscard]] constexpr auto floor2(T x)
251  {
252  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
253 
254  return x ? static_cast<T>(T{1} << (digits_v<T> - 1 - countl_zero(x))) : T{0};
255  }
256 
257  // log2p1 - one plus log2(x)
258  template<class T>
259  [[nodiscard]] constexpr auto log2p1(T x)
260  {
261  static_assert(_bit_impl::is_integral_unsigned<T>(), "T must be unsigned integer");
262 
263  return digits_v<T> - countl_zero(x);
264  }
265 
267  // additional bit-level functions needed by CNL
268 
269  // countl_rsb - count redundant sign bits to the left
270  template<typename T>
271  [[nodiscard]] constexpr auto countl_rsb(T x);
272 
273 #if defined(CNL_GCC_INTRINSICS_ENABLED) && !defined(__clang__)
274 
275  template<>
276  [[nodiscard]] constexpr auto countl_rsb(int x)
277  {
278  return __builtin_clrsb(x);
279  }
280 
281  template<>
282  [[nodiscard]] constexpr auto countl_rsb(long x)
283  {
284  return __builtin_clrsbl(x);
285  }
286 
287  template<>
288  [[nodiscard]] constexpr auto countl_rsb(long long x)
289  {
290  return __builtin_clrsbll(x);
291  }
292 
293 #endif
294 
295  template<typename T>
296  [[nodiscard]] constexpr auto countl_rsb(T x)
297  {
298  static_assert(_bit_impl::is_integral_signed<T>(), "T must be signed integer");
299 
300  using unsigned_type = numbers::set_signedness_t<T, false>;
301 
302  return ((x < 0) ? countl_one(static_cast<unsigned_type>(x))
303  : countl_zero(static_cast<unsigned_type>(x)))
304  - 1;
305  }
306 
307  // countl_rb - count redundant bits to the left
308  namespace _bit_impl {
309  template<bool IsSigned>
310  struct countl_rb {
311  template<class Integer>
312  [[nodiscard]] constexpr auto operator()(Integer const& value) const
313  {
314  static_assert(
315  _bit_impl::is_integral_unsigned<Integer>(), "T must be unsigned integer");
316 
317  return countl_zero(value);
318  }
319  };
320 
321  template<>
322  struct countl_rb<true> {
323  template<class Integer>
324  [[nodiscard]] constexpr auto operator()(Integer const& value) const
325  {
326  static_assert(_bit_impl::is_integral_signed<Integer>(), "T must be signed integer");
327 
328  return countl_rsb(value);
329  }
330  };
331  }
332 
333  template<typename T>
334  [[nodiscard]] constexpr auto countl_rb(T x) // NOLINT(misc-unused-parameters)
335  {
336  return _bit_impl::countl_rb<numbers::signedness<T>::value>()(x);
337  }
338 
339  // countr_used - count total used bits to the right
340  template<typename T>
341  [[nodiscard]] constexpr auto countr_used(T x)
342  {
343  return digits_v<T> - countl_rb(x);
344  }
345 
346 }
347 
348 #endif // CNL_BIT_H
cnl::digits_v
constexpr int digits_v
provide number of binary digits of the given type
Definition: digits.h:31
cnl
compositional numeric library
Definition: abort.h:15
std::numeric_limits