Turi Create  4.0
bitops.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_BITOPS_H
7 #define TURI_BITOPS_H
8 
10 #include <cmath>
11 #include <type_traits>
12 #include <climits>
13 #include <core/util/code_optimization.hpp>
14 // #include <bitset>
15 // #include <iostream>
16 
17 #define bitsizeof(t) (8*sizeof(t))
18 
19 namespace turi {
20 
21 #define _ENABLE_IF_UINT(T) \
22  typename std::enable_if<std::is_same<T, uint8_t>::value \
23  || std::is_same<T, uint16_t>::value \
24  || std::is_same<T, uint32_t>::value \
25  || std::is_same<T, uint64_t>::value \
26  || std::is_same<T, unsigned int>::value \
27  || std::is_same<T, unsigned long>::value \
28  || std::is_same<T, unsigned long long>::value \
29  || std::is_same<T, uint128_t>::value>::type* = 0
30 
31 ////////////////////////////////////////////////////////////
32 // For helping with some of the templating later on
33 template <typename T>
34 bool static constexpr __bitsize_gt(unsigned n) {
35  return n < bitsizeof(T);
36 }
37 
38 #define _ENABLE_IF_BITSIZE_GT(T, n) \
39  typename std::enable_if<__bitsize_gt<T>(n)>::type* = 0
40 
41 #define _ENABLE_IF_BITSIZE_LEQ(T, n) \
42  typename std::enable_if<!__bitsize_gt<T>(n)>::type* = 0
43 
44 ////////////////////////////////////////////////////////////
45 
46 /**
47  * Tests if x is a power of 2 (i.e. if just one bit is on).
48  *
49  * \param x Unsigned integer to test.
50  */
51 template <typename T>
52 static inline bool is_power_of_2(const T& x, _ENABLE_IF_UINT(T)) {
53  return ( ! ((x) & ((x) - 1) ) );
54 }
55 
56 /**
57  * Returns true if a bit is on. Other bits are ignored.
58  *
59  * \param x Unsigned integer to test.
60  * \param bit Index of the bit to test.
61  */
62 template <typename T>
63 static inline bool bit_on(T x, unsigned int bit, _ENABLE_IF_UINT(T)) {
64  return !!(x & (T(1) << bit));
65 }
66 
67 
68 /**
69  * Returns true if a bit is off. Other bits are ignored.
70  *
71  * \param x Unsigned integer to test.
72  * \param bit Index of the bit to test.
73  */
74 template <typename T>
75 static inline bool bit_off(T x, unsigned int bit, _ENABLE_IF_UINT(T))
76 {
77  return (x & (T(1) << bit) ) == 0;
78 }
79 
80 /**
81  * Sets a bit to be off.
82  *
83  * \param x Reference to unsigned integer to change.
84  * \param bit Index of the bit to set off.
85  */
86 template <typename T>
87 static inline void set_bit_off(T& x, unsigned int bit, _ENABLE_IF_UINT(T))
88 {
89  x &= (~((T(1) << bit)));
90 }
91 
92 /**
93  * Sets a bit to be on.
94  *
95  * \param x Reference to unsigned integer to change.
96  * \param bit Index of the bit to set on.
97  */
98 template <typename T>
99 static inline void set_bit_on(T& x, unsigned int bit, _ENABLE_IF_UINT(T))
100 {
101  x |= (T(1) << bit);
102 }
103 
104 /**
105  * Flips a bit.
106  *
107  * \param x Reference to unsigned integer to change.
108  * \param bit Index of the bit to flip.
109  */
110 template <typename T>
111 static inline void flip_bit(T& x, unsigned int bit, _ENABLE_IF_UINT(T))
112 {
113  x ^= (T(1) << bit);
114 }
115 
116 /**
117  * Returns a bitwise mask of the first n_bits customised to type T.
118  * For example, bit_bask<uint16_t>(5) & (000101011101011101 b) returns
119  * 11101 b.
120  *
121  * \tparam T Type of the mask to be created.
122  * \param n_bits Index of the bit to flip.
123  */
124 template <typename T>
125 static inline T bit_mask(unsigned int n_bits, _ENABLE_IF_UINT(T)) {
126 
127  static constexpr unsigned int _n_mask = ~static_cast<unsigned int>(bitsizeof(T) - 1);
128 
129  return UNLIKELY(n_bits & _n_mask) ? T(-1) : (T(1) << n_bits) - 1;
130 }
131 
132 /**
133  * Returns a bitwise mask of a segment of bits, [index_begin, index_end).
134  *
135  * \tparam T Type of the mask to be created.
136  * \param index_begin Start of interval.
137  * \param index_end End of interval.
138  */
139 template <typename T>
140 static inline T bit_mask(size_t index_begin, unsigned int index_end, _ENABLE_IF_UINT(T)) {
141  return bit_mask<T>(index_begin) ^ bit_mask<T>(index_end);
142 }
143 
144 #ifdef __clang__
145 #pragma clang diagnostic push
146 #pragma clang diagnostic ignored "-Wshift-count-overflow"
147 #endif
148 /**
149  * Counts the number of bits on in x.
150  *
151  * \param v Unsigned integer.
152  */
153 template <typename T>
154 static inline unsigned int num_bits_on(T v, _ENABLE_IF_UINT(T))
155 {
156  if(sizeof(unsigned int) >= sizeof(T))
157  return __builtin_popcount((unsigned int)v);
158  else if(sizeof(unsigned long) >= sizeof(T))
159  return __builtin_popcountl((unsigned long)v);
160  else if(sizeof(unsigned long long) >= sizeof(T))
161  return __builtin_popcountll((unsigned long long)v);
162  else if(bitsizeof(unsigned long long) == 64 && bitsizeof(T) == 128)
163  // This errors with error: shift count >= width of type [-Werror,-Wshift-count-overflow]
164  // but, at runtime, we've already checked for that in the else if condition.
165  return (__builtin_popcountll((unsigned long long)(v))
166  + __builtin_popcountll((unsigned long long)(uint64_t(uint128_t(v) >> 64))));
167  else {
168  unsigned int bitcount = 0;
169  T vt = v;
170  for(size_t i = 0; i < bitsizeof(T); i += bitsizeof(unsigned long long) ) {
171  bitcount += __builtin_popcountll( (unsigned long long)(vt) );
172  vt = T(uint128_t(vt) >> bitsizeof(unsigned long long));
173  }
174 
175  return bitcount;
176  }
177 }
178 
179 #ifdef __clang__
180 #pragma clang diagnostic pop
181 #endif
182 template <int n, typename T>
183 static inline void __n_trailing_zeros_disect(
184  T& v, int& c, _ENABLE_IF_BITSIZE_GT(T, n)) {
185 
186  if( T(v << (bitsizeof(T) - n)) == 0) {
187  v >>= n;
188  c += n;
189  }
190 }
191 
192 template <int n, typename T>
193 static inline void __n_trailing_zeros_disect(
194  T& v, int& c, _ENABLE_IF_BITSIZE_LEQ(T, n)) {
195 }
196 
197 /**
198  * Counts the number of trailing zeros in v. For example,
199  * 010111011000 has 3 trailing zeros. Returns bitsizeof(T) if v is
200  * zero.
201  *
202  * \tparam T type of v.
203  * \param v Unsigned integer.
204  */
205 template <typename T>
206 static inline unsigned int n_trailing_zeros(T v, _ENABLE_IF_UINT(T)) {
207  if(!v) return bitsizeof(T);
208 
209  if(sizeof(unsigned int) >= sizeof(T))
210  return __builtin_ctz((unsigned int)v);
211  else if(sizeof(unsigned long) >= sizeof(T))
212  return __builtin_ctzl((unsigned long)v);
213  else if(sizeof(unsigned long long) >= sizeof(T))
214  return __builtin_ctzll((unsigned long long)v);
215  else if(bitsizeof(unsigned long long) == 64 && bitsizeof(T) == 128)
216  return ((uint64_t(v) != 0)
217  ? __builtin_ctzll((unsigned long long)v)
218  : (64 + __builtin_ctzll((unsigned long long)(uint128_t(v) >> 64))));
219  else
220  {
221 
222  int c = 1; // c will be the number of zero bits on the right,
223  // so if v is 1101000 (base 2), then c will be 3
224 
225  __n_trailing_zeros_disect<128>(v, c);
226  __n_trailing_zeros_disect<64>(v, c);
227  __n_trailing_zeros_disect<32>(v, c);
228  __n_trailing_zeros_disect<16>(v, c);
229  __n_trailing_zeros_disect<8>(v, c);
230  __n_trailing_zeros_disect<4>(v, c);
231  __n_trailing_zeros_disect<2>(v, c);
232  __n_trailing_zeros_disect<1>(v, c);
233 
234  c -= (v & 0x1);
235  return c;
236  }
237 }
238 
239 /**
240  * Counts the number of trailing ones in v. For example,
241  * 010111010111 has 3 trailing ones. Returns bitsizeof(T) if v is
242  * (~0).
243  *
244  * \tparam T type of v.
245  * \param v Unsigned integer.
246  */
247 template <typename T>
248 static inline unsigned int n_trailing_ones(const T& v, _ENABLE_IF_UINT(T)) {
249  return n_trailing_zeros(T(~v));
250 }
251 
252 /**
253  * Returns the index of the first on bit in v. For example,
254  * 010111011000 gives 3. Returns bitsizeof(T) if v is zero.
255  *
256  * \tparam T type of v.
257  * \param v Unsigned integer.
258  */
259 template <typename T>
260 static inline unsigned int index_first_on_bit(const T& v, _ENABLE_IF_UINT(T)) {
261  return n_trailing_zeros(v);
262 }
263 
264 
265 ////////////////////////////////////////////////////////////
266 
267 template <int n, typename T>
268 static inline void __n_leading_zeros_disect(T& v, int& c, _ENABLE_IF_BITSIZE_GT(T, n)) {
269  if((v >> (bitsizeof(T) - n)) == 0) {
270  v <<= n; c += n;
271  }
272 }
273 
274 template <int n, typename T>
275 static inline void __n_leading_zeros_disect(T& v, int& c, _ENABLE_IF_BITSIZE_LEQ(T, n))
276 {}
277 
278 
279 /**
280  * Counts the number of leading zeros in v. For example, 01011000 has
281  * 1 leading zero. Returns bitsizeof(T) if v is zero.
282  *
283  * \tparam T type of v.
284  * \param v Unsigned integer value.
285  */
286 template <typename T>
287 static inline unsigned int n_leading_zeros(T v, _ENABLE_IF_UINT(T)) {
288 
289  if(!v) return bitsizeof(T);
290 
291 
292  if(sizeof(unsigned int) >= sizeof(T))
293  return __builtin_clz((unsigned int)v) - (bitsizeof(unsigned int) - bitsizeof(T));
294  else if(sizeof(unsigned long) >= sizeof(T))
295  return __builtin_clzl((unsigned long)v) - (bitsizeof(unsigned long) - bitsizeof(T));
296  else if(sizeof(unsigned long long) >= sizeof(T))
297  return __builtin_clzll((unsigned long long)v) - (bitsizeof(unsigned long long) - bitsizeof(T));
298  else if(bitsizeof(unsigned long long) == 64 && bitsizeof(v) == 128)
299  return (((uint128_t(v) >> 64) != 0)
300  ? __builtin_clzll((unsigned long long)(uint128_t(v) >> 64))
301  : (64 + __builtin_clzll((unsigned long long)(v))));
302  else
303  {
304  int c = 0;
305  // c will be the number of zero bits on the right,
306  // so if v is 1101000 (base 2), then c will be 3
307 
308  __n_leading_zeros_disect<128>(v, c);
309  __n_leading_zeros_disect<64>(v, c);
310  __n_leading_zeros_disect<32>(v, c);
311  __n_leading_zeros_disect<16>(v, c);
312  __n_leading_zeros_disect<8>(v, c);
313  __n_leading_zeros_disect<4>(v, c);
314  __n_leading_zeros_disect<2>(v, c);
315  __n_leading_zeros_disect<1>(v, c);
316 
317  // c += !(v >> (bitsizeof(T) - 1));
318 
319  return c;
320  }
321 }
322 
323 /**
324  * Counts the number of leading ones in v. For example, 11011000 has
325  * 2 leading ones. Returns bitsizeof(T) if v is (~0).
326  *
327  * \tparam T type of v.
328  * \param v Unsigned integer value.
329  */
330 template <typename T>
331 static inline unsigned int n_leading_ones(T v, _ENABLE_IF_UINT(T)) {
332  return n_leading_zeros(T(~v));
333 }
334 
335 
336 /**
337  * Index of the last on bit. For example, 01101100 is 6. Returns bitsizeof(T) if v is zero.
338  *
339  * \tparam T Type of v.
340  * \param v Unsigned integer value.
341  */
342 template <typename T>
343 static inline unsigned int index_last_on_bit(const T& v, _ENABLE_IF_UINT(T)) {
344  return bitsizeof(T) - (( (!v) - 1) & (1 + n_leading_zeros(v)));
345 }
346 
347 /**
348  * Returns the rounded up version of the bitwise log base two of the
349  * number. For example, 00010000 returns 4, and 00010001 returns 5.
350  * If v is zero, zero is returned.
351  *
352  * \tparam T Type of v.
353  * \param v Unsigned integer value.
354  */
355 template <typename T>
356 static inline unsigned int bitwise_log2_ceil(const T& v, _ENABLE_IF_UINT(T)) {
357  return ( (!v) - 1) & (index_last_on_bit(v) + !is_power_of_2(v));
358 }
359 
360 /**
361  * Returns the rounded down version of the bitwise log base two of the
362  * number. For example, 00010000 returns 4, 00011111 returns 4, and
363  * 00100000 returns 5. If v is zero, zero is returned.
364  *
365  * \tparam T Type of v.
366  * \param v Unsigned integer value.
367  */
368 template <typename T>
369 static inline unsigned int bitwise_log2_floor(const T& v, _ENABLE_IF_UINT(T)) {
370  return ((!v) - 1) & (index_last_on_bit(v));
371 }
372 
373 /**
374  * Returns the modulus of v rounded to the pow2_idx bit. It is the
375  * same as v % (2 ** pow2_idx). For example, bitwise_pow2_mod(10, 3)
376  * = 10 % 8 = 2.
377  *
378  * \tparam T Type of v.
379  * \param v Unsigned integer value.
380  * \param pow2_idx Power of 2 with which to take the mod.
381  */
382 template <typename T>
383 static inline T bitwise_pow2_mod(const T& v, unsigned pow2_idx, _ENABLE_IF_UINT(T)) {
384  return (!! pow2_idx) * bit_mask<T>(pow2_idx) & v;
385 }
386 
387 /**
388  * Returns true if the first n bits of v are on.
389  *
390  * \tparam T Type of v.
391  * \param v Unsigned integer value.
392  */
393 template <typename T>
394 static inline bool first_n_bits_on(const T& v, unsigned int top_bit, _ENABLE_IF_UINT(T)) {
395  return (v & bit_mask<T>(top_bit)) == bit_mask<T>(top_bit);
396 }
397 
398 };
399 
400 #endif
static unsigned int n_trailing_zeros(T v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:206
static T bitwise_pow2_mod(const T &v, unsigned pow2_idx, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:383
static unsigned int n_leading_zeros(T v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:287
static unsigned int num_bits_on(T v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:154
static unsigned int n_trailing_ones(const T &v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:248
static unsigned int bitwise_log2_floor(const T &v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:369
static bool bit_on(T x, unsigned int bit, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:63
static bool is_power_of_2(const T &x, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:52
static unsigned int index_last_on_bit(const T &v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:343
static void flip_bit(T &x, unsigned int bit, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:111
static T bit_mask(unsigned int n_bits, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:125
static void set_bit_on(T &x, unsigned int bit, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:99
static unsigned int n_leading_ones(T v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:331
static bool first_n_bits_on(const T &v, unsigned int top_bit, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:394
static unsigned int bitwise_log2_ceil(const T &v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:356
static void set_bit_off(T &x, unsigned int bit, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:87
static unsigned int index_first_on_bit(const T &v, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:260
static bool bit_off(T x, unsigned int bit, _ENABLE_IF_UINT(T))
Definition: bitops.hpp:75