├── .gitignore ├── README.md ├── LICENSE.txt ├── bitset.go └── bitset_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Package bitset implements bitsets, a mapping 2 | between non-negative integers and boolean values. It should be more 3 | efficient than map[uint] bool. 4 | 5 | It provides methods for setting, clearing, flipping, and testing 6 | individual integers. 7 | 8 | But it also provides set intersection, union, difference, 9 | complement, and symmetric operations, as well as tests to 10 | check whether any, all, or no bits are set, and querying a 11 | bitset's current length and number of postive bits. 12 | 13 | BitSets are expanded to the size of the largest set bit; the 14 | memory allocation is approximately Max bits, where Max is 15 | the largest set bit. BitSets are never shrunk. On creation, 16 | a hint can be given for the number of bits that will be used. 17 | 18 | Many of the methods, including Set, Clear, and Flip, return 19 | a BitSet pointer, which allows for chaining. 20 | 21 | Example use: 22 | 23 | import "bitset" 24 | var b BitSet 25 | b.Set(10).Set(11) 26 | if b.Test(1000) { 27 | b.Clear(1000) 28 | } 29 | if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { 30 | fmt.Println("Intersection works.") 31 | } 32 | 33 | As an alternative to BitSets, one should check out the 'big' package, 34 | which provides a (less set-theoretical) view of bitsets. 35 | 36 | Discussions goland-nuts Google Group: 37 | 38 | * [Revised BitSet](https://groups.google.com/forum/#!topic/golang-nuts/5i3l0CXDiBg) 39 | * [simple bitset?](https://groups.google.com/d/topic/golang-nuts/7n1VkRTlBf4/discussion) 40 | 41 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /bitset.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | 7 | Package bitset implements bitsets, a mapping 8 | between non-negative integers and boolean values. It should be more 9 | efficient than map[uint] bool. 10 | 11 | It provides methods for setting, clearing, flipping, and testing 12 | individual integers. 13 | 14 | But it also provides set intersection, union, difference, 15 | complement, and symmetric operations, as well as tests to 16 | check whether any, all, or no bits are set, and querying a 17 | bitset's current length and number of postive bits. 18 | 19 | BitSets are expanded to the size of the largest set bit; the 20 | memory allocation is approximately Max bits, where Max is 21 | the largest set bit. BitSets are never shrunk. On creation, 22 | a hint can be given for the number of bits that will be used. 23 | 24 | Many of the methods, including Set,Clear, and Flip, return 25 | a BitSet pointer, which allows for chaining. 26 | 27 | Example use: 28 | 29 | import "bitset" 30 | var b BitSet 31 | b.Set(10).Set(11) 32 | if b.Test(1000) { 33 | b.Clear(1000) 34 | } 35 | if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { 36 | fmt.Println("Intersection works.") 37 | } 38 | 39 | As an alternative to BitSets, one should check out the 'big' package, 40 | which provides a (less set-theoretical) view of bitsets. 41 | 42 | */ 43 | package bitset 44 | 45 | import ( 46 | "bytes" 47 | "fmt" 48 | "math" 49 | ) 50 | 51 | // Word size of a bit set 52 | const wordSize = uint(32) 53 | 54 | // Mask for cleaning last word 55 | const allBits uint32 = 0xffffffff 56 | 57 | // for laster arith. 58 | const log2WordSize = uint(5) 59 | 60 | // The zero value of a BitSet is an empty set of length 0. 61 | type BitSet struct { 62 | length uint 63 | set []uint32 64 | } 65 | 66 | type BitSetError string 67 | 68 | // fixup b.set to be non-nil and return the field value 69 | func (b *BitSet) safeSet() []uint32 { 70 | if b.set == nil { 71 | b.set = make([]uint32, wordsNeeded(0)) 72 | } 73 | return b.set 74 | } 75 | 76 | func wordsNeeded(i uint) uint { 77 | if i == math.MaxUint32 { 78 | return math.MaxUint32 >> log2WordSize 79 | } else if i == 0 { 80 | return 1 81 | } 82 | return (i + (wordSize - 1)) >> log2WordSize 83 | } 84 | 85 | func New(length uint) *BitSet { 86 | return &BitSet{length, make([]uint32, wordsNeeded(length))} 87 | } 88 | 89 | func (b *BitSet) Cap() uint { 90 | return uint(math.MaxUint32) 91 | } 92 | 93 | func (b *BitSet) Len() uint { 94 | return b.length 95 | } 96 | 97 | // 98 | func (b *BitSet) extendSetMaybe(i uint) { 99 | if i >= b.length { // if we need more bits, make 'em 100 | nsize := wordsNeeded(i + 1) 101 | if b.set == nil { 102 | b.set = make([]uint32, nsize) 103 | } else if uint(len(b.set)) < nsize { 104 | newset := make([]uint32, nsize) 105 | copy(newset, b.set) 106 | b.set = newset 107 | } 108 | b.length = i+1 109 | } 110 | } 111 | 112 | /// Test whether bit i is set. 113 | func (b *BitSet) Test(i uint) bool { 114 | if i >= b.length { 115 | return false 116 | } 117 | return ((b.set[i>>log2WordSize] & (1 << (i & (wordSize - 1)))) != 0) 118 | } 119 | 120 | // Set bit i to 1 121 | func (b *BitSet) Set(i uint) *BitSet { 122 | b.extendSetMaybe(i) 123 | //fmt.Printf("length in bits: %d, real size of sets: %d, bits: %d, index: %d\n", b.length, len(b.set), i, i>>log2WordSize) 124 | b.set[i>>log2WordSize] |= (1 << (i & (wordSize - 1))) 125 | return b 126 | } 127 | 128 | // Clear bit i to 0 129 | func (b *BitSet) Clear(i uint) *BitSet { 130 | if i >= b.length { 131 | return b 132 | } 133 | b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1)) 134 | return b 135 | } 136 | 137 | // Set bit i to value 138 | func (b *BitSet) SetTo(i uint, value bool) *BitSet { 139 | if value { 140 | return b.Set(i) 141 | } 142 | return b.Clear(i) 143 | } 144 | 145 | // Flip bit at i 146 | func (b *BitSet) Flip(i uint) *BitSet { 147 | if i >= b.length { 148 | return b.Set(i) 149 | } 150 | b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1)) 151 | return b 152 | } 153 | 154 | // Clear entire BitSet 155 | func (b *BitSet) ClearAll() *BitSet { 156 | if b != nil && b.set != nil { 157 | for i := range b.set { 158 | b.set[i] = 0 159 | } 160 | } 161 | return b 162 | } 163 | 164 | // Query words used in a bit set 165 | func (b *BitSet) wordCount() uint { 166 | return wordsNeeded(b.length) 167 | } 168 | 169 | // Clone this BitSet 170 | func (b *BitSet) Clone() *BitSet { 171 | c := New(b.length) 172 | copy(c.set, b.safeSet()) 173 | return c 174 | } 175 | 176 | // Copy this BitSet into a destination BitSet 177 | // Returning the size of the destination BitSet 178 | // like array copy 179 | func (b *BitSet) Copy(c *BitSet) (count uint) { 180 | if c == nil { 181 | return 182 | } 183 | copy(c.set, b.safeSet()) 184 | count = c.length 185 | if b.length < c.length { 186 | count = b.length 187 | } 188 | return 189 | } 190 | 191 | // From Wikipedia: http://en.wikipedia.org/wiki/Hamming_weight 192 | const m1 uint32 = 0x55555555 //binary: 0101... 193 | const m2 uint32 = 0x33333333 //binary: 00110011.. 194 | const m4 uint32 = 0x0f0f0f0f //binary: 4 zeros, 4 ones ... 195 | 196 | // From Wikipedia: count number of set bits. 197 | // This is algorithm popcount_2 in the article retrieved May 9, 2011 198 | func popCountUint32(x uint32) uint32 { 199 | x -= (x >> 1) & m1 //put count of each 2 bits into those 2 bits 200 | x = (x & m2) + ((x >> 2) & m2) //put count of each 4 bits into those 4 bits 201 | x = (x + (x >> 4)) & m4 //put count of each 8 bits into those 8 bits 202 | x += x >> 8 //put count of each 16 bits into their lowest 8 bits 203 | x += x >> 16 //put count of each 32 bits into their lowest 8 bits 204 | //x += x >> 32; //put count of each 64 bits into their lowest 8 bits 205 | return x & 0x7f 206 | } 207 | 208 | // Count (number of set bits) 209 | func (b *BitSet) Count() uint { 210 | if b != nil && b.set != nil { 211 | cnt := uint32(0) 212 | for _, word := range b.set { 213 | cnt += popCountUint32(word) 214 | } 215 | return uint(cnt) 216 | } 217 | return 0 218 | } 219 | 220 | // Test the equvalence of two BitSets. 221 | // False if they are of different sizes, otherwise true 222 | // only if all the same bits are set 223 | func (b *BitSet) Equal(c *BitSet) bool { 224 | if c == nil { 225 | return false 226 | } 227 | if b.length != c.length { 228 | return false 229 | } 230 | for p, v := range b.safeSet() { 231 | if c.set[p] != v { 232 | return false 233 | } 234 | } 235 | return true 236 | } 237 | 238 | func panicIfNull(b *BitSet) { 239 | if b == nil { 240 | panic(BitSetError("BitSet must not be null")) 241 | } 242 | } 243 | 244 | // Difference of base set and other set 245 | // This is the BitSet equivalent of &^ (and not) 246 | func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { 247 | panicIfNull(b) 248 | panicIfNull(compare) 249 | result = b.Clone() // clone b (in case b is bigger than compare) 250 | szl := compare.wordCount() 251 | for i, word := range b.safeSet() { 252 | if uint(i) >= szl { 253 | break 254 | } 255 | result.set[i] = word &^ compare.set[i] 256 | } 257 | return 258 | } 259 | 260 | // Convenience function: return two bitsets ordered by 261 | // increasing length. Note: neither can be nil 262 | func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { 263 | if a.length <= b.length { 264 | ap, bp = a, b 265 | } else { 266 | ap, bp = b, a 267 | } 268 | return 269 | } 270 | 271 | // Intersection of base set and other set 272 | // This is the BitSet equivalent of & (and) 273 | func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { 274 | panicIfNull(b) 275 | panicIfNull(compare) 276 | b, compare = sortByLength(b, compare) 277 | result = New(b.length) 278 | for i, word := range b.safeSet() { 279 | result.set[i] = word & compare.set[i] 280 | } 281 | return 282 | } 283 | 284 | // Union of base set and other set 285 | // This is the BitSet equivalent of | (or) 286 | func (b *BitSet) Union(compare *BitSet) (result *BitSet) { 287 | panicIfNull(b) 288 | panicIfNull(compare) 289 | b, compare = sortByLength(b, compare) 290 | result = compare.Clone() 291 | szl := compare.wordCount() 292 | for i, word := range b.safeSet() { 293 | if uint(i) >= szl { 294 | break 295 | } 296 | result.set[i] = word | compare.set[i] 297 | } 298 | return 299 | } 300 | 301 | // SymmetricDifference of base set and other set 302 | // This is the BitSet equivalent of ^ (xor) 303 | func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { 304 | panicIfNull(b) 305 | panicIfNull(compare) 306 | b, compare = sortByLength(b, compare) 307 | // compare is bigger, so clone it 308 | result = compare.Clone() 309 | szl := b.wordCount() 310 | for i, word := range b.safeSet() { 311 | if uint(i) >= szl { 312 | break 313 | } 314 | result.set[i] = word ^ compare.set[i] 315 | } 316 | return 317 | } 318 | 319 | // Is the length an exact multiple of word sizes? 320 | func (b *BitSet) isEven() bool { 321 | return (b.length % wordSize) == 0 322 | } 323 | 324 | // Clean last word by setting unused bits to 0 325 | func (b *BitSet) cleanLastWord() { 326 | if !b.isEven() { 327 | b.set[wordsNeeded(b.length)-1] &= (allBits >> (wordSize - (b.length % wordSize))) 328 | } 329 | } 330 | 331 | // Return the (local) Complement of a biset (up to length bits) 332 | func (b *BitSet) Complement() (result *BitSet) { 333 | panicIfNull(b) 334 | result = New(b.length) 335 | for i, word := range b.safeSet() { 336 | result.set[i] = ^(word) 337 | } 338 | result.cleanLastWord() 339 | return 340 | } 341 | 342 | // Returns true if all bits are set, false otherwise 343 | func (b *BitSet) All() bool { 344 | panicIfNull(b) 345 | return b.Count() == b.length 346 | } 347 | 348 | // Return true if no bit is set, false otherwise 349 | func (b *BitSet) None() bool { 350 | panicIfNull(b) 351 | if b != nil && b.set != nil { 352 | for _, word := range b.set { 353 | if word > 0 { 354 | return false 355 | } 356 | } 357 | return true 358 | } 359 | return true 360 | } 361 | 362 | // Return true if any bit is set, false otherwise 363 | func (b *BitSet) Any() bool { 364 | panicIfNull(b) 365 | return !b.None() 366 | } 367 | 368 | // Dump as bits 369 | func (b *BitSet) DumpAsBits() string { 370 | buffer := bytes.NewBufferString("") 371 | b.safeSet() 372 | i := int(wordsNeeded(b.length) - 1) 373 | for ; i >= 0; i-- { 374 | fmt.Fprintf(buffer, "%032b.", b.set[i]) 375 | } 376 | return string(buffer.Bytes()) 377 | } 378 | -------------------------------------------------------------------------------- /bitset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Will Fitzgerald. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file tests bit sets 6 | 7 | package bitset 8 | 9 | import ( 10 | "math" 11 | "math/rand" 12 | "testing" 13 | ) 14 | 15 | func TestEmptyBitSet(t *testing.T) { 16 | defer func() { 17 | if r := recover(); r != nil { 18 | t.Error("A zero-length bitset should be fine") 19 | } 20 | }() 21 | b := New(0) 22 | if b.Len() != 0 { 23 | t.Errorf("Empty set should have capacity 0, not %d", b.Cap()) 24 | } 25 | } 26 | 27 | func TestZeroValueBitSet(t *testing.T) { 28 | defer func() { 29 | if r := recover(); r != nil { 30 | t.Error("A zero-length bitset should be fine") 31 | } 32 | }() 33 | var b BitSet 34 | if b.Len() != 0 { 35 | t.Errorf("Empty set should have capacity 0, not %d", b.Cap()) 36 | } 37 | } 38 | 39 | func TestBitSetNew(t *testing.T) { 40 | v := New(16) 41 | if v.Test(0) != false { 42 | t.Errorf("Unable to make a bit set and read its 0th value.") 43 | } 44 | } 45 | 46 | func TestBitSetHuge(t *testing.T) { 47 | v := New(uint(math.MaxUint32)) 48 | if v.Test(0) != false { 49 | t.Errorf("Unable to make a huge bit set and read its 0th value.") 50 | } 51 | } 52 | 53 | func TestCap(t *testing.T) { 54 | v := New(1000) 55 | if v.Cap() != uint(math.MaxUint32) { 56 | t.Errorf("Cap should be MaxUint32, but is %d.", v.Cap()) 57 | } 58 | } 59 | 60 | func TestLen(t *testing.T) { 61 | v := New(1000) 62 | if v.Len() != 1000 { 63 | t.Errorf("Len should be 1000, but is %d.", v.Cap()) 64 | } 65 | } 66 | 67 | func TestBitSetIsClear(t *testing.T) { 68 | v := New(1000) 69 | for i := uint(0); i < 1000; i++ { 70 | if v.Test(i) != false { 71 | t.Errorf("Bit %d is set, and it shouldn't be.", i) 72 | } 73 | } 74 | } 75 | 76 | func TestExendOnBoundary(t *testing.T) { 77 | v := New(32) 78 | defer func() { 79 | if r := recover(); r != nil { 80 | t.Error("Border out of index error should not have caused a panic") 81 | } 82 | }() 83 | v.Set(32) 84 | } 85 | 86 | func TestExpand(t *testing.T) { 87 | v := New(0) 88 | defer func() { 89 | if r := recover(); r != nil { 90 | t.Error("Expansion should not have caused a panic") 91 | } 92 | }() 93 | for i := uint(0); i < 1000; i++ { 94 | v.Set(i) 95 | } 96 | } 97 | 98 | func TestBitSetAndGet(t *testing.T) { 99 | v := New(1000) 100 | v.Set(100) 101 | if v.Test(100) != true { 102 | t.Errorf("Bit %d is clear, and it shouldn't be.", 100) 103 | } 104 | } 105 | 106 | func TestSetTo(t *testing.T) { 107 | v := New(1000) 108 | v.SetTo(100, true) 109 | if v.Test(100) != true { 110 | t.Errorf("Bit %d is clear, and it shouldn't be.", 100) 111 | } 112 | v.SetTo(100, false) 113 | if v.Test(100) != false { 114 | t.Errorf("Bit %d is set, and it shouldn't be.", 100) 115 | } 116 | } 117 | 118 | func TestChain(t *testing.T) { 119 | if New(1000).Set(100).Set(99).Clear(99).Test(100) != true { 120 | t.Errorf("Bit %d is clear, and it shouldn't be.", 100) 121 | } 122 | } 123 | 124 | func TestOutOfBoundsLong(t *testing.T) { 125 | v := New(64) 126 | defer func() { 127 | if r := recover(); r != nil { 128 | t.Error("Long distance out of index error should not have caused a panic") 129 | } 130 | }() 131 | v.Set(1000) 132 | } 133 | 134 | func TestOutOfBoundsClose(t *testing.T) { 135 | v := New(65) 136 | defer func() { 137 | if r := recover(); r != nil { 138 | t.Error("Local out of index error should not have caused a panic") 139 | } 140 | }() 141 | v.Set(66) 142 | } 143 | 144 | func TestCount(t *testing.T) { 145 | tot := uint(64*4 + 11) // just some multi unit64 number 146 | v := New(tot) 147 | checkLast := true 148 | for i := uint(0); i < tot; i++ { 149 | sz := v.Count() 150 | if sz != i { 151 | t.Errorf("Count reported as %d, but it should be %d", sz, i) 152 | checkLast = false 153 | break 154 | } 155 | v.Set(i) 156 | } 157 | if checkLast { 158 | sz := v.Count() 159 | if sz != tot { 160 | t.Errorf("After all bits set, size reported as %d, but it should be %d", sz, tot) 161 | } 162 | } 163 | } 164 | 165 | // test setting every 3rd bit, just in case something odd is happening 166 | func TestCount2(t *testing.T) { 167 | tot := uint(64*4 + 11) // just some multi unit64 number 168 | v := New(tot) 169 | for i := uint(0); i < tot; i += 3 { 170 | sz := v.Count() 171 | if sz != i/3 { 172 | t.Errorf("Count reported as %d, but it should be %d", sz, i) 173 | break 174 | } 175 | v.Set(i) 176 | } 177 | } 178 | 179 | // nil tests 180 | 181 | func TestNullTest(t *testing.T) { 182 | var v *BitSet = nil 183 | defer func() { 184 | if r := recover(); r == nil { 185 | t.Error("Checking bit of null reference should have caused a panic") 186 | } 187 | }() 188 | v.Test(66) 189 | } 190 | 191 | func TestNullSet(t *testing.T) { 192 | var v *BitSet = nil 193 | defer func() { 194 | if r := recover(); r == nil { 195 | t.Error("Setting bit of null reference should have caused a panic") 196 | } 197 | }() 198 | v.Set(66) 199 | } 200 | 201 | func TestNullClear(t *testing.T) { 202 | var v *BitSet = nil 203 | defer func() { 204 | if r := recover(); r == nil { 205 | t.Error("Clearning bit of null reference should have caused a panic") 206 | } 207 | }() 208 | v.Clear(66) 209 | } 210 | 211 | func TestNullCount(t *testing.T) { 212 | var v *BitSet = nil 213 | defer func() { 214 | if r := recover(); r != nil { 215 | t.Error("Counting null reference should not have caused a panic") 216 | } 217 | }() 218 | cnt := v.Count() 219 | if cnt != 0 { 220 | t.Errorf("Count reported as %d, but it should be 0", cnt) 221 | } 222 | } 223 | 224 | func TestPanicDifferenceBNil(t *testing.T) { 225 | var b *BitSet = nil 226 | var compare = New(10) 227 | defer func() { 228 | if r := recover(); r == nil { 229 | t.Error("Nil First should should have caused a panic") 230 | } 231 | }() 232 | b.Difference(compare) 233 | } 234 | 235 | func TestPanicDifferenceCompareNil(t *testing.T) { 236 | var compare *BitSet = nil 237 | var b = New(10) 238 | defer func() { 239 | if r := recover(); r == nil { 240 | t.Error("Nil Second should should have caused a panic") 241 | } 242 | }() 243 | b.Difference(compare) 244 | } 245 | 246 | func TestPanicUnionBNil(t *testing.T) { 247 | var b *BitSet = nil 248 | var compare = New(10) 249 | defer func() { 250 | if r := recover(); r == nil { 251 | t.Error("Nil First should should have caused a panic") 252 | } 253 | }() 254 | b.Union(compare) 255 | } 256 | 257 | func TestPanicUnionCompareNil(t *testing.T) { 258 | var compare *BitSet = nil 259 | var b = New(10) 260 | defer func() { 261 | if r := recover(); r == nil { 262 | t.Error("Nil Second should should have caused a panic") 263 | } 264 | }() 265 | b.Union(compare) 266 | } 267 | 268 | func TestPanicIntersectionBNil(t *testing.T) { 269 | var b *BitSet = nil 270 | var compare = New(10) 271 | defer func() { 272 | if r := recover(); r == nil { 273 | t.Error("Nil First should should have caused a panic") 274 | } 275 | }() 276 | b.Intersection(compare) 277 | } 278 | 279 | func TestPanicIntersectionCompareNil(t *testing.T) { 280 | var compare *BitSet = nil 281 | var b = New(10) 282 | defer func() { 283 | if r := recover(); r == nil { 284 | t.Error("Nil Second should should have caused a panic") 285 | } 286 | }() 287 | b.Intersection(compare) 288 | } 289 | 290 | func TestPanicSymmetricDifferenceBNil(t *testing.T) { 291 | var b *BitSet = nil 292 | var compare = New(10) 293 | defer func() { 294 | if r := recover(); r == nil { 295 | t.Error("Nil First should should have caused a panic") 296 | } 297 | }() 298 | b.SymmetricDifference(compare) 299 | } 300 | 301 | func TestPanicSymmetricDifferenceCompareNil(t *testing.T) { 302 | var compare *BitSet = nil 303 | var b = New(10) 304 | defer func() { 305 | if r := recover(); r == nil { 306 | t.Error("Nil Second should should have caused a panic") 307 | } 308 | }() 309 | b.SymmetricDifference(compare) 310 | } 311 | 312 | func TestPanicComplementBNil(t *testing.T) { 313 | var b *BitSet = nil 314 | defer func() { 315 | if r := recover(); r == nil { 316 | t.Error("Nil should should have caused a panic") 317 | } 318 | }() 319 | b.Complement() 320 | } 321 | 322 | func TestPanicAnytBNil(t *testing.T) { 323 | var b *BitSet = nil 324 | defer func() { 325 | if r := recover(); r == nil { 326 | t.Error("Nil should should have caused a panic") 327 | } 328 | }() 329 | b.Any() 330 | } 331 | 332 | func TestPanicNonetBNil(t *testing.T) { 333 | var b *BitSet = nil 334 | defer func() { 335 | if r := recover(); r == nil { 336 | t.Error("Nil should should have caused a panic") 337 | } 338 | }() 339 | b.None() 340 | } 341 | 342 | func TestPanicAlltBNil(t *testing.T) { 343 | var b *BitSet = nil 344 | defer func() { 345 | if r := recover(); r == nil { 346 | t.Error("Nil should should have caused a panic") 347 | } 348 | }() 349 | b.All() 350 | } 351 | 352 | func TestEqual(t *testing.T) { 353 | a := New(100) 354 | b := New(99) 355 | c := New(100) 356 | if a.Equal(b) { 357 | t.Error("Sets of different sizes should be not be equal") 358 | } 359 | if !a.Equal(c) { 360 | t.Error("Two empty sets of the same size should be equal") 361 | } 362 | a.Set(99) 363 | c.Set(0) 364 | if a.Equal(c) { 365 | t.Error("Two sets with differences should not be equal") 366 | } 367 | c.Set(99) 368 | a.Set(0) 369 | if !a.Equal(c) { 370 | t.Error("Two sets with the same bits set should be equal") 371 | } 372 | } 373 | 374 | func TestUnion(t *testing.T) { 375 | a := New(100) 376 | b := New(200) 377 | for i := uint(1); i < 100; i += 2 { 378 | a.Set(i) 379 | b.Set(i - 1) 380 | } 381 | for i := uint(100); i < 200; i++ { 382 | b.Set(i) 383 | } 384 | c := a.Union(b) 385 | d := b.Union(a) 386 | if c.Count() != 200 { 387 | t.Errorf("Union should have 200 bits set, but had %d", c.Count()) 388 | } 389 | if !c.Equal(d) { 390 | t.Errorf("Union should be symmetric") 391 | } 392 | } 393 | 394 | func TestIntersection(t *testing.T) { 395 | a := New(100) 396 | b := New(200) 397 | for i := uint(1); i < 100; i += 2 { 398 | a.Set(i) 399 | b.Set(i - 1).Set(i) 400 | } 401 | for i := uint(100); i < 200; i++ { 402 | b.Set(i) 403 | } 404 | c := a.Intersection(b) 405 | d := b.Intersection(a) 406 | if c.Count() != 50 { 407 | t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) 408 | } 409 | if !c.Equal(d) { 410 | t.Errorf("Intersection should be symmetric") 411 | } 412 | } 413 | 414 | func TestDifference(t *testing.T) { 415 | a := New(100) 416 | b := New(200) 417 | for i := uint(1); i < 100; i += 2 { 418 | a.Set(i) 419 | b.Set(i - 1) 420 | } 421 | for i := uint(100); i < 200; i++ { 422 | b.Set(i) 423 | } 424 | c := a.Difference(b) 425 | d := b.Difference(a) 426 | if c.Count() != 50 { 427 | t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) 428 | } 429 | if d.Count() != 150 { 430 | t.Errorf("b-a Difference should have 150 bits set, but had %d", c.Count()) 431 | } 432 | if c.Equal(d) { 433 | t.Errorf("Difference, here, should not be symmetric") 434 | } 435 | } 436 | 437 | func TestSymmetricDifference(t *testing.T) { 438 | a := New(100) 439 | b := New(200) 440 | for i := uint(1); i < 100; i += 2 { 441 | a.Set(i) // 01010101010 ... 0000000 442 | b.Set(i - 1).Set(i) // 11111111111111111000000 443 | } 444 | for i := uint(100); i < 200; i++ { 445 | b.Set(i) 446 | } 447 | c := a.SymmetricDifference(b) 448 | d := b.SymmetricDifference(a) 449 | if c.Count() != 150 { 450 | t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) 451 | } 452 | if d.Count() != 150 { 453 | t.Errorf("b^a Difference should have 150 bits set, but had %d", c.Count()) 454 | } 455 | if !c.Equal(d) { 456 | t.Errorf("SymmetricDifference should be symmetric") 457 | } 458 | } 459 | 460 | func TestComplement(t *testing.T) { 461 | a := New(50) 462 | b := a.Complement() 463 | if b.Count() != 50 { 464 | t.Errorf("Complement failed, size should be 50, but was %d", b.Count()) 465 | } 466 | a = New(50) 467 | a.Set(10).Set(20).Set(42) 468 | b = a.Complement() 469 | if b.Count() != 47 { 470 | t.Errorf("Complement failed, size should be 47, but was %d", b.Count()) 471 | } 472 | } 473 | 474 | func TestDumpAsBits(t *testing.T) { 475 | a := New(10).Set(10) 476 | astr := "00000000000000000000010000000000." 477 | if a.DumpAsBits() != astr { 478 | t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", astr, a.DumpAsBits()) 479 | } 480 | var b BitSet // zero value (b.set == nil) 481 | bstr := "00000000000000000000000000000000." 482 | if b.DumpAsBits() != bstr { 483 | t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", bstr, b.DumpAsBits()) 484 | } 485 | } 486 | 487 | // BENCHMARKS 488 | 489 | func BenchmarkSet(b *testing.B) { 490 | b.StopTimer() 491 | r := rand.New(rand.NewSource(0)) 492 | sz := 100000 493 | s := New(uint(sz)) 494 | b.StartTimer() 495 | for i := 0; i < b.N; i++ { 496 | s.Set(uint(r.Int31n(int32(sz)))) 497 | } 498 | } 499 | 500 | func BenchmarkGetTest(b *testing.B) { 501 | b.StopTimer() 502 | r := rand.New(rand.NewSource(0)) 503 | sz := 100000 504 | s := New(uint(sz)) 505 | b.StartTimer() 506 | for i := 0; i < b.N; i++ { 507 | s.Test(uint(r.Int31n(int32(sz)))) 508 | } 509 | } 510 | 511 | func BenchmarkSetExpand(b *testing.B) { 512 | b.StopTimer() 513 | sz := uint(100000) 514 | b.StartTimer() 515 | for i := 0; i < b.N; i++ { 516 | var s BitSet 517 | s.Set(sz) 518 | } 519 | } 520 | --------------------------------------------------------------------------------