-
Notifications
You must be signed in to change notification settings - Fork 5
/
bitfield.go
104 lines (82 loc) · 2.48 KB
/
bitfield.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
package bitfield
import (
"github.com/kiambogo/go-hypercore/mempager"
)
type Bitfield struct {
pager *mempager.Pager
byteLength uint64
}
func NewBitfield(pageSize int) *Bitfield {
pgr := mempager.NewPager(pageSize)
return &Bitfield{pager: &pgr}
}
// PageSize returns the size of the pages used by the internal pager
func (b Bitfield) PageSize() int {
return b.pager.PageSize()
}
// ByteLength returns the number of bytes in the bitfield
func (b Bitfield) ByteLength() uint64 {
return b.byteLength
}
// Len returns the number of bits set in the bitfield
func (b Bitfield) Len() uint64 {
return b.byteLength * 8
}
// IsEmpty returns true if no bits are stored in the bitfield
func (b Bitfield) IsEmpty() bool {
return b.pager.IsEmpty()
}
// SetBit sets the bit at a particular index within the bitfield
// Returns true if a change was inacted
func (b *Bitfield) SetBit(index int, value bool) bool {
byteIndex := uint64(index / 8)
byteAtOffset := b.GetByte(byteIndex)
bitIndex := byte(1 << (index % 8))
var updatedByte byte
if value {
updatedByte = byteAtOffset | bitIndex
} else {
updatedByte = byteAtOffset & ^bitIndex
}
if updatedByte == byteAtOffset {
return false
}
return b.SetByte(byteIndex, updatedByte)
}
// SetByte sets the byte at a particular index within the bitfield
// Returns true if a change was inacted
func (b *Bitfield) SetByte(index uint64, value byte) bool {
pageIndex, bufferOffset := b.calculatePageIndexAndBufferOffset(index)
page := b.pager.GetOrAlloc(int(pageIndex))
pageBuffer := *page.Buffer()
// Update the byte length of the bitfield
if index >= b.byteLength {
b.byteLength = index + 1
}
if pageBuffer[bufferOffset] == value {
return false
}
pageBuffer[bufferOffset] = value
return true
}
// GetBit returns the value of the bit at a provided index
func (b *Bitfield) GetBit(index uint64) bool {
byteAtOffset := b.GetByte((index / 8))
bitIndex := byte(1 << (index % 8))
return byteAtOffset&bitIndex > 0
}
// GetByte returns the value of the byte at a provided index
func (b *Bitfield) GetByte(index uint64) byte {
pageIndex, bufferOffset := b.calculatePageIndexAndBufferOffset(index)
page := b.pager.Get(int(pageIndex))
if page == nil {
return byte(0)
}
pageBuffer := *page.Buffer()
return pageBuffer[bufferOffset]
}
func (b Bitfield) calculatePageIndexAndBufferOffset(index uint64) (uint64, uint64) {
pageIndex := index / uint64(b.pager.PageSize())
bufferOffset := index % uint64(b.pager.PageSize())
return pageIndex, bufferOffset
}