Use gcc builtins instead of library functions for ffs*
[folly.git] / folly / Bits.h
1 /*
2  * Copyright 2012 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * Various low-level, bit-manipulation routines.
19  *
20  * findFirstSet(x)
21  *    find first (least significant) bit set in a value of an integral type,
22  *    1-based (like ffs()).  0 = no bits are set (x == 0)
23  *
24  * findLastSet(x)
25  *    find last (most significant) bit set in a value of an integral type,
26  *    1-based.  0 = no bits are set (x == 0)
27  *    for x != 0, findLastSet(x) == 1 + floor(log2(x))
28  *
29  * popcount(x)
30  *    return the number of 1 bits in x
31  *
32  * nextPowTwo(x)
33  *    Finds the next power of two >= x.
34  *
35  * Endian
36  *    convert between native, big, and little endian representation
37  *    Endian::big(x)      big <-> native
38  *    Endian::little(x)   little <-> native
39  *    Endian::swap(x)     big <-> little
40  *
41  * BitIterator
42  *    Wrapper around an iterator over an integral type that iterates
43  *    over its underlying bits in MSb to LSb order
44  *
45  * findFirstSet(BitIterator begin, BitIterator end)
46  *    return a BitIterator pointing to the first 1 bit in [begin, end), or
47  *    end if all bits in [begin, end) are 0
48  *
49  * @author Tudor Bosman (tudorb@fb.com)
50  */
51
52 #ifndef FOLLY_BITS_H_
53 #define FOLLY_BITS_H_
54
55 #include "folly/Portability.h"
56
57 #ifndef _GNU_SOURCE
58 #define _GNU_SOURCE 1
59 #endif
60
61 #ifndef __GNUC__
62 #error GCC required
63 #endif
64
65 #include "folly/detail/BitsDetail.h"
66 #include "folly/detail/BitIteratorDetail.h"
67 #include "folly/Likely.h"
68
69 #include <byteswap.h>
70 #include <cassert>
71 #include <cinttypes>
72 #include <endian.h>
73 #include <iterator>
74 #include <limits>
75 #include <type_traits>
76 #include <boost/iterator/iterator_adaptor.hpp>
77 #include <stdint.h>
78
79 namespace folly {
80
81 // Generate overloads for findFirstSet as wrappers around
82 // appropriate ffs, ffsl, ffsll gcc builtins
83 template <class T>
84 typename std::enable_if<
85   (std::is_integral<T>::value &&
86    std::is_unsigned<T>::value &&
87    (std::numeric_limits<T>::digits <=
88     std::numeric_limits<unsigned int>::digits)),
89   unsigned int>::type
90   findFirstSet(T x) {
91   return __builtin_ffs(x);
92 }
93
94 template <class T>
95 typename std::enable_if<
96   (std::is_integral<T>::value &&
97    std::is_unsigned<T>::value &&
98    (std::numeric_limits<T>::digits >
99     std::numeric_limits<unsigned int>::digits) &&
100    (std::numeric_limits<T>::digits <=
101     std::numeric_limits<unsigned long>::digits)),
102   unsigned int>::type
103   findFirstSet(T x) {
104   return __builtin_ffsl(x);
105 }
106
107 template <class T>
108 typename std::enable_if<
109   (std::is_integral<T>::value &&
110    std::is_unsigned<T>::value &&
111    (std::numeric_limits<T>::digits >
112     std::numeric_limits<unsigned long>::digits) &&
113    (std::numeric_limits<T>::digits <=
114     std::numeric_limits<unsigned long long>::digits)),
115   unsigned int>::type
116   findFirstSet(T x) {
117   return __builtin_ffsll(x);
118 }
119
120 template <class T>
121 typename std::enable_if<
122   (std::is_integral<T>::value && std::is_signed<T>::value),
123   unsigned int>::type
124   findFirstSet(T x) {
125   // Note that conversion from a signed type to the corresponding unsigned
126   // type is technically implementation-defined, but will likely work
127   // on any impementation that uses two's complement.
128   return findFirstSet(static_cast<typename std::make_unsigned<T>::type>(x));
129 }
130
131 // findLastSet: return the 1-based index of the highest bit set
132 // for x > 0, findLastSet(x) == 1 + floor(log2(x))
133 template <class T>
134 typename std::enable_if<
135   (std::is_integral<T>::value &&
136    std::is_unsigned<T>::value &&
137    (std::numeric_limits<T>::digits <=
138     std::numeric_limits<unsigned int>::digits)),
139   unsigned int>::type
140   findLastSet(T x) {
141   return x ? 8 * sizeof(unsigned int) - __builtin_clz(x) : 0;
142 }
143
144 template <class T>
145 typename std::enable_if<
146   (std::is_integral<T>::value &&
147    std::is_unsigned<T>::value &&
148    (std::numeric_limits<T>::digits >
149     std::numeric_limits<unsigned int>::digits) &&
150    (std::numeric_limits<T>::digits <=
151     std::numeric_limits<unsigned long>::digits)),
152   unsigned int>::type
153   findLastSet(T x) {
154   return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
155 }
156
157 template <class T>
158 typename std::enable_if<
159   (std::is_integral<T>::value &&
160    std::is_unsigned<T>::value &&
161    (std::numeric_limits<T>::digits >
162     std::numeric_limits<unsigned long>::digits) &&
163    (std::numeric_limits<T>::digits <=
164     std::numeric_limits<unsigned long long>::digits)),
165   unsigned int>::type
166   findLastSet(T x) {
167   return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
168 }
169
170 template <class T>
171 typename std::enable_if<
172   (std::is_integral<T>::value &&
173    std::is_signed<T>::value),
174   unsigned int>::type
175   findLastSet(T x) {
176   return findLastSet(static_cast<typename std::make_unsigned<T>::type>(x));
177 }
178
179 template <class T>
180 inline
181 typename std::enable_if<
182   std::is_integral<T>::value && std::is_unsigned<T>::value,
183   T>::type
184 nextPowTwo(T v) {
185   if (UNLIKELY(v == 0)) {
186     return 1;
187   }
188   return 1ul << findLastSet(v - 1);
189 }
190
191 /**
192  * Population count
193  */
194 template <class T>
195 inline typename std::enable_if<
196   (std::is_integral<T>::value &&
197    std::is_unsigned<T>::value &&
198    sizeof(T) <= sizeof(unsigned int)),
199   size_t>::type
200   popcount(T x) {
201   return detail::popcount(x);
202 }
203
204 template <class T>
205 inline typename std::enable_if<
206   (std::is_integral<T>::value &&
207    std::is_unsigned<T>::value &&
208    sizeof(T) > sizeof(unsigned int) &&
209    sizeof(T) <= sizeof(unsigned long long)),
210   size_t>::type
211   popcount(T x) {
212   return detail::popcountll(x);
213 }
214
215 /**
216  * Endianness detection and manipulation primitives.
217  */
218 namespace detail {
219
220 template <class T>
221 struct EndianIntBase {
222  public:
223   static T swap(T x);
224 };
225
226 #define FB_GEN(t, fn) \
227 template<> inline t EndianIntBase<t>::swap(t x) { return fn(x); }
228
229 // fn(x) expands to (x) if the second argument is empty, which is exactly
230 // what we want for [u]int8_t
231 FB_GEN( int8_t,)
232 FB_GEN(uint8_t,)
233 FB_GEN( int64_t, bswap_64)
234 FB_GEN(uint64_t, bswap_64)
235 FB_GEN( int32_t, bswap_32)
236 FB_GEN(uint32_t, bswap_32)
237 FB_GEN( int16_t, bswap_16)
238 FB_GEN(uint16_t, bswap_16)
239
240 #undef FB_GEN
241
242 #if __BYTE_ORDER == __LITTLE_ENDIAN
243
244 template <class T>
245 struct EndianInt : public detail::EndianIntBase<T> {
246  public:
247   static T big(T x) { return EndianInt::swap(x); }
248   static T little(T x) { return x; }
249 };
250
251 #elif __BYTE_ORDER == __BIG_ENDIAN
252
253 template <class T>
254 struct EndianInt : public detail::EndianIntBase<T> {
255  public:
256   static T big(T x) { return x; }
257   static T little(T x) { return EndianInt::swap(x); }
258 };
259
260 #else
261 # error Your machine uses a weird endianness!
262 #endif  /* __BYTE_ORDER */
263
264 }  // namespace detail
265
266 // big* convert between native and big-endian representations
267 // little* convert between native and little-endian representations
268 // swap* convert between big-endian and little-endian representations
269 //
270 // ntohs, htons == big16
271 // ntohl, htonl == big32
272 #define FB_GEN1(fn, t, sz) \
273   static t fn##sz(t x) { return fn<t>(x); } \
274
275 #define FB_GEN2(t, sz) \
276   FB_GEN1(swap, t, sz) \
277   FB_GEN1(big, t, sz) \
278   FB_GEN1(little, t, sz)
279
280 #define FB_GEN(sz) \
281   FB_GEN2(uint##sz##_t, sz) \
282   FB_GEN2(int##sz##_t, sz)
283
284 class Endian {
285  public:
286   enum class Order : uint8_t {
287     LITTLE,
288     BIG
289   };
290
291   static constexpr Order order =
292 #if __BYTE_ORDER == __LITTLE_ENDIAN
293     Order::LITTLE;
294 #elif __BYTE_ORDER == __BIG_ENDIAN
295     Order::BIG;
296 #else
297 # error Your machine uses a weird endianness!
298 #endif  /* __BYTE_ORDER */
299
300   template <class T> static T swap(T x) {
301     return detail::EndianInt<T>::swap(x);
302   }
303   template <class T> static T big(T x) {
304     return detail::EndianInt<T>::big(x);
305   }
306   template <class T> static T little(T x) {
307     return detail::EndianInt<T>::little(x);
308   }
309
310   FB_GEN(64)
311   FB_GEN(32)
312   FB_GEN(16)
313   FB_GEN(8)
314 };
315
316 #undef FB_GEN
317 #undef FB_GEN2
318 #undef FB_GEN1
319
320 /**
321  * Fast bit iteration facility.
322  */
323
324
325 template <class BaseIter> class BitIterator;
326 template <class BaseIter>
327 BitIterator<BaseIter> findFirstSet(BitIterator<BaseIter>,
328                                    BitIterator<BaseIter>);
329 /**
330  * Wrapper around an iterator over an integer type that iterates
331  * over its underlying bits in LSb to MSb order.
332  *
333  * BitIterator models the same iterator concepts as the base iterator.
334  */
335 template <class BaseIter>
336 class BitIterator
337   : public bititerator_detail::BitIteratorBase<BaseIter>::type {
338  public:
339   /**
340    * Return the number of bits in an element of the underlying iterator.
341    */
342   static size_t bitsPerBlock() {
343     return std::numeric_limits<
344       typename std::make_unsigned<
345         typename std::iterator_traits<BaseIter>::value_type
346       >::type
347     >::digits;
348   }
349
350   /**
351    * Construct a BitIterator that points at a given bit offset (default 0)
352    * in iter.
353    */
354   explicit BitIterator(const BaseIter& iter, size_t bitOffset=0)
355     : bititerator_detail::BitIteratorBase<BaseIter>::type(iter),
356       bitOffset_(bitOffset) {
357     assert(bitOffset_ < bitsPerBlock());
358   }
359
360   size_t bitOffset() const {
361     return bitOffset_;
362   }
363
364   void advanceToNextBlock() {
365     bitOffset_ = 0;
366     ++this->base_reference();
367   }
368
369   BitIterator& operator=(const BaseIter& other) {
370     this->~BitIterator();
371     new (this) BitIterator(other);
372     return *this;
373   }
374
375  private:
376   friend class boost::iterator_core_access;
377   friend BitIterator findFirstSet<>(BitIterator, BitIterator);
378
379   typedef bititerator_detail::BitReference<
380       typename std::iterator_traits<BaseIter>::reference,
381       typename std::iterator_traits<BaseIter>::value_type
382     > BitRef;
383
384   void advanceInBlock(size_t n) {
385     bitOffset_ += n;
386     assert(bitOffset_ < bitsPerBlock());
387   }
388
389   BitRef dereference() const {
390     return BitRef(*this->base_reference(), bitOffset_);
391   }
392
393   void advance(ssize_t n) {
394     size_t bpb = bitsPerBlock();
395     ssize_t blocks = n / bpb;
396     bitOffset_ += n % bpb;
397     if (bitOffset_ >= bpb) {
398       bitOffset_ -= bpb;
399       ++blocks;
400     }
401     this->base_reference() += blocks;
402   }
403
404   void increment() {
405     if (++bitOffset_ == bitsPerBlock()) {
406       advanceToNextBlock();
407     }
408   }
409
410   void decrement() {
411     if (bitOffset_-- == 0) {
412       bitOffset_ = bitsPerBlock() - 1;
413       --this->base_reference();
414     }
415   }
416
417   bool equal(const BitIterator& other) const {
418     return (bitOffset_ == other.bitOffset_ &&
419             this->base_reference() == other.base_reference());
420   }
421
422   ssize_t distance_to(const BitIterator& other) const {
423     return
424       (other.base_reference() - this->base_reference()) * bitsPerBlock() +
425       (other.bitOffset_ - bitOffset_);
426   }
427
428   ssize_t bitOffset_;
429 };
430
431 /**
432  * Helper function, so you can write
433  * auto bi = makeBitIterator(container.begin());
434  */
435 template <class BaseIter>
436 BitIterator<BaseIter> makeBitIterator(const BaseIter& iter) {
437   return BitIterator<BaseIter>(iter);
438 }
439
440
441 /**
442  * Find first bit set in a range of bit iterators.
443  * 4.5x faster than the obvious std::find(begin, end, true);
444  */
445 template <class BaseIter>
446 BitIterator<BaseIter> findFirstSet(BitIterator<BaseIter> begin,
447                                    BitIterator<BaseIter> end) {
448   // shortcut to avoid ugly static_cast<>
449   static const typename BaseIter::value_type one = 1;
450
451   while (begin.base() != end.base()) {
452     typename BaseIter::value_type v = *begin.base();
453     // mask out the bits that don't matter (< begin.bitOffset)
454     v &= ~((one << begin.bitOffset()) - 1);
455     size_t firstSet = findFirstSet(v);
456     if (firstSet) {
457       --firstSet;  // now it's 0-based
458       assert(firstSet >= begin.bitOffset());
459       begin.advanceInBlock(firstSet - begin.bitOffset());
460       return begin;
461     }
462     begin.advanceToNextBlock();
463   }
464
465   // now begin points to the same block as end
466   if (end.bitOffset() != 0) {  // assume end is dereferenceable
467     typename BaseIter::value_type v = *begin.base();
468     // mask out the bits that don't matter (< begin.bitOffset)
469     v &= ~((one << begin.bitOffset()) - 1);
470     // mask out the bits that don't matter (>= end.bitOffset)
471     v &= (one << end.bitOffset()) - 1;
472     size_t firstSet = findFirstSet(v);
473     if (firstSet) {
474       --firstSet;  // now it's 0-based
475       assert(firstSet >= begin.bitOffset());
476       begin.advanceInBlock(firstSet - begin.bitOffset());
477       return begin;
478     }
479   }
480
481   return end;
482 }
483
484
485 template <class T, class Enable=void> struct Unaligned;
486
487 /**
488  * Representation of an unaligned value of a POD type.
489  */
490 template <class T>
491 struct Unaligned<
492     T,
493     typename std::enable_if<std::is_pod<T>::value>::type> {
494   Unaligned() { }  // uninitialized
495   /* implicit */ Unaligned(T v) : value(v) { }
496   T value;
497 } __attribute__((packed));
498
499 /**
500  * Read an unaligned value of type T and return it.
501  */
502 template <class T>
503 inline T loadUnaligned(const void* p) {
504   static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size");
505   static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment");
506   return static_cast<const Unaligned<T>*>(p)->value;
507 }
508
509 /**
510  * Write an unaligned value of type T.
511  */
512 template <class T>
513 inline void storeUnaligned(void* p, T value) {
514   static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size");
515   static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment");
516   new (p) Unaligned<T>(value);
517 }
518
519 }  // namespace folly
520
521 #endif /* FOLLY_BITS_H_ */
522