-
Notifications
You must be signed in to change notification settings - Fork 1
/
bit.hpp
141 lines (125 loc) · 4.15 KB
/
bit.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#pragma once
#include <nall/stdint.hpp>
namespace nall {
template<u32 bits, typename T> inline auto uclamp(T x) -> u64 {
enum : u64 { b = 1ull << (bits - 1), y = b * 2 - 1 };
if constexpr(is_unsigned_v<T>) {
return y + ((x - y) & -(x < y)); //min(x, y);
}
if constexpr(is_signed_v<T>) {
return x < 0 ? 0 : x > y ? y : x;
}
}
template<u32 bits> inline auto uclip(u64 x) -> u64 {
enum : u64 { b = 1ull << (bits - 1), m = b * 2 - 1 };
return (x & m);
}
template<u32 bits> inline auto sclamp(s64 x) -> s64 {
enum : s64 { b = 1ull << (bits - 1), m = b - 1 };
return (x > m) ? m : (x < -b) ? -b : x;
}
template<u32 bits> inline auto sclip(s64 x) -> s64 {
enum : u64 { b = 1ull << (bits - 1), m = b * 2 - 1 };
return ((x & m) ^ b) - b;
}
namespace bit {
constexpr inline auto mask(const char* s, u64 sum = 0) -> u64 {
return (
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
*s ? mask(s + 1, sum << 1) :
sum
);
}
constexpr inline auto test(const char* s, u64 sum = 0) -> u64 {
return (
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
*s == ' ' || *s == '_' ? test(s + 1, sum) :
*s ? test(s + 1, sum << 1) :
sum
);
}
//lowest(0b1110) == 0b0010
constexpr inline auto lowest(const u64 x) -> u64 {
return x & -x;
}
//clear_lowest(0b1110) == 0b1100
constexpr inline auto clearLowest(const u64 x) -> u64 {
return x & (x - 1);
}
//set_lowest(0b0101) == 0b0111
constexpr inline auto setLowest(const u64 x) -> u64 {
return x | (x + 1);
}
//count number of bits set in a byte
constexpr inline auto count(u64 x) -> u32 {
u32 count = 0;
while(x) x &= x - 1, count++; //clear the least significant bit
return count;
}
//return index of the first bit set (or zero of no bits are set)
//first(0b1000) == 3
constexpr inline auto first(u64 x) -> u32 {
u32 first = 0;
while(x) { if(x & 1) break; x >>= 1; first++; }
return first;
}
//round up to next highest single bit:
//round(15) == 16, round(16) == 16, round(17) == 32
constexpr inline auto round(u64 x) -> u64 {
if((x & (x - 1)) == 0) return x;
while(x & (x - 1)) x &= x - 1;
return x << 1;
}
template<typename T>
constexpr inline auto reverse(T x) -> T {
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
if constexpr(sizeof(T) == 1) {
#if __has_builtin(__builtin_bitreverse8)
return __builtin_bitreverse8(x);
#else
x = (x & 0xaa) >> 1 | (x & 0x55) << 1;
x = (x & 0xcc) >> 2 | (x & 0x33) << 2;
x = (x & 0xf0) >> 4 | (x & 0x0f) << 4;
return x;
#endif
}
if constexpr(sizeof(T) == 2) {
#if __has_builtin(__builtin_bitreverse16)
return __builtin_bitreverse16(x);
#else
x = (x & 0xaaaa) >> 1 | (x & 0x5555) << 1;
x = (x & 0xcccc) >> 2 | (x & 0x3333) << 2;
x = (x & 0xf0f0) >> 4 | (x & 0x0f0f) << 4;
x = (x & 0xff00) >> 8 | (x & 0x00ff) << 8;
return x;
#endif
}
if constexpr(sizeof(T) == 4) {
#if __has_builtin(__builtin_bitreverse32)
return __builtin_bitreverse32(x);
#else
x = (x & 0xaaaaaaaa) >> 1 | (x & 0x55555555) << 1;
x = (x & 0xcccccccc) >> 2 | (x & 0x33333333) << 2;
x = (x & 0xf0f0f0f0) >> 4 | (x & 0x0f0f0f0f) << 4;
x = (x & 0xff00ff00) >> 8 | (x & 0x00ff00ff) << 8;
x = (x & 0xffff0000) >> 16 | (x & 0x0000ffff) << 16;
return x;
#endif
}
if constexpr(sizeof(T) == 8) {
#if __has_builtin(__builtin_bitreverse64)
return __builtin_bitreverse64(x);
#else
x = (x & 0xaaaaaaaaaaaaaaaaULL) >> 1 | (x & 0x5555555555555555ULL) << 1;
x = (x & 0xccccccccccccccccULL) >> 2 | (x & 0x3333333333333333ULL) << 2;
x = (x & 0xf0f0f0f0f0f0f0f0ULL) >> 4 | (x & 0x0f0f0f0f0f0f0f0fULL) << 4;
x = (x & 0xff00ff00ff00ff00ULL) >> 8 | (x & 0x00ff00ff00ff00ffULL) << 8;
x = (x & 0xffff0000ffff0000ULL) >> 16 | (x & 0x0000ffff0000ffffULL) << 16;
x = (x & 0xffffffff00000000ULL) >> 32 | (x & 0x00000000ffffffffULL) << 32;
return x;
#endif
}
}
}
}