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