Fix copyright lines for Bits.h and move BitsBenchmark.cpp
[folly.git] / folly / lang / Bits.h
1 /*
2  * Copyright 2011-present 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)  [constexpr]
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)  [constexpr]
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  * nextPowTwo(x)  [constexpr]
30  *    Finds the next power of two >= x.
31  *
32  * isPowTwo(x)  [constexpr]
33  *    return true iff x is a power of two
34  *
35  * popcount(x)
36  *    return the number of 1 bits in x
37  *
38  * Endian
39  *    convert between native, big, and little endian representation
40  *    Endian::big(x)      big <-> native
41  *    Endian::little(x)   little <-> native
42  *    Endian::swap(x)     big <-> little
43  *
44  * @author Tudor Bosman (tudorb@fb.com)
45  */
46
47 #pragma once
48
49 // MSVC does not support intrinsics constexpr
50 #if defined(_MSC_VER)
51 #define FOLLY_INTRINSIC_CONSTEXPR const
52 #else
53 #define FOLLY_INTRINSIC_CONSTEXPR constexpr
54 #endif
55
56 #include <cassert>
57 #include <cinttypes>
58 #include <cstdint>
59 #include <cstring>
60 #include <limits>
61 #include <type_traits>
62
63 #include <folly/Portability.h>
64 #include <folly/lang/Assume.h>
65 #include <folly/portability/Builtins.h>
66
67 namespace folly {
68
69 // Generate overloads for findFirstSet as wrappers around
70 // appropriate ffs, ffsl, ffsll gcc builtins
71 template <class T>
72 inline FOLLY_INTRINSIC_CONSTEXPR
73 typename std::enable_if<
74   (std::is_integral<T>::value &&
75    std::is_unsigned<T>::value &&
76    sizeof(T) <= sizeof(unsigned int)),
77   unsigned int>::type
78   findFirstSet(T x) {
79   return static_cast<unsigned int>(__builtin_ffs(static_cast<int>(x)));
80 }
81
82 template <class T>
83 inline FOLLY_INTRINSIC_CONSTEXPR
84 typename std::enable_if<
85   (std::is_integral<T>::value &&
86    std::is_unsigned<T>::value &&
87    sizeof(T) > sizeof(unsigned int) &&
88    sizeof(T) <= sizeof(unsigned long)),
89   unsigned int>::type
90   findFirstSet(T x) {
91   return static_cast<unsigned int>(__builtin_ffsl(static_cast<long>(x)));
92 }
93
94 template <class T>
95 inline FOLLY_INTRINSIC_CONSTEXPR
96 typename std::enable_if<
97   (std::is_integral<T>::value &&
98    std::is_unsigned<T>::value &&
99    sizeof(T) > sizeof(unsigned long) &&
100    sizeof(T) <= sizeof(unsigned long long)),
101   unsigned int>::type
102   findFirstSet(T x) {
103   return static_cast<unsigned int>(__builtin_ffsll(static_cast<long long>(x)));
104 }
105
106 template <class T>
107 inline FOLLY_INTRINSIC_CONSTEXPR
108 typename std::enable_if<
109   (std::is_integral<T>::value && std::is_signed<T>::value),
110   unsigned int>::type
111   findFirstSet(T x) {
112   // Note that conversion from a signed type to the corresponding unsigned
113   // type is technically implementation-defined, but will likely work
114   // on any impementation that uses two's complement.
115   return findFirstSet(static_cast<typename std::make_unsigned<T>::type>(x));
116 }
117
118 // findLastSet: return the 1-based index of the highest bit set
119 // for x > 0, findLastSet(x) == 1 + floor(log2(x))
120 template <class T>
121 inline FOLLY_INTRINSIC_CONSTEXPR
122 typename std::enable_if<
123   (std::is_integral<T>::value &&
124    std::is_unsigned<T>::value &&
125    sizeof(T) <= sizeof(unsigned int)),
126   unsigned int>::type
127   findLastSet(T x) {
128   // If X is a power of two X - Y = ((X - 1) ^ Y) + 1. Doing this transformation
129   // allows GCC to remove its own xor that it adds to implement clz using bsr
130   return x ? ((8 * sizeof(unsigned int) - 1) ^ __builtin_clz(x)) + 1 : 0;
131 }
132
133 template <class T>
134 inline FOLLY_INTRINSIC_CONSTEXPR
135 typename std::enable_if<
136   (std::is_integral<T>::value &&
137    std::is_unsigned<T>::value &&
138    sizeof(T) > sizeof(unsigned int) &&
139    sizeof(T) <= sizeof(unsigned long)),
140   unsigned int>::type
141   findLastSet(T x) {
142   return x ? ((8 * sizeof(unsigned long) - 1) ^ __builtin_clzl(x)) + 1 : 0;
143 }
144
145 template <class T>
146 inline FOLLY_INTRINSIC_CONSTEXPR
147 typename std::enable_if<
148   (std::is_integral<T>::value &&
149    std::is_unsigned<T>::value &&
150    sizeof(T) > sizeof(unsigned long) &&
151    sizeof(T) <= sizeof(unsigned long long)),
152   unsigned int>::type
153   findLastSet(T x) {
154   return x ? ((8 * sizeof(unsigned long long) - 1) ^ __builtin_clzll(x)) + 1
155            : 0;
156 }
157
158 template <class T>
159 inline FOLLY_INTRINSIC_CONSTEXPR
160 typename std::enable_if<
161   (std::is_integral<T>::value &&
162    std::is_signed<T>::value),
163   unsigned int>::type
164   findLastSet(T x) {
165   return findLastSet(static_cast<typename std::make_unsigned<T>::type>(x));
166 }
167
168 template <class T>
169 inline FOLLY_INTRINSIC_CONSTEXPR
170 typename std::enable_if<
171   std::is_integral<T>::value && std::is_unsigned<T>::value,
172   T>::type
173 nextPowTwo(T v) {
174   return v ? (T(1) << findLastSet(v - 1)) : 1;
175 }
176
177 template <class T>
178 inline FOLLY_INTRINSIC_CONSTEXPR typename std::
179     enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
180     prevPowTwo(T v) {
181   return v ? (T(1) << (findLastSet(v) - 1)) : 0;
182 }
183
184 template <class T>
185 inline constexpr typename std::enable_if<
186     std::is_integral<T>::value && std::is_unsigned<T>::value,
187     bool>::type
188 isPowTwo(T v) {
189   return (v != 0) && !(v & (v - 1));
190 }
191
192 /**
193  * Population count
194  */
195 template <class T>
196 inline typename std::enable_if<
197   (std::is_integral<T>::value &&
198    std::is_unsigned<T>::value &&
199    sizeof(T) <= sizeof(unsigned int)),
200   size_t>::type
201   popcount(T x) {
202   return size_t(__builtin_popcount(x));
203 }
204
205 template <class T>
206 inline typename std::enable_if<
207   (std::is_integral<T>::value &&
208    std::is_unsigned<T>::value &&
209    sizeof(T) > sizeof(unsigned int) &&
210    sizeof(T) <= sizeof(unsigned long long)),
211   size_t>::type
212   popcount(T x) {
213   return size_t(__builtin_popcountll(x));
214 }
215
216 /**
217  * Endianness detection and manipulation primitives.
218  */
219 namespace detail {
220
221 template <size_t Size>
222 struct uint_types_by_size;
223
224 #define FB_GEN(sz, fn)                                      \
225   static inline uint##sz##_t byteswap_gen(uint##sz##_t v) { \
226     return fn(v);                                           \
227   }                                                         \
228   template <>                                               \
229   struct uint_types_by_size<sz / 8> {                       \
230     using type = uint##sz##_t;                              \
231   };
232
233 FB_GEN(8, uint8_t)
234 #ifdef _MSC_VER
235 FB_GEN(64, _byteswap_uint64)
236 FB_GEN(32, _byteswap_ulong)
237 FB_GEN(16, _byteswap_ushort)
238 #else
239 FB_GEN(64, __builtin_bswap64)
240 FB_GEN(32, __builtin_bswap32)
241 FB_GEN(16, __builtin_bswap16)
242 #endif
243
244 #undef FB_GEN
245
246 template <class T>
247 struct EndianInt {
248   static_assert(
249       (std::is_integral<T>::value && !std::is_same<T, bool>::value) ||
250           std::is_floating_point<T>::value,
251       "template type parameter must be non-bool integral or floating point");
252   static T swap(T x) {
253     // we implement this with memcpy because that is defined behavior in C++
254     // we rely on compilers to optimize away the memcpy calls
255     constexpr auto s = sizeof(T);
256     using B = typename uint_types_by_size<s>::type;
257     B b;
258     std::memcpy(&b, &x, s);
259     b = byteswap_gen(b);
260     std::memcpy(&x, &b, s);
261     return x;
262   }
263   static T big(T x) {
264     return kIsLittleEndian ? EndianInt::swap(x) : x;
265   }
266   static T little(T x) {
267     return kIsBigEndian ? EndianInt::swap(x) : x;
268   }
269 };
270
271 } // namespace detail
272
273 // big* convert between native and big-endian representations
274 // little* convert between native and little-endian representations
275 // swap* convert between big-endian and little-endian representations
276 //
277 // ntohs, htons == big16
278 // ntohl, htonl == big32
279 #define FB_GEN1(fn, t, sz) \
280   static t fn##sz(t x) { return fn<t>(x); } \
281
282 #define FB_GEN2(t, sz) \
283   FB_GEN1(swap, t, sz) \
284   FB_GEN1(big, t, sz) \
285   FB_GEN1(little, t, sz)
286
287 #define FB_GEN(sz) \
288   FB_GEN2(uint##sz##_t, sz) \
289   FB_GEN2(int##sz##_t, sz)
290
291 class Endian {
292  public:
293   enum class Order : uint8_t {
294     LITTLE,
295     BIG
296   };
297
298   static constexpr Order order = kIsLittleEndian ? Order::LITTLE : Order::BIG;
299
300   template <class T> static T swap(T x) {
301     return folly::detail::EndianInt<T>::swap(x);
302   }
303   template <class T> static T big(T x) {
304     return folly::detail::EndianInt<T>::big(x);
305   }
306   template <class T> static T little(T x) {
307     return folly::detail::EndianInt<T>::little(x);
308   }
309
310 #if !defined(__ANDROID__)
311   FB_GEN(64)
312   FB_GEN(32)
313   FB_GEN(16)
314   FB_GEN(8)
315 #endif
316 };
317
318 #undef FB_GEN
319 #undef FB_GEN2
320 #undef FB_GEN1
321
322
323 template <class T, class Enable=void> struct Unaligned;
324
325 /**
326  * Representation of an unaligned value of a POD type.
327  */
328 FOLLY_PACK_PUSH
329 template <class T>
330 struct Unaligned<
331     T,
332     typename std::enable_if<std::is_pod<T>::value>::type> {
333   Unaligned() = default;  // uninitialized
334   /* implicit */ Unaligned(T v) : value(v) { }
335   T value;
336 } FOLLY_PACK_ATTR;
337 FOLLY_PACK_POP
338
339 /**
340  * Read an unaligned value of type T and return it.
341  */
342 template <class T>
343 inline T loadUnaligned(const void* p) {
344   static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size");
345   static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment");
346   if (kHasUnalignedAccess) {
347     return static_cast<const Unaligned<T>*>(p)->value;
348   } else {
349     T value;
350     memcpy(&value, p, sizeof(T));
351     return value;
352   }
353 }
354
355 /**
356  * Write an unaligned value of type T.
357  */
358 template <class T>
359 inline void storeUnaligned(void* p, T value) {
360   static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size");
361   static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment");
362   if (kHasUnalignedAccess) {
363     // Prior to C++14, the spec says that a placement new like this
364     // is required to check that p is not nullptr, and to do nothing
365     // if p is a nullptr. By assuming it's not a nullptr, we get a
366     // nice loud segfault in optimized builds if p is nullptr, rather
367     // than just silently doing nothing.
368     folly::assume(p != nullptr);
369     new (p) Unaligned<T>(value);
370   } else {
371     memcpy(p, &value, sizeof(T));
372   }
373 }
374
375 template <typename T>
376 T bitReverse(T n) {
377   auto m = static_cast<typename std::make_unsigned<T>::type>(n);
378   m = ((m & 0xAAAAAAAAAAAAAAAA) >> 1) | ((m & 0x5555555555555555) << 1);
379   m = ((m & 0xCCCCCCCCCCCCCCCC) >> 2) | ((m & 0x3333333333333333) << 2);
380   m = ((m & 0xF0F0F0F0F0F0F0F0) >> 4) | ((m & 0x0F0F0F0F0F0F0F0F) << 4);
381   return static_cast<T>(Endian::swap(m));
382 }
383
384 } // namespace folly