├── go.sum ├── go.mod ├── SECURITY.md ├── .github ├── FUNDING.yml ├── workflows │ ├── legacy86.yaml │ ├── test.yml │ └── scorecard.yml ├── dependabot.yml └── SECURITY.md ├── .gitignore ├── bitset_iter.go ├── .travis.yml ├── select.go ├── azure-pipelines.yml ├── popcnt_test.go ├── LICENSE ├── popcnt.go ├── bitset_iter_test.go ├── cmd └── pextgen │ └── main.go ├── README.md ├── bitset_benchmark_test.go ├── bitset.go └── bitset_test.go /go.sum: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bits-and-blooms/bitset 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | You can report privately a vulnerability by email at daniel@lemire.me (current maintainer). 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # You can add one username per supported platform and one custom link 2 | patreon: # Replace with your Patreon username 3 | open_collective: # Replace with your Open Collective username 4 | ko_fi: # Replace with your Ko-fi username 5 | custom: https://donate.mcc.org/ # Replace with your custom donation URL 6 | -------------------------------------------------------------------------------- /.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 23 | *.test 24 | *.prof 25 | 26 | target 27 | -------------------------------------------------------------------------------- /.github/workflows/legacy86.yaml: -------------------------------------------------------------------------------- 1 | name: Go-legacy-CI 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | go-version: ['1.20.x', '1.21.x'] 9 | steps: 10 | - name: Install Go 11 | uses: actions/setup-go@v5 12 | with: 13 | go-version: ${{ matrix.go-version }} 14 | - name: Checkout code 15 | uses: actions/checkout@v4 16 | - name: Test on 386 17 | run: | 18 | GOARCH=386 go test 19 | -------------------------------------------------------------------------------- /bitset_iter.go: -------------------------------------------------------------------------------- 1 | //go:build go1.23 2 | // +build go1.23 3 | 4 | package bitset 5 | 6 | import ( 7 | "iter" 8 | "math/bits" 9 | ) 10 | 11 | func (b *BitSet) EachSet() iter.Seq[uint] { 12 | return func(yield func(uint) bool) { 13 | for wordIndex, word := range b.set { 14 | idx := 0 15 | for trail := bits.TrailingZeros64(word); trail != 64; trail = bits.TrailingZeros64(word >> idx) { 16 | if !yield(uint(wordIndex<> 32 12 | seen += 32 13 | j -= n 14 | } 15 | ww := part 16 | 17 | // Divide 32bit 18 | part = ww & 0xFFFF 19 | 20 | n = uint(bits.OnesCount64(part)) 21 | if n <= j { 22 | part = ww >> 16 23 | seen += 16 24 | j -= n 25 | } 26 | ww = part 27 | 28 | // Divide 16bit 29 | part = ww & 0xFF 30 | n = uint(bits.OnesCount64(part)) 31 | if n <= j { 32 | part = ww >> 8 33 | seen += 8 34 | j -= n 35 | } 36 | ww = part 37 | 38 | // Lookup in final byte 39 | counter := 0 40 | for ; counter < 8; counter++ { 41 | j -= uint((ww >> counter) & 1) 42 | if j+1 == 0 { 43 | break 44 | } 45 | } 46 | return uint(seen + counter) 47 | } 48 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Security updates are applied only to the latest release. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. 10 | 11 | Please use the following contact information for reporting a vulnerability: 12 | 13 | - [Daniel Lemire](https://github.com/lemire) - [daniel@lemire.me](mailto:daniel@lemire.me) 14 | 15 | In your report, please include: 16 | 17 | - A description of the vulnerability and its impact 18 | - How to reproduce the it 19 | - Affected versions 20 | 21 | This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. 22 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Go 2 | # Build your Go project. 3 | # Add steps that test, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/go 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'Ubuntu-16.04' 11 | 12 | variables: 13 | GOBIN: '$(GOPATH)/bin' # Go binaries path 14 | GOROOT: '/usr/local/go1.11' # Go installation path 15 | GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path 16 | modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code 17 | 18 | steps: 19 | - script: | 20 | mkdir -p '$(GOBIN)' 21 | mkdir -p '$(GOPATH)/pkg' 22 | mkdir -p '$(modulePath)' 23 | shopt -s extglob 24 | shopt -s dotglob 25 | mv !(gopath) '$(modulePath)' 26 | echo '##vso[task.prependpath]$(GOBIN)' 27 | echo '##vso[task.prependpath]$(GOROOT)/bin' 28 | displayName: 'Set up the Go workspace' 29 | 30 | - script: | 31 | go version 32 | go get -v -t -d ./... 33 | if [ -f Gopkg.toml ]; then 34 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 35 | dep ensure 36 | fi 37 | go build -v . 38 | workingDirectory: '$(modulePath)' 39 | displayName: 'Get dependencies, then build' 40 | -------------------------------------------------------------------------------- /popcnt_test.go: -------------------------------------------------------------------------------- 1 | // This file tests the popcnt functions 2 | 3 | package bitset 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func TestPopcntSlice(t *testing.T) { 10 | s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} 11 | res := popcntSlice(s) 12 | const l uint64 = 27 13 | if res != l { 14 | t.Errorf("Wrong popcount %d != %d", res, l) 15 | } 16 | } 17 | 18 | func TestPopcntMaskSlice(t *testing.T) { 19 | s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} 20 | m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} 21 | res := popcntMaskSlice(s, m) 22 | const l uint64 = 9 23 | if res != l { 24 | t.Errorf("Wrong mask %d != %d", res, l) 25 | } 26 | } 27 | 28 | func TestPopcntAndSlice(t *testing.T) { 29 | s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} 30 | m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} 31 | res := popcntAndSlice(s, m) 32 | const l uint64 = 18 33 | if res != l { 34 | t.Errorf("Wrong And %d != %d", res, l) 35 | } 36 | } 37 | 38 | func TestPopcntOrSlice(t *testing.T) { 39 | s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} 40 | m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} 41 | res := popcntOrSlice(s, m) 42 | const l uint64 = 50 43 | if res != l { 44 | t.Errorf("Wrong OR %d != %d", res, l) 45 | } 46 | } 47 | 48 | func TestPopcntXorSlice(t *testing.T) { 49 | s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} 50 | m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} 51 | res := popcntXorSlice(s, m) 52 | const l uint64 = 32 53 | if res != l { 54 | t.Errorf("Wrong OR %d != %d", res, l) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Will Fitzgerald. 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 | -------------------------------------------------------------------------------- /popcnt.go: -------------------------------------------------------------------------------- 1 | package bitset 2 | 3 | import "math/bits" 4 | 5 | func popcntSlice(s []uint64) (cnt uint64) { 6 | for _, x := range s { 7 | cnt += uint64(bits.OnesCount64(x)) 8 | } 9 | return 10 | } 11 | 12 | func popcntMaskSlice(s, m []uint64) (cnt uint64) { 13 | // The next line is to help the bounds checker, it matters! 14 | _ = m[len(s)-1] // BCE 15 | for i := range s { 16 | cnt += uint64(bits.OnesCount64(s[i] &^ m[i])) 17 | } 18 | return 19 | } 20 | 21 | // popcntAndSlice computes the population count of the AND of two slices. 22 | // It assumes that len(m) >= len(s) > 0. 23 | func popcntAndSlice(s, m []uint64) (cnt uint64) { 24 | // The next line is to help the bounds checker, it matters! 25 | _ = m[len(s)-1] // BCE 26 | for i := range s { 27 | cnt += uint64(bits.OnesCount64(s[i] & m[i])) 28 | } 29 | return 30 | } 31 | 32 | // popcntOrSlice computes the population count of the OR of two slices. 33 | // It assumes that len(m) >= len(s) > 0. 34 | func popcntOrSlice(s, m []uint64) (cnt uint64) { 35 | // The next line is to help the bounds checker, it matters! 36 | _ = m[len(s)-1] // BCE 37 | for i := range s { 38 | cnt += uint64(bits.OnesCount64(s[i] | m[i])) 39 | } 40 | return 41 | } 42 | 43 | // popcntXorSlice computes the population count of the XOR of two slices. 44 | // It assumes that len(m) >= len(s) > 0. 45 | func popcntXorSlice(s, m []uint64) (cnt uint64) { 46 | // The next line is to help the bounds checker, it matters! 47 | _ = m[len(s)-1] // BCE 48 | for i := range s { 49 | cnt += uint64(bits.OnesCount64(s[i] ^ m[i])) 50 | } 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /bitset_iter_test.go: -------------------------------------------------------------------------------- 1 | //go:build go1.23 2 | // +build go1.23 3 | 4 | package bitset 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func TestIter(t *testing.T) { 11 | var b BitSet 12 | b.Set(0).Set(3).Set(5).Set(6).Set(63).Set(64).Set(65).Set(127).Set(128).Set(1000000) 13 | 14 | // Expected values that should be set 15 | expected := []uint{0, 3, 5, 6, 63, 64, 65, 127, 128, 1000000} 16 | got := make([]uint, 0) 17 | 18 | // Collect all values from iterator 19 | for i := range b.EachSet() { 20 | got = append(got, i) 21 | } 22 | 23 | // Test 1: Check length matches expected 24 | if len(got) != len(expected) { 25 | t.Errorf("Expected %d elements, got %d", len(expected), len(got)) 26 | } 27 | 28 | // Test 2: Check all expected values are present and in correct order 29 | for i, want := range expected { 30 | if i >= len(got) { 31 | t.Errorf("Missing expected value %d at position %d", want, i) 32 | continue 33 | } 34 | if got[i] != want { 35 | t.Errorf("At position %d: expected %d, got %d", i, want, got[i]) 36 | } 37 | } 38 | 39 | // Test 3: Check no extra values 40 | if len(got) > len(expected) { 41 | t.Errorf("Got extra values: %v", got[len(expected):]) 42 | } 43 | } 44 | func BenchmarkIter(b *testing.B) { 45 | b.StopTimer() 46 | s := New(10000) 47 | for i := 0; i < 10000; i += 3 { 48 | s.Set(uint(i)) 49 | } 50 | 51 | b.StartTimer() 52 | for j := 0; j < b.N; j++ { 53 | c := uint(0) 54 | for range s.EachSet() { 55 | c++ 56 | } 57 | } 58 | } 59 | 60 | func BenchmarkNonInter(b *testing.B) { 61 | b.StopTimer() 62 | s := New(10000) 63 | for i := 0; i < 10000; i += 3 { 64 | s.Set(uint(i)) 65 | } 66 | 67 | b.StartTimer() 68 | for j := 0; j < b.N; j++ { 69 | c := uint(0) 70 | for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { 71 | c++ 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '40 9 * * 2' 14 | push: 15 | branches: [ "master" ] 16 | 17 | # Declare default permissions as read only. 18 | permissions: read-all 19 | 20 | jobs: 21 | analysis: 22 | name: Scorecard analysis 23 | runs-on: ubuntu-latest 24 | permissions: 25 | # Needed to upload the results to code-scanning dashboard. 26 | security-events: write 27 | # Needed to publish results and get a badge (see publish_results below). 28 | id-token: write 29 | # Uncomment the permissions below if installing in a private repository. 30 | # contents: read 31 | # actions: read 32 | 33 | steps: 34 | - name: "Checkout code" 35 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 36 | with: 37 | persist-credentials: false 38 | 39 | - name: "Run analysis" 40 | uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 41 | with: 42 | results_file: results.sarif 43 | results_format: sarif 44 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 45 | # - you want to enable the Branch-Protection check on a *public* repository, or 46 | # - you are installing Scorecard on a *private* repository 47 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 48 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 49 | 50 | # Public repositories: 51 | # - Publish results to OpenSSF REST API for easy access by consumers 52 | # - Allows the repository to include the Scorecard badge. 53 | # - See https://github.com/ossf/scorecard-action#publishing-results. 54 | # For private repositories: 55 | # - `publish_results` will always be set to `false`, regardless 56 | # of the value entered here. 57 | publish_results: true 58 | 59 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 60 | # format to the repository Actions tab. 61 | - name: "Upload artifact" 62 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 63 | with: 64 | name: SARIF file 65 | path: results.sarif 66 | retention-days: 5 67 | 68 | # Upload the results to GitHub's code scanning dashboard. 69 | - name: "Upload to code-scanning" 70 | uses: github/codeql-action/upload-sarif@8e0b1c74b1d5a0077b04d064c76ee714d3da7637 # v2.14.6 71 | with: 72 | sarif_file: results.sarif 73 | -------------------------------------------------------------------------------- /cmd/pextgen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "go/format" 8 | "math/bits" 9 | "os" 10 | ) 11 | 12 | // pextByte handles single-byte PEXT operation 13 | func pextByte(b, m uint8) uint8 { 14 | var result, bitPos uint8 15 | for i := uint8(0); i < 8; i++ { 16 | if m&(1<Mastering Programming: From Testing to Performance in Go

176 |
177 | -------------------------------------------------------------------------------- /bitset_benchmark_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 | "bytes" 11 | "fmt" 12 | "math/bits" 13 | "math/rand" 14 | "testing" 15 | ) 16 | 17 | func BenchmarkSet(b *testing.B) { 18 | b.StopTimer() 19 | r := rand.New(rand.NewSource(0)) 20 | sz := 100000 21 | s := New(uint(sz)) 22 | b.StartTimer() 23 | for i := 0; i < b.N; i++ { 24 | s.Set(uint(r.Int31n(int32(sz)))) 25 | } 26 | } 27 | 28 | func BenchmarkGetTest(b *testing.B) { 29 | b.StopTimer() 30 | r := rand.New(rand.NewSource(0)) 31 | sz := 100000 32 | s := New(uint(sz)) 33 | b.StartTimer() 34 | for i := 0; i < b.N; i++ { 35 | s.Test(uint(r.Int31n(int32(sz)))) 36 | } 37 | } 38 | 39 | func BenchmarkSetExpand(b *testing.B) { 40 | b.StopTimer() 41 | sz := uint(100000) 42 | b.StartTimer() 43 | for i := 0; i < b.N; i++ { 44 | var s BitSet 45 | s.Set(sz) 46 | } 47 | } 48 | 49 | // go test -bench=Count 50 | func BenchmarkCount(b *testing.B) { 51 | b.StopTimer() 52 | s := New(100000) 53 | for i := 0; i < 100000; i += 100 { 54 | s.Set(uint(i)) 55 | } 56 | b.StartTimer() 57 | for i := 0; i < b.N; i++ { 58 | s.Count() 59 | } 60 | } 61 | 62 | // go test -bench=Iterate 63 | func BenchmarkIterate(b *testing.B) { 64 | b.StopTimer() 65 | s := New(10000) 66 | for i := 0; i < 10000; i += 3 { 67 | s.Set(uint(i)) 68 | } 69 | b.StartTimer() 70 | for j := 0; j < b.N; j++ { 71 | c := uint(0) 72 | for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { 73 | c++ 74 | } 75 | } 76 | } 77 | 78 | // go test -bench=SparseIterate 79 | func BenchmarkSparseIterate(b *testing.B) { 80 | b.StopTimer() 81 | s := New(100000) 82 | for i := 0; i < 100000; i += 30 { 83 | s.Set(uint(i)) 84 | } 85 | b.StartTimer() 86 | for j := 0; j < b.N; j++ { 87 | c := uint(0) 88 | for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { 89 | c++ 90 | } 91 | } 92 | } 93 | 94 | // go test -bench=BitsetOps 95 | func BenchmarkBitsetOps(b *testing.B) { 96 | // let's not write into s inside the benchmarks 97 | s := New(100000) 98 | for i := 0; i < 100000; i += 100 { 99 | s.Set(uint(i)) 100 | } 101 | cpy := s.Clone() 102 | 103 | b.Run("Equal", func(b *testing.B) { 104 | for i := 0; i < b.N; i++ { 105 | s.Equal(cpy) 106 | } 107 | }) 108 | 109 | b.Run("FlipRange", func(b *testing.B) { 110 | s = s.Clone() 111 | b.ResetTimer() 112 | for i := 0; i < b.N; i++ { 113 | s.FlipRange(0, 100000) 114 | } 115 | }) 116 | 117 | b.Run("NextSet", func(b *testing.B) { 118 | s = New(100000) 119 | b.ResetTimer() 120 | for i := 0; i < b.N; i++ { 121 | s.NextSet(0) 122 | } 123 | }) 124 | 125 | b.Run("NextClear", func(b *testing.B) { 126 | s = New(100000) 127 | s.FlipRange(0, 100000) 128 | b.ResetTimer() 129 | for i := 0; i < b.N; i++ { 130 | s.NextClear(0) 131 | } 132 | }) 133 | 134 | b.Run("PreviousSet", func(b *testing.B) { 135 | s = New(100000) 136 | b.ResetTimer() 137 | for i := 0; i < b.N; i++ { 138 | s.PreviousSet(99999) 139 | } 140 | }) 141 | 142 | b.Run("PreviousClear", func(b *testing.B) { 143 | s = New(100000) 144 | s.FlipRange(0, 100000) 145 | b.ResetTimer() 146 | for i := 0; i < b.N; i++ { 147 | s.PreviousClear(99999) 148 | } 149 | }) 150 | 151 | b.Run("DifferenceCardinality", func(b *testing.B) { 152 | empty := New(100000) 153 | b.ResetTimer() 154 | for i := 0; i < b.N; i++ { 155 | s.DifferenceCardinality(empty) 156 | } 157 | }) 158 | 159 | b.Run("InPlaceDifference", func(b *testing.B) { 160 | s = s.Clone() 161 | b.ResetTimer() 162 | for i := 0; i < b.N; i++ { 163 | s.InPlaceDifference(cpy) 164 | } 165 | }) 166 | 167 | b.Run("InPlaceUnion", func(b *testing.B) { 168 | s = s.Clone() 169 | b.ResetTimer() 170 | for i := 0; i < b.N; i++ { 171 | s.InPlaceUnion(cpy) 172 | } 173 | }) 174 | 175 | b.Run("InPlaceIntersection", func(b *testing.B) { 176 | s = s.Clone() 177 | b.ResetTimer() 178 | for i := 0; i < b.N; i++ { 179 | s.InPlaceIntersection(cpy) 180 | } 181 | }) 182 | 183 | b.Run("InPlaceSymmetricDifference", func(b *testing.B) { 184 | s = s.Clone() 185 | b.ResetTimer() 186 | for i := 0; i < b.N; i++ { 187 | s.InPlaceSymmetricDifference(cpy) 188 | } 189 | }) 190 | } 191 | 192 | // go test -bench=LemireCreate 193 | // see https://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ 194 | func BenchmarkLemireCreate(b *testing.B) { 195 | for i := 0; i < b.N; i++ { 196 | bitmap := New(0) // we force dynamic memory allocation 197 | for v := uint(0); v <= 100000000; v += 100 { 198 | bitmap.Set(v) 199 | } 200 | } 201 | } 202 | 203 | // go test -bench=LemireCount 204 | // see https://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ 205 | func BenchmarkLemireCount(b *testing.B) { 206 | bitmap := New(100000000) 207 | for v := uint(0); v <= 100000000; v += 100 { 208 | bitmap.Set(v) 209 | } 210 | b.ResetTimer() 211 | sum := uint(0) 212 | for i := 0; i < b.N; i++ { 213 | sum += bitmap.Count() 214 | } 215 | if sum == 0 { // added just to fool ineffassign 216 | return 217 | } 218 | } 219 | 220 | // go test -bench=LemireIterate 221 | // see https://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ 222 | func BenchmarkLemireIterate(b *testing.B) { 223 | bitmap := New(100000000) 224 | for v := uint(0); v <= 100000000; v += 100 { 225 | bitmap.Set(v) 226 | } 227 | b.ResetTimer() 228 | sum := uint(0) 229 | for i := 0; i < b.N; i++ { 230 | for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { 231 | sum++ 232 | } 233 | } 234 | if sum == 0 { // added just to fool ineffassign 235 | return 236 | } 237 | } 238 | 239 | // go test -bench=LemireIterateb 240 | // see https://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ 241 | func BenchmarkLemireIterateb(b *testing.B) { 242 | bitmap := New(100000000) 243 | for v := uint(0); v <= 100000000; v += 100 { 244 | bitmap.Set(v) 245 | } 246 | b.ResetTimer() 247 | sum := uint(0) 248 | for i := 0; i < b.N; i++ { 249 | for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { 250 | sum += j 251 | } 252 | } 253 | 254 | if sum == 0 { // added just to fool ineffassign 255 | return 256 | } 257 | } 258 | 259 | // go test -bench=BenchmarkLemireIterateManyb 260 | // see https://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ 261 | func BenchmarkLemireIterateManyb(b *testing.B) { 262 | bitmap := New(100000000) 263 | for v := uint(0); v <= 100000000; v += 100 { 264 | bitmap.Set(v) 265 | } 266 | buffer := make([]uint, 256) 267 | b.ResetTimer() 268 | sum := uint(0) 269 | for i := 0; i < b.N; i++ { 270 | j := uint(0) 271 | j, buffer = bitmap.NextSetMany(j, buffer) 272 | for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { 273 | for k := range buffer { 274 | sum += buffer[k] 275 | } 276 | j++ 277 | } 278 | } 279 | 280 | if sum == 0 { // added just to fool ineffassign 281 | return 282 | } 283 | } 284 | 285 | func setRnd(bits []uint64, halfings int) { 286 | rnd := rand.NewSource(0).(rand.Source64) 287 | for i := range bits { 288 | bits[i] = 0xFFFFFFFFFFFFFFFF 289 | for j := 0; j < halfings; j++ { 290 | bits[i] &= rnd.Uint64() 291 | } 292 | } 293 | } 294 | 295 | // go test -bench=BenchmarkFlorianUekermannIterateMany 296 | func BenchmarkFlorianUekermannIterateMany(b *testing.B) { 297 | input := make([]uint64, 68) 298 | setRnd(input, 4) 299 | bitmap := From(input) 300 | buffer := make([]uint, 256) 301 | b.ResetTimer() 302 | checksum := uint(0) 303 | for i := 0; i < b.N; i++ { 304 | last, batch := bitmap.NextSetMany(0, buffer) 305 | for len(batch) > 0 { 306 | for _, idx := range batch { 307 | checksum += idx 308 | } 309 | last, batch = bitmap.NextSetMany(last+1, batch) 310 | } 311 | } 312 | if checksum == 0 { // added just to fool ineffassign 313 | return 314 | } 315 | } 316 | 317 | func BenchmarkFlorianUekermannIterateManyReg(b *testing.B) { 318 | input := make([]uint64, 68) 319 | setRnd(input, 4) 320 | bitmap := From(input) 321 | b.ResetTimer() 322 | checksum := uint(0) 323 | for i := 0; i < b.N; i++ { 324 | for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { 325 | checksum += j 326 | } 327 | } 328 | if checksum == 0 { // added just to fool ineffassign 329 | return 330 | } 331 | } 332 | 333 | // function provided by FlorianUekermann 334 | func good(set []uint64) (checksum uint) { 335 | for wordIdx, word := range set { 336 | wordIdx := uint(wordIdx * 64) 337 | for word != 0 { 338 | bitIdx := uint(bits.TrailingZeros64(word)) 339 | word ^= 1 << bitIdx 340 | index := wordIdx + bitIdx 341 | checksum += index 342 | } 343 | } 344 | return checksum 345 | } 346 | 347 | func BenchmarkFlorianUekermannIterateManyComp(b *testing.B) { 348 | input := make([]uint64, 68) 349 | setRnd(input, 4) 350 | b.ResetTimer() 351 | checksum := uint(0) 352 | for i := 0; i < b.N; i++ { 353 | checksum += good(input) 354 | } 355 | if checksum == 0 { // added just to fool ineffassign 356 | return 357 | } 358 | } 359 | 360 | /////// Mid density 361 | 362 | // go test -bench=BenchmarkFlorianUekermannLowDensityIterateMany 363 | func BenchmarkFlorianUekermannLowDensityIterateMany(b *testing.B) { 364 | input := make([]uint64, 1000000) 365 | rnd := rand.NewSource(0).(rand.Source64) 366 | for i := 0; i < 50000; i++ { 367 | input[rnd.Uint64()%1000000] = 1 368 | } 369 | bitmap := From(input) 370 | buffer := make([]uint, 256) 371 | b.ResetTimer() 372 | sum := uint(0) 373 | for i := 0; i < b.N; i++ { 374 | j := uint(0) 375 | j, buffer = bitmap.NextSetMany(j, buffer) 376 | for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { 377 | for k := range buffer { 378 | sum += buffer[k] 379 | } 380 | j++ 381 | } 382 | } 383 | if sum == 0 { // added just to fool ineffassign 384 | return 385 | } 386 | } 387 | 388 | func BenchmarkFlorianUekermannLowDensityIterateManyReg(b *testing.B) { 389 | input := make([]uint64, 1000000) 390 | rnd := rand.NewSource(0).(rand.Source64) 391 | for i := 0; i < 50000; i++ { 392 | input[rnd.Uint64()%1000000] = 1 393 | } 394 | bitmap := From(input) 395 | b.ResetTimer() 396 | checksum := uint(0) 397 | for i := 0; i < b.N; i++ { 398 | for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { 399 | checksum += j 400 | } 401 | } 402 | if checksum == 0 { // added just to fool ineffassign 403 | return 404 | } 405 | } 406 | 407 | func BenchmarkFlorianUekermannLowDensityIterateManyComp(b *testing.B) { 408 | input := make([]uint64, 1000000) 409 | rnd := rand.NewSource(0).(rand.Source64) 410 | for i := 0; i < 50000; i++ { 411 | input[rnd.Uint64()%1000000] = 1 412 | } 413 | b.ResetTimer() 414 | checksum := uint(0) 415 | for i := 0; i < b.N; i++ { 416 | checksum += good(input) 417 | } 418 | if checksum == 0 { // added just to fool ineffassign 419 | return 420 | } 421 | } 422 | 423 | /////// Mid density 424 | 425 | // go test -bench=BenchmarkFlorianUekermannMidDensityIterateMany 426 | func BenchmarkFlorianUekermannMidDensityIterateMany(b *testing.B) { 427 | input := make([]uint64, 1000000) 428 | rnd := rand.NewSource(0).(rand.Source64) 429 | for i := 0; i < 3000000; i++ { 430 | input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) 431 | } 432 | bitmap := From(input) 433 | buffer := make([]uint, 256) 434 | b.ResetTimer() 435 | sum := uint(0) 436 | for i := 0; i < b.N; i++ { 437 | j := uint(0) 438 | j, buffer = bitmap.NextSetMany(j, buffer) 439 | for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { 440 | for k := range buffer { 441 | sum += buffer[k] 442 | } 443 | j++ 444 | } 445 | } 446 | 447 | if sum == 0 { // added just to fool ineffassign 448 | return 449 | } 450 | } 451 | 452 | func BenchmarkFlorianUekermannMidDensityIterateManyReg(b *testing.B) { 453 | input := make([]uint64, 1000000) 454 | rnd := rand.NewSource(0).(rand.Source64) 455 | for i := 0; i < 3000000; i++ { 456 | input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) 457 | } 458 | bitmap := From(input) 459 | b.ResetTimer() 460 | checksum := uint(0) 461 | for i := 0; i < b.N; i++ { 462 | for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { 463 | checksum += j 464 | } 465 | } 466 | if checksum == 0 { // added just to fool ineffassign 467 | return 468 | } 469 | } 470 | 471 | func BenchmarkFlorianUekermannMidDensityIterateManyComp(b *testing.B) { 472 | input := make([]uint64, 1000000) 473 | rnd := rand.NewSource(0).(rand.Source64) 474 | for i := 0; i < 3000000; i++ { 475 | input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) 476 | } 477 | b.ResetTimer() 478 | checksum := uint(0) 479 | for i := 0; i < b.N; i++ { 480 | checksum += good(input) 481 | } 482 | if checksum == 0 { // added just to fool ineffassign 483 | return 484 | } 485 | } 486 | 487 | ////////// High density 488 | 489 | func BenchmarkFlorianUekermannMidStrongDensityIterateMany(b *testing.B) { 490 | input := make([]uint64, 1000000) 491 | rnd := rand.NewSource(0).(rand.Source64) 492 | for i := 0; i < 20000000; i++ { 493 | input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) 494 | } 495 | bitmap := From(input) 496 | buffer := make([]uint, 256) 497 | b.ResetTimer() 498 | sum := uint(0) 499 | for i := 0; i < b.N; i++ { 500 | j := uint(0) 501 | j, buffer = bitmap.NextSetMany(j, buffer) 502 | for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { 503 | for k := range buffer { 504 | sum += buffer[k] 505 | } 506 | j++ 507 | } 508 | } 509 | 510 | if sum == 0 { // added just to fool ineffassign 511 | return 512 | } 513 | } 514 | 515 | func BenchmarkFlorianUekermannMidStrongDensityIterateManyReg(b *testing.B) { 516 | input := make([]uint64, 1000000) 517 | rnd := rand.NewSource(0).(rand.Source64) 518 | for i := 0; i < 20000000; i++ { 519 | input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) 520 | } 521 | bitmap := From(input) 522 | b.ResetTimer() 523 | checksum := uint(0) 524 | for i := 0; i < b.N; i++ { 525 | for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { 526 | checksum += j 527 | } 528 | } 529 | if checksum == 0 { // added just to fool ineffassign 530 | return 531 | } 532 | } 533 | 534 | func BenchmarkFlorianUekermannMidStrongDensityIterateManyComp(b *testing.B) { 535 | input := make([]uint64, 1000000) 536 | rnd := rand.NewSource(0).(rand.Source64) 537 | for i := 0; i < 20000000; i++ { 538 | input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) 539 | } 540 | b.ResetTimer() 541 | checksum := uint(0) 542 | for i := 0; i < b.N; i++ { 543 | checksum += good(input) 544 | } 545 | if checksum == 0 { // added just to fool ineffassign 546 | return 547 | } 548 | } 549 | 550 | func BenchmarkBitsetReadWrite(b *testing.B) { 551 | s := New(100000) 552 | for i := 0; i < 100000; i += 100 { 553 | s.Set(uint(i)) 554 | } 555 | buffer := bytes.Buffer{} 556 | temp := New(100000) 557 | b.ResetTimer() 558 | for i := 0; i < b.N; i++ { 559 | s.WriteTo(&buffer) 560 | temp.ReadFrom(&buffer) 561 | buffer.Reset() 562 | } 563 | } 564 | 565 | func BenchmarkIsSuperSet(b *testing.B) { 566 | new := func(len int, density float64) *BitSet { 567 | r := rand.New(rand.NewSource(42)) 568 | bs := New(uint(len)) 569 | for i := 0; i < len; i++ { 570 | bs.SetTo(uint(i), r.Float64() < density) 571 | } 572 | return bs 573 | } 574 | 575 | bench := func(name string, lenS, lenSS int, density float64, overrideS, overrideSS map[int]bool, f func(*BitSet, *BitSet) bool) { 576 | s := new(lenS, density) 577 | ss := new(lenSS, density) 578 | 579 | for i, v := range overrideS { 580 | s.SetTo(uint(i), v) 581 | } 582 | for i, v := range overrideSS { 583 | ss.SetTo(uint(i), v) 584 | } 585 | 586 | b.Run(name, func(b *testing.B) { 587 | for i := 0; i < b.N; i++ { 588 | _ = f(ss, s) 589 | } 590 | }) 591 | } 592 | 593 | f := func(ss, s *BitSet) bool { 594 | return ss.IsSuperSet(s) 595 | } 596 | fStrict := func(ss, s *BitSet) bool { 597 | return ss.IsStrictSuperSet(s) 598 | } 599 | 600 | for _, len := range []int{1, 10, 100, 1000, 10000, 100000} { 601 | density := 0.5 602 | bench(fmt.Sprintf("equal, len=%d", len), 603 | len, len, density, nil, nil, f) 604 | bench(fmt.Sprintf("equal, len=%d, strict", len), 605 | len, len, density, nil, nil, fStrict) 606 | } 607 | 608 | for _, density := range []float64{0, 0.05, 0.2, 0.8, 0.95, 1} { 609 | len := 10000 610 | bench(fmt.Sprintf("equal, density=%.2f", density), 611 | len, len, density, nil, nil, f) 612 | bench(fmt.Sprintf("equal, density=%.2f, strict", density), 613 | len, len, density, nil, nil, fStrict) 614 | } 615 | 616 | for _, diff := range []int{0, 100, 1000, 9999} { 617 | len := 10000 618 | density := 0.5 619 | overrideS := map[int]bool{diff: true} 620 | overrideSS := map[int]bool{diff: false} 621 | bench(fmt.Sprintf("subset, len=%d, diff=%d", len, diff), 622 | len, len, density, overrideS, overrideSS, f) 623 | bench(fmt.Sprintf("subset, len=%d, diff=%d, strict", len, diff), 624 | len, len, density, overrideS, overrideSS, fStrict) 625 | } 626 | 627 | for _, diff := range []int{0, 100, 1000, 9999} { 628 | len := 10000 629 | density := 0.5 630 | overrideS := map[int]bool{diff: false} 631 | overrideSS := map[int]bool{diff: true} 632 | bench(fmt.Sprintf("superset, len=%d, diff=%d", len, diff), 633 | len, len, density, overrideS, overrideSS, f) 634 | bench(fmt.Sprintf("superset, len=%d, diff=%d, strict", len, diff), 635 | len, len, density, overrideS, overrideSS, fStrict) 636 | } 637 | } 638 | 639 | // clear the right most bit (C-RMS) 640 | // test two different algorithms 641 | func BenchmarkClearRMS(b *testing.B) { 642 | var word uint64 643 | 644 | // cryptic 645 | b.Run("cryptic", func(b *testing.B) { 646 | word = 0xaaaa_aaaa_aaaa_aaaa 647 | for i := 0; i < b.N; i++ { 648 | t := word & ((^word) + 1) 649 | word = word ^ t 650 | } 651 | }) 652 | 653 | // less cryptic 654 | b.Run("simple", func(b *testing.B) { 655 | word = 0xaaaa_aaaa_aaaa_aaaa 656 | for i := 0; i < b.N; i++ { 657 | word &= word - 1 658 | } 659 | }) 660 | } 661 | 662 | // go test -bench=Rank 663 | func BenchmarkRank(b *testing.B) { 664 | s := New(100000) 665 | for i := 0; i < 100000; i += 100 { 666 | s.Set(uint(i)) 667 | } 668 | for _, u := range []uint{1, 20, 50, 100, 200, 500, 1_000, 10_000, 20_000, 50_000, 100_000, 200_000} { 669 | b.Run(fmt.Sprintf("Rank(%d)", u), func(b *testing.B) { 670 | b.ResetTimer() 671 | for i := 0; i < b.N; i++ { 672 | _ = s.Rank(u) 673 | } 674 | }) 675 | } 676 | } 677 | -------------------------------------------------------------------------------- /bitset.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package bitset implements bitsets, a mapping 3 | between non-negative integers and boolean values. It should be more 4 | efficient than map[uint] bool. 5 | 6 | It provides methods for setting, clearing, flipping, and testing 7 | individual integers. 8 | 9 | But it also provides set intersection, union, difference, 10 | complement, and symmetric operations, as well as tests to 11 | check whether any, all, or no bits are set, and querying a 12 | bitset's current length and number of positive bits. 13 | 14 | BitSets are expanded to the size of the largest set bit; the 15 | memory allocation is approximately Max bits, where Max is 16 | the largest set bit. BitSets are never shrunk. On creation, 17 | a hint can be given for the number of bits that will be used. 18 | 19 | Many of the methods, including Set,Clear, and Flip, return 20 | a BitSet pointer, which allows for chaining. 21 | 22 | Example use: 23 | 24 | import "bitset" 25 | var b BitSet 26 | b.Set(10).Set(11) 27 | if b.Test(1000) { 28 | b.Clear(1000) 29 | } 30 | if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { 31 | fmt.Println("Intersection works.") 32 | } 33 | 34 | As an alternative to BitSets, one should check out the 'big' package, 35 | which provides a (less set-theoretical) view of bitsets. 36 | */ 37 | package bitset 38 | 39 | import ( 40 | "bytes" 41 | "encoding/base64" 42 | "encoding/binary" 43 | "encoding/json" 44 | "errors" 45 | "fmt" 46 | "io" 47 | "math/bits" 48 | "strconv" 49 | ) 50 | 51 | // the wordSize of a bit set 52 | const wordSize = 64 53 | 54 | // the wordSize of a bit set in bytes 55 | const wordBytes = wordSize / 8 56 | 57 | // wordMask is wordSize-1, used for bit indexing in a word 58 | const wordMask = wordSize - 1 59 | 60 | // log2WordSize is lg(wordSize) 61 | const log2WordSize = 6 62 | 63 | // allBits has every bit set 64 | const allBits uint64 = 0xffffffffffffffff 65 | 66 | // default binary BigEndian 67 | var binaryOrder binary.ByteOrder = binary.BigEndian 68 | 69 | // default json encoding base64.URLEncoding 70 | var base64Encoding = base64.URLEncoding 71 | 72 | // Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) 73 | func Base64StdEncoding() { base64Encoding = base64.StdEncoding } 74 | 75 | // LittleEndian sets Marshal/Unmarshal Binary as Little Endian (Default: binary.BigEndian) 76 | func LittleEndian() { binaryOrder = binary.LittleEndian } 77 | 78 | // BigEndian sets Marshal/Unmarshal Binary as Big Endian (Default: binary.BigEndian) 79 | func BigEndian() { binaryOrder = binary.BigEndian } 80 | 81 | // BinaryOrder returns the current binary order, see also LittleEndian() 82 | // and BigEndian() to change the order. 83 | func BinaryOrder() binary.ByteOrder { return binaryOrder } 84 | 85 | // A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. 86 | type BitSet struct { 87 | length uint 88 | set []uint64 89 | } 90 | 91 | // Error is used to distinguish errors (panics) generated in this package. 92 | type Error string 93 | 94 | // safeSet will fixup b.set to be non-nil and return the field value 95 | func (b *BitSet) safeSet() []uint64 { 96 | if b.set == nil { 97 | b.set = make([]uint64, wordsNeeded(0)) 98 | } 99 | return b.set 100 | } 101 | 102 | // SetBitsetFrom fills the bitset with an array of integers without creating a new BitSet instance 103 | func (b *BitSet) SetBitsetFrom(buf []uint64) { 104 | b.length = uint(len(buf)) * 64 105 | b.set = buf 106 | } 107 | 108 | // From is a constructor used to create a BitSet from an array of words 109 | func From(buf []uint64) *BitSet { 110 | return FromWithLength(uint(len(buf))*64, buf) 111 | } 112 | 113 | // FromWithLength constructs from an array of words and length in bits. 114 | // This function is for advanced users, most users should prefer 115 | // the From function. 116 | // As a user of FromWithLength, you are responsible for ensuring 117 | // that the length is correct: your slice should have length at 118 | // least (length+63)/64 in 64-bit words. 119 | func FromWithLength(length uint, set []uint64) *BitSet { 120 | if len(set) < wordsNeeded(length) { 121 | panic("BitSet.FromWithLength: slice is too short") 122 | } 123 | return &BitSet{length, set} 124 | } 125 | 126 | // Bytes returns the bitset as array of 64-bit words, giving direct access to the internal representation. 127 | // It is not a copy, so changes to the returned slice will affect the bitset. 128 | // It is meant for advanced users. 129 | // 130 | // Deprecated: Bytes is deprecated. Use [BitSet.Words] instead. 131 | func (b *BitSet) Bytes() []uint64 { 132 | return b.set 133 | } 134 | 135 | // Words returns the bitset as array of 64-bit words, giving direct access to the internal representation. 136 | // It is not a copy, so changes to the returned slice will affect the bitset. 137 | // It is meant for advanced users. 138 | func (b *BitSet) Words() []uint64 { 139 | return b.set 140 | } 141 | 142 | // wordsNeeded calculates the number of words needed for i bits 143 | func wordsNeeded(i uint) int { 144 | if i > (Cap() - wordMask) { 145 | return int(Cap() >> log2WordSize) 146 | } 147 | return int((i + wordMask) >> log2WordSize) 148 | } 149 | 150 | // wordsNeededUnbound calculates the number of words needed for i bits, possibly exceeding the capacity. 151 | // This function is useful if you know that the capacity cannot be exceeded (e.g., you have an existing BitSet). 152 | func wordsNeededUnbound(i uint) int { 153 | return (int(i) + wordMask) >> log2WordSize 154 | } 155 | 156 | // wordsIndex calculates the index of words in a `uint64` 157 | func wordsIndex(i uint) uint { 158 | return i & wordMask 159 | } 160 | 161 | // New creates a new BitSet with a hint that length bits will be required. 162 | // The memory usage is at least length/8 bytes. 163 | // In case of allocation failure, the function will return a BitSet with zero 164 | // capacity. 165 | func New(length uint) (bset *BitSet) { 166 | defer func() { 167 | if r := recover(); r != nil { 168 | bset = &BitSet{ 169 | 0, 170 | make([]uint64, 0), 171 | } 172 | } 173 | }() 174 | 175 | bset = &BitSet{ 176 | length, 177 | make([]uint64, wordsNeeded(length)), 178 | } 179 | 180 | return bset 181 | } 182 | 183 | // MustNew creates a new BitSet with the given length bits. 184 | // It panics if length exceeds the possible capacity or by a lack of memory. 185 | func MustNew(length uint) (bset *BitSet) { 186 | if length >= Cap() { 187 | panic("You are exceeding the capacity") 188 | } 189 | 190 | return &BitSet{ 191 | length, 192 | make([]uint64, wordsNeeded(length)), // may panic on lack of memory 193 | } 194 | } 195 | 196 | // Cap returns the total possible capacity, or number of bits 197 | // that can be stored in the BitSet theoretically. Under 32-bit system, 198 | // it is 4294967295 and under 64-bit system, it is 18446744073709551615. 199 | // Note that this is further limited by the maximum allocation size in Go, 200 | // and your available memory, as any Go data structure. 201 | func Cap() uint { 202 | return ^uint(0) 203 | } 204 | 205 | // Len returns the number of bits in the BitSet. 206 | // Note that it differ from Count function. 207 | func (b *BitSet) Len() uint { 208 | return b.length 209 | } 210 | 211 | // extendSet adds additional words to incorporate new bits if needed 212 | func (b *BitSet) extendSet(i uint) { 213 | if i >= Cap() { 214 | panic("You are exceeding the capacity") 215 | } 216 | nsize := wordsNeeded(i + 1) 217 | if b.set == nil { 218 | b.set = make([]uint64, nsize) 219 | } else if cap(b.set) >= nsize { 220 | b.set = b.set[:nsize] // fast resize 221 | } else if len(b.set) < nsize { 222 | newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x 223 | copy(newset, b.set) 224 | b.set = newset 225 | } 226 | b.length = i + 1 227 | } 228 | 229 | // Test whether bit i is set. 230 | func (b *BitSet) Test(i uint) bool { 231 | if i >= b.length { 232 | return false 233 | } 234 | return b.set[i>>log2WordSize]&(1<> log2WordSize) 240 | subWordIndex := wordsIndex(i) 241 | 242 | // The word that the index falls within, shifted so the index is at bit 0 243 | var firstWord, secondWord uint64 244 | if firstWordIndex < len(b.set) { 245 | firstWord = b.set[firstWordIndex] >> subWordIndex 246 | } 247 | 248 | // The next word, masked to only include the necessary bits and shifted to cover the 249 | // top of the word 250 | if (firstWordIndex + 1) < len(b.set) { 251 | secondWord = b.set[firstWordIndex+1] << uint64(wordSize-subWordIndex) 252 | } 253 | 254 | return firstWord | secondWord 255 | } 256 | 257 | // Set bit i to 1, the capacity of the bitset is automatically 258 | // increased accordingly. 259 | // Warning: using a very large value for 'i' 260 | // may lead to a memory shortage and a panic: the caller is responsible 261 | // for providing sensible parameters in line with their memory capacity. 262 | // The memory usage is at least slightly over i/8 bytes. 263 | func (b *BitSet) Set(i uint) *BitSet { 264 | if i >= b.length { // if we need more bits, make 'em 265 | b.extendSet(i) 266 | } 267 | b.set[i>>log2WordSize] |= 1 << wordsIndex(i) 268 | return b 269 | } 270 | 271 | // Clear bit i to 0. This never cause a memory allocation. It is always safe. 272 | func (b *BitSet) Clear(i uint) *BitSet { 273 | if i >= b.length { 274 | return b 275 | } 276 | b.set[i>>log2WordSize] &^= 1 << wordsIndex(i) 277 | return b 278 | } 279 | 280 | // SetTo sets bit i to value. 281 | // Warning: using a very large value for 'i' 282 | // may lead to a memory shortage and a panic: the caller is responsible 283 | // for providing sensible parameters in line with their memory capacity. 284 | func (b *BitSet) SetTo(i uint, value bool) *BitSet { 285 | if value { 286 | return b.Set(i) 287 | } 288 | return b.Clear(i) 289 | } 290 | 291 | // Flip bit at i. 292 | // Warning: using a very large value for 'i' 293 | // may lead to a memory shortage and a panic: the caller is responsible 294 | // for providing sensible parameters in line with their memory capacity. 295 | func (b *BitSet) Flip(i uint) *BitSet { 296 | if i >= b.length { 297 | return b.Set(i) 298 | } 299 | b.set[i>>log2WordSize] ^= 1 << wordsIndex(i) 300 | return b 301 | } 302 | 303 | // FlipRange bit in [start, end). 304 | // Warning: using a very large value for 'end' 305 | // may lead to a memory shortage and a panic: the caller is responsible 306 | // for providing sensible parameters in line with their memory capacity. 307 | func (b *BitSet) FlipRange(start, end uint) *BitSet { 308 | if start >= end { 309 | return b 310 | } 311 | 312 | if end-1 >= b.length { // if we need more bits, make 'em 313 | b.extendSet(end - 1) 314 | } 315 | 316 | startWord := int(start >> log2WordSize) 317 | endWord := int(end >> log2WordSize) 318 | 319 | // b.set[startWord] ^= ^(^uint64(0) << wordsIndex(start)) 320 | // e.g: 321 | // start = 71, 322 | // startWord = 1 323 | // wordsIndex(start) = 71 % 64 = 7 324 | // (^uint64(0) << 7) = 0b111111....11110000000 325 | // 326 | // mask = ^(^uint64(0) << 7) = 0b000000....00001111111 327 | // 328 | // flips the first 7 bits in b.set[1] and 329 | // in the range loop, the b.set[1] gets again flipped 330 | // so the two expressions flip results in a flip 331 | // in b.set[1] from [7,63] 332 | // 333 | // handle startWord special, get's reflipped in range loop 334 | b.set[startWord] ^= ^(^uint64(0) << wordsIndex(start)) 335 | 336 | for idx := range b.set[startWord:endWord] { 337 | b.set[startWord+idx] = ^b.set[startWord+idx] 338 | } 339 | 340 | // handle endWord special 341 | // e.g. 342 | // end = 135 343 | // endWord = 2 344 | // 345 | // wordsIndex(-7) = 57 346 | // see the golang spec: 347 | // "For unsigned integer values, the operations +, -, *, and << are computed 348 | // modulo 2n, where n is the bit width of the unsigned integer's type." 349 | // 350 | // mask = ^uint64(0) >> 57 = 0b00000....0001111111 351 | // 352 | // flips in b.set[2] from [0,7] 353 | // 354 | // is end at word boundary? 355 | if idx := wordsIndex(-end); idx != 0 { 356 | b.set[endWord] ^= ^uint64(0) >> wordsIndex(idx) 357 | } 358 | 359 | return b 360 | } 361 | 362 | // Shrink shrinks BitSet so that the provided value is the last possible 363 | // set value. It clears all bits > the provided index and reduces the size 364 | // and length of the set. 365 | // 366 | // Note that the parameter value is not the new length in bits: it is the 367 | // maximal value that can be stored in the bitset after the function call. 368 | // The new length in bits is the parameter value + 1. Thus it is not possible 369 | // to use this function to set the length to 0, the minimal value of the length 370 | // after this function call is 1. 371 | // 372 | // A new slice is allocated to store the new bits, so you may see an increase in 373 | // memory usage until the GC runs. Normally this should not be a problem, but if you 374 | // have an extremely large BitSet its important to understand that the old BitSet will 375 | // remain in memory until the GC frees it. 376 | // If you are memory constrained, this function may cause a panic. 377 | func (b *BitSet) Shrink(lastbitindex uint) *BitSet { 378 | length := lastbitindex + 1 379 | idx := wordsNeeded(length) 380 | if idx > len(b.set) { 381 | return b 382 | } 383 | shrunk := make([]uint64, idx) 384 | copy(shrunk, b.set[:idx]) 385 | b.set = shrunk 386 | b.length = length 387 | lastWordUsedBits := length % 64 388 | if lastWordUsedBits != 0 { 389 | b.set[idx-1] &= allBits >> uint64(64-wordsIndex(lastWordUsedBits)) 390 | } 391 | return b 392 | } 393 | 394 | // Compact shrinks BitSet to so that we preserve all set bits, while minimizing 395 | // memory usage. Compact calls Shrink. 396 | // A new slice is allocated to store the new bits, so you may see an increase in 397 | // memory usage until the GC runs. Normally this should not be a problem, but if you 398 | // have an extremely large BitSet its important to understand that the old BitSet will 399 | // remain in memory until the GC frees it. 400 | // If you are memory constrained, this function may cause a panic. 401 | func (b *BitSet) Compact() *BitSet { 402 | idx := len(b.set) - 1 403 | for ; idx >= 0 && b.set[idx] == 0; idx-- { 404 | } 405 | newlength := uint((idx + 1) << log2WordSize) 406 | if newlength >= b.length { 407 | return b // nothing to do 408 | } 409 | if newlength > 0 { 410 | return b.Shrink(newlength - 1) 411 | } 412 | // We preserve one word 413 | return b.Shrink(63) 414 | } 415 | 416 | // InsertAt takes an index which indicates where a bit should be 417 | // inserted. Then it shifts all the bits in the set to the left by 1, starting 418 | // from the given index position, and sets the index position to 0. 419 | // 420 | // Depending on the size of your BitSet, and where you are inserting the new entry, 421 | // this method could be extremely slow and in some cases might cause the entire BitSet 422 | // to be recopied. 423 | func (b *BitSet) InsertAt(idx uint) *BitSet { 424 | insertAtElement := idx >> log2WordSize 425 | 426 | // if length of set is a multiple of wordSize we need to allocate more space first 427 | if b.isLenExactMultiple() { 428 | b.set = append(b.set, uint64(0)) 429 | } 430 | 431 | var i uint 432 | for i = uint(len(b.set) - 1); i > insertAtElement; i-- { 433 | // all elements above the position where we want to insert can simply by shifted 434 | b.set[i] <<= 1 435 | 436 | // we take the most significant bit of the previous element and set it as 437 | // the least significant bit of the current element 438 | b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63 439 | } 440 | 441 | // generate a mask to extract the data that we need to shift left 442 | // within the element where we insert a bit 443 | dataMask := uint64(1)< 0x40000 { 473 | buffer.WriteString("...") 474 | break 475 | } 476 | buffer.WriteString(strconv.FormatInt(int64(i), 10)) 477 | i, e = b.NextSet(i + 1) 478 | if e { 479 | buffer.WriteString(",") 480 | } 481 | } 482 | buffer.WriteString("}") 483 | return buffer.String() 484 | } 485 | 486 | // DeleteAt deletes the bit at the given index position from 487 | // within the bitset 488 | // All the bits residing on the left of the deleted bit get 489 | // shifted right by 1 490 | // The running time of this operation may potentially be 491 | // relatively slow, O(length) 492 | func (b *BitSet) DeleteAt(i uint) *BitSet { 493 | // the index of the slice element where we'll delete a bit 494 | deleteAtElement := i >> log2WordSize 495 | 496 | // generate a mask for the data that needs to be shifted right 497 | // within that slice element that gets modified 498 | dataMask := ^((uint64(1) << wordsIndex(i)) - 1) 499 | 500 | // extract the data that we'll shift right from the slice element 501 | data := b.set[deleteAtElement] & dataMask 502 | 503 | // set the masked area to 0 while leaving the rest as it is 504 | b.set[deleteAtElement] &= ^dataMask 505 | 506 | // shift the previously extracted data to the right and then 507 | // set it in the previously masked area 508 | b.set[deleteAtElement] |= (data >> 1) & dataMask 509 | 510 | // loop over all the consecutive slice elements to copy each 511 | // lowest bit into the highest position of the previous element, 512 | // then shift the entire content to the right by 1 513 | for i := int(deleteAtElement) + 1; i < len(b.set); i++ { 514 | b.set[i-1] |= (b.set[i] & 1) << 63 515 | b.set[i] >>= 1 516 | } 517 | 518 | b.length = b.length - 1 519 | 520 | return b 521 | } 522 | 523 | // AppendTo appends all set bits to buf and returns the (maybe extended) buf. 524 | // In case of allocation failure, the function will panic. 525 | // 526 | // See also [BitSet.AsSlice] and [BitSet.NextSetMany]. 527 | func (b *BitSet) AppendTo(buf []uint) []uint { 528 | // In theory, we could overflow uint, but in practice, we will not. 529 | for idx, word := range b.set { 530 | for word != 0 { 531 | // In theory idx<> log2WordSize) 576 | if x >= len(b.set) { 577 | return 0, false 578 | } 579 | 580 | // process first (partial) word 581 | word := b.set[x] >> wordsIndex(i) 582 | if word != 0 { 583 | return i + uint(bits.TrailingZeros64(word)), true 584 | } 585 | 586 | // process the following full words until next bit is set 587 | // x < len(b.set), no out-of-bounds panic in following slice expression 588 | x++ 589 | for idx, word := range b.set[x:] { 590 | if word != 0 { 591 | return uint((x+idx)< 0; j, buffer = bitmap.NextSetMany(j,buffer) { 606 | // for k := range buffer { 607 | // do something with buffer[k] 608 | // } 609 | // j += 1 610 | // } 611 | // 612 | // It is possible to retrieve all set bits as follow: 613 | // 614 | // indices := make([]uint, bitmap.Count()) 615 | // bitmap.NextSetMany(0, indices) 616 | // 617 | // It is also possible to retrieve all set bits with [BitSet.AppendTo] 618 | // or [BitSet.AsSlice]. 619 | // 620 | // However if Count() is large, it might be preferable to 621 | // use several calls to NextSetMany for memory reasons. 622 | func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { 623 | // In theory, we could overflow uint, but in practice, we will not. 624 | capacity := cap(buffer) 625 | result := buffer[:capacity] 626 | 627 | x := int(i >> log2WordSize) 628 | if x >= len(b.set) || capacity == 0 { 629 | return 0, result[:0] 630 | } 631 | 632 | // process first (partial) word 633 | word := b.set[x] >> wordsIndex(i) 634 | 635 | size := 0 636 | for word != 0 { 637 | result[size] = i + uint(bits.TrailingZeros64(word)) 638 | 639 | size++ 640 | if size == capacity { 641 | return result[size-1], result[:size] 642 | } 643 | 644 | // clear the rightmost set bit 645 | word &= word - 1 646 | } 647 | 648 | // process the following full words 649 | // x < len(b.set), no out-of-bounds panic in following slice expression 650 | x++ 651 | for idx, word := range b.set[x:] { 652 | for word != 0 { 653 | result[size] = uint((x+idx)< 0 { 666 | return result[size-1], result[:size] 667 | } 668 | return 0, result[:0] 669 | } 670 | 671 | // NextClear returns the next clear bit from the specified index, 672 | // including possibly the current index 673 | // along with an error code (true = valid, false = no bit found i.e. all bits are set) 674 | func (b *BitSet) NextClear(i uint) (uint, bool) { 675 | x := int(i >> log2WordSize) 676 | if x >= len(b.set) { 677 | return 0, false 678 | } 679 | 680 | // process first (maybe partial) word 681 | word := b.set[x] 682 | word = word >> wordsIndex(i) 683 | wordAll := allBits >> wordsIndex(i) 684 | 685 | index := i + uint(bits.TrailingZeros64(^word)) 686 | if word != wordAll && index < b.length { 687 | return index, true 688 | } 689 | 690 | // process the following full words until next bit is cleared 691 | // x < len(b.set), no out-of-bounds panic in following slice expression 692 | x++ 693 | for idx, word := range b.set[x:] { 694 | if word != allBits { 695 | index = uint((x+idx)*wordSize + bits.TrailingZeros64(^word)) 696 | if index < b.length { 697 | return index, true 698 | } 699 | } 700 | } 701 | 702 | return 0, false 703 | } 704 | 705 | // PreviousSet returns the previous set bit from the specified index, 706 | // including possibly the current index 707 | // along with an error code (true = valid, false = no bit found i.e. all bits are clear) 708 | func (b *BitSet) PreviousSet(i uint) (uint, bool) { 709 | x := int(i >> log2WordSize) 710 | if x >= len(b.set) { 711 | return 0, false 712 | } 713 | word := b.set[x] 714 | 715 | // Clear the bits above the index 716 | word = word & ((1 << (wordsIndex(i) + 1)) - 1) 717 | if word != 0 { 718 | return uint(x<= 0; x-- { 722 | word = b.set[x] 723 | if word != 0 { 724 | return uint(x<> log2WordSize) 735 | if x >= len(b.set) { 736 | return 0, false 737 | } 738 | word := b.set[x] 739 | 740 | // Flip all bits and find the highest one bit 741 | word = ^word 742 | 743 | // Clear the bits above the index 744 | word = word & ((1 << (wordsIndex(i) + 1)) - 1) 745 | 746 | if word != 0 { 747 | return uint(x<= 0; x-- { 751 | word = b.set[x] 752 | word = ^word 753 | if word != 0 { 754 | return uint(x< b.wordCount() { 891 | l = b.wordCount() 892 | } 893 | for i := 0; i < l; i++ { 894 | result.set[i] = b.set[i] &^ compare.set[i] 895 | } 896 | return 897 | } 898 | 899 | // DifferenceCardinality computes the cardinality of the difference 900 | func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { 901 | panicIfNull(b) 902 | panicIfNull(compare) 903 | l := compare.wordCount() 904 | if l > b.wordCount() { 905 | l = b.wordCount() 906 | } 907 | cnt := uint64(0) 908 | if l > 0 { 909 | cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) 910 | } 911 | cnt += popcntSlice(b.set[l:]) 912 | return uint(cnt) 913 | } 914 | 915 | // InPlaceDifference computes the difference of base set and other set 916 | // This is the BitSet equivalent of &^ (and not) 917 | func (b *BitSet) InPlaceDifference(compare *BitSet) { 918 | panicIfNull(b) 919 | panicIfNull(compare) 920 | l := compare.wordCount() 921 | if l > b.wordCount() { 922 | l = b.wordCount() 923 | } 924 | if l <= 0 { 925 | return 926 | } 927 | // bounds check elimination 928 | data, cmpData := b.set, compare.set 929 | _ = data[l-1] 930 | _ = cmpData[l-1] 931 | for i := 0; i < l; i++ { 932 | data[i] &^= cmpData[i] 933 | } 934 | } 935 | 936 | // Convenience function: return two bitsets ordered by 937 | // increasing length. Note: neither can be nil 938 | func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { 939 | if a.length <= b.length { 940 | ap, bp = a, b 941 | } else { 942 | ap, bp = b, a 943 | } 944 | return 945 | } 946 | 947 | // Intersection of base set and other set 948 | // This is the BitSet equivalent of & (and) 949 | // In case of allocation failure, the function will return an empty BitSet. 950 | func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { 951 | panicIfNull(b) 952 | panicIfNull(compare) 953 | b, compare = sortByLength(b, compare) 954 | result = New(b.length) 955 | for i, word := range b.set { 956 | result.set[i] = word & compare.set[i] 957 | } 958 | return 959 | } 960 | 961 | // IntersectionCardinality computes the cardinality of the intersection 962 | func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { 963 | panicIfNull(b) 964 | panicIfNull(compare) 965 | if b.length == 0 || compare.length == 0 { 966 | return 0 967 | } 968 | b, compare = sortByLength(b, compare) 969 | cnt := popcntAndSlice(b.set, compare.set) 970 | return uint(cnt) 971 | } 972 | 973 | // InPlaceIntersection destructively computes the intersection of 974 | // base set and the compare set. 975 | // This is the BitSet equivalent of & (and) 976 | func (b *BitSet) InPlaceIntersection(compare *BitSet) { 977 | panicIfNull(b) 978 | panicIfNull(compare) 979 | l := compare.wordCount() 980 | if l > b.wordCount() { 981 | l = b.wordCount() 982 | } 983 | if l > 0 { 984 | // bounds check elimination 985 | data, cmpData := b.set, compare.set 986 | _ = data[l-1] 987 | _ = cmpData[l-1] 988 | 989 | for i := 0; i < l; i++ { 990 | data[i] &= cmpData[i] 991 | } 992 | } 993 | if l >= 0 { 994 | for i := l; i < len(b.set); i++ { 995 | b.set[i] = 0 996 | } 997 | } 998 | if compare.length > 0 { 999 | if compare.length-1 >= b.length { 1000 | b.extendSet(compare.length - 1) 1001 | } 1002 | } 1003 | } 1004 | 1005 | // Union of base set and other set 1006 | // This is the BitSet equivalent of | (or) 1007 | func (b *BitSet) Union(compare *BitSet) (result *BitSet) { 1008 | panicIfNull(b) 1009 | panicIfNull(compare) 1010 | b, compare = sortByLength(b, compare) 1011 | result = compare.Clone() 1012 | for i, word := range b.set { 1013 | result.set[i] = word | compare.set[i] 1014 | } 1015 | return 1016 | } 1017 | 1018 | // UnionCardinality computes the cardinality of the uniton of the base set 1019 | // and the compare set. 1020 | func (b *BitSet) UnionCardinality(compare *BitSet) uint { 1021 | panicIfNull(b) 1022 | panicIfNull(compare) 1023 | b, compare = sortByLength(b, compare) 1024 | cnt := uint64(0) 1025 | if len(b.set) > 0 { 1026 | cnt += popcntOrSlice(b.set, compare.set) 1027 | } 1028 | if len(compare.set) > len(b.set) { 1029 | cnt += popcntSlice(compare.set[len(b.set):]) 1030 | } 1031 | return uint(cnt) 1032 | } 1033 | 1034 | // InPlaceUnion creates the destructive union of base set and compare set. 1035 | // This is the BitSet equivalent of | (or). 1036 | func (b *BitSet) InPlaceUnion(compare *BitSet) { 1037 | panicIfNull(b) 1038 | panicIfNull(compare) 1039 | l := compare.wordCount() 1040 | if l > b.wordCount() { 1041 | l = b.wordCount() 1042 | } 1043 | if compare.length > 0 && compare.length-1 >= b.length { 1044 | b.extendSet(compare.length - 1) 1045 | } 1046 | if l > 0 { 1047 | // bounds check elimination 1048 | data, cmpData := b.set, compare.set 1049 | _ = data[l-1] 1050 | _ = cmpData[l-1] 1051 | 1052 | for i := 0; i < l; i++ { 1053 | data[i] |= cmpData[i] 1054 | } 1055 | } 1056 | if len(compare.set) > l { 1057 | for i := l; i < len(compare.set); i++ { 1058 | b.set[i] = compare.set[i] 1059 | } 1060 | } 1061 | } 1062 | 1063 | // SymmetricDifference of base set and other set 1064 | // This is the BitSet equivalent of ^ (xor) 1065 | func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { 1066 | panicIfNull(b) 1067 | panicIfNull(compare) 1068 | b, compare = sortByLength(b, compare) 1069 | // compare is bigger, so clone it 1070 | result = compare.Clone() 1071 | for i, word := range b.set { 1072 | result.set[i] = word ^ compare.set[i] 1073 | } 1074 | return 1075 | } 1076 | 1077 | // SymmetricDifferenceCardinality computes the cardinality of the symmetric difference 1078 | func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { 1079 | panicIfNull(b) 1080 | panicIfNull(compare) 1081 | b, compare = sortByLength(b, compare) 1082 | cnt := uint64(0) 1083 | if len(b.set) > 0 { 1084 | cnt += popcntXorSlice(b.set, compare.set) 1085 | } 1086 | if len(compare.set) > len(b.set) { 1087 | cnt += popcntSlice(compare.set[len(b.set):]) 1088 | } 1089 | return uint(cnt) 1090 | } 1091 | 1092 | // InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set 1093 | // This is the BitSet equivalent of ^ (xor) 1094 | func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { 1095 | panicIfNull(b) 1096 | panicIfNull(compare) 1097 | l := compare.wordCount() 1098 | if l > b.wordCount() { 1099 | l = b.wordCount() 1100 | } 1101 | if compare.length > 0 && compare.length-1 >= b.length { 1102 | b.extendSet(compare.length - 1) 1103 | } 1104 | if l > 0 { 1105 | // bounds check elimination 1106 | data, cmpData := b.set, compare.set 1107 | _ = data[l-1] 1108 | _ = cmpData[l-1] 1109 | for i := 0; i < l; i++ { 1110 | data[i] ^= cmpData[i] 1111 | } 1112 | } 1113 | if len(compare.set) > l { 1114 | for i := l; i < len(compare.set); i++ { 1115 | b.set[i] = compare.set[i] 1116 | } 1117 | } 1118 | } 1119 | 1120 | // Is the length an exact multiple of word sizes? 1121 | func (b *BitSet) isLenExactMultiple() bool { 1122 | return wordsIndex(b.length) == 0 1123 | } 1124 | 1125 | // Clean last word by setting unused bits to 0 1126 | func (b *BitSet) cleanLastWord() { 1127 | if !b.isLenExactMultiple() { 1128 | b.set[len(b.set)-1] &= allBits >> (wordSize - wordsIndex(b.length)) 1129 | } 1130 | } 1131 | 1132 | // Complement computes the (local) complement of a bitset (up to length bits) 1133 | // In case of allocation failure, the function will return an empty BitSet. 1134 | func (b *BitSet) Complement() (result *BitSet) { 1135 | panicIfNull(b) 1136 | result = New(b.length) 1137 | for i, word := range b.set { 1138 | result.set[i] = ^word 1139 | } 1140 | result.cleanLastWord() 1141 | return 1142 | } 1143 | 1144 | // All returns true if all bits are set, false otherwise. Returns true for 1145 | // empty sets. 1146 | func (b *BitSet) All() bool { 1147 | panicIfNull(b) 1148 | return b.Count() == b.length 1149 | } 1150 | 1151 | // None returns true if no bit is set, false otherwise. Returns true for 1152 | // empty sets. 1153 | func (b *BitSet) None() bool { 1154 | panicIfNull(b) 1155 | if b != nil && b.set != nil { 1156 | for _, word := range b.set { 1157 | if word > 0 { 1158 | return false 1159 | } 1160 | } 1161 | } 1162 | return true 1163 | } 1164 | 1165 | // Any returns true if any bit is set, false otherwise 1166 | func (b *BitSet) Any() bool { 1167 | panicIfNull(b) 1168 | return !b.None() 1169 | } 1170 | 1171 | // IsSuperSet returns true if this is a superset of the other set 1172 | func (b *BitSet) IsSuperSet(other *BitSet) bool { 1173 | l := other.wordCount() 1174 | if b.wordCount() < l { 1175 | l = b.wordCount() 1176 | } 1177 | for i, word := range other.set[:l] { 1178 | if b.set[i]&word != word { 1179 | return false 1180 | } 1181 | } 1182 | return popcntSlice(other.set[l:]) == 0 1183 | } 1184 | 1185 | // IsStrictSuperSet returns true if this is a strict superset of the other set 1186 | func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { 1187 | return b.Count() > other.Count() && b.IsSuperSet(other) 1188 | } 1189 | 1190 | // DumpAsBits dumps a bit set as a string of bits. Following the usual convention in Go, 1191 | // the least significant bits are printed last (index 0 is at the end of the string). 1192 | // This is useful for debugging and testing. It is not suitable for serialization. 1193 | func (b *BitSet) DumpAsBits() string { 1194 | if b.set == nil { 1195 | return "." 1196 | } 1197 | buffer := bytes.NewBufferString("") 1198 | i := len(b.set) - 1 1199 | for ; i >= 0; i-- { 1200 | fmt.Fprintf(buffer, "%064b.", b.set[i]) 1201 | } 1202 | return buffer.String() 1203 | } 1204 | 1205 | // BinaryStorageSize returns the binary storage requirements (see WriteTo) in bytes. 1206 | func (b *BitSet) BinaryStorageSize() int { 1207 | return wordBytes + wordBytes*b.wordCount() 1208 | } 1209 | 1210 | func readUint64Array(reader io.Reader, data []uint64) error { 1211 | length := len(data) 1212 | bufferSize := 128 1213 | buffer := make([]byte, bufferSize*wordBytes) 1214 | for i := 0; i < length; i += bufferSize { 1215 | end := i + bufferSize 1216 | if end > length { 1217 | end = length 1218 | buffer = buffer[:wordBytes*(end-i)] 1219 | } 1220 | chunk := data[i:end] 1221 | if _, err := io.ReadFull(reader, buffer); err != nil { 1222 | return err 1223 | } 1224 | for i := range chunk { 1225 | chunk[i] = uint64(binaryOrder.Uint64(buffer[8*i:])) 1226 | } 1227 | } 1228 | return nil 1229 | } 1230 | 1231 | func writeUint64Array(writer io.Writer, data []uint64) error { 1232 | bufferSize := 128 1233 | buffer := make([]byte, bufferSize*wordBytes) 1234 | for i := 0; i < len(data); i += bufferSize { 1235 | end := i + bufferSize 1236 | if end > len(data) { 1237 | end = len(data) 1238 | buffer = buffer[:wordBytes*(end-i)] 1239 | } 1240 | chunk := data[i:end] 1241 | for i, x := range chunk { 1242 | binaryOrder.PutUint64(buffer[8*i:], x) 1243 | } 1244 | _, err := writer.Write(buffer) 1245 | if err != nil { 1246 | return err 1247 | } 1248 | } 1249 | return nil 1250 | } 1251 | 1252 | // WriteTo writes a BitSet to a stream. The format is: 1253 | // 1. uint64 length 1254 | // 2. []uint64 set 1255 | // The length is the number of bits in the BitSet. 1256 | // 1257 | // The set is a slice of uint64s containing between length and length + 63 bits. 1258 | // It is interpreted as a big-endian array of uint64s by default (see BinaryOrder()) 1259 | // meaning that the first 8 bits are stored at byte index 7, the next 8 bits are stored 1260 | // at byte index 6... the bits 64 to 71 are stored at byte index 8, etc. 1261 | // If you change the binary order, you need to do so for both reading and writing. 1262 | // We recommend using the default binary order. 1263 | // 1264 | // Upon success, the number of bytes written is returned. 1265 | // 1266 | // Performance: if this function is used to write to a disk or network 1267 | // connection, it might be beneficial to wrap the stream in a bufio.Writer. 1268 | // E.g., 1269 | // 1270 | // f, err := os.Create("myfile") 1271 | // w := bufio.NewWriter(f) 1272 | func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { 1273 | length := uint64(b.length) 1274 | // Write length 1275 | err := binary.Write(stream, binaryOrder, &length) 1276 | if err != nil { 1277 | // Upon failure, we do not guarantee that we 1278 | // return the number of bytes written. 1279 | return int64(0), err 1280 | } 1281 | err = writeUint64Array(stream, b.set[:b.wordCount()]) 1282 | if err != nil { 1283 | // Upon failure, we do not guarantee that we 1284 | // return the number of bytes written. 1285 | return int64(wordBytes), err 1286 | } 1287 | return int64(b.BinaryStorageSize()), nil 1288 | } 1289 | 1290 | // ReadFrom reads a BitSet from a stream written using WriteTo 1291 | // The format is: 1292 | // 1. uint64 length 1293 | // 2. []uint64 set 1294 | // See WriteTo for details. 1295 | // Upon success, the number of bytes read is returned. 1296 | // If the current BitSet is not large enough to hold the data, 1297 | // it is extended. In case of error, the BitSet is either 1298 | // left unchanged or made empty if the error occurs too late 1299 | // to preserve the content. 1300 | // 1301 | // Performance: if this function is used to read from a disk or network 1302 | // connection, it might be beneficial to wrap the stream in a bufio.Reader. 1303 | // E.g., 1304 | // 1305 | // f, err := os.Open("myfile") 1306 | // r := bufio.NewReader(f) 1307 | func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { 1308 | var length uint64 1309 | err := binary.Read(stream, binaryOrder, &length) 1310 | if err != nil { 1311 | if err == io.EOF { 1312 | err = io.ErrUnexpectedEOF 1313 | } 1314 | return 0, err 1315 | } 1316 | newlength := uint(length) 1317 | 1318 | if uint64(newlength) != length { 1319 | return 0, errors.New("unmarshalling error: type mismatch") 1320 | } 1321 | nWords := wordsNeeded(uint(newlength)) 1322 | if cap(b.set) >= nWords { 1323 | b.set = b.set[:nWords] 1324 | } else { 1325 | b.set = make([]uint64, nWords) 1326 | } 1327 | 1328 | b.length = newlength 1329 | 1330 | err = readUint64Array(stream, b.set) 1331 | if err != nil { 1332 | if err == io.EOF { 1333 | err = io.ErrUnexpectedEOF 1334 | } 1335 | // We do not want to leave the BitSet partially filled as 1336 | // it is error prone. 1337 | b.set = b.set[:0] 1338 | b.length = 0 1339 | return 0, err 1340 | } 1341 | 1342 | return int64(b.BinaryStorageSize()), nil 1343 | } 1344 | 1345 | // MarshalBinary encodes a BitSet into a binary form and returns the result. 1346 | // Please see WriteTo for details. 1347 | func (b *BitSet) MarshalBinary() ([]byte, error) { 1348 | var buf bytes.Buffer 1349 | _, err := b.WriteTo(&buf) 1350 | if err != nil { 1351 | return []byte{}, err 1352 | } 1353 | 1354 | return buf.Bytes(), err 1355 | } 1356 | 1357 | // UnmarshalBinary decodes the binary form generated by MarshalBinary. 1358 | // Please see WriteTo for details. 1359 | func (b *BitSet) UnmarshalBinary(data []byte) error { 1360 | buf := bytes.NewReader(data) 1361 | _, err := b.ReadFrom(buf) 1362 | return err 1363 | } 1364 | 1365 | // MarshalJSON marshals a BitSet as a JSON structure 1366 | func (b BitSet) MarshalJSON() ([]byte, error) { 1367 | buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) 1368 | _, err := b.WriteTo(buffer) 1369 | if err != nil { 1370 | return nil, err 1371 | } 1372 | 1373 | // URLEncode all bytes 1374 | return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes())) 1375 | } 1376 | 1377 | // UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON 1378 | func (b *BitSet) UnmarshalJSON(data []byte) error { 1379 | // Unmarshal as string 1380 | var s string 1381 | err := json.Unmarshal(data, &s) 1382 | if err != nil { 1383 | return err 1384 | } 1385 | 1386 | // URLDecode string 1387 | buf, err := base64Encoding.DecodeString(s) 1388 | if err != nil { 1389 | return err 1390 | } 1391 | 1392 | _, err = b.ReadFrom(bytes.NewReader(buf)) 1393 | return err 1394 | } 1395 | 1396 | // Rank returns the number of set bits up to and including the index 1397 | // that are set in the bitset. 1398 | // See https://en.wikipedia.org/wiki/Ranking#Ranking_in_statistics 1399 | func (b *BitSet) Rank(index uint) (rank uint) { 1400 | index++ // Rank is up to and including 1401 | 1402 | // needed more than once 1403 | length := len(b.set) 1404 | 1405 | // TODO: built-in min requires go1.21 or later 1406 | // idx := min(int(index>>6), len(b.set)) 1407 | idx := int(index >> 6) 1408 | if idx > length { 1409 | idx = length 1410 | } 1411 | 1412 | // sum up the popcounts until idx ... 1413 | // TODO: cannot range over idx (...): requires go1.22 or later 1414 | // for j := range idx { 1415 | for j := 0; j < idx; j++ { 1416 | if w := b.set[j]; w != 0 { 1417 | rank += uint(bits.OnesCount64(w)) 1418 | } 1419 | } 1420 | 1421 | // ... plus partial word at idx, 1422 | // make Rank inlineable and faster in the end 1423 | // don't test index&63 != 0, just add, less branching 1424 | if idx < length { 1425 | rank += uint(bits.OnesCount64(b.set[idx] << (64 - index&63))) 1426 | } 1427 | 1428 | return 1429 | } 1430 | 1431 | // Select returns the index of the jth set bit, where j is the argument. 1432 | // The caller is responsible to ensure that 0 <= j < Count(): when j is 1433 | // out of range, the function returns the length of the bitset (b.length). 1434 | // 1435 | // Note that this function differs in convention from the Rank function which 1436 | // returns 1 when ranking the smallest value. We follow the conventional 1437 | // textbook definition of Select and Rank. 1438 | func (b *BitSet) Select(index uint) uint { 1439 | leftover := index 1440 | for idx, word := range b.set { 1441 | w := uint(bits.OnesCount64(word)) 1442 | if w > leftover { 1443 | return uint(idx)*64 + select64(word, leftover) 1444 | } 1445 | leftover -= w 1446 | } 1447 | return b.length 1448 | } 1449 | 1450 | // top detects the top bit set 1451 | func (b *BitSet) top() (uint, bool) { 1452 | for idx := len(b.set) - 1; idx >= 0; idx-- { 1453 | if word := b.set[idx]; word != 0 { 1454 | return uint(idx<= b.length { 1492 | b.length = top + bits + 1 1493 | } 1494 | 1495 | pad, idx := top%wordSize, top>>log2WordSize 1496 | shift, pages := bits%wordSize, bits>>log2WordSize 1497 | if bits%wordSize == 0 { // happy case: just add pages 1498 | copy(dst[pages:nsize], b.set) 1499 | } else { 1500 | if pad+shift >= wordSize { 1501 | dst[idx+pages+1] = b.set[idx] >> (wordSize - shift) 1502 | } 1503 | 1504 | for i := int(idx); i >= 0; i-- { 1505 | if i > 0 { 1506 | dst[i+int(pages)] = (b.set[i] << shift) | (b.set[i-1] >> (wordSize - shift)) 1507 | } else { 1508 | dst[i+int(pages)] = b.set[i] << shift 1509 | } 1510 | } 1511 | } 1512 | 1513 | // zeroing extra pages 1514 | for i := 0; i < int(pages); i++ { 1515 | dst[i] = 0 1516 | } 1517 | 1518 | b.set = dst 1519 | } 1520 | 1521 | // ShiftRight shifts the bitset like >> operation would do. 1522 | func (b *BitSet) ShiftRight(bits uint) { 1523 | panicIfNull(b) 1524 | 1525 | if bits == 0 { 1526 | return 1527 | } 1528 | 1529 | top, ok := b.top() 1530 | if !ok { 1531 | return 1532 | } 1533 | 1534 | if bits > top { 1535 | b.set = make([]uint64, wordsNeeded(b.length)) 1536 | return 1537 | } 1538 | 1539 | pad, idx := top%wordSize, top>>log2WordSize 1540 | shift, pages := bits%wordSize, bits>>log2WordSize 1541 | if bits%wordSize == 0 { // happy case: just clear pages 1542 | b.set = b.set[pages:] 1543 | b.length -= pages * wordSize 1544 | } else { 1545 | for i := 0; i <= int(idx-pages); i++ { 1546 | if i < int(idx-pages) { 1547 | b.set[i] = (b.set[i+int(pages)] >> shift) | (b.set[i+int(pages)+1] << (wordSize - shift)) 1548 | } else { 1549 | b.set[i] = b.set[i+int(pages)] >> shift 1550 | } 1551 | } 1552 | 1553 | if pad < shift { 1554 | b.set[int(idx-pages)] = 0 1555 | } 1556 | } 1557 | 1558 | for i := int(idx-pages) + 1; i < len(b.set); i++ { 1559 | b.set[i] = 0 1560 | } 1561 | } 1562 | 1563 | // OnesBetween returns the number of set bits in the range [from, to). 1564 | // The range is inclusive of 'from' and exclusive of 'to'. 1565 | // Returns 0 if from >= to. 1566 | func (b *BitSet) OnesBetween(from, to uint) uint { 1567 | panicIfNull(b) 1568 | 1569 | if from >= to { 1570 | return 0 1571 | } 1572 | 1573 | // Calculate indices and masks for the starting and ending words 1574 | startWord := from >> log2WordSize // Divide by wordSize 1575 | endWord := to >> log2WordSize 1576 | startOffset := from & wordMask // Mod wordSize 1577 | endOffset := to & wordMask 1578 | 1579 | // Case 1: Bits lie within a single word 1580 | if startWord == endWord { 1581 | // Create mask for bits between from and to 1582 | mask := uint64((1<= startOffset 1591 | count = uint(bits.OnesCount64(b.set[startWord] & startMask)) 1592 | 1593 | // 2b: Count all bits in complete words between start and end 1594 | if endWord > startWord+1 { 1595 | count += uint(popcntSlice(b.set[startWord+1 : endWord])) 1596 | } 1597 | 1598 | // 2c: Count bits in last word (from start of word to endOffset) 1599 | if endOffset > 0 { 1600 | endMask := uint64(1<> log2WordSize 1655 | bitOffset := outPos & wordMask 1656 | 1657 | // Write extracted bits, handling word boundary crossing 1658 | dst.set[wordIdx] |= extracted << bitOffset 1659 | if bitOffset+bitsExtracted > wordSize { 1660 | dst.set[wordIdx+1] = extracted >> (wordSize - bitOffset) 1661 | } 1662 | 1663 | outPos += bitsExtracted 1664 | } 1665 | } 1666 | 1667 | // Deposit creates a new BitSet and deposits bits according to a mask. 1668 | // See DepositTo for details. 1669 | func (b *BitSet) Deposit(mask *BitSet) *BitSet { 1670 | dst := New(mask.length) 1671 | b.DepositTo(mask, dst) 1672 | return dst 1673 | } 1674 | 1675 | // DepositTo spreads bits from a compacted form in the BitSet into positions 1676 | // specified by mask in dst. This is the inverse operation of Extract. 1677 | // 1678 | // For example, if mask has bits set at positions 1,4,5, then DepositTo will 1679 | // take consecutive bits 0,1,2 from the source BitSet and place them into 1680 | // positions 1,4,5 in the destination BitSet. 1681 | func (b *BitSet) DepositTo(mask *BitSet, dst *BitSet) { 1682 | panicIfNull(b) 1683 | panicIfNull(mask) 1684 | panicIfNull(dst) 1685 | 1686 | if len(dst.set) == 0 || len(mask.set) == 0 || len(b.set) == 0 { 1687 | return 1688 | } 1689 | 1690 | inPos := uint(0) 1691 | length := len(mask.set) 1692 | if len(dst.set) < length { 1693 | length = len(dst.set) 1694 | } 1695 | 1696 | // Process each word 1697 | for i := 0; i < length; i++ { 1698 | if mask.set[i] == 0 { 1699 | continue // Skip words with no bits to deposit 1700 | } 1701 | 1702 | // Calculate source word index 1703 | wordIdx := inPos >> log2WordSize 1704 | if wordIdx >= uint(len(b.set)) { 1705 | break // No more source bits available 1706 | } 1707 | 1708 | // Get source bits, handling word boundary crossing 1709 | sourceBits := b.set[wordIdx] 1710 | bitOffset := inPos & wordMask 1711 | if wordIdx+1 < uint(len(b.set)) && bitOffset != 0 { 1712 | // Combine bits from current and next word 1713 | sourceBits = (sourceBits >> bitOffset) | 1714 | (b.set[wordIdx+1] << (wordSize - bitOffset)) 1715 | } else { 1716 | sourceBits >>= bitOffset 1717 | } 1718 | 1719 | // Deposit bits according to mask 1720 | dst.set[i] = (dst.set[i] &^ mask.set[i]) | pdep(sourceBits, mask.set[i]) 1721 | inPos += uint(bits.OnesCount64(mask.set[i])) 1722 | } 1723 | } 1724 | 1725 | //go:generate go run cmd/pextgen/main.go -pkg=bitset 1726 | 1727 | func pext(w, m uint64) (result uint64) { 1728 | var outPos uint 1729 | 1730 | // Process byte by byte 1731 | for i := 0; i < 8; i++ { 1732 | shift := i << 3 // i * 8 using bit shift 1733 | b := uint8(w >> shift) 1734 | mask := uint8(m >> shift) 1735 | 1736 | extracted := pextLUT[b][mask] 1737 | bits := popLUT[mask] 1738 | 1739 | result |= uint64(extracted) << outPos 1740 | outPos += uint(bits) 1741 | } 1742 | 1743 | return result 1744 | } 1745 | 1746 | func pdep(w, m uint64) (result uint64) { 1747 | var inPos uint 1748 | 1749 | // Process byte by byte 1750 | for i := 0; i < 8; i++ { 1751 | shift := i << 3 // i * 8 using bit shift 1752 | mask := uint8(m >> shift) 1753 | bits := popLUT[mask] 1754 | 1755 | // Get the bits we'll deposit from the source 1756 | b := uint8(w >> inPos) 1757 | 1758 | // Deposit them according to the mask for this byte 1759 | deposited := pdepLUT[b][mask] 1760 | 1761 | // Add to result 1762 | result |= uint64(deposited) << shift 1763 | inPos += uint(bits) 1764 | } 1765 | 1766 | return result 1767 | } 1768 | -------------------------------------------------------------------------------- /bitset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 | "bytes" 11 | "compress/gzip" 12 | "encoding" 13 | "encoding/base64" 14 | "encoding/binary" 15 | "encoding/json" 16 | "errors" 17 | "fmt" 18 | "io" 19 | "math" 20 | "math/bits" 21 | "math/rand" 22 | "reflect" 23 | "strconv" 24 | "testing" 25 | "time" 26 | ) 27 | 28 | func TestStringer(t *testing.T) { 29 | v := New(0) 30 | for i := uint(0); i < 10; i++ { 31 | v.Set(i) 32 | } 33 | if v.String() != "{0,1,2,3,4,5,6,7,8,9}" { 34 | t.Error("bad string output") 35 | } 36 | } 37 | 38 | func TestStringLong(t *testing.T) { 39 | v := New(0) 40 | for i := uint(0); i < 262145; i++ { 41 | v.Set(i) 42 | } 43 | str := v.String() 44 | if len(str) != 1723903 { 45 | t.Error("Unexpected string length: ", len(str)) 46 | } 47 | } 48 | 49 | func TestEmptyBitSet(t *testing.T) { 50 | defer func() { 51 | if r := recover(); r != nil { 52 | t.Error("A zero-length bitset should be fine") 53 | } 54 | }() 55 | b := New(0) 56 | if b.Len() != 0 { 57 | t.Errorf("Empty set should have capacity 0, not %d", b.Len()) 58 | } 59 | } 60 | 61 | func TestZeroValueBitSet(t *testing.T) { 62 | defer func() { 63 | if r := recover(); r != nil { 64 | t.Error("A zero-length bitset should be fine") 65 | } 66 | }() 67 | var b BitSet 68 | if b.Len() != 0 { 69 | t.Errorf("Empty set should have capacity 0, not %d", b.Len()) 70 | } 71 | } 72 | 73 | func TestBitSetNew(t *testing.T) { 74 | v := New(16) 75 | if v.Test(0) { 76 | t.Errorf("Unable to make a bit set and read its 0th value.") 77 | } 78 | } 79 | 80 | func TestBitSetHuge(t *testing.T) { 81 | v := New(uint(math.MaxUint32)) 82 | if v.Test(0) { 83 | t.Errorf("Unable to make a huge bit set and read its 0th value.") 84 | } 85 | } 86 | 87 | func TestLen(t *testing.T) { 88 | v := New(1000) 89 | if v.Len() != 1000 { 90 | t.Errorf("Len should be 1000, but is %d.", v.Len()) 91 | } 92 | } 93 | 94 | func TestLenIsNumberOfBitsNotBytes(t *testing.T) { 95 | var b BitSet 96 | if b.Len() != 0 { 97 | t.Errorf("empty bitset should have Len 0, got %v", b.Len()) 98 | } 99 | 100 | b.Set(0) 101 | if b.Len() != 1 { 102 | t.Errorf("bitset with first bit set should have Len 1, got %v", b.Len()) 103 | } 104 | 105 | b.Set(8) 106 | if b.Len() != 9 { 107 | t.Errorf("bitset with 0th and 8th bit set should have Len 9, got %v", b.Len()) 108 | } 109 | 110 | b.Set(1) 111 | if b.Len() != 9 { 112 | t.Errorf("bitset with 0th, 1st and 8th bit set should have Len 9, got %v", b.Len()) 113 | } 114 | } 115 | 116 | func ExampleBitSet_Len() { 117 | var b BitSet 118 | b.Set(8) 119 | fmt.Println("len", b.Len()) 120 | fmt.Println("count", b.Count()) 121 | // Output: 122 | // len 9 123 | // count 1 124 | } 125 | 126 | func TestBitSetIsClear(t *testing.T) { 127 | v := New(1000) 128 | for i := uint(0); i < 1000; i++ { 129 | if v.Test(i) { 130 | t.Errorf("Bit %d is set, and it shouldn't be.", i) 131 | } 132 | } 133 | } 134 | 135 | func TestExtendOnBoundary(t *testing.T) { 136 | v := New(32) 137 | defer func() { 138 | if r := recover(); r != nil { 139 | t.Error("Border out of index error should not have caused a panic") 140 | } 141 | }() 142 | v.Set(32) 143 | } 144 | 145 | func TestExceedCap(t *testing.T) { 146 | defer func() { 147 | if r := recover(); r == nil { 148 | t.Error("Set to capacity should have caused a panic") 149 | } 150 | }() 151 | NumHosts := uint(32768) 152 | bmp := New(NumHosts) 153 | bmp.ClearAll() 154 | d := Cap() 155 | bmp.Set(d) 156 | } 157 | 158 | func TestExpand(t *testing.T) { 159 | v := New(0) 160 | defer func() { 161 | if r := recover(); r != nil { 162 | t.Error("Expansion should not have caused a panic") 163 | } 164 | }() 165 | for i := uint(0); i < 1000; i++ { 166 | v.Set(i) 167 | } 168 | } 169 | 170 | func TestBitSetAndGet(t *testing.T) { 171 | v := New(1000) 172 | v.Set(100) 173 | if !v.Test(100) { 174 | t.Errorf("Bit %d is clear, and it shouldn't be.", 100) 175 | } 176 | } 177 | 178 | func TestNextClear(t *testing.T) { 179 | v := New(1000) 180 | v.Set(0).Set(1) 181 | next, found := v.NextClear(0) 182 | if !found || next != 2 { 183 | t.Errorf("Found next clear bit as %d, it should have been 2", next) 184 | } 185 | 186 | v = New(1000) 187 | for i := uint(0); i < 66; i++ { 188 | v.Set(i) 189 | } 190 | next, found = v.NextClear(0) 191 | if !found || next != 66 { 192 | t.Errorf("Found next clear bit as %d, it should have been 66", next) 193 | } 194 | 195 | v = New(1000) 196 | for i := uint(0); i < 64; i++ { 197 | v.Set(i) 198 | } 199 | v.Clear(45) 200 | v.Clear(52) 201 | next, found = v.NextClear(10) 202 | if !found || next != 45 { 203 | t.Errorf("Found next clear bit as %d, it should have been 45", next) 204 | } 205 | 206 | v = New(1000) 207 | for i := uint(0); i < 128; i++ { 208 | v.Set(i) 209 | } 210 | v.Clear(73) 211 | v.Clear(99) 212 | next, found = v.NextClear(10) 213 | if !found || next != 73 { 214 | t.Errorf("Found next clear bit as %d, it should have been 73", next) 215 | } 216 | 217 | next, found = v.NextClear(72) 218 | if !found || next != 73 { 219 | t.Errorf("Found next clear bit as %d, it should have been 73", next) 220 | } 221 | next, found = v.NextClear(73) 222 | if !found || next != 73 { 223 | t.Errorf("Found next clear bit as %d, it should have been 73", next) 224 | } 225 | next, found = v.NextClear(74) 226 | if !found || next != 99 { 227 | t.Errorf("Found next clear bit as %d, it should have been 73", next) 228 | } 229 | 230 | v = New(128) 231 | next, found = v.NextClear(0) 232 | if !found || next != 0 { 233 | t.Errorf("Found next clear bit as %d, it should have been 0", next) 234 | } 235 | 236 | for i := uint(0); i < 128; i++ { 237 | v.Set(i) 238 | } 239 | _, found = v.NextClear(0) 240 | if found { 241 | t.Errorf("There are not clear bits") 242 | } 243 | 244 | b := new(BitSet) 245 | c, d := b.NextClear(1) 246 | if c != 0 || d { 247 | t.Error("Unexpected values") 248 | return 249 | } 250 | 251 | v = New(100) 252 | for i := uint(0); i != 100; i++ { 253 | v.Set(i) 254 | } 255 | next, found = v.NextClear(0) 256 | if found || next != 0 { 257 | t.Errorf("Found next clear bit as %d, it should have return (0, false)", next) 258 | } 259 | } 260 | 261 | func TestIterate(t *testing.T) { 262 | v := New(10000) 263 | v.Set(0) 264 | v.Set(1) 265 | v.Set(2) 266 | data := make([]uint, 3) 267 | c := 0 268 | for i, e := v.NextSet(0); e; i, e = v.NextSet(i + 1) { 269 | data[c] = i 270 | c++ 271 | } 272 | if data[0] != 0 { 273 | t.Errorf("bug 0") 274 | } 275 | if data[1] != 1 { 276 | t.Errorf("bug 1") 277 | } 278 | if data[2] != 2 { 279 | t.Errorf("bug 2") 280 | } 281 | v.Set(10) 282 | v.Set(2000) 283 | data = make([]uint, 5) 284 | c = 0 285 | for i, e := v.NextSet(0); e; i, e = v.NextSet(i + 1) { 286 | data[c] = i 287 | c++ 288 | } 289 | if data[0] != 0 { 290 | t.Errorf("bug 0") 291 | } 292 | if data[1] != 1 { 293 | t.Errorf("bug 1") 294 | } 295 | if data[2] != 2 { 296 | t.Errorf("bug 2") 297 | } 298 | if data[3] != 10 { 299 | t.Errorf("bug 3") 300 | } 301 | if data[4] != 2000 { 302 | t.Errorf("bug 4") 303 | } 304 | } 305 | 306 | func TestNextSet(t *testing.T) { 307 | testCases := []struct { 308 | name string 309 | // 310 | set []uint 311 | del []uint 312 | // 313 | startIdx uint 314 | wantIdx uint 315 | wantOk bool 316 | }{ 317 | { 318 | name: "null", 319 | set: []uint{}, 320 | startIdx: 0, 321 | wantIdx: 0, 322 | wantOk: false, 323 | }, 324 | { 325 | name: "zero", 326 | set: []uint{0}, 327 | startIdx: 0, 328 | wantIdx: 0, 329 | wantOk: true, 330 | }, 331 | { 332 | name: "1,5", 333 | set: []uint{1, 5}, 334 | startIdx: 0, 335 | wantIdx: 1, 336 | wantOk: true, 337 | }, 338 | { 339 | name: "many", 340 | set: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 341 | startIdx: 100, 342 | wantIdx: 130, 343 | wantOk: true, 344 | }, 345 | { 346 | name: "many-2", 347 | set: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 348 | del: []uint{130, 190, 300, 420}, 349 | startIdx: 100, 350 | wantIdx: 250, 351 | wantOk: true, 352 | }, 353 | { 354 | name: "last", 355 | set: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 356 | startIdx: 511, 357 | wantIdx: 511, 358 | wantOk: true, 359 | }, 360 | { 361 | name: "last-2", 362 | set: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 363 | del: []uint{511}, 364 | startIdx: 511, 365 | wantIdx: 0, 366 | wantOk: false, 367 | }, 368 | } 369 | 370 | for _, tc := range testCases { 371 | var b BitSet 372 | for _, u := range tc.set { 373 | b.Set(u) 374 | } 375 | 376 | for _, u := range tc.del { 377 | b.Clear(u) // without compact 378 | } 379 | 380 | idx, ok := b.NextSet(tc.startIdx) 381 | 382 | if ok != tc.wantOk { 383 | t.Errorf("NextSet, %s: got ok: %v, want: %v", tc.name, ok, tc.wantOk) 384 | } 385 | if idx != tc.wantIdx { 386 | t.Errorf("NextSet, %s: got next idx: %d, want: %d", tc.name, idx, tc.wantIdx) 387 | } 388 | } 389 | } 390 | 391 | func TestNextSetMany(t *testing.T) { 392 | testCases := []struct { 393 | name string 394 | // 395 | set []uint 396 | del []uint 397 | // 398 | buf []uint 399 | wantData []uint 400 | // 401 | startIdx uint 402 | wantIdx uint 403 | }{ 404 | { 405 | name: "null", 406 | set: []uint{}, 407 | del: []uint{}, 408 | buf: make([]uint, 0, 512), 409 | wantData: []uint{}, 410 | startIdx: 0, 411 | wantIdx: 0, 412 | }, 413 | { 414 | name: "zero", 415 | set: []uint{0}, 416 | del: []uint{}, 417 | buf: make([]uint, 0, 512), 418 | wantData: []uint{0}, // bit #0 is set 419 | startIdx: 0, 420 | wantIdx: 0, 421 | }, 422 | { 423 | name: "1,5", 424 | set: []uint{1, 5}, 425 | del: []uint{}, 426 | buf: make([]uint, 0, 512), 427 | wantData: []uint{1, 5}, 428 | startIdx: 0, 429 | wantIdx: 5, 430 | }, 431 | { 432 | name: "many", 433 | set: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 434 | del: []uint{}, 435 | buf: make([]uint, 0, 512), 436 | wantData: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 437 | startIdx: 0, 438 | wantIdx: 511, 439 | }, 440 | { 441 | name: "start idx", 442 | set: []uint{1, 65, 130, 190, 250, 300, 380, 420, 480, 511}, 443 | del: []uint{}, 444 | buf: make([]uint, 0, 512), 445 | wantData: []uint{250, 300, 380, 420, 480, 511}, 446 | startIdx: 195, 447 | wantIdx: 511, 448 | }, 449 | { 450 | name: "zero buffer", 451 | set: []uint{1, 2, 3, 4, 511}, 452 | del: []uint{}, 453 | buf: make([]uint, 0), // buffer 454 | wantData: []uint{}, 455 | startIdx: 0, 456 | wantIdx: 0, 457 | }, 458 | { 459 | name: "buffer too short, first word", 460 | set: []uint{1, 2, 3, 4, 5, 6, 7, 8, 9}, 461 | del: []uint{}, 462 | buf: make([]uint, 0, 5), // buffer 463 | wantData: []uint{1, 2, 3, 4, 5}, 464 | startIdx: 0, 465 | wantIdx: 5, 466 | }, 467 | { 468 | name: "buffer too short", 469 | set: []uint{65, 66, 67, 68, 69, 70}, 470 | del: []uint{}, 471 | buf: make([]uint, 0, 5), // buffer 472 | wantData: []uint{65, 66, 67, 68, 69}, 473 | startIdx: 0, 474 | wantIdx: 69, 475 | }, 476 | { 477 | name: "special, last return", 478 | set: []uint{1}, 479 | del: []uint{1}, // delete without compact 480 | buf: make([]uint, 0, 5), // buffer 481 | wantData: []uint{}, 482 | startIdx: 0, 483 | wantIdx: 0, 484 | }, 485 | } 486 | 487 | for _, tc := range testCases { 488 | var b BitSet 489 | for _, u := range tc.set { 490 | b.Set(u) 491 | } 492 | 493 | for _, u := range tc.del { 494 | b.Clear(u) // without compact 495 | } 496 | 497 | idx, buf := b.NextSetMany(tc.startIdx, tc.buf) 498 | 499 | if idx != tc.wantIdx { 500 | t.Errorf("NextSetMany, %s: got next idx: %d, want: %d", tc.name, idx, tc.wantIdx) 501 | } 502 | 503 | if !reflect.DeepEqual(buf, tc.wantData) { 504 | t.Errorf("NextSetMany, %s: returned buf is not equal as expected:\ngot: %v\nwant: %v", 505 | tc.name, buf, tc.wantData) 506 | } 507 | } 508 | } 509 | 510 | func TestAppendTo(t *testing.T) { 511 | testCases := []struct { 512 | name string 513 | set []uint 514 | buf []uint 515 | }{ 516 | { 517 | name: "null", 518 | set: nil, 519 | buf: nil, 520 | }, 521 | { 522 | name: "one", 523 | set: []uint{42}, 524 | buf: make([]uint, 0, 5), 525 | }, 526 | { 527 | name: "many", 528 | set: []uint{1, 42, 55, 258, 7211, 54666}, 529 | buf: make([]uint, 0), 530 | }, 531 | } 532 | 533 | for _, tc := range testCases { 534 | var b BitSet 535 | for _, u := range tc.set { 536 | b.Set(u) 537 | } 538 | 539 | tc.buf = b.AppendTo(tc.buf) 540 | 541 | if !reflect.DeepEqual(tc.buf, tc.set) { 542 | t.Errorf("AppendTo, %s: returned buf is not equal as expected:\ngot: %v\nwant: %v", 543 | tc.name, tc.buf, tc.set) 544 | } 545 | } 546 | } 547 | 548 | func TestAsSlice(t *testing.T) { 549 | testCases := []struct { 550 | name string 551 | set []uint 552 | buf []uint 553 | }{ 554 | { 555 | name: "null", 556 | set: nil, 557 | buf: nil, 558 | }, 559 | { 560 | name: "one", 561 | set: []uint{42}, 562 | buf: make([]uint, 1), 563 | }, 564 | { 565 | name: "many", 566 | set: []uint{1, 42, 55, 258, 7211, 54666}, 567 | buf: make([]uint, 6), 568 | }, 569 | } 570 | 571 | for _, tc := range testCases { 572 | var b BitSet 573 | for _, u := range tc.set { 574 | b.Set(u) 575 | } 576 | 577 | tc.buf = b.AsSlice(tc.buf) 578 | 579 | if !reflect.DeepEqual(tc.buf, tc.set) { 580 | t.Errorf("AsSlice, %s: returned buf is not equal as expected:\ngot: %v\nwant: %v", 581 | tc.name, tc.buf, tc.set) 582 | } 583 | } 584 | } 585 | 586 | func TestPanicAppendTo(t *testing.T) { 587 | defer func() { 588 | if r := recover(); r != nil { 589 | t.Error("AppendTo with empty buf should not have caused a panic") 590 | } 591 | }() 592 | v := New(1000) 593 | v.Set(1000) 594 | _ = v.AppendTo(nil) 595 | } 596 | 597 | func TestPanicAsSlice(t *testing.T) { 598 | defer func() { 599 | if r := recover(); r == nil { 600 | t.Error("AsSlice with buf too small should have caused a panic") 601 | } 602 | }() 603 | v := New(1000) 604 | v.Set(1000) 605 | _ = v.AsSlice(nil) 606 | } 607 | 608 | func TestSetTo(t *testing.T) { 609 | v := New(1000) 610 | v.SetTo(100, true) 611 | if !v.Test(100) { 612 | t.Errorf("Bit %d is clear, and it shouldn't be.", 100) 613 | } 614 | v.SetTo(100, false) 615 | if v.Test(100) { 616 | t.Errorf("Bit %d is set, and it shouldn't be.", 100) 617 | } 618 | } 619 | 620 | func TestChain(t *testing.T) { 621 | if !New(1000).Set(100).Set(99).Clear(99).Test(100) { 622 | t.Errorf("Bit %d is clear, and it shouldn't be.", 100) 623 | } 624 | } 625 | 626 | func TestOutOfBoundsLong(t *testing.T) { 627 | v := New(64) 628 | defer func() { 629 | if r := recover(); r != nil { 630 | t.Error("Long distance out of index error should not have caused a panic") 631 | } 632 | }() 633 | v.Set(1000) 634 | } 635 | 636 | func TestOutOfBoundsClose(t *testing.T) { 637 | v := New(65) 638 | defer func() { 639 | if r := recover(); r != nil { 640 | t.Error("Local out of index error should not have caused a panic") 641 | } 642 | }() 643 | v.Set(66) 644 | } 645 | 646 | func TestCount(t *testing.T) { 647 | tot := uint(64*4 + 11) // just some multi unit64 number 648 | v := New(tot) 649 | checkLast := true 650 | for i := uint(0); i < tot; i++ { 651 | sz := uint(v.Count()) 652 | if sz != i { 653 | t.Errorf("Count reported as %d, but it should be %d", sz, i) 654 | checkLast = false 655 | break 656 | } 657 | v.Set(i) 658 | } 659 | if checkLast { 660 | sz := uint(v.Count()) 661 | if sz != tot { 662 | t.Errorf("After all bits set, size reported as %d, but it should be %d", sz, tot) 663 | } 664 | } 665 | } 666 | 667 | // test setting every 3rd bit, just in case something odd is happening 668 | func TestCount2(t *testing.T) { 669 | tot := uint(64*4 + 11) // just some multi unit64 number 670 | v := New(tot) 671 | for i := uint(0); i < tot; i += 3 { 672 | sz := uint(v.Count()) 673 | if sz != i/3 { 674 | t.Errorf("Count reported as %d, but it should be %d", sz, i) 675 | break 676 | } 677 | v.Set(i) 678 | } 679 | } 680 | 681 | // nil tests 682 | func TestNullTest(t *testing.T) { 683 | var v *BitSet 684 | defer func() { 685 | if r := recover(); r == nil { 686 | t.Error("Checking bit of null reference should have caused a panic") 687 | } 688 | }() 689 | v.Test(66) 690 | } 691 | 692 | func TestNullSet(t *testing.T) { 693 | var v *BitSet 694 | defer func() { 695 | if r := recover(); r == nil { 696 | t.Error("Setting bit of null reference should have caused a panic") 697 | } 698 | }() 699 | v.Set(66) 700 | } 701 | 702 | func TestNullClear(t *testing.T) { 703 | var v *BitSet 704 | defer func() { 705 | if r := recover(); r == nil { 706 | t.Error("Clearning bit of null reference should have caused a panic") 707 | } 708 | }() 709 | v.Clear(66) 710 | } 711 | 712 | func TestNullCount(t *testing.T) { 713 | var v *BitSet 714 | defer func() { 715 | if r := recover(); r != nil { 716 | t.Error("Counting null reference should not have caused a panic") 717 | } 718 | }() 719 | cnt := v.Count() 720 | if cnt != 0 { 721 | t.Errorf("Count reported as %d, but it should be 0", cnt) 722 | } 723 | } 724 | 725 | func TestMustNew(t *testing.T) { 726 | testCases := []struct { 727 | length uint 728 | nwords int 729 | }{ 730 | { 731 | length: 0, 732 | nwords: 0, 733 | }, 734 | { 735 | length: 1, 736 | nwords: 1, 737 | }, 738 | { 739 | length: 64, 740 | nwords: 1, 741 | }, 742 | { 743 | length: 65, 744 | nwords: 2, 745 | }, 746 | { 747 | length: 512, 748 | nwords: 8, 749 | }, 750 | { 751 | length: 513, 752 | nwords: 9, 753 | }, 754 | } 755 | 756 | for _, tc := range testCases { 757 | b := MustNew(tc.length) 758 | if len(b.set) != tc.nwords { 759 | t.Errorf("length = %d, len(b.set) got: %d, want: %d", tc.length, len(b.set), tc.nwords) 760 | } 761 | } 762 | } 763 | 764 | func TestPanicMustNew(t *testing.T) { 765 | defer func() { 766 | if r := recover(); r == nil { 767 | t.Error("length too big should have caused a panic") 768 | } 769 | }() 770 | MustNew(Cap()) 771 | } 772 | 773 | func TestPanicDifferenceBNil(t *testing.T) { 774 | var b *BitSet 775 | compare := New(10) 776 | defer func() { 777 | if r := recover(); r == nil { 778 | t.Error("Nil First should should have caused a panic") 779 | } 780 | }() 781 | b.Difference(compare) 782 | } 783 | 784 | func TestPanicDifferenceCompareNil(t *testing.T) { 785 | var compare *BitSet 786 | b := New(10) 787 | defer func() { 788 | if r := recover(); r == nil { 789 | t.Error("Nil Second should should have caused a panic") 790 | } 791 | }() 792 | b.Difference(compare) 793 | } 794 | 795 | func TestPanicUnionBNil(t *testing.T) { 796 | var b *BitSet 797 | compare := New(10) 798 | defer func() { 799 | if r := recover(); r == nil { 800 | t.Error("Nil First should should have caused a panic") 801 | } 802 | }() 803 | b.Union(compare) 804 | } 805 | 806 | func TestPanicUnionCompareNil(t *testing.T) { 807 | var compare *BitSet 808 | b := New(10) 809 | defer func() { 810 | if r := recover(); r == nil { 811 | t.Error("Nil Second should should have caused a panic") 812 | } 813 | }() 814 | b.Union(compare) 815 | } 816 | 817 | func TestPanicIntersectionBNil(t *testing.T) { 818 | var b *BitSet 819 | compare := New(10) 820 | defer func() { 821 | if r := recover(); r == nil { 822 | t.Error("Nil First should should have caused a panic") 823 | } 824 | }() 825 | b.Intersection(compare) 826 | } 827 | 828 | func TestPanicIntersectionCompareNil(t *testing.T) { 829 | var compare *BitSet 830 | b := New(10) 831 | defer func() { 832 | if r := recover(); r == nil { 833 | t.Error("Nil Second should should have caused a panic") 834 | } 835 | }() 836 | b.Intersection(compare) 837 | } 838 | 839 | func TestPanicSymmetricDifferenceBNil(t *testing.T) { 840 | var b *BitSet 841 | compare := New(10) 842 | defer func() { 843 | if r := recover(); r == nil { 844 | t.Error("Nil First should should have caused a panic") 845 | } 846 | }() 847 | b.SymmetricDifference(compare) 848 | } 849 | 850 | func TestPanicSymmetricDifferenceCompareNil(t *testing.T) { 851 | var compare *BitSet 852 | b := New(10) 853 | defer func() { 854 | if r := recover(); r == nil { 855 | t.Error("Nil Second should should have caused a panic") 856 | } 857 | }() 858 | b.SymmetricDifference(compare) 859 | } 860 | 861 | func TestPanicComplementBNil(t *testing.T) { 862 | var b *BitSet 863 | defer func() { 864 | if r := recover(); r == nil { 865 | t.Error("Nil should should have caused a panic") 866 | } 867 | }() 868 | b.Complement() 869 | } 870 | 871 | func TestPanicAnytBNil(t *testing.T) { 872 | var b *BitSet 873 | defer func() { 874 | if r := recover(); r == nil { 875 | t.Error("Nil should should have caused a panic") 876 | } 877 | }() 878 | b.Any() 879 | } 880 | 881 | func TestPanicNonetBNil(t *testing.T) { 882 | var b *BitSet 883 | defer func() { 884 | if r := recover(); r == nil { 885 | t.Error("Nil should should have caused a panic") 886 | } 887 | }() 888 | b.None() 889 | } 890 | 891 | func TestPanicAlltBNil(t *testing.T) { 892 | var b *BitSet 893 | defer func() { 894 | if r := recover(); r == nil { 895 | t.Error("Nil should should have caused a panic") 896 | } 897 | }() 898 | b.All() 899 | } 900 | 901 | func TestAll(t *testing.T) { 902 | v := New(0) 903 | if !v.All() { 904 | t.Error("Empty sets should return true on All()") 905 | } 906 | v = New(2) 907 | v.SetTo(0, true) 908 | v.SetTo(1, true) 909 | if !v.All() { 910 | t.Error("Non-empty sets with all bits set should return true on All()") 911 | } 912 | v = New(2) 913 | if v.All() { 914 | t.Error("Non-empty sets with no bits set should return false on All()") 915 | } 916 | v = New(2) 917 | v.SetTo(0, true) 918 | if v.All() { 919 | t.Error("Non-empty sets with some bits set should return false on All()") 920 | } 921 | } 922 | 923 | func TestShrink(t *testing.T) { 924 | bs := New(10) 925 | bs.Set(0) 926 | bs.Shrink(63) 927 | if !bs.Test(0) { 928 | t.Error("0 should be set") 929 | return 930 | } 931 | b := New(0) 932 | 933 | b.Set(0) 934 | b.Set(1) 935 | b.Set(2) 936 | b.Set(3) 937 | b.Set(64) 938 | b.Compact() 939 | if !b.Test(0) { 940 | t.Error("0 should be set") 941 | return 942 | } 943 | if !b.Test(1) { 944 | t.Error("1 should be set") 945 | return 946 | } 947 | if !b.Test(2) { 948 | t.Error("2 should be set") 949 | return 950 | } 951 | if !b.Test(3) { 952 | t.Error("3 should be set") 953 | return 954 | } 955 | if !b.Test(64) { 956 | t.Error("64 should be set") 957 | return 958 | } 959 | 960 | b.Shrink(2) 961 | if !b.Test(0) { 962 | t.Error("0 should be set") 963 | return 964 | } 965 | if !b.Test(1) { 966 | t.Error("1 should be set") 967 | return 968 | } 969 | if !b.Test(2) { 970 | t.Error("2 should be set") 971 | return 972 | } 973 | if b.Test(3) { 974 | t.Error("3 should not be set") 975 | return 976 | } 977 | if b.Test(64) { 978 | t.Error("64 should not be set") 979 | return 980 | } 981 | 982 | b.Set(24) 983 | b.Shrink(100) 984 | if !b.Test(24) { 985 | t.Error("24 should be set") 986 | return 987 | } 988 | 989 | b.Set(127) 990 | b.Set(128) 991 | b.Set(129) 992 | b.Compact() 993 | if !b.Test(127) { 994 | t.Error("127 should be set") 995 | return 996 | } 997 | if !b.Test(128) { 998 | t.Error("128 should be set") 999 | return 1000 | } 1001 | if !b.Test(129) { 1002 | t.Error("129 be set") 1003 | return 1004 | } 1005 | 1006 | b.Shrink(128) 1007 | if !b.Test(127) { 1008 | t.Error("127 should be set") 1009 | return 1010 | } 1011 | if !b.Test(128) { 1012 | t.Error("128 should be set") 1013 | return 1014 | } 1015 | if b.Test(129) { 1016 | t.Error("129 should not be set") 1017 | return 1018 | } 1019 | 1020 | b.Set(129) 1021 | b.Shrink(129) 1022 | if !b.Test(129) { 1023 | t.Error("129 should be set") 1024 | return 1025 | } 1026 | 1027 | b.Set(1000) 1028 | b.Set(2000) 1029 | b.Set(3000) 1030 | b.Shrink(3000) 1031 | if len(b.set) != 3000/64+1 { 1032 | t.Error("Wrong length of BitSet.set") 1033 | return 1034 | } 1035 | if !b.Test(3000) { 1036 | t.Error("3000 should be set") 1037 | return 1038 | } 1039 | 1040 | b.Shrink(2000) 1041 | if len(b.set) != 2000/64+1 { 1042 | t.Error("Wrong length of BitSet.set") 1043 | return 1044 | } 1045 | if b.Test(3000) { 1046 | t.Error("3000 should not be set") 1047 | return 1048 | } 1049 | if !b.Test(2000) { 1050 | t.Error("2000 should be set") 1051 | return 1052 | } 1053 | if !b.Test(1000) { 1054 | t.Error("1000 should be set") 1055 | return 1056 | } 1057 | if !b.Test(24) { 1058 | t.Error("24 should be set") 1059 | return 1060 | } 1061 | 1062 | b = New(110) 1063 | b.Set(80) 1064 | b.Shrink(70) 1065 | for _, word := range b.set { 1066 | if word != 0 { 1067 | t.Error("word should be 0", word) 1068 | } 1069 | } 1070 | } 1071 | 1072 | func TestInsertAtWithSet(t *testing.T) { 1073 | b := New(0) 1074 | b.Set(0) 1075 | b.Set(1) 1076 | b.Set(63) 1077 | b.Set(64) 1078 | b.Set(65) 1079 | 1080 | b.InsertAt(3) 1081 | if !b.Test(0) { 1082 | t.Error("0 should be set") 1083 | return 1084 | } 1085 | if !b.Test(1) { 1086 | t.Error("1 should be set") 1087 | return 1088 | } 1089 | if b.Test(3) { 1090 | t.Error("3 should not be set") 1091 | return 1092 | } 1093 | if !b.Test(64) { 1094 | t.Error("64 should be set") 1095 | return 1096 | } 1097 | if !b.Test(65) { 1098 | t.Error("65 should be set") 1099 | return 1100 | } 1101 | if !b.Test(66) { 1102 | t.Error("66 should be set") 1103 | return 1104 | } 1105 | } 1106 | 1107 | func TestInsertAt(t *testing.T) { 1108 | type testCase struct { 1109 | input []string 1110 | insertIdx uint 1111 | expected []string 1112 | } 1113 | 1114 | testCases := []testCase{ 1115 | { 1116 | input: []string{ 1117 | "1111111111111111111111111111111111111111111111111111111111111111", 1118 | }, 1119 | insertIdx: uint(62), 1120 | expected: []string{ 1121 | "1011111111111111111111111111111111111111111111111111111111111111", 1122 | "0000000000000000000000000000000000000000000000000000000000000001", 1123 | }, 1124 | }, 1125 | { 1126 | input: []string{ 1127 | "1111111111111111111111111111111111111111111111111111111111111111", 1128 | }, 1129 | insertIdx: uint(63), 1130 | expected: []string{ 1131 | "0111111111111111111111111111111111111111111111111111111111111111", 1132 | "0000000000000000000000000000000000000000000000000000000000000001", 1133 | }, 1134 | }, 1135 | { 1136 | input: []string{ 1137 | "1111111111111111111111111111111111111111111111111111111111111111", 1138 | }, 1139 | insertIdx: uint(0), 1140 | expected: []string{ 1141 | "1111111111111111111111111111111111111111111111111111111111111110", 1142 | "0000000000000000000000000000000000000000000000000000000000000001", 1143 | }, 1144 | }, 1145 | { 1146 | input: []string{ 1147 | "1111111111111111111111111111111111111111111111111111111111111111", 1148 | "1111111111111111111111111111111111111111111111111111111111111111", 1149 | "1111111111111111111111111111111111111111111111111111111111111111", 1150 | }, 1151 | insertIdx: uint(70), 1152 | expected: []string{ 1153 | "1111111111111111111111111111111111111111111111111111111111111111", 1154 | "1111111111111111111111111111111111111111111111111111111110111111", 1155 | "1111111111111111111111111111111111111111111111111111111111111111", 1156 | "0000000000000000000000000000000000000000000000000000000000000001", 1157 | }, 1158 | }, 1159 | { 1160 | input: []string{ 1161 | "1111111111111111111111111111111111111111111111111111111111111111", 1162 | "1111111111111111111111111111111111111111111111111111111111111111", 1163 | "1111111111111111111111111111111111111111111111111111111111110000", 1164 | }, 1165 | insertIdx: uint(70), 1166 | expected: []string{ 1167 | "1111111111111111111111111111111111111111111111111111111111111111", 1168 | "1111111111111111111111111111111111111111111111111111111110111111", 1169 | "1111111111111111111111111111111111111111111111111111111111100001", 1170 | "0000000000000000000000000000000000000000000000000000000000000001", 1171 | }, 1172 | }, 1173 | { 1174 | input: []string{ 1175 | "1111111111111111111111111111111111111111111111111111111111110000", 1176 | }, 1177 | insertIdx: uint(10), 1178 | expected: []string{ 1179 | "1111111111111111111111111111111111111111111111111111101111110000", 1180 | "0000000000000000000000000000000000000000000000000000000000000001", 1181 | }, 1182 | }, 1183 | } 1184 | 1185 | for _, tc := range testCases { 1186 | var input []uint64 1187 | for _, inputElement := range tc.input { 1188 | parsed, _ := strconv.ParseUint(inputElement, 2, 64) 1189 | input = append(input, parsed) 1190 | } 1191 | 1192 | var expected []uint64 1193 | for _, expectedElement := range tc.expected { 1194 | parsed, _ := strconv.ParseUint(expectedElement, 2, 64) 1195 | expected = append(expected, parsed) 1196 | } 1197 | 1198 | b := From(input) 1199 | b.InsertAt(tc.insertIdx) 1200 | if len(b.set) != len(expected) { 1201 | t.Error("Length of sets should be equal") 1202 | return 1203 | } 1204 | for i := range b.set { 1205 | if b.set[i] != expected[i] { 1206 | t.Error("Unexpected results found in set") 1207 | return 1208 | } 1209 | } 1210 | } 1211 | } 1212 | 1213 | func TestNone(t *testing.T) { 1214 | v := New(0) 1215 | if !v.None() { 1216 | t.Error("Empty sets should return true on None()") 1217 | } 1218 | v = New(2) 1219 | v.SetTo(0, true) 1220 | v.SetTo(1, true) 1221 | if v.None() { 1222 | t.Error("Non-empty sets with all bits set should return false on None()") 1223 | } 1224 | v = New(2) 1225 | if !v.None() { 1226 | t.Error("Non-empty sets with no bits set should return true on None()") 1227 | } 1228 | v = New(2) 1229 | v.SetTo(0, true) 1230 | if v.None() { 1231 | t.Error("Non-empty sets with some bits set should return false on None()") 1232 | } 1233 | v = new(BitSet) 1234 | if !v.None() { 1235 | t.Error("Empty sets should return true on None()") 1236 | } 1237 | } 1238 | 1239 | func TestEqual(t *testing.T) { 1240 | a := New(100) 1241 | b := New(99) 1242 | c := New(100) 1243 | if a.Equal(b) { 1244 | t.Error("Sets of different sizes should be not be equal") 1245 | } 1246 | if !a.Equal(c) { 1247 | t.Error("Two empty sets of the same size should be equal") 1248 | } 1249 | a.Set(99) 1250 | c.Set(0) 1251 | if a.Equal(c) { 1252 | t.Error("Two sets with differences should not be equal") 1253 | } 1254 | c.Set(99) 1255 | a.Set(0) 1256 | if !a.Equal(c) { 1257 | t.Error("Two sets with the same bits set should be equal") 1258 | } 1259 | if a.Equal(nil) { 1260 | t.Error("The sets should be different") 1261 | } 1262 | a = New(0) 1263 | b = New(0) 1264 | if !a.Equal(b) { 1265 | t.Error("Two empty set should be equal") 1266 | } 1267 | var x *BitSet 1268 | var y *BitSet 1269 | z := New(0) 1270 | if !x.Equal(y) { 1271 | t.Error("Two nil bitsets should be equal") 1272 | } 1273 | if x.Equal(z) { 1274 | t.Error("Nil receiver bitset should not be equal to non-nil bitset") 1275 | } 1276 | } 1277 | 1278 | func TestUnion(t *testing.T) { 1279 | a := New(100) 1280 | b := New(200) 1281 | for i := uint(1); i < 100; i += 2 { 1282 | a.Set(i) 1283 | b.Set(i - 1) 1284 | } 1285 | for i := uint(100); i < 200; i++ { 1286 | b.Set(i) 1287 | } 1288 | if a.UnionCardinality(b) != 200 { 1289 | t.Errorf("Union should have 200 bits set, but had %d", a.UnionCardinality(b)) 1290 | } 1291 | if a.UnionCardinality(b) != b.UnionCardinality(a) { 1292 | t.Errorf("Union should be symmetric") 1293 | } 1294 | 1295 | c := a.Union(b) 1296 | d := b.Union(a) 1297 | if c.Count() != 200 { 1298 | t.Errorf("Union should have 200 bits set, but had %d", c.Count()) 1299 | } 1300 | if !c.Equal(d) { 1301 | t.Errorf("Union should be symmetric") 1302 | } 1303 | } 1304 | 1305 | func TestEmptyUnionCardinality(t *testing.T) { 1306 | a := New(0) 1307 | b := New(0) 1308 | if a.UnionCardinality(b) != 0 { 1309 | t.Error("UnionCardinality should be zero") 1310 | } 1311 | } 1312 | 1313 | func TestInPlaceUnion(t *testing.T) { 1314 | a := New(100) 1315 | b := New(200) 1316 | for i := uint(1); i < 100; i += 2 { 1317 | a.Set(i) 1318 | b.Set(i - 1) 1319 | } 1320 | for i := uint(100); i < 200; i++ { 1321 | b.Set(i) 1322 | } 1323 | c := a.Clone() 1324 | c.InPlaceUnion(b) 1325 | d := b.Clone() 1326 | d.InPlaceUnion(a) 1327 | if c.Count() != 200 { 1328 | t.Errorf("Union should have 200 bits set, but had %d", c.Count()) 1329 | } 1330 | if d.Count() != 200 { 1331 | t.Errorf("Union should have 200 bits set, but had %d", d.Count()) 1332 | } 1333 | if !c.Equal(d) { 1334 | t.Errorf("Union should be symmetric") 1335 | } 1336 | } 1337 | 1338 | func TestIntersection(t *testing.T) { 1339 | a := New(100) 1340 | b := New(200) 1341 | for i := uint(1); i < 100; i += 2 { 1342 | a.Set(i) 1343 | b.Set(i - 1).Set(i) 1344 | } 1345 | for i := uint(100); i < 200; i++ { 1346 | b.Set(i) 1347 | } 1348 | if a.IntersectionCardinality(b) != 50 { 1349 | t.Errorf("Intersection should have 50 bits set, but had %d", a.IntersectionCardinality(b)) 1350 | } 1351 | if a.IntersectionCardinality(b) != b.IntersectionCardinality(a) { 1352 | t.Errorf("Intersection should be symmetric") 1353 | } 1354 | c := a.Intersection(b) 1355 | d := b.Intersection(a) 1356 | if c.Count() != 50 { 1357 | t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) 1358 | } 1359 | if !c.Equal(d) { 1360 | t.Errorf("Intersection should be symmetric") 1361 | } 1362 | } 1363 | 1364 | func TestEmptyIntersectionCardinality(t *testing.T) { 1365 | a := New(0) 1366 | b := New(0) 1367 | if a.IntersectionCardinality(b) != 0 { 1368 | t.Error("IntersectionCardinality should be zero") 1369 | } 1370 | } 1371 | 1372 | func TestInplaceIntersection(t *testing.T) { 1373 | a := New(100) 1374 | b := New(200) 1375 | for i := uint(1); i < 100; i += 2 { 1376 | a.Set(i) 1377 | b.Set(i - 1).Set(i) 1378 | } 1379 | for i := uint(100); i < 200; i++ { 1380 | b.Set(i) 1381 | } 1382 | c := a.Clone() 1383 | c.InPlaceIntersection(b) 1384 | d := b.Clone() 1385 | d.InPlaceIntersection(a) 1386 | if c.Count() != 50 { 1387 | t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) 1388 | } 1389 | if d.Count() != 50 { 1390 | t.Errorf("Intersection should have 50 bits set, but had %d", d.Count()) 1391 | } 1392 | if !c.Equal(d) { 1393 | t.Errorf("Intersection should be symmetric") 1394 | } 1395 | } 1396 | 1397 | func TestDifference(t *testing.T) { 1398 | a := New(100) 1399 | b := New(200) 1400 | for i := uint(1); i < 100; i += 2 { 1401 | a.Set(i) 1402 | b.Set(i - 1) 1403 | } 1404 | for i := uint(100); i < 200; i++ { 1405 | b.Set(i) 1406 | } 1407 | if a.DifferenceCardinality(b) != 50 { 1408 | t.Errorf("a-b Difference should have 50 bits set, but had %d", a.DifferenceCardinality(b)) 1409 | } 1410 | if b.DifferenceCardinality(a) != 150 { 1411 | t.Errorf("b-a Difference should have 150 bits set, but had %d", b.DifferenceCardinality(a)) 1412 | } 1413 | 1414 | c := a.Difference(b) 1415 | d := b.Difference(a) 1416 | if c.Count() != 50 { 1417 | t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) 1418 | } 1419 | if d.Count() != 150 { 1420 | t.Errorf("b-a Difference should have 150 bits set, but had %d", d.Count()) 1421 | } 1422 | if c.Equal(d) { 1423 | t.Errorf("Difference, here, should not be symmetric") 1424 | } 1425 | } 1426 | 1427 | func TestEmptyDifferenceCardinality(t *testing.T) { 1428 | a := New(0) 1429 | b := New(0) 1430 | if a.DifferenceCardinality(b) != 0 { 1431 | t.Error("DifferenceCardinality should be zero") 1432 | } 1433 | } 1434 | 1435 | func TestInPlaceDifference(t *testing.T) { 1436 | a := New(100) 1437 | b := New(200) 1438 | for i := uint(1); i < 100; i += 2 { 1439 | a.Set(i) 1440 | b.Set(i - 1) 1441 | } 1442 | for i := uint(100); i < 200; i++ { 1443 | b.Set(i) 1444 | } 1445 | c := a.Clone() 1446 | c.InPlaceDifference(b) 1447 | d := b.Clone() 1448 | d.InPlaceDifference(a) 1449 | if c.Count() != 50 { 1450 | t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) 1451 | } 1452 | if d.Count() != 150 { 1453 | t.Errorf("b-a Difference should have 150 bits set, but had %d", d.Count()) 1454 | } 1455 | if c.Equal(d) { 1456 | t.Errorf("Difference, here, should not be symmetric") 1457 | } 1458 | } 1459 | 1460 | func TestSymmetricDifference(t *testing.T) { 1461 | a := New(100) 1462 | b := New(200) 1463 | for i := uint(1); i < 100; i += 2 { 1464 | a.Set(i) // 01010101010 ... 0000000 1465 | b.Set(i - 1).Set(i) // 11111111111111111000000 1466 | } 1467 | for i := uint(100); i < 200; i++ { 1468 | b.Set(i) 1469 | } 1470 | if a.SymmetricDifferenceCardinality(b) != 150 { 1471 | t.Errorf("a^b Difference should have 150 bits set, but had %d", a.SymmetricDifferenceCardinality(b)) 1472 | } 1473 | if b.SymmetricDifferenceCardinality(a) != 150 { 1474 | t.Errorf("b^a Difference should have 150 bits set, but had %d", b.SymmetricDifferenceCardinality(a)) 1475 | } 1476 | 1477 | c := a.SymmetricDifference(b) 1478 | d := b.SymmetricDifference(a) 1479 | if c.Count() != 150 { 1480 | t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) 1481 | } 1482 | if d.Count() != 150 { 1483 | t.Errorf("b^a Difference should have 150 bits set, but had %d", d.Count()) 1484 | } 1485 | if !c.Equal(d) { 1486 | t.Errorf("SymmetricDifference should be symmetric") 1487 | } 1488 | } 1489 | 1490 | func TestEmptySymmetricDifferenceCardinality(t *testing.T) { 1491 | a := New(0) 1492 | b := New(0) 1493 | if a.SymmetricDifferenceCardinality(b) != 0 { 1494 | t.Error("SymmetricDifferenceCardinality should be zero") 1495 | } 1496 | } 1497 | 1498 | func TestInPlaceSymmetricDifference(t *testing.T) { 1499 | a := New(100) 1500 | b := New(200) 1501 | for i := uint(1); i < 100; i += 2 { 1502 | a.Set(i) // 01010101010 ... 0000000 1503 | b.Set(i - 1).Set(i) // 11111111111111111000000 1504 | } 1505 | for i := uint(100); i < 200; i++ { 1506 | b.Set(i) 1507 | } 1508 | c := a.Clone() 1509 | c.InPlaceSymmetricDifference(b) 1510 | d := b.Clone() 1511 | d.InPlaceSymmetricDifference(a) 1512 | if c.Count() != 150 { 1513 | t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) 1514 | } 1515 | if d.Count() != 150 { 1516 | t.Errorf("b^a Difference should have 150 bits set, but had %d", d.Count()) 1517 | } 1518 | if !c.Equal(d) { 1519 | t.Errorf("SymmetricDifference should be symmetric") 1520 | } 1521 | } 1522 | 1523 | func TestComplement(t *testing.T) { 1524 | a := New(50) 1525 | b := a.Complement() 1526 | if b.Count() != 50 { 1527 | t.Errorf("Complement failed, size should be 50, but was %d", b.Count()) 1528 | } 1529 | a = New(50) 1530 | a.Set(10).Set(20).Set(42) 1531 | b = a.Complement() 1532 | if b.Count() != 47 { 1533 | t.Errorf("Complement failed, size should be 47, but was %d", b.Count()) 1534 | } 1535 | } 1536 | 1537 | func TestIsSuperSet(t *testing.T) { 1538 | test := func(name string, lenS, lenSS int, overrideS, overrideSS map[int]bool, want, wantStrict bool) { 1539 | t.Run(name, func(t *testing.T) { 1540 | s := New(uint(lenS)) 1541 | ss := New(uint(lenSS)) 1542 | 1543 | l := lenS 1544 | if lenSS < lenS { 1545 | l = lenSS 1546 | } 1547 | 1548 | r := rand.New(rand.NewSource(42)) 1549 | for i := 0; i < l; i++ { 1550 | bit := r.Intn(2) == 1 1551 | s.SetTo(uint(i), bit) 1552 | ss.SetTo(uint(i), bit) 1553 | } 1554 | 1555 | for i, v := range overrideS { 1556 | s.SetTo(uint(i), v) 1557 | } 1558 | for i, v := range overrideSS { 1559 | ss.SetTo(uint(i), v) 1560 | } 1561 | 1562 | if got := ss.IsSuperSet(s); got != want { 1563 | t.Errorf("IsSuperSet() = %v, want %v", got, want) 1564 | } 1565 | if got := ss.IsStrictSuperSet(s); got != wantStrict { 1566 | t.Errorf("IsStrictSuperSet() = %v, want %v", got, wantStrict) 1567 | } 1568 | }) 1569 | } 1570 | 1571 | test("empty", 0, 0, nil, nil, true, false) 1572 | test("empty vs non-empty", 0, 100, nil, nil, true, false) 1573 | test("non-empty vs empty", 100, 0, nil, nil, true, false) 1574 | test("equal", 100, 100, nil, nil, true, false) 1575 | 1576 | test("set is shorter, subset", 100, 200, map[int]bool{50: true}, map[int]bool{50: false}, false, false) 1577 | test("set is shorter, equal", 100, 200, nil, nil, true, false) 1578 | test("set is shorter, superset", 100, 200, map[int]bool{50: false}, map[int]bool{50: true}, true, true) 1579 | test("set is shorter, neither", 100, 200, map[int]bool{50: true}, map[int]bool{50: false, 150: true}, false, false) 1580 | 1581 | test("set is longer, subset", 200, 100, map[int]bool{50: true}, map[int]bool{50: false}, false, false) 1582 | test("set is longer, equal", 200, 100, nil, nil, true, false) 1583 | test("set is longer, superset", 200, 100, nil, map[int]bool{150: true}, true, true) 1584 | test("set is longer, neither", 200, 100, map[int]bool{50: false, 150: true}, map[int]bool{50: true}, false, false) 1585 | } 1586 | 1587 | func TestDumpAsBits(t *testing.T) { 1588 | a := New(10).Set(10) 1589 | astr := "0000000000000000000000000000000000000000000000000000010000000000." 1590 | if a.DumpAsBits() != astr { 1591 | t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", astr, a.DumpAsBits()) 1592 | } 1593 | var b BitSet // zero value (b.set == nil) 1594 | bstr := "." 1595 | if b.DumpAsBits() != bstr { 1596 | t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", bstr, b.DumpAsBits()) 1597 | } 1598 | } 1599 | 1600 | func TestMarshalUnmarshalBinary(t *testing.T) { 1601 | a := New(1010).Set(10).Set(1001) 1602 | b := new(BitSet) 1603 | 1604 | copyBinary(t, a, b) 1605 | 1606 | // BitSets must be equal after marshalling and unmarshalling 1607 | if !a.Equal(b) { 1608 | t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) 1609 | return 1610 | } 1611 | 1612 | aSetBit := uint(128) 1613 | a = New(256).Set(aSetBit) 1614 | aExpectedMarshaledSize := 8 /* length: uint64 */ + 4*8 /* set : [4]uint64 */ 1615 | aMarshaled, err := a.MarshalBinary() 1616 | 1617 | if err != nil || aExpectedMarshaledSize != len(aMarshaled) || aExpectedMarshaledSize != a.BinaryStorageSize() { 1618 | t.Error("MarshalBinary failed to produce expected (", aExpectedMarshaledSize, ") number of bytes") 1619 | return 1620 | } 1621 | 1622 | shiftAmount := uint(72) 1623 | // https://github.com/bits-and-blooms/bitset/issues/114 1624 | for i := uint(0); i < shiftAmount; i++ { 1625 | a.DeleteAt(0) 1626 | } 1627 | 1628 | aExpectedMarshaledSize = 8 /* length: uint64 */ + 3*8 /* set : [3]uint64 */ 1629 | aMarshaled, err = a.MarshalBinary() 1630 | if err != nil || aExpectedMarshaledSize != len(aMarshaled) || aExpectedMarshaledSize != a.BinaryStorageSize() { 1631 | t.Error("MarshalBinary failed to produce expected (", aExpectedMarshaledSize, ") number of bytes") 1632 | return 1633 | } 1634 | 1635 | copyBinary(t, a, b) 1636 | 1637 | if b.Len() != 256-shiftAmount || !b.Test(aSetBit-shiftAmount) { 1638 | t.Error("Shifted bitset is not copied correctly") 1639 | } 1640 | } 1641 | 1642 | func TestMarshalUnmarshalBinaryByLittleEndian(t *testing.T) { 1643 | LittleEndian() 1644 | defer func() { 1645 | // Revert when done. 1646 | binaryOrder = binary.BigEndian 1647 | }() 1648 | a := New(1010).Set(10).Set(1001) 1649 | b := new(BitSet) 1650 | 1651 | copyBinary(t, a, b) 1652 | 1653 | // BitSets must be equal after marshalling and unmarshalling 1654 | if !a.Equal(b) { 1655 | t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) 1656 | return 1657 | } 1658 | } 1659 | 1660 | func copyBinary(t *testing.T, from encoding.BinaryMarshaler, to encoding.BinaryUnmarshaler) { 1661 | data, err := from.MarshalBinary() 1662 | if err != nil { 1663 | t.Error(err.Error()) 1664 | return 1665 | } 1666 | 1667 | err = to.UnmarshalBinary(data) 1668 | if err != nil { 1669 | t.Error(err.Error()) 1670 | return 1671 | } 1672 | } 1673 | 1674 | func TestMarshalUnmarshalJSON(t *testing.T) { 1675 | t.Run("value", func(t *testing.T) { 1676 | a := BitSet{} 1677 | a.Set(10).Set(1001) 1678 | data, err := json.Marshal(a) 1679 | if err != nil { 1680 | t.Error(err.Error()) 1681 | return 1682 | } 1683 | 1684 | b := new(BitSet) 1685 | err = json.Unmarshal(data, b) 1686 | if err != nil { 1687 | t.Error(err.Error()) 1688 | return 1689 | } 1690 | 1691 | // Bitsets must be equal after marshalling and unmarshalling 1692 | if !a.Equal(b) { 1693 | t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) 1694 | return 1695 | } 1696 | }) 1697 | t.Run("pointer", func(t *testing.T) { 1698 | a := New(1010).Set(10).Set(1001) 1699 | data, err := json.Marshal(a) 1700 | if err != nil { 1701 | t.Error(err.Error()) 1702 | return 1703 | } 1704 | 1705 | b := new(BitSet) 1706 | err = json.Unmarshal(data, b) 1707 | if err != nil { 1708 | t.Error(err.Error()) 1709 | return 1710 | } 1711 | 1712 | // Bitsets must be equal after marshalling and unmarshalling 1713 | if !a.Equal(b) { 1714 | t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) 1715 | return 1716 | } 1717 | }) 1718 | } 1719 | 1720 | func TestMarshalUnmarshalJSONWithTrailingData(t *testing.T) { 1721 | a := New(1010).Set(10).Set(1001) 1722 | data, err := json.Marshal(a) 1723 | if err != nil { 1724 | t.Error(err.Error()) 1725 | return 1726 | } 1727 | 1728 | // appending some noise 1729 | data = data[:len(data)-3] // remove " 1730 | data = append(data, []byte(`AAAAAAAAAA"`)...) 1731 | 1732 | b := new(BitSet) 1733 | err = json.Unmarshal(data, b) 1734 | if err != nil { 1735 | t.Error(err.Error()) 1736 | return 1737 | } 1738 | 1739 | // Bitsets must be equal after marshalling and unmarshalling 1740 | // Do not over-reading when unmarshalling 1741 | if !a.Equal(b) { 1742 | t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) 1743 | return 1744 | } 1745 | } 1746 | 1747 | func TestMarshalUnmarshalJSONByStdEncoding(t *testing.T) { 1748 | Base64StdEncoding() 1749 | a := New(1010).Set(10).Set(1001) 1750 | data, err := json.Marshal(a) 1751 | if err != nil { 1752 | t.Error(err.Error()) 1753 | return 1754 | } 1755 | 1756 | b := new(BitSet) 1757 | err = json.Unmarshal(data, b) 1758 | if err != nil { 1759 | t.Error(err.Error()) 1760 | return 1761 | } 1762 | 1763 | // Bitsets must be equal after marshalling and unmarshalling 1764 | if !a.Equal(b) { 1765 | t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) 1766 | return 1767 | } 1768 | } 1769 | 1770 | func TestSafeSet(t *testing.T) { 1771 | b := new(BitSet) 1772 | c := b.safeSet() 1773 | outType := fmt.Sprintf("%T", c) 1774 | expType := "[]uint64" 1775 | if outType != expType { 1776 | t.Error("Expecting type: ", expType, ", gotf:", outType) 1777 | return 1778 | } 1779 | if len(c) != 0 { 1780 | t.Error("The slice should be empty") 1781 | return 1782 | } 1783 | } 1784 | 1785 | func TestSetBitsetFrom(t *testing.T) { 1786 | u := []uint64{2, 3, 5, 7, 11} 1787 | b := new(BitSet) 1788 | b.SetBitsetFrom(u) 1789 | outType := fmt.Sprintf("%T", b) 1790 | expType := "*bitset.BitSet" 1791 | if outType != expType { 1792 | t.Error("Expecting type: ", expType, ", gotf:", outType) 1793 | return 1794 | } 1795 | } 1796 | 1797 | func TestIssue116(t *testing.T) { 1798 | a := []uint64{2, 3, 5, 7, 11} 1799 | b := []uint64{2, 3, 5, 7, 11, 0, 1} 1800 | bitset1 := FromWithLength(320, a) 1801 | bitset2 := FromWithLength(320, b) 1802 | if !bitset1.Equal(bitset2) || !bitset2.Equal(bitset1) { 1803 | t.Error("Bitsets should be equal irrespective of the underlying capacity") 1804 | } 1805 | } 1806 | 1807 | func TestFrom(t *testing.T) { 1808 | u := []uint64{2, 3, 5, 7, 11} 1809 | b := From(u) 1810 | outType := fmt.Sprintf("%T", b) 1811 | expType := "*bitset.BitSet" 1812 | if outType != expType { 1813 | t.Error("Expecting type: ", expType, ", gotf:", outType) 1814 | return 1815 | } 1816 | } 1817 | 1818 | func TestWords(t *testing.T) { 1819 | b := new(BitSet) 1820 | c := b.Words() 1821 | outType := fmt.Sprintf("%T", c) 1822 | expType := "[]uint64" 1823 | if outType != expType { 1824 | t.Error("Expecting type: ", expType, ", gotf:", outType) 1825 | return 1826 | } 1827 | if len(c) != 0 { 1828 | t.Error("The slice should be empty") 1829 | return 1830 | } 1831 | } 1832 | 1833 | // Bytes is deprecated 1834 | func TestBytes(t *testing.T) { 1835 | b := new(BitSet) 1836 | c := b.Bytes() 1837 | outType := fmt.Sprintf("%T", c) 1838 | expType := "[]uint64" 1839 | if outType != expType { 1840 | t.Error("Expecting type: ", expType, ", gotf:", outType) 1841 | return 1842 | } 1843 | if len(c) != 0 { 1844 | t.Error("The slice should be empty") 1845 | return 1846 | } 1847 | } 1848 | 1849 | func TestCap(t *testing.T) { 1850 | c := Cap() 1851 | if c <= 0 { 1852 | t.Error("The uint capacity should be >= 0") 1853 | return 1854 | } 1855 | } 1856 | 1857 | func TestWordsNeededLong(t *testing.T) { 1858 | i := Cap() 1859 | out := wordsNeeded(i) 1860 | if out <= 0 { 1861 | t.Error("Unexpected value: ", out) 1862 | return 1863 | } 1864 | } 1865 | 1866 | func TestTestTooLong(t *testing.T) { 1867 | b := new(BitSet) 1868 | if b.Test(1) { 1869 | t.Error("Unexpected value: true") 1870 | return 1871 | } 1872 | } 1873 | 1874 | func TestClearTooLong(t *testing.T) { 1875 | b := new(BitSet) 1876 | c := b.Clear(1) 1877 | if b != c { 1878 | t.Error("Unexpected value") 1879 | return 1880 | } 1881 | } 1882 | 1883 | func TestClearAll(t *testing.T) { 1884 | u := []uint64{2, 3, 5, 7, 11} 1885 | b := From(u) 1886 | c := b.ClearAll() 1887 | if c.length != 320 { 1888 | t.Error("Unexpected length: ", b.length) 1889 | return 1890 | } 1891 | if c.Test(0) || c.Test(1) || c.Test(2) || c.Test(3) || c.Test(4) || c.Test(5) { 1892 | t.Error("All bits should be unset") 1893 | return 1894 | } 1895 | } 1896 | 1897 | func TestRankSelect(t *testing.T) { 1898 | u := []uint{2, 3, 5, 7, 11, 700, 1500} 1899 | b := BitSet{} 1900 | for _, v := range u { 1901 | b.Set(v) 1902 | } 1903 | 1904 | if b.Rank(5) != 3 { 1905 | t.Error("Unexpected rank") 1906 | return 1907 | } 1908 | if b.Rank(6) != 3 { 1909 | t.Error("Unexpected rank") 1910 | return 1911 | } 1912 | if b.Rank(1500) != 7 { 1913 | t.Error("Unexpected rank") 1914 | return 1915 | } 1916 | if b.Select(0) != 2 { 1917 | t.Error("Unexpected select") 1918 | return 1919 | } 1920 | if b.Select(1) != 3 { 1921 | t.Error("Unexpected select") 1922 | return 1923 | } 1924 | if b.Select(2) != 5 { 1925 | t.Error("Unexpected select") 1926 | return 1927 | } 1928 | 1929 | if b.Select(5) != 700 { 1930 | t.Error("Unexpected select") 1931 | return 1932 | } 1933 | } 1934 | 1935 | func TestFlip(t *testing.T) { 1936 | b := new(BitSet) 1937 | c := b.Flip(11) 1938 | if c.length != 12 { 1939 | t.Error("Unexpected value: ", c.length) 1940 | return 1941 | } 1942 | d := c.Flip(7) 1943 | if d.length != 12 { 1944 | t.Error("Unexpected value: ", d.length) 1945 | return 1946 | } 1947 | } 1948 | 1949 | func TestFlipRange(t *testing.T) { 1950 | b := new(BitSet) 1951 | b.Set(1).Set(3).Set(5).Set(7).Set(9).Set(11).Set(13).Set(15) 1952 | c := b.FlipRange(4, 25) 1953 | if c.length != 25 { 1954 | t.Error("Unexpected value: ", c.length) 1955 | return 1956 | } 1957 | d := c.FlipRange(8, 24) 1958 | if d.length != 25 { 1959 | t.Error("Unexpected value: ", d.length) 1960 | return 1961 | } 1962 | // 1963 | for i := uint(0); i < 256; i++ { 1964 | for j := uint(0); j <= i; j++ { 1965 | bits := New(i) 1966 | bits.FlipRange(0, j) 1967 | c := bits.Count() 1968 | if c != j { 1969 | t.Error("Unexpected value: ", c, " expected: ", j) 1970 | return 1971 | } 1972 | } 1973 | } 1974 | } 1975 | 1976 | func TestCopy(t *testing.T) { 1977 | a := New(10) 1978 | if a.Copy(nil) != 0 { 1979 | t.Error("No values should be copied") 1980 | return 1981 | } 1982 | a = New(10) 1983 | b := New(20) 1984 | if a.Copy(b) != 10 { 1985 | t.Error("Unexpected value") 1986 | return 1987 | } 1988 | } 1989 | 1990 | func TestCopyUnaligned(t *testing.T) { 1991 | a := New(16) 1992 | a.FlipRange(0, 16) 1993 | b := New(1) 1994 | a.Copy(b) 1995 | if b.Count() > b.Len() { 1996 | t.Errorf("targets copied set count (%d) should never be larger than target's length (%d)", b.Count(), b.Len()) 1997 | } 1998 | if !b.Test(0) { 1999 | t.Errorf("first bit should still be set in copy: %+v", b) 2000 | } 2001 | 2002 | // Test a more complex scenario with a mix of bits set in the unaligned space to verify no bits are lost. 2003 | a = New(32) 2004 | a.Set(0).Set(3).Set(4).Set(16).Set(17).Set(29).Set(31) 2005 | b = New(19) 2006 | a.Copy(b) 2007 | 2008 | const expectedCount = 5 2009 | if b.Count() != expectedCount { 2010 | t.Errorf("targets copied set count: %d, want %d", b.Count(), expectedCount) 2011 | } 2012 | 2013 | if !(b.Test(0) && b.Test(3) && b.Test(4) && b.Test(16) && b.Test(17)) { 2014 | t.Errorf("expected set bits are not set: %+v", b) 2015 | } 2016 | } 2017 | 2018 | func TestCopyFull(t *testing.T) { 2019 | a := New(10) 2020 | b := &BitSet{} 2021 | a.CopyFull(b) 2022 | if b.length != a.length || len(b.set) != len(a.set) { 2023 | t.Error("Expected full length copy") 2024 | return 2025 | } 2026 | for i, v := range a.set { 2027 | if v != b.set[i] { 2028 | t.Error("Unexpected value") 2029 | return 2030 | } 2031 | } 2032 | } 2033 | 2034 | func TestNextSetError(t *testing.T) { 2035 | b := new(BitSet) 2036 | c, d := b.NextSet(1) 2037 | if c != 0 || d { 2038 | t.Error("Unexpected values") 2039 | return 2040 | } 2041 | } 2042 | 2043 | func TestDeleteWithBitStrings(t *testing.T) { 2044 | type testCase struct { 2045 | input []string 2046 | deleteIdx uint 2047 | expected []string 2048 | } 2049 | 2050 | testCases := []testCase{ 2051 | { 2052 | input: []string{ 2053 | "1110000000000000000000000000000000000000000000000000000000000001", 2054 | }, 2055 | deleteIdx: uint(63), 2056 | expected: []string{ 2057 | "0110000000000000000000000000000000000000000000000000000000000001", 2058 | }, 2059 | }, 2060 | { 2061 | input: []string{ 2062 | "1000000000000000000000000000000000000000000000000000000000010101", 2063 | }, 2064 | deleteIdx: uint(0), 2065 | expected: []string{ 2066 | "0100000000000000000000000000000000000000000000000000000000001010", 2067 | }, 2068 | }, 2069 | { 2070 | input: []string{ 2071 | "0000000000000000000000000000000000000000000000000000000000111000", 2072 | }, 2073 | deleteIdx: uint(4), 2074 | expected: []string{ 2075 | "0000000000000000000000000000000000000000000000000000000000011000", 2076 | }, 2077 | }, 2078 | { 2079 | input: []string{ 2080 | "1000000000000000000000000000000000000000000000000000000000000001", 2081 | "1010000000000000000000000000000000000000000000000000000000000001", 2082 | }, 2083 | deleteIdx: uint(63), 2084 | expected: []string{ 2085 | "1000000000000000000000000000000000000000000000000000000000000001", 2086 | "0101000000000000000000000000000000000000000000000000000000000000", 2087 | }, 2088 | }, 2089 | { 2090 | input: []string{ 2091 | "1000000000000000000000000000000000000000000000000000000000000000", 2092 | "1000000000000000000000000000000000000000000000000000000000000001", 2093 | "1000000000000000000000000000000000000000000000000000000000000001", 2094 | }, 2095 | deleteIdx: uint(64), 2096 | expected: []string{ 2097 | "1000000000000000000000000000000000000000000000000000000000000000", 2098 | "1100000000000000000000000000000000000000000000000000000000000000", 2099 | "0100000000000000000000000000000000000000000000000000000000000000", 2100 | }, 2101 | }, 2102 | { 2103 | input: []string{ 2104 | "0000000000000000000000000000000000000000000000000000000000000001", 2105 | "0000000000000000000000000000000000000000000000000000000000000001", 2106 | "0000000000000000000000000000000000000000000000000000000000000001", 2107 | "0000000000000000000000000000000000000000000000000000000000000001", 2108 | "0000000000000000000000000000000000000000000000000000000000000001", 2109 | }, 2110 | deleteIdx: uint(256), 2111 | expected: []string{ 2112 | "0000000000000000000000000000000000000000000000000000000000000001", 2113 | "0000000000000000000000000000000000000000000000000000000000000001", 2114 | "0000000000000000000000000000000000000000000000000000000000000001", 2115 | "0000000000000000000000000000000000000000000000000000000000000001", 2116 | "0000000000000000000000000000000000000000000000000000000000000000", 2117 | }, 2118 | }, 2119 | } 2120 | 2121 | for _, tc := range testCases { 2122 | var input []uint64 2123 | for _, inputElement := range tc.input { 2124 | parsed, _ := strconv.ParseUint(inputElement, 2, 64) 2125 | input = append(input, parsed) 2126 | } 2127 | 2128 | var expected []uint64 2129 | for _, expectedElement := range tc.expected { 2130 | parsed, _ := strconv.ParseUint(expectedElement, 2, 64) 2131 | expected = append(expected, parsed) 2132 | } 2133 | 2134 | b := From(input) 2135 | b.DeleteAt(tc.deleteIdx) 2136 | if len(b.set) != len(expected) { 2137 | t.Errorf("Length of sets expected to be %d, but was %d", len(expected), len(b.set)) 2138 | return 2139 | } 2140 | for i := range b.set { 2141 | if b.set[i] != expected[i] { 2142 | t.Errorf("Unexpected output\nExpected: %b\nGot: %b", expected[i], b.set[i]) 2143 | return 2144 | } 2145 | } 2146 | } 2147 | } 2148 | 2149 | func TestDeleteWithBitSetInstance(t *testing.T) { 2150 | length := uint(256) 2151 | bitSet := New(length) 2152 | 2153 | // the indexes that get set in the bit set 2154 | indexesToSet := []uint{0, 1, 126, 127, 128, 129, 170, 171, 200, 201, 202, 203, 255} 2155 | 2156 | // the position we delete from the bitset 2157 | deleteAt := uint(127) 2158 | 2159 | // the indexes that we expect to be set after the delete 2160 | expectedToBeSet := []uint{0, 1, 126, 127, 128, 169, 170, 199, 200, 201, 202, 254} 2161 | 2162 | expected := make(map[uint]struct{}) 2163 | for _, index := range expectedToBeSet { 2164 | expected[index] = struct{}{} 2165 | } 2166 | 2167 | for _, index := range indexesToSet { 2168 | bitSet.Set(index) 2169 | } 2170 | 2171 | bitSet.DeleteAt(deleteAt) 2172 | 2173 | for i := uint(0); i < length; i++ { 2174 | if _, ok := expected[i]; ok { 2175 | if !bitSet.Test(i) { 2176 | t.Errorf("Expected index %d to be set, but wasn't", i) 2177 | } 2178 | } else { 2179 | if bitSet.Test(i) { 2180 | t.Errorf("Expected index %d to not be set, but was", i) 2181 | } 2182 | } 2183 | } 2184 | } 2185 | 2186 | func TestWriteTo(t *testing.T) { 2187 | const length = 9585 2188 | const oneEvery = 97 2189 | addBuf := []byte(`12345678`) 2190 | bs := New(length) 2191 | // Add some bits 2192 | for i := uint(0); i < length; i += oneEvery { 2193 | bs = bs.Set(i) 2194 | } 2195 | 2196 | var buf bytes.Buffer 2197 | n, err := bs.WriteTo(&buf) 2198 | if err != nil { 2199 | t.Fatal(err) 2200 | } 2201 | wantSz := buf.Len() // Size of the serialized data in bytes. 2202 | if n != int64(wantSz) { 2203 | t.Errorf("want write size to be %d, got %d", wantSz, n) 2204 | } 2205 | buf.Write(addBuf) // Add additional data on stream. 2206 | 2207 | // Generate test input for regression tests: 2208 | if false { 2209 | gzout := bytes.NewBuffer(nil) 2210 | gz, err := gzip.NewWriterLevel(gzout, 9) 2211 | if err != nil { 2212 | t.Fatal(err) 2213 | } 2214 | gz.Write(buf.Bytes()) 2215 | gz.Close() 2216 | t.Log("Encoded:", base64.StdEncoding.EncodeToString(gzout.Bytes())) 2217 | } 2218 | 2219 | // Read back. 2220 | bs = New(length) 2221 | n, err = bs.ReadFrom(&buf) 2222 | if err != nil { 2223 | t.Fatal(err) 2224 | } 2225 | if n != int64(wantSz) { 2226 | t.Errorf("want read size to be %d, got %d", wantSz, n) 2227 | } 2228 | // Check bits 2229 | for i := uint(0); i < length; i += oneEvery { 2230 | if !bs.Test(i) { 2231 | t.Errorf("bit %d was not set", i) 2232 | } 2233 | } 2234 | 2235 | more, err := io.ReadAll(&buf) 2236 | if err != nil { 2237 | t.Fatal(err) 2238 | } 2239 | if !bytes.Equal(more, addBuf) { 2240 | t.Fatalf("extra mismatch. got %v, want %v", more, addBuf) 2241 | } 2242 | } 2243 | 2244 | type inCompleteRetBufReader struct { 2245 | returnEvery int64 2246 | reader io.Reader 2247 | offset int64 2248 | } 2249 | 2250 | func (ir *inCompleteRetBufReader) Read(b []byte) (n int, err error) { 2251 | if ir.returnEvery > 0 { 2252 | maxRead := ir.returnEvery - (ir.offset % ir.returnEvery) 2253 | if len(b) > int(maxRead) { 2254 | b = b[:maxRead] 2255 | } 2256 | } 2257 | n, err = ir.reader.Read(b) 2258 | ir.offset += int64(n) 2259 | return 2260 | } 2261 | 2262 | func TestReadFrom(t *testing.T) { 2263 | addBuf := []byte(`12345678`) // Bytes after stream 2264 | tests := []struct { 2265 | length uint 2266 | oneEvery uint 2267 | input string // base64+gzipped 2268 | wantErr error 2269 | returnEvery int64 2270 | }{ 2271 | { 2272 | length: 9585, 2273 | oneEvery: 97, 2274 | input: "H4sIAAAAAAAC/2IAA9VCCM3AyMDAwMSACVgYGBg4sIgLMDAwKGARd2BgYGjAFB41noDx6IAJajw64IAajw4UoMajg4ZR4/EaP5pQh1g+MDQyNjE1M7cABAAA//9W5OoOwAQAAA==", 2275 | returnEvery: 127, 2276 | }, 2277 | { 2278 | length: 1337, 2279 | oneEvery: 42, 2280 | input: "H4sIAAAAAAAC/2IAA1ZLBgYWEIPRAUQKgJkMcCZYisEBzkSSYkSTYqCxAYZGxiamZuYWgAAAAP//D0wyWbgAAAA=", 2281 | }, 2282 | { 2283 | length: 1337, // Truncated input. 2284 | oneEvery: 42, 2285 | input: "H4sIAAAAAAAC/2IAA9VCCM3AyMDAwARmAQIAAP//vR3xdRkAAAA=", 2286 | wantErr: io.ErrUnexpectedEOF, 2287 | }, 2288 | { 2289 | length: 1337, // Empty input. 2290 | oneEvery: 42, 2291 | input: "H4sIAAAAAAAC/wEAAP//AAAAAAAAAAA=", 2292 | wantErr: io.ErrUnexpectedEOF, 2293 | }, 2294 | } 2295 | 2296 | for i, test := range tests { 2297 | t.Run(fmt.Sprint(i), func(t *testing.T) { 2298 | fatalErr := func(err error) { 2299 | t.Helper() 2300 | if err != nil { 2301 | t.Fatal(err) 2302 | } 2303 | } 2304 | 2305 | var buf bytes.Buffer 2306 | b, err := base64.StdEncoding.DecodeString(test.input) 2307 | fatalErr(err) 2308 | gz, err := gzip.NewReader(bytes.NewBuffer(b)) 2309 | fatalErr(err) 2310 | _, err = io.Copy(&buf, gz) 2311 | fatalErr(err) 2312 | fatalErr(gz.Close()) 2313 | 2314 | bs := New(test.length) 2315 | _, err = bs.ReadFrom(&inCompleteRetBufReader{returnEvery: test.returnEvery, reader: &buf}) 2316 | if err != nil { 2317 | if errors.Is(err, test.wantErr) { 2318 | // Correct, nothing more we can test. 2319 | return 2320 | } 2321 | t.Fatalf("did not get expected error %v, got %v", test.wantErr, err) 2322 | } else { 2323 | if test.wantErr != nil { 2324 | t.Fatalf("did not get expected error %v", test.wantErr) 2325 | } 2326 | } 2327 | fatalErr(err) 2328 | 2329 | // Test if correct bits are set. 2330 | for i := uint(0); i < test.length; i++ { 2331 | want := i%test.oneEvery == 0 2332 | got := bs.Test(i) 2333 | if want != got { 2334 | t.Errorf("bit %d was %v, should be %v", i, got, want) 2335 | } 2336 | } 2337 | 2338 | more, err := io.ReadAll(&buf) 2339 | fatalErr(err) 2340 | 2341 | if !bytes.Equal(more, addBuf) { 2342 | t.Errorf("extra mismatch. got %v, want %v", more, addBuf) 2343 | } 2344 | }) 2345 | } 2346 | } 2347 | 2348 | func TestSetAll(t *testing.T) { 2349 | test := func(name string, bs *BitSet, want uint) { 2350 | t.Run(name, func(t *testing.T) { 2351 | bs.SetAll() 2352 | if bs.Count() != want { 2353 | t.Errorf("expected %d bits to be set, got %d", want, bs.Count()) 2354 | } 2355 | }) 2356 | } 2357 | 2358 | test("nil", nil, 0) 2359 | for _, length := range []uint{0, 1, 10, 63, 64, 65, 100, 640} { 2360 | test(fmt.Sprintf("length %d", length), New(length), length) 2361 | } 2362 | } 2363 | 2364 | func TestShiftLeft(t *testing.T) { 2365 | data := []uint{5, 28, 45, 72, 89, 560} 2366 | 2367 | test := func(name string, bits uint) { 2368 | t.Run(name, func(t *testing.T) { 2369 | b := New(200) 2370 | for _, i := range data { 2371 | b.Set(i) 2372 | } 2373 | 2374 | b.ShiftLeft(bits) 2375 | 2376 | if int(b.Count()) != len(data) { 2377 | t.Error("bad bits count") 2378 | } 2379 | 2380 | for _, i := range data { 2381 | if !b.Test(i + bits) { 2382 | t.Errorf("bit %v is not set", i+bits) 2383 | } 2384 | } 2385 | }) 2386 | } 2387 | 2388 | test("zero", 0) 2389 | test("no page change", 19) 2390 | test("shift to full page", 38) 2391 | test("full page shift", 64) 2392 | test("no page split", 80) 2393 | test("with page split", 114) 2394 | test("with extension", 242) 2395 | test("with extra word", 16) 2396 | } 2397 | 2398 | func TestShiftRight(t *testing.T) { 2399 | data := []uint{5, 28, 45, 72, 89} 2400 | 2401 | test := func(name string, bits uint) { 2402 | t.Run(name, func(t *testing.T) { 2403 | b := New(200) 2404 | for _, i := range data { 2405 | b.Set(i) 2406 | } 2407 | 2408 | b.ShiftRight(bits) 2409 | 2410 | count := 0 2411 | for _, i := range data { 2412 | if i >= bits { 2413 | count++ 2414 | 2415 | if !b.Test(i - bits) { 2416 | t.Errorf("bit %v is not set", i-bits) 2417 | } 2418 | } 2419 | } 2420 | 2421 | if int(b.Count()) != count { 2422 | t.Errorf("bad bits count: expected %d, got %d", count, b.Count()) 2423 | } 2424 | }) 2425 | } 2426 | 2427 | test("zero", 0) 2428 | test("no page change", 3) 2429 | test("no page split", 20) 2430 | test("with page split", 40) 2431 | test("full page shift", 64) 2432 | test("with extension", 70) 2433 | test("full shift", 89) 2434 | test("remove all", 242) 2435 | } 2436 | 2437 | func TestShiftRightFull(t *testing.T) { 2438 | testCases := []struct{ 2439 | data []uint 2440 | shiftDistance uint 2441 | }{ 2442 | { 2443 | []uint{20}, 20, 2444 | }, 2445 | { 2446 | []uint{0, 20, 40, 1260, 1280}, 1, 2447 | }, 2448 | { 2449 | []uint{0, 20, 40, 1260, 1280}, 1281, 2450 | }, 2451 | { 2452 | []uint{961}, 64, 2453 | }, 2454 | } 2455 | 2456 | test := func(data []uint, shiftDistance uint) { 2457 | b := New(0) 2458 | for i := range data { 2459 | b.Set(data[i]) 2460 | } 2461 | b.ShiftRight(shiftDistance) 2462 | for i := range data { 2463 | shiftedBit := int(data[i])-int(shiftDistance) 2464 | if shiftedBit >= 0 { 2465 | if !b.Test(uint(shiftedBit)) { 2466 | t.Errorf("bit %d should be set after ShiftRight(%d) if bit %d was set prior", data[i]-shiftDistance, shiftDistance, data[i]) 2467 | } 2468 | } 2469 | } 2470 | } 2471 | 2472 | for i := range testCases { 2473 | test(testCases[i].data, testCases[i].shiftDistance) 2474 | } 2475 | } 2476 | 2477 | func TestWord(t *testing.T) { 2478 | data := []uint64{0x0bfd85fc01af96dd, 0x3fe212a7eae11414, 0x7aa412221245dee1, 0x557092c1711306d5} 2479 | testCases := map[string]struct { 2480 | index uint 2481 | expected uint64 2482 | }{ 2483 | "first word": { 2484 | index: 0, 2485 | expected: 0x0bfd85fc01af96dd, 2486 | }, 2487 | "third word": { 2488 | index: 128, 2489 | expected: 0x7aa412221245dee1, 2490 | }, 2491 | "off the edge": { 2492 | index: 256, 2493 | expected: 0, 2494 | }, 2495 | "way off the edge": { 2496 | index: 63235235, 2497 | expected: 0, 2498 | }, 2499 | "split between two words": { 2500 | index: 96, 2501 | expected: 0x1245dee13fe212a7, 2502 | }, 2503 | "partly off edge": { 2504 | index: 254, 2505 | expected: 1, 2506 | }, 2507 | "skip one nibble": { 2508 | index: 4, 2509 | expected: 0x40bfd85fc01af96d, 2510 | }, 2511 | "slightly offset results": { 2512 | index: 65, 2513 | expected: 0x9ff10953f5708a0a, 2514 | }, 2515 | } 2516 | 2517 | for name, testCase := range testCases { 2518 | t.Run(name, func(t *testing.T) { 2519 | bitSet := From(data) 2520 | output := bitSet.GetWord64AtBit(testCase.index) 2521 | 2522 | if output != testCase.expected { 2523 | t.Errorf("Word should have returned %d for input %d, but returned %d", testCase.expected, testCase.index, output) 2524 | } 2525 | }) 2526 | } 2527 | } 2528 | 2529 | func TestPreviousSet(t *testing.T) { 2530 | v := New(128) 2531 | v.Set(0) 2532 | v.Set(2) 2533 | v.Set(4) 2534 | v.Set(120) 2535 | for _, tt := range []struct { 2536 | index uint 2537 | want uint 2538 | wantFound bool 2539 | }{ 2540 | {0, 0, true}, 2541 | {1, 0, true}, 2542 | {2, 2, true}, 2543 | {3, 2, true}, 2544 | {4, 4, true}, 2545 | {5, 4, true}, 2546 | {100, 4, true}, 2547 | {120, 120, true}, 2548 | {121, 120, true}, 2549 | {1024, 0, false}, 2550 | } { 2551 | t.Run(fmt.Sprintf("@%d", tt.index), func(t *testing.T) { 2552 | got, found := v.PreviousSet(tt.index) 2553 | if got != tt.want || found != tt.wantFound { 2554 | t.Errorf("PreviousSet(%d) = %d, %v, want %d, %v", tt.index, got, found, tt.want, tt.wantFound) 2555 | } 2556 | }) 2557 | } 2558 | v.ClearAll() 2559 | for _, tt := range []struct { 2560 | index uint 2561 | want uint 2562 | wantFound bool 2563 | }{ 2564 | {0, 0, false}, 2565 | {120, 0, false}, 2566 | {1024, 0, false}, 2567 | } { 2568 | t.Run(fmt.Sprintf("@%d", tt.index), func(t *testing.T) { 2569 | got, found := v.PreviousSet(tt.index) 2570 | if got != tt.want || found != tt.wantFound { 2571 | t.Errorf("PreviousSet(%d) = %d, %v, want %d, %v", tt.index, got, found, tt.want, tt.wantFound) 2572 | } 2573 | }) 2574 | } 2575 | } 2576 | 2577 | func TestPreviousClear(t *testing.T) { 2578 | v := New(128) 2579 | v.Set(0) 2580 | v.Set(2) 2581 | v.Set(4) 2582 | v.Set(120) 2583 | for _, tt := range []struct { 2584 | index uint 2585 | want uint 2586 | wantFound bool 2587 | }{ 2588 | {0, 0, false}, 2589 | {1, 1, true}, 2590 | {2, 1, true}, 2591 | {3, 3, true}, 2592 | {4, 3, true}, 2593 | {5, 5, true}, 2594 | {100, 100, true}, 2595 | {120, 119, true}, 2596 | {121, 121, true}, 2597 | {1024, 0, false}, 2598 | } { 2599 | t.Run(fmt.Sprintf("@%d", tt.index), func(t *testing.T) { 2600 | got, found := v.PreviousClear(tt.index) 2601 | if got != tt.want || found != tt.wantFound { 2602 | t.Errorf("PreviousClear(%d) = %d, %v, want %d, %v", tt.index, got, found, tt.want, tt.wantFound) 2603 | } 2604 | }) 2605 | } 2606 | v.SetAll() 2607 | for _, tt := range []struct { 2608 | index uint 2609 | want uint 2610 | wantFound bool 2611 | }{ 2612 | {0, 0, false}, 2613 | {120, 0, false}, 2614 | {1024, 0, false}, 2615 | } { 2616 | t.Run(fmt.Sprintf("@%d", tt.index), func(t *testing.T) { 2617 | got, found := v.PreviousClear(tt.index) 2618 | if got != tt.want || found != tt.wantFound { 2619 | t.Errorf("PreviousClear(%d) = %d, %v, want %d, %v", tt.index, got, found, tt.want, tt.wantFound) 2620 | } 2621 | }) 2622 | } 2623 | } 2624 | 2625 | func TestBitSetOnesBetween(t *testing.T) { 2626 | testCases := []struct { 2627 | name string 2628 | input *BitSet 2629 | from uint 2630 | to uint 2631 | expected uint 2632 | }{ 2633 | {"empty range", New(64).Set(0).Set(1), 5, 5, 0}, 2634 | {"invalid range", New(64).Set(0).Set(1), 5, 3, 0}, 2635 | {"single word", New(64).Set(1).Set(2).Set(3), 1, 3, 2}, 2636 | {"single word full", New(64).Set(0).Set(1).Set(2).Set(3), 0, 4, 4}, 2637 | {"cross word boundary", New(128).Set(63).Set(64).Set(65), 63, 66, 3}, 2638 | {"multiple words", New(256).Set(0).Set(63).Set(64).Set(127).Set(128), 0, 129, 5}, 2639 | {"large gap", New(256).Set(0).Set(100).Set(200), 0, 201, 3}, 2640 | } 2641 | 2642 | for _, tc := range testCases { 2643 | t.Run(tc.name, func(t *testing.T) { 2644 | got := tc.input.OnesBetween(tc.from, tc.to) 2645 | if got != tc.expected { 2646 | t.Errorf("OnesBetween(%d, %d) = %d, want %d", 2647 | tc.from, tc.to, got, tc.expected) 2648 | } 2649 | }) 2650 | } 2651 | 2652 | // Property-based testing 2653 | const numTests = 1e5 2654 | seed := time.Now().UnixNano() 2655 | rng := rand.New(rand.NewSource(seed)) 2656 | t.Logf("Seed: %d", seed) 2657 | 2658 | for i := 0; i < numTests; i++ { 2659 | size := uint(rng.Intn(1024) + 64) 2660 | bs := New(size) 2661 | 2662 | // Set random bits 2663 | for j := 0; j < int(size/4); j++ { 2664 | bs.Set(uint(rng.Intn(int(size)))) 2665 | } 2666 | 2667 | // Generate random range 2668 | from := uint(rng.Intn(int(size))) 2669 | to := from + uint(rng.Intn(int(size-from))) 2670 | 2671 | // Compare with naive implementation 2672 | got := bs.OnesBetween(from, to) 2673 | want := uint(0) 2674 | for j := from; j < to; j++ { 2675 | if bs.Test(j) { 2676 | want++ 2677 | } 2678 | } 2679 | 2680 | if got != want { 2681 | t.Errorf("Case %d: OnesBetween(%d, %d) = %d, want %d", 2682 | i, from, to, got, want) 2683 | } 2684 | } 2685 | } 2686 | 2687 | func BenchmarkBitSetOnesBetween(b *testing.B) { 2688 | sizes := []int{64, 256, 1024, 4096, 16384} 2689 | densities := []float64{0.1, 0.5, 0.9} // Different bit densities to test 2690 | rng := rand.New(rand.NewSource(42)) 2691 | 2692 | for _, size := range sizes { 2693 | for _, density := range densities { 2694 | // Create bitset with given density 2695 | bs := New(uint(size)) 2696 | for i := 0; i < int(float64(size)*density); i++ { 2697 | bs.Set(uint(rng.Intn(size))) 2698 | } 2699 | 2700 | // Generate random ranges 2701 | ranges := make([][2]uint, 1000) 2702 | for i := range ranges { 2703 | from := uint(rng.Intn(size)) 2704 | to := from + uint(rng.Intn(size-int(from))) 2705 | ranges[i] = [2]uint{from, to} 2706 | } 2707 | 2708 | name := fmt.Sprintf("size=%d/density=%.1f", size, density) 2709 | b.Run(name, func(b *testing.B) { 2710 | for i := 0; i < b.N; i++ { 2711 | r := ranges[i%len(ranges)] 2712 | _ = bs.OnesBetween(r[0], r[1]) 2713 | } 2714 | }) 2715 | } 2716 | } 2717 | } 2718 | 2719 | func generatePextTestCases(n int) [][2]uint64 { 2720 | cases := make([][2]uint64, n) 2721 | for i := range cases { 2722 | cases[i][0] = rand.Uint64() 2723 | cases[i][1] = rand.Uint64() 2724 | } 2725 | return cases 2726 | } 2727 | 2728 | func BenchmarkPEXT(b *testing.B) { 2729 | // Generate test cases 2730 | testCases := generatePextTestCases(1000) 2731 | 2732 | b.ResetTimer() 2733 | 2734 | var r uint64 2735 | for i := 0; i < b.N; i++ { 2736 | tc := testCases[i%len(testCases)] 2737 | r = pext(tc[0], tc[1]) 2738 | } 2739 | _ = r // prevent optimization 2740 | } 2741 | 2742 | func BenchmarkPDEP(b *testing.B) { 2743 | // Generate test cases 2744 | testCases := generatePextTestCases(1000) 2745 | 2746 | b.ResetTimer() 2747 | 2748 | var r uint64 2749 | for i := 0; i < b.N; i++ { 2750 | tc := testCases[i%len(testCases)] 2751 | r = pdep(tc[0], tc[1]) 2752 | } 2753 | _ = r // prevent optimization 2754 | } 2755 | 2756 | func TestPext(t *testing.T) { 2757 | const numTests = 1e6 2758 | seed := time.Now().UnixNano() 2759 | rng := rand.New(rand.NewSource(seed)) 2760 | t.Logf("Seed: %d", seed) 2761 | 2762 | for i := 0; i < numTests; i++ { 2763 | w := rng.Uint64() 2764 | m := rng.Uint64() 2765 | result := pext(w, m) 2766 | popCount := bits.OnesCount64(m) 2767 | 2768 | // Test invariants 2769 | if popCount > 0 && result >= (uint64(1)< bits.OnesCount64(w&m) { 2775 | t.Fatalf("Case %d: result has more 1s than masked input: result=%x, input&mask=%x", 2776 | i, result, w&m) 2777 | } 2778 | 2779 | // Test that extracted bits preserve relative ordering: 2780 | // For each bit position that's set in the mask (m): 2781 | // 1. Extract a bit from result (resultCopy&1) 2782 | // 2. Get corresponding input bit from w (w>>j&1) 2783 | // 3. XOR them - if different, bits weren't preserved correctly 2784 | resultCopy := result 2785 | for j := 0; j < 64; j++ { 2786 | // Check if mask bit is set at position j 2787 | if m&(uint64(1)<>j&1 gets bit j from original input 2790 | // XOR (^) checks if they match 2791 | if (resultCopy&1)^(w>>j&1) != 0 { 2792 | t.Fatalf("Case %d: bit ordering violation at position %d", i, j) 2793 | } 2794 | // Shift to examine next bit in packed result 2795 | resultCopy >>= 1 2796 | } 2797 | } 2798 | } 2799 | } 2800 | 2801 | func TestPdep(t *testing.T) { 2802 | const numTests = 1e6 2803 | seed := time.Now().UnixNano() 2804 | rng := rand.New(rand.NewSource(seed)) 2805 | t.Logf("Seed: %d", seed) 2806 | 2807 | for i := 0; i < numTests; i++ { 2808 | w := rng.Uint64() // value to deposit 2809 | m := rng.Uint64() // mask 2810 | result := pdep(w, m) 2811 | popCount := bits.OnesCount64(m) 2812 | 2813 | // Test invariants 2814 | if result&^m != 0 { 2815 | t.Fatalf("Case %d: result %x has bits set outside of mask %x", 2816 | i, result, m) 2817 | } 2818 | 2819 | if bits.OnesCount64(result) > bits.OnesCount64(w) { 2820 | t.Fatalf("Case %d: result has more 1s than input: result=%x, input=%x", 2821 | i, result, w) 2822 | } 2823 | 2824 | // Verify by using PEXT to extract bits back 2825 | // The composition of PEXT(PDEP(x,m),m) should equal x masked to popcount bits 2826 | extracted := pext(result, m) 2827 | maskBits := (uint64(1) << popCount) - 1 2828 | if (extracted & maskBits) != (w & maskBits) { 2829 | t.Fatalf("Case %d: PEXT(PDEP(w,m),m) != w: got=%x, want=%x (w=%x, m=%x)", 2830 | i, extracted&maskBits, w&maskBits, w, m) 2831 | } 2832 | } 2833 | } 2834 | 2835 | func TestBitSetExtract(t *testing.T) { 2836 | // Property-based tests 2837 | const numTests = 1e4 2838 | seed := time.Now().UnixNano() 2839 | rng := rand.New(rand.NewSource(seed)) 2840 | t.Logf("Seed: %d", seed) 2841 | 2842 | for i := 0; i < numTests; i++ { 2843 | // Create random bitsets 2844 | size := uint(rng.Intn(1024) + 64) // Random size between 64-1087 bits 2845 | src := New(size) 2846 | mask := New(size) 2847 | dst := New(size) 2848 | 2849 | // Set random bits 2850 | for j := 0; j < int(size/4); j++ { 2851 | src.Set(uint(rng.Intn(int(size)))) 2852 | mask.Set(uint(rng.Intn(int(size)))) 2853 | } 2854 | 2855 | // Extract bits 2856 | src.ExtractTo(mask, dst) 2857 | 2858 | // Test invariants 2859 | if dst.Count() > src.IntersectionCardinality(mask) { 2860 | t.Errorf("Case %d: result has more 1s than masked input", i) 2861 | } 2862 | 2863 | // Test bits are properly extracted and packed 2864 | pos := uint(0) 2865 | for j := uint(0); j < size; j++ { 2866 | if mask.Test(j) { 2867 | if src.Test(j) != dst.Test(pos) { 2868 | t.Errorf("Case %d: bit ordering violation at source position %d", i, j) 2869 | } 2870 | pos++ 2871 | } 2872 | } 2873 | } 2874 | 2875 | // Keep existing test cases 2876 | testCases := []struct { 2877 | name string 2878 | src *BitSet // source bits 2879 | mask *BitSet // mask bits 2880 | expected *BitSet // expected extracted bits 2881 | }{ 2882 | { 2883 | name: "single bit", 2884 | src: New(8).Set(1), // 0b01 2885 | mask: New(8).Set(1), // 0b01 2886 | expected: New(8).Set(0), // 0b1 2887 | }, 2888 | { 2889 | name: "two sequential bits", 2890 | src: New(8).Set(0).Set(1), // 0b11 2891 | mask: New(8).Set(0).Set(1), // 0b11 2892 | expected: New(8).Set(0).Set(1), // 0b11 2893 | }, 2894 | { 2895 | name: "sparse bits", 2896 | src: New(16).Set(0).Set(10), // 0b10000000001 2897 | mask: New(16).Set(0).Set(5).Set(10), // 0b10000100001 2898 | expected: New(8).Set(0).Set(2), // 0b101 2899 | }, 2900 | { 2901 | name: "masked off bits", 2902 | src: New(8).Set(0).Set(1).Set(2).Set(3), // 0b1111 2903 | mask: New(8).Set(0).Set(2), // 0b0101 2904 | expected: New(8).Set(0).Set(1), // 0b11 2905 | }, 2906 | { 2907 | name: "cross word boundary", 2908 | src: New(128).Set(63).Set(64).Set(65), 2909 | mask: New(128).Set(63).Set(64).Set(65), 2910 | expected: New(8).Set(0).Set(1).Set(2), 2911 | }, 2912 | { 2913 | name: "large gap", 2914 | src: New(256).Set(0).Set(100).Set(200), 2915 | mask: New(256).Set(0).Set(100).Set(200), 2916 | expected: New(8).Set(0).Set(1).Set(2), 2917 | }, 2918 | { 2919 | name: "extracting zeros", 2920 | src: New(8), // 0b00 2921 | mask: New(8).Set(0).Set(1).Set(2), // 0b111 2922 | expected: New(8), // 0b000 2923 | }, 2924 | } 2925 | 2926 | for _, tc := range testCases { 2927 | t.Run(tc.name, func(t *testing.T) { 2928 | dst := New(tc.expected.Len()) 2929 | tc.src.ExtractTo(tc.mask, dst) 2930 | if !dst.Equal(tc.expected) { 2931 | t.Errorf("got %v, expected %v", dst, tc.expected) 2932 | } 2933 | 2934 | // Verify inverse relationship within the mask bits 2935 | deposited := New(tc.src.Len()) 2936 | dst.DepositTo(tc.mask, deposited) 2937 | 2938 | // Only bits selected by the mask should match between source and deposited 2939 | maskedSource := tc.src.Intersection(tc.mask) 2940 | maskedDeposited := deposited.Intersection(tc.mask) 2941 | 2942 | if !maskedSource.Equal(maskedDeposited) { 2943 | t.Error("DepositTo(ExtractTo(x,m),m) doesn't preserve masked source bits") 2944 | } 2945 | }) 2946 | } 2947 | } 2948 | 2949 | func TestBitSetDeposit(t *testing.T) { 2950 | // Property-based tests 2951 | const numTests = 1e4 2952 | seed := time.Now().UnixNano() 2953 | rng := rand.New(rand.NewSource(seed)) 2954 | t.Logf("Seed: %d", seed) 2955 | 2956 | for i := 0; i < numTests; i++ { 2957 | // Create random bitsets 2958 | size := uint(rng.Intn(1024) + 64) // Random size between 64-1087 bits 2959 | src := New(size) 2960 | mask := New(size) 2961 | dst := New(size) 2962 | 2963 | // Set random bits 2964 | for j := 0; j < int(size/4); j++ { 2965 | src.Set(uint(rng.Intn(int(mask.Count() + 1)))) 2966 | mask.Set(uint(rng.Intn(int(size)))) 2967 | } 2968 | 2969 | // Deposit bits 2970 | src.DepositTo(mask, dst) 2971 | 2972 | // Test invariants 2973 | if dst.Count() > src.Count() { 2974 | t.Errorf("Case %d: result has more 1s than input", i) 2975 | } 2976 | 2977 | if (dst.Bytes()[0] &^ mask.Bytes()[0]) != 0 { 2978 | t.Errorf("Case %d: result has bits set outside of mask", i) 2979 | } 2980 | 2981 | // Extract bits back and verify 2982 | extracted := New(size) 2983 | dst.ExtractTo(mask, extracted) 2984 | maskBits := New(size) 2985 | for j := uint(0); j < mask.Count(); j++ { 2986 | maskBits.Set(j) 2987 | } 2988 | srcMasked := src.Clone() 2989 | srcMasked.InPlaceIntersection(maskBits) 2990 | if !extracted.Equal(srcMasked) { 2991 | t.Errorf("Case %d: ExtractTo(DepositTo(x,m),m) != x", i) 2992 | } 2993 | } 2994 | 2995 | // Keep existing test cases 2996 | testCases := []struct { 2997 | name string 2998 | src *BitSet // source bits (packed in low positions) 2999 | mask *BitSet // mask bits (positions to deposit into) 3000 | dst *BitSet // destination bits (initially set) 3001 | expected *BitSet // expected result 3002 | }{ 3003 | { 3004 | name: "sparse bits", 3005 | src: New(8).Set(0), // 0b01 3006 | mask: New(8).Set(0).Set(5), // 0b100001 3007 | expected: New(8).Set(0), // 0b000001 3008 | }, 3009 | { 3010 | name: "masked off bits", 3011 | src: New(8).Set(0).Set(1), // 0b11 3012 | mask: New(8).Set(0).Set(2), // 0b101 3013 | expected: New(8).Set(0).Set(2), // 0b101 3014 | }, 3015 | { 3016 | name: "cross word boundary", 3017 | src: New(8).Set(0).Set(1), // 0b11 3018 | mask: New(128).Set(63).Set(64), // bits across word boundary 3019 | expected: New(128).Set(63).Set(64), // bits deposited across boundary 3020 | }, 3021 | { 3022 | name: "large gaps", 3023 | src: New(8).Set(0).Set(1), // 0b11 3024 | mask: New(128).Set(0).Set(100), // widely spaced bits 3025 | expected: New(128).Set(0).Set(100), // deposited into sparse positions 3026 | }, 3027 | { 3028 | name: "depositing zeros", 3029 | src: New(8), // 0b00 3030 | mask: New(8).Set(0).Set(1).Set(2), // 0b111 3031 | expected: New(8), // 0b000 3032 | }, 3033 | { 3034 | name: "preserve unmasked bits", 3035 | src: New(8), // empty source 3036 | mask: New(8), // empty mask 3037 | dst: New(8).Set(1).Set(2).Set(3), // dst has some bits set 3038 | expected: New(8).Set(1).Set(2).Set(3), // should remain unchanged 3039 | }, 3040 | { 3041 | name: "preserve bits outside mask within word", 3042 | src: New(8).Set(0), // source has bit 0 set 3043 | mask: New(8).Set(1), // only depositing into bit 1 3044 | dst: New(8).Set(0).Set(2).Set(3), // dst has bits 0,2,3 set 3045 | expected: New(8).Set(0).Set(1).Set(2).Set(3), // bits 0,2,3 should remain, bit 1 should be set 3046 | }, 3047 | } 3048 | 3049 | for _, tc := range testCases { 3050 | t.Run(tc.name, func(t *testing.T) { 3051 | var dst *BitSet 3052 | if tc.dst == nil { 3053 | dst = New(tc.expected.Len()) 3054 | } else { 3055 | dst = tc.dst.Clone() 3056 | } 3057 | tc.src.DepositTo(tc.mask, dst) 3058 | if !dst.Equal(tc.expected) { 3059 | t.Errorf("got %v, expected %v", dst, tc.expected) 3060 | } 3061 | 3062 | // Verify inverse relationship for set bits up to mask cardinality 3063 | extracted := New(tc.src.Len()) 3064 | dst.ExtractTo(tc.mask, extracted) 3065 | 3066 | if !extracted.Equal(tc.src) { 3067 | t.Error("ExtractTo(DepositTo(x,m),m) doesn't preserve source bits that were selected by mask") 3068 | } 3069 | }) 3070 | } 3071 | } 3072 | 3073 | func BenchmarkBitSetExtractDeposit(b *testing.B) { 3074 | sizes := []int{64, 256, 1024, 4096, 16384, 2 << 15} 3075 | rng := rand.New(rand.NewSource(42)) // fixed seed for reproducibility 3076 | 3077 | for _, size := range sizes { 3078 | // Create source with random bits 3079 | src := New(uint(size)) 3080 | for i := 0; i < size/4; i++ { // Set ~25% of bits 3081 | src.Set(uint(rng.Intn(size))) 3082 | } 3083 | 3084 | // Create mask with random bits 3085 | mask := New(uint(size)) 3086 | for i := 0; i < size/4; i++ { 3087 | mask.Set(uint(rng.Intn(size))) 3088 | } 3089 | 3090 | b.Run(fmt.Sprintf("size=%d/fn=ExtractTo", size), func(b *testing.B) { 3091 | dst := New(uint(size)) 3092 | b.ReportAllocs() 3093 | b.ResetTimer() 3094 | for i := 0; i < b.N; i++ { 3095 | src.ExtractTo(mask, dst) 3096 | dst.ClearAll() 3097 | } 3098 | }) 3099 | 3100 | b.Run(fmt.Sprintf("size=%d/fn=DepositTo", size), func(b *testing.B) { 3101 | dst := New(uint(size)) 3102 | b.ReportAllocs() 3103 | b.ResetTimer() 3104 | for i := 0; i < b.N; i++ { 3105 | src.DepositTo(mask, dst) 3106 | dst.ClearAll() 3107 | } 3108 | }) 3109 | } 3110 | } 3111 | --------------------------------------------------------------------------------