OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package bf | |
6 | |
7 import ( | |
8 "fmt" | |
9 ) | |
10 | |
11 // BitField is a AppEngine-serializable bit field implementation. It should | |
12 // be nice and fast for non-AppEngine use as well. | |
13 // | |
14 // You should construct a new one with bf.Make, rather than by direct | |
15 // construction. The field names are public due to an appengine artifact. | |
16 type BitField struct { | |
17 // fields are public so that datastore can see them... but don't touch t
hem if | |
18 // you know what's good for you. | |
19 | |
20 // Data is the actual bits data. rightmost bit of 0th number is the firs
t bit. | |
21 Data []int64 `datastore:",noindex"` | |
22 | |
23 // NumBits is the number of bits held in this BitField. It's stored as a | |
24 // casted uint64 since datastore can't store unsigned things, apparently
. | |
25 NumBits int64 `datastore:",noindex"` | |
26 } | |
27 | |
28 // Make creates a new properly-initialized BitField. | |
29 func Make(size uint64) BitField { | |
30 return BitField{ | |
31 Data: make([]int64, (size+64-1)>>6), | |
32 NumBits: int64(size), | |
33 } | |
34 } | |
35 | |
36 // Size returns the number of bits which this BitField can hold. | |
37 func (bf BitField) Size() uint64 { | |
38 return uint64(bf.NumBits) | |
39 } | |
40 | |
41 // Set turns the given bit to true, regardless of its previous value. Error | |
42 // returned is for bounds checking. | |
43 func (bf BitField) Set(idx uint64) error { | |
44 if idx >= bf.Size() { | |
45 return fmt.Errorf("Cannot set bit %d in BitField of size %d", id
x, bf.Size()) | |
46 } | |
47 bf.Data[idx>>6] |= 1 << (idx % 64) | |
48 return nil | |
49 } | |
50 | |
51 // Clear turns the given bit to false, regardless of its previous value. Error | |
52 // returned is for bounds checking. | |
53 func (bf BitField) Clear(idx uint64) error { | |
54 if idx >= bf.Size() { | |
55 return fmt.Errorf("Cannot clear bit %d in BitField of size %d",
idx, bf.Size()) | |
56 } | |
57 bf.Data[idx>>6] &^= 1 << (idx % 64) | |
58 return nil | |
59 } | |
60 | |
61 // All returns true iff all of the bits are equal to `val`. | |
62 func (bf BitField) All(val bool) bool { | |
63 targ := bf.Size() | |
64 if !val { | |
65 targ = 0 | |
66 } | |
67 return bf.CountSet() == targ | |
68 } | |
69 | |
70 func countBitsSet(v uint64) uint8 { | |
71 // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetPara
llel | |
72 const ( | |
73 maxUint64 = ^(uint64(0)) | |
74 eightyfives = maxUint64 / 3 // 0x555555... | |
75 fiftyones = maxUint64 / 15 * 3 // 0x333333... | |
76 fifteens = maxUint64 / 255 * 15 // 0x0f0f0f... | |
77 ones = maxUint64 / 255 // 0x010101... | |
78 offset = (64/8 - 1) * 8 // 56 | |
79 ) | |
80 | |
81 v -= v >> 1 & eightyfives | |
82 v = v&fiftyones + v>>2&fiftyones | |
83 v = (v + v>>4) & fifteens | |
84 return uint8(v * ones >> offset) | |
85 } | |
86 | |
87 // CountSet returns the number of true bits. | |
88 func (bf BitField) CountSet() uint64 { | |
89 ret := uint64(0) | |
90 for _, word := range bf.Data { | |
91 if word != 0 { | |
92 ret += uint64(countBitsSet(uint64(word))) | |
93 } | |
94 } | |
95 return ret | |
96 } | |
97 | |
98 // IsSet returns the value of a given bit. | |
99 func (bf BitField) IsSet(idx uint64) bool { | |
100 return idx < bf.Size() && ((bf.Data[idx>>6] & (1 << (idx % 64))) != 0) | |
101 } | |
OLD | NEW |