1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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  * extractFirstSet(x)  [constexpr]
30  *    extract first (least significant) bit set in a value of an integral
31  *    type, 0 = no bits are set (x == 0)
32  *
33  * nextPowTwo(x)  [constexpr]
34  *    Finds the next power of two >= x.
35  *
36  * strictNextPowTwo(x)  [constexpr]
37  *    Finds the next power of two > x.
38  *
39  * isPowTwo(x)  [constexpr]
40  *    return true iff x is a power of two
41  *
42  * popcount(x)
43  *    return the number of 1 bits in x
44  *
45  * Endian
46  *    convert between native, big, and little endian representation
47  *    Endian::big(x)      big <-> native
48  *    Endian::little(x)   little <-> native
49  *    Endian::swap(x)     big <-> little
50  *
51  * @author Tudor Bosman (tudorb@fb.com)
52  */
53 
54 #pragma once
55 
56 #include <cassert>
57 #include <cinttypes>
58 #include <cstdint>
59 #include <cstring>
60 #include <limits>
61 #include <type_traits>
62 
63 #include <folly/ConstexprMath.h>
64 #include <folly/Portability.h>
65 #include <folly/Traits.h>
66 #include <folly/Utility.h>
67 #include <folly/lang/Assume.h>
68 #include <folly/portability/Builtins.h>
69 
70 #if __has_include(<bit>) && __cplusplus >= 202002L
71 #include <bit>
72 #endif
73 
74 namespace folly {
75 
76 #ifdef __cpp_lib_bit_cast
77 
78 using std::bit_cast;
79 
80 #else
81 
82 //  mimic: std::bit_cast, C++20
83 template <
84     typename To,
85     typename From,
86     std::enable_if_t<
87         sizeof(From) == sizeof(To) && is_trivially_copyable<To>::value &&
88             is_trivially_copyable<From>::value,
89         int> = 0>
90 To bit_cast(const From& src) noexcept {
91   aligned_storage_for_t<To> storage;
92   std::memcpy(&storage, &src, sizeof(From));
93   return reinterpret_cast<To&>(storage);
94 }
95 
96 #endif
97 
98 namespace detail {
99 template <typename Dst, typename Src>
bits_to_signed(Src const s)100 constexpr std::make_signed_t<Dst> bits_to_signed(Src const s) {
101   static_assert(std::is_signed<Dst>::value, "unsigned type");
102   return to_signed(static_cast<std::make_unsigned_t<Dst>>(to_unsigned(s)));
103 }
104 template <typename Dst, typename Src>
bits_to_unsigned(Src const s)105 constexpr std::make_unsigned_t<Dst> bits_to_unsigned(Src const s) {
106   static_assert(std::is_unsigned<Dst>::value, "signed type");
107   return static_cast<Dst>(to_unsigned(s));
108 }
109 } // namespace detail
110 
111 /// findFirstSet
112 ///
113 /// Return the 1-based index of the least significant bit which is set.
114 /// For x > 0, the exponent in the largest power of two which does not divide x.
115 template <typename T>
findFirstSet(T const v)116 inline constexpr unsigned int findFirstSet(T const v) {
117   using S0 = int;
118   using S1 = long int;
119   using S2 = long long int;
120   using detail::bits_to_signed;
121   static_assert(sizeof(T) <= sizeof(S2), "over-sized type");
122   static_assert(std::is_integral<T>::value, "non-integral type");
123   static_assert(!std::is_same<T, bool>::value, "bool type");
124 
125   // clang-format off
126   return static_cast<unsigned int>(
127       sizeof(T) <= sizeof(S0) ? __builtin_ffs(bits_to_signed<S0>(v)) :
128       sizeof(T) <= sizeof(S1) ? __builtin_ffsl(bits_to_signed<S1>(v)) :
129       sizeof(T) <= sizeof(S2) ? __builtin_ffsll(bits_to_signed<S2>(v)) :
130       0);
131   // clang-format on
132 }
133 
134 /// findLastSet
135 ///
136 /// Return the 1-based index of the most significant bit which is set.
137 /// For x > 0, findLastSet(x) == 1 + floor(log2(x)).
138 template <typename T>
findLastSet(T const v)139 inline constexpr unsigned int findLastSet(T const v) {
140   using U0 = unsigned int;
141   using U1 = unsigned long int;
142   using U2 = unsigned long long int;
143   using detail::bits_to_unsigned;
144   static_assert(sizeof(T) <= sizeof(U2), "over-sized type");
145   static_assert(std::is_integral<T>::value, "non-integral type");
146   static_assert(!std::is_same<T, bool>::value, "bool type");
147 
148   // If X is a power of two X - Y = 1 + ((X - 1) ^ Y). Doing this transformation
149   // allows GCC to remove its own xor that it adds to implement clz using bsr.
150   // clang-format off
151   using size = index_constant<constexpr_max(sizeof(T), sizeof(U0))>;
152   return v ? 1u + static_cast<unsigned int>((8u * size{} - 1u) ^ (
153       sizeof(T) <= sizeof(U0) ? __builtin_clz(bits_to_unsigned<U0>(v)) :
154       sizeof(T) <= sizeof(U1) ? __builtin_clzl(bits_to_unsigned<U1>(v)) :
155       sizeof(T) <= sizeof(U2) ? __builtin_clzll(bits_to_unsigned<U2>(v)) :
156       0)) : 0u;
157   // clang-format on
158 }
159 
160 /// extractFirstSet
161 ///
162 /// Return a value where all the bits but the least significant are cleared.
163 template <typename T>
extractFirstSet(T const v)164 inline constexpr T extractFirstSet(T const v) {
165   static_assert(std::is_integral<T>::value, "non-integral type");
166   static_assert(std::is_unsigned<T>::value, "signed type");
167   static_assert(!std::is_same<T, bool>::value, "bool type");
168 
169   return v & -v;
170 }
171 
172 /// popcount
173 ///
174 /// Returns the number of bits which are set.
175 template <typename T>
popcount(T const v)176 inline constexpr unsigned int popcount(T const v) {
177   using U0 = unsigned int;
178   using U1 = unsigned long int;
179   using U2 = unsigned long long int;
180   using detail::bits_to_unsigned;
181   static_assert(sizeof(T) <= sizeof(U2), "over-sized type");
182   static_assert(std::is_integral<T>::value, "non-integral type");
183   static_assert(!std::is_same<T, bool>::value, "bool type");
184 
185   // clang-format off
186   return static_cast<unsigned int>(
187       sizeof(T) <= sizeof(U0) ? __builtin_popcount(bits_to_unsigned<U0>(v)) :
188       sizeof(T) <= sizeof(U1) ? __builtin_popcountl(bits_to_unsigned<U1>(v)) :
189       sizeof(T) <= sizeof(U2) ? __builtin_popcountll(bits_to_unsigned<U2>(v)) :
190       0);
191   // clang-format on
192 }
193 
194 template <class T>
nextPowTwo(T const v)195 inline constexpr T nextPowTwo(T const v) {
196   static_assert(std::is_unsigned<T>::value, "signed type");
197   return v ? (T(1) << findLastSet(v - 1)) : T(1);
198 }
199 
200 template <class T>
prevPowTwo(T const v)201 inline constexpr T prevPowTwo(T const v) {
202   static_assert(std::is_unsigned<T>::value, "signed type");
203   return v ? (T(1) << (findLastSet(v) - 1)) : T(0);
204 }
205 
206 template <class T>
isPowTwo(T const v)207 inline constexpr bool isPowTwo(T const v) {
208   static_assert(std::is_integral<T>::value, "non-integral type");
209   static_assert(std::is_unsigned<T>::value, "signed type");
210   static_assert(!std::is_same<T, bool>::value, "bool type");
211   return (v != 0) && !(v & (v - 1));
212 }
213 
214 template <class T>
strictNextPowTwo(T const v)215 inline constexpr T strictNextPowTwo(T const v) {
216   static_assert(std::is_unsigned<T>::value, "signed type");
217   return nextPowTwo(T(v + 1));
218 }
219 
220 template <class T>
strictPrevPowTwo(T const v)221 inline constexpr T strictPrevPowTwo(T const v) {
222   static_assert(std::is_unsigned<T>::value, "signed type");
223   return v > 1 ? prevPowTwo(T(v - 1)) : T(0);
224 }
225 
226 /**
227  * Endianness detection and manipulation primitives.
228  */
229 namespace detail {
230 
231 template <size_t Size>
232 struct uint_types_by_size;
233 
234 #define FB_GEN(sz, fn)                                                      \
235   static inline uint##sz##_t byteswap_gen(uint##sz##_t v) { return fn(v); } \
236   template <>                                                               \
237   struct uint_types_by_size<sz / 8> {                                       \
238     using type = uint##sz##_t;                                              \
239   };
240 
241 FB_GEN(8, uint8_t)
242 #ifdef _MSC_VER
243 FB_GEN(64, _byteswap_uint64)
244 FB_GEN(32, _byteswap_ulong)
245 FB_GEN(16, _byteswap_ushort)
246 #else
247 FB_GEN(64, __builtin_bswap64)
248 FB_GEN(32, __builtin_bswap32)
249 FB_GEN(16, __builtin_bswap16)
250 #endif
251 
252 #undef FB_GEN
253 
254 template <class T>
255 struct EndianInt {
256   static_assert(
257       (std::is_integral<T>::value && !std::is_same<T, bool>::value) ||
258           std::is_floating_point<T>::value,
259       "template type parameter must be non-bool integral or floating point");
swapEndianInt260   static T swap(T x) {
261     // we implement this with bit_cast because that is defined behavior in C++
262     // we rely on compilers to optimize away the bit_cast calls
263     constexpr auto s = sizeof(T);
264     using B = typename uint_types_by_size<s>::type;
265     return bit_cast<T>(byteswap_gen(bit_cast<B>(x)));
266   }
bigEndianInt267   static T big(T x) { return kIsLittleEndian ? EndianInt::swap(x) : x; }
littleEndianInt268   static T little(T x) { return kIsBigEndian ? EndianInt::swap(x) : x; }
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>
swap(T x)301   static T swap(T x) {
302     return folly::detail::EndianInt<T>::swap(x);
303   }
304   template <class T>
big(T x)305   static T big(T x) {
306     return folly::detail::EndianInt<T>::big(x);
307   }
308   template <class T>
little(T x)309   static T little(T x) {
310     return folly::detail::EndianInt<T>::little(x);
311   }
312 
313 #if !defined(__ANDROID__)
314   FB_GEN(64)
315   FB_GEN(32)
316   FB_GEN(16)
317   FB_GEN(8)
318 #endif
319 };
320 
321 #undef FB_GEN
322 #undef FB_GEN2
323 #undef FB_GEN1
324 
325 template <class T, class Enable = void>
326 struct Unaligned;
327 
328 /**
329  * Representation of an unaligned value of a POD type.
330  */
331 FOLLY_PUSH_WARNING
332 FOLLY_CLANG_DISABLE_WARNING("-Wpacked")
333 FOLLY_PACK_PUSH
334 template <class T>
335 struct Unaligned<T, typename std::enable_if<std::is_pod<T>::value>::type> {
336   Unaligned() = default; // uninitialized
337   /* implicit */ Unaligned(T v) : value(v) {}
338   T value;
339 } FOLLY_PACK_ATTR;
340 FOLLY_PACK_POP
341 FOLLY_POP_WARNING
342 
343 /**
344  * Read an unaligned value of type T and return it.
345  */
346 template <class T>
347 inline constexpr T loadUnaligned(const void* p) {
348   static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size");
349   static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment");
350   if (kHasUnalignedAccess) {
351     return static_cast<const Unaligned<T>*>(p)->value;
352   } else {
353     T value{};
354     memcpy(&value, p, sizeof(T));
355     return value;
356   }
357 }
358 
359 /**
360  * Read l bytes into the low bits of a value of an unsigned integral
361  * type T, where l < sizeof(T).
362  *
363  * This is intended as a complement to loadUnaligned to read the tail
364  * of a buffer when it is processed one word at a time.
365  */
366 template <class T>
367 inline T partialLoadUnaligned(const void* p, size_t l) {
368   static_assert(
369       std::is_integral<T>::value && std::is_unsigned<T>::value &&
370           sizeof(T) <= 8,
371       "Invalid type");
372   assume(l < sizeof(T));
373 
374   auto cp = static_cast<const char*>(p);
375   T value = 0;
376   if (!kHasUnalignedAccess || !kIsLittleEndian) {
377     // Unsupported, use memcpy.
378     memcpy(&value, cp, l);
379     return value;
380   }
381 
382   auto avail = l;
383   if (l & 4) {
384     avail -= 4;
385     value = static_cast<T>(loadUnaligned<uint32_t>(cp + avail)) << (avail * 8);
386   }
387   if (l & 2) {
388     avail -= 2;
389     value |= static_cast<T>(loadUnaligned<uint16_t>(cp + avail)) << (avail * 8);
390   }
391   if (l & 1) {
392     value |= loadUnaligned<uint8_t>(cp);
393   }
394   return value;
395 }
396 
397 /**
398  * Write an unaligned value of type T.
399  */
400 template <class T>
401 inline void storeUnaligned(void* p, T value) {
402   static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size");
403   static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment");
404   if (kHasUnalignedAccess) {
405     // Prior to C++14, the spec says that a placement new like this
406     // is required to check that p is not nullptr, and to do nothing
407     // if p is a nullptr. By assuming it's not a nullptr, we get a
408     // nice loud segfault in optimized builds if p is nullptr, rather
409     // than just silently doing nothing.
410     assume(p != nullptr);
411     new (p) Unaligned<T>(value);
412   } else {
413     memcpy(p, &value, sizeof(T));
414   }
415 }
416 
417 template <typename T>
418 T bitReverse(T n) {
419   auto m = static_cast<typename std::make_unsigned<T>::type>(n);
420   m = ((m & 0xAAAAAAAAAAAAAAAA) >> 1) | ((m & 0x5555555555555555) << 1);
421   m = ((m & 0xCCCCCCCCCCCCCCCC) >> 2) | ((m & 0x3333333333333333) << 2);
422   m = ((m & 0xF0F0F0F0F0F0F0F0) >> 4) | ((m & 0x0F0F0F0F0F0F0F0F) << 4);
423   return static_cast<T>(Endian::swap(m));
424 }
425 
426 } // namespace folly
427