cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
bit.hpp
1#pragma once
2
3#include <x86intrin.h>
4
5#include "cplib/port/bit.hpp"
6
7#pragma GCC push_options
8#ifndef _CPLIB_NO_FORCE_BMI2_
9#pragma GCC target("abm,bmi,bmi2")
10#endif
11
12namespace cplib::impl {
13
14// Manually inserting BZHI intrinsic because GCC won't optimize x & ((1ull << n) - 1) to BZHI until version 10.
15// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93346
16inline uint64_t low_bits(uint64_t x, int n) {
17#if __GNUC__ < 10 && (defined(__BMI2__) || !defined(_CPLIB_NO_FORCE_BMI2_))
18 return _bzhi_u64(x, n);
19#else
20 return n >= 64 ? x : x & ((1ull << n) - 1);
21#endif
22}
23
24// Count the number of 1s in the lowest n bits of x.
25inline int popcount_low(uint64_t x, int n) { return port::popcount(low_bits(x, n)); }
26
27// Returns the largest i such that x[i]=1 and 0<=i<n, or -1 if no such i exists.
28inline int prev_set_bit(uint64_t x, int n) { return port::bit_width(low_bits(x, n)) - 1; }
29
30// Returns the smallest i such that x[i]=1 and n<=i<64, or 64 if no such i exists.
31inline int next_set_bit(uint64_t x, int n) { return n >= 64 ? 64 : port::countr_zero(x >> n << n); }
32
33// Returns y where y[i]=x[i^xval]
34inline uint64_t xor_permute(uint64_t x, int xor_val) {
35 static constexpr uint64_t checkerboard[6]{0x5555555555555555ull, 0x3333333333333333ull, 0x0f0f0f0f0f0f0f0full,
36 0x00ff00ff00ff00ffull, 0x0000ffff0000ffffull, 0x00000000ffffffffull};
37 uint64_t ret = x;
38 for (int i = 0; i < 6 && xor_val != 0; i++) {
39 if (xor_val & 1) {
40 uint64_t lo = ret & checkerboard[i];
41 uint64_t hi = ret & ~checkerboard[i];
42 lo <<= (1 << i);
43 hi >>= (1 << i);
44 ret = lo | hi;
45 }
46 xor_val >>= 1;
47 }
48 return ret;
49}
50
51} // namespace cplib::impl
52
53#pragma GCC pop_options