-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitfield64.go
148 lines (125 loc) · 3.82 KB
/
bitfield64.go
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
142
143
144
145
146
147
148
/*
Package bitfield64 is a simple, quick stack-based bit-field manipulator
package of 64 bits (or less) in length. If you need more
bits you either need to create an array of bitfield64-s (and stay on the stack)
or need to switch to the heap-based bitfield package.
Methods are stateless and free from side-effects.
It was designed to be chainable. Range for position must be [0, 63]. position
outside this range will get the modulo treatment, so 64 will point to the 0th
element, -1 will address the last element (i.e. 63rd), -2 the one before
(i.e. 62nd), etc.
*/
package bitfield64
import (
"math"
"math/bits"
)
// BitField64 type utilizing the power of 64bit CPUs. It lives on the stack
type BitField64 uint64
// New returns a zeroed (all false) bit-field that can store size elements
func New() BitField64 {
return BitField64(0)
}
// the modulo treatment for positions outside of range [0,63]
func posNormalize(pos int) int {
const n = 64
for pos < 0 {
pos += n
}
return pos % n
}
// pos => bit mask: 1 at bit position pos, 0 everywhere else
func posToBitMask(pos int) BitField64 {
return 1 << uint64(posNormalize(pos))
}
// Set sets the bit at position pos
func (bf64 BitField64) Set(pos int) BitField64 {
return bf64 | posToBitMask(pos)
}
// Get returns true if bit at position pos is set, false otherwise
func (bf64 BitField64) Get(pos int) bool {
return bf64&posToBitMask(pos) > 0
}
// Clear clears the bit at position pos
func (bf64 BitField64) Clear(pos int) BitField64 {
return bf64 & ^posToBitMask(pos)
}
// Flip inverts the bit at position pos
func (bf64 BitField64) Flip(pos int) BitField64 {
if bf64.Get(pos) {
return bf64.Clear(pos)
}
return bf64.Set(pos)
}
// SetAll returns a bitfield where all 64 bits are set
func (bf64 BitField64) SetAll() BitField64 {
return math.MaxUint64
}
// ClearAll returns a bitfield where all 64 bits are set
func (bf64 BitField64) ClearAll() BitField64 {
return BitField64(0)
}
// And returns the binary AND of the two bitfields
func (bf64 BitField64) And(bfo BitField64) BitField64 {
return bf64 & bfo
}
// Or returns the binary OR of the two bitfields
func (bf64 BitField64) Or(bfo BitField64) BitField64 {
return bf64 | bfo
}
// Not returns the bitfield with each bit inverted: 0 becomes 1, 1 becomes 0
func (bf64 BitField64) Not() BitField64 {
return ^bf64
}
// Xor returns the binary XOR of the two bitfields
func (bf64 BitField64) Xor(bfo BitField64) BitField64 {
return bf64 ^ bfo
}
// OnesCount returns the number of bits set
func (bf64 BitField64) OnesCount() int {
return bits.OnesCount64(uint64(bf64))
}
// Mid returns count bits from position pos
func (bf64 BitField64) Mid(pos, count int) BitField64 {
if count < 0 {
panic("count is negative")
}
const n = 64
count = count % n
pos = posNormalize(pos)
end := pos + count
a := bf64 << (n - end)
a = a >> (n - count)
return a
}
// Left returns leftmost count bits: [0, count-1]
func (bf64 BitField64) Left(count int) BitField64 {
return bf64.Mid(0, count)
}
// Right returns rightmost count bits [63-count, 63]
func (bf64 BitField64) Right(count int) BitField64 {
const n = 64
return bf64.Mid(n-count, count)
}
// Rotate rotates by count bits: Bits exiting at one end entering at the other end.
// If count is positive it rotates towards higher positions; If negative it rotates
// towards lower positions.
func (bf64 BitField64) Rotate(count int) BitField64 {
if count == 0 {
return bf64
}
return BitField64(bits.RotateLeft64(uint64(bf64), count))
}
// Shift shift bits by count positions. Bits exiting at one end are discarded;
// bits entering at the other end are zeroed.
// If count is positive it shifts towards higher positions; If negative it shifts
// towards lower positions.
func (bf64 BitField64) Shift(count int) BitField64 {
if count == 0 {
return bf64
}
if count < 0 {
return bf64 >> -count
}
return bf64 << count
}