pax_global_header00006660000000000000000000000064145423245330014517gustar00rootroot0000000000000052 comment=95402fefb34e958f948af0489f1b435328cf0af4 bitset-1.13.0/000077500000000000000000000000001454232453300130735ustar00rootroot00000000000000bitset-1.13.0/.github/000077500000000000000000000000001454232453300144335ustar00rootroot00000000000000bitset-1.13.0/.github/FUNDING.yml000066400000000000000000000004441454232453300162520ustar00rootroot00000000000000# You can add one username per supported platform and one custom link patreon: # Replace with your Patreon username open_collective: # Replace with your Open Collective username ko_fi: # Replace with your Ko-fi username custom: https://donate.mcc.org/ # Replace with your custom donation URL bitset-1.13.0/.github/SECURITY.md000066400000000000000000000015651454232453300162330ustar00rootroot00000000000000# Security Policy ## Supported Versions Security updates are applied only to the latest release. ## Reporting a Vulnerability 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. Please use the following contact information for reporting a vulnerability: - [Daniel Lemire](https://github.com/lemire) - [daniel@lemire.me](mailto:daniel@lemire.me) In your report, please include: - A description of the vulnerability and its impact - How to reproduce the it - Affected versions 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. bitset-1.13.0/.github/dependabot.yml000066400000000000000000000007761454232453300172750ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "monthly" groups: github-actions: patterns: - "*" bitset-1.13.0/.github/workflows/000077500000000000000000000000001454232453300164705ustar00rootroot00000000000000bitset-1.13.0/.github/workflows/scorecard.yml000066400000000000000000000056441454232453300211710ustar00rootroot00000000000000# This workflow uses actions that are not certified by GitHub. They are provided # by a third-party and are governed by separate terms of service, privacy # policy, and support documentation. name: Scorecard supply-chain security on: # For Branch-Protection check. Only the default branch is supported. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection branch_protection_rule: # To guarantee Maintained check is occasionally updated. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained schedule: - cron: '40 9 * * 2' push: branches: [ "master" ] # Declare default permissions as read only. permissions: read-all jobs: analysis: name: Scorecard analysis runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. security-events: write # Needed to publish results and get a badge (see publish_results below). id-token: write # Uncomment the permissions below if installing in a private repository. # contents: read # actions: read steps: - name: "Checkout code" uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 with: results_file: results.sarif results_format: sarif # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: # - you want to enable the Branch-Protection check on a *public* repository, or # - you are installing Scorecard on a *private* repository # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. # repo_token: ${{ secrets.SCORECARD_TOKEN }} # Public repositories: # - Publish results to OpenSSF REST API for easy access by consumers # - Allows the repository to include the Scorecard badge. # - See https://github.com/ossf/scorecard-action#publishing-results. # For private repositories: # - `publish_results` will always be set to `false`, regardless # of the value entered here. publish_results: true # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: SARIF file path: results.sarif retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@8e0b1c74b1d5a0077b04d064c76ee714d3da7637 # v2.14.6 with: sarif_file: results.sarif bitset-1.13.0/.github/workflows/test.yml000066400000000000000000000010741454232453300201740ustar00rootroot00000000000000name: Test on: [push, pull_request] permissions: contents: read jobs: test: strategy: matrix: go-version: [1.16.x, 1.17.x, 1.18.x, 1.19.x,1.20.x] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - name: Install Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0 - name: Test run: go test ./... bitset-1.13.0/.gitignore000066400000000000000000000004221454232453300150610ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof target bitset-1.13.0/.travis.yml000066400000000000000000000012271454232453300152060ustar00rootroot00000000000000language: go sudo: false branches: except: - release branches: only: - master - travis go: - "1.11.x" - tip matrix: allow_failures: - go: tip before_install: - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi; - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi; - go get github.com/mattn/goveralls before_script: - make deps script: - make qa after_failure: - cat ./target/test/report.xml after_success: - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; bitset-1.13.0/LICENSE000066400000000000000000000027101454232453300141000ustar00rootroot00000000000000Copyright (c) 2014 Will Fitzgerald. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bitset-1.13.0/README.md000066400000000000000000000114331454232453300143540ustar00rootroot00000000000000# bitset *Go language library to map between non-negative integers and boolean values* [![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest) [![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset) [![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc) This library is part of the [awesome go collection](https://github.com/avelino/awesome-go). It is used in production by several important systems: * [beego](https://github.com/beego/beego) * [CubeFS](https://github.com/cubefs/cubefs) * [Amazon EKS Distro](https://github.com/aws/eks-distro) * [sourcegraph](https://github.com/sourcegraph/sourcegraph) * [torrent](https://github.com/anacrolix/torrent) ## Description Package bitset implements bitsets, a mapping between non-negative integers and boolean values. It should be more efficient than map[uint] bool. It provides methods for setting, clearing, flipping, and testing individual integers. But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits. BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used. Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining. ### Example use: ```go package main import ( "fmt" "math/rand" "github.com/bits-and-blooms/bitset" ) func main() { fmt.Printf("Hello from BitSet!\n") var b bitset.BitSet // play some Go Fish for i := 0; i < 100; i++ { card1 := uint(rand.Intn(52)) card2 := uint(rand.Intn(52)) b.Set(card1) if b.Test(card2) { fmt.Println("Go Fish!") } b.Clear(card1) } // Chaining b.Set(10).Set(11) for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) { fmt.Println("The following bit is set:", i) } if b.Intersection(bitset.New(100).Set(10)).Count() == 1 { fmt.Println("Intersection works.") } else { fmt.Println("Intersection doesn't work???") } } ``` Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc ## Serialization You may serialize a bitset safely and portably to a stream of bytes as follows: ```Go const length = 9585 const oneEvery = 97 bs := bitset.New(length) // Add some bits for i := uint(0); i < length; i += oneEvery { bs = bs.Set(i) } var buf bytes.Buffer n, err := bs.WriteTo(&buf) if err != nil { // failure } // Here n == buf.Len() ``` You can later deserialize the result as follows: ```Go // Read back from buf bs = bitset.New() n, err = bs.ReadFrom(&buf) if err != nil { // error } // n is the number of bytes read ``` The `ReadFrom` function attempts to read the data into the existing BitSet instance, to minimize memory allocations. *Performance tip*: When reading and writing to a file or a network connection, you may get better performance by wrapping your streams with `bufio` instances. E.g., ```Go f, err := os.Create("myfile") w := bufio.NewWriter(f) ``` ```Go f, err := os.Open("myfile") r := bufio.NewReader(f) ``` ## Memory Usage The memory usage of a bitset using `N` bits is at least `N/8` bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). The `roaring` library allows you to go back and forth between compressed Roaring bitmaps and the conventional bitset instances: ```Go mybitset := roaringbitmap.ToBitSet() newroaringbitmap := roaring.FromBitSet(mybitset) ``` ## Implementation Note Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `uint64`). If so, the version will be bumped. ## Installation ```bash go get github.com/bits-and-blooms/bitset ``` ## Contributing If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)") ## Running all tests Before committing the code, please check if it passes tests, has adequate coverage, etc. ```bash go test go test -cover ``` bitset-1.13.0/SECURITY.md000066400000000000000000000002151454232453300146620ustar00rootroot00000000000000# Security Policy ## Reporting a Vulnerability You can report privately a vulnerability by email at daniel@lemire.me (current maintainer). bitset-1.13.0/azure-pipelines.yml000066400000000000000000000021001454232453300167230ustar00rootroot00000000000000# Go # Build your Go project. # Add steps that test, save build artifacts, deploy, and more: # https://docs.microsoft.com/azure/devops/pipelines/languages/go trigger: - master pool: vmImage: 'Ubuntu-16.04' variables: GOBIN: '$(GOPATH)/bin' # Go binaries path GOROOT: '/usr/local/go1.11' # Go installation path GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code steps: - script: | mkdir -p '$(GOBIN)' mkdir -p '$(GOPATH)/pkg' mkdir -p '$(modulePath)' shopt -s extglob shopt -s dotglob mv !(gopath) '$(modulePath)' echo '##vso[task.prependpath]$(GOBIN)' echo '##vso[task.prependpath]$(GOROOT)/bin' displayName: 'Set up the Go workspace' - script: | go version go get -v -t -d ./... if [ -f Gopkg.toml ]; then curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh dep ensure fi go build -v . workingDirectory: '$(modulePath)' displayName: 'Get dependencies, then build' bitset-1.13.0/bitset.go000066400000000000000000000750011454232453300147170ustar00rootroot00000000000000/* Package bitset implements bitsets, a mapping between non-negative integers and boolean values. It should be more efficient than map[uint] bool. It provides methods for setting, clearing, flipping, and testing individual integers. But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits. BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used. Many of the methods, including Set,Clear, and Flip, return a BitSet pointer, which allows for chaining. Example use: import "bitset" var b BitSet b.Set(10).Set(11) if b.Test(1000) { b.Clear(1000) } if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { fmt.Println("Intersection works.") } As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets. */ package bitset import ( "bytes" "encoding/base64" "encoding/binary" "encoding/json" "errors" "fmt" "io" "strconv" ) // the wordSize of a bit set const wordSize = uint(64) // the wordSize of a bit set in bytes const wordBytes = wordSize / 8 // log2WordSize is lg(wordSize) const log2WordSize = uint(6) // allBits has every bit set const allBits uint64 = 0xffffffffffffffff // default binary BigEndian var binaryOrder binary.ByteOrder = binary.BigEndian // default json encoding base64.URLEncoding var base64Encoding = base64.URLEncoding // Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) func Base64StdEncoding() { base64Encoding = base64.StdEncoding } // LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian) func LittleEndian() { binaryOrder = binary.LittleEndian } // A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. type BitSet struct { length uint set []uint64 } // Error is used to distinguish errors (panics) generated in this package. type Error string // safeSet will fixup b.set to be non-nil and return the field value func (b *BitSet) safeSet() []uint64 { if b.set == nil { b.set = make([]uint64, wordsNeeded(0)) } return b.set } // SetBitsetFrom fills the bitset with an array of integers without creating a new BitSet instance func (b *BitSet) SetBitsetFrom(buf []uint64) { b.length = uint(len(buf)) * 64 b.set = buf } // From is a constructor used to create a BitSet from an array of words func From(buf []uint64) *BitSet { return FromWithLength(uint(len(buf))*64, buf) } // FromWithLength constructs from an array of words and length. func FromWithLength(len uint, set []uint64) *BitSet { return &BitSet{len, set} } // Bytes returns the bitset as array of words func (b *BitSet) Bytes() []uint64 { return b.set } // wordsNeeded calculates the number of words needed for i bits func wordsNeeded(i uint) int { if i > (Cap() - wordSize + 1) { return int(Cap() >> log2WordSize) } return int((i + (wordSize - 1)) >> log2WordSize) } // wordsNeededUnbound calculates the number of words needed for i bits, possibly exceeding the capacity. // This function is useful if you know that the capacity cannot be exceeded (e.g., you have an existing bitmap). func wordsNeededUnbound(i uint) int { return int((i + (wordSize - 1)) >> log2WordSize) } // wordsIndex calculates the index of words in a `uint64` func wordsIndex(i uint) uint { return i & (wordSize - 1) } // New creates a new BitSet with a hint that length bits will be required func New(length uint) (bset *BitSet) { defer func() { if r := recover(); r != nil { bset = &BitSet{ 0, make([]uint64, 0), } } }() bset = &BitSet{ length, make([]uint64, wordsNeeded(length)), } return bset } // Cap returns the total possible capacity, or number of bits func Cap() uint { return ^uint(0) } // Len returns the number of bits in the BitSet. // Note the difference to method Count, see example. func (b *BitSet) Len() uint { return b.length } // extendSet adds additional words to incorporate new bits if needed func (b *BitSet) extendSet(i uint) { if i >= Cap() { panic("You are exceeding the capacity") } nsize := wordsNeeded(i + 1) if b.set == nil { b.set = make([]uint64, nsize) } else if cap(b.set) >= nsize { b.set = b.set[:nsize] // fast resize } else if len(b.set) < nsize { newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x copy(newset, b.set) b.set = newset } b.length = i + 1 } // Test whether bit i is set. func (b *BitSet) Test(i uint) bool { if i >= b.length { return false } return b.set[i>>log2WordSize]&(1<= Cap(), this function will panic. // Warning: using a very large value for 'i' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. func (b *BitSet) Set(i uint) *BitSet { if i >= b.length { // if we need more bits, make 'em b.extendSet(i) } b.set[i>>log2WordSize] |= 1 << wordsIndex(i) return b } // Clear bit i to 0 func (b *BitSet) Clear(i uint) *BitSet { if i >= b.length { return b } b.set[i>>log2WordSize] &^= 1 << wordsIndex(i) return b } // SetTo sets bit i to value. // If i>= Cap(), this function will panic. // Warning: using a very large value for 'i' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. func (b *BitSet) SetTo(i uint, value bool) *BitSet { if value { return b.Set(i) } return b.Clear(i) } // Flip bit at i. // If i>= Cap(), this function will panic. // Warning: using a very large value for 'i' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. func (b *BitSet) Flip(i uint) *BitSet { if i >= b.length { return b.Set(i) } b.set[i>>log2WordSize] ^= 1 << wordsIndex(i) return b } // FlipRange bit in [start, end). // If end>= Cap(), this function will panic. // Warning: using a very large value for 'end' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. func (b *BitSet) FlipRange(start, end uint) *BitSet { if start >= end { return b } if end-1 >= b.length { // if we need more bits, make 'em b.extendSet(end - 1) } var startWord uint = start >> log2WordSize var endWord uint = end >> log2WordSize b.set[startWord] ^= ^(^uint64(0) << wordsIndex(start)) if endWord > 0 { // bounds check elimination data := b.set _ = data[endWord-1] for i := startWord; i < endWord; i++ { data[i] = ^data[i] } } if end&(wordSize-1) != 0 { b.set[endWord] ^= ^uint64(0) >> wordsIndex(-end) } return b } // Shrink shrinks BitSet so that the provided value is the last possible // set value. It clears all bits > the provided index and reduces the size // and length of the set. // // Note that the parameter value is not the new length in bits: it is the // maximal value that can be stored in the bitset after the function call. // The new length in bits is the parameter value + 1. Thus it is not possible // to use this function to set the length to 0, the minimal value of the length // after this function call is 1. // // A new slice is allocated to store the new bits, so you may see an increase in // memory usage until the GC runs. Normally this should not be a problem, but if you // have an extremely large BitSet its important to understand that the old BitSet will // remain in memory until the GC frees it. func (b *BitSet) Shrink(lastbitindex uint) *BitSet { length := lastbitindex + 1 idx := wordsNeeded(length) if idx > len(b.set) { return b } shrunk := make([]uint64, idx) copy(shrunk, b.set[:idx]) b.set = shrunk b.length = length lastWordUsedBits := length % 64 if lastWordUsedBits != 0 { b.set[idx-1] &= allBits >> uint64(64-wordsIndex(lastWordUsedBits)) } return b } // Compact shrinks BitSet to so that we preserve all set bits, while minimizing // memory usage. Compact calls Shrink. func (b *BitSet) Compact() *BitSet { idx := len(b.set) - 1 for ; idx >= 0 && b.set[idx] == 0; idx-- { } newlength := uint((idx + 1) << log2WordSize) if newlength >= b.length { return b // nothing to do } if newlength > 0 { return b.Shrink(newlength - 1) } // We preserve one word return b.Shrink(63) } // InsertAt takes an index which indicates where a bit should be // inserted. Then it shifts all the bits in the set to the left by 1, starting // from the given index position, and sets the index position to 0. // // Depending on the size of your BitSet, and where you are inserting the new entry, // this method could be extremely slow and in some cases might cause the entire BitSet // to be recopied. func (b *BitSet) InsertAt(idx uint) *BitSet { insertAtElement := idx >> log2WordSize // if length of set is a multiple of wordSize we need to allocate more space first if b.isLenExactMultiple() { b.set = append(b.set, uint64(0)) } var i uint for i = uint(len(b.set) - 1); i > insertAtElement; i-- { // all elements above the position where we want to insert can simply by shifted b.set[i] <<= 1 // we take the most significant bit of the previous element and set it as // the least significant bit of the current element b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63 } // generate a mask to extract the data that we need to shift left // within the element where we insert a bit dataMask := uint64(1)< 0x40000 { buffer.WriteString("...") break } buffer.WriteString(strconv.FormatInt(int64(i), 10)) i, e = b.NextSet(i + 1) if e { buffer.WriteString(",") } } buffer.WriteString("}") return buffer.String() } // DeleteAt deletes the bit at the given index position from // within the bitset // All the bits residing on the left of the deleted bit get // shifted right by 1 // The running time of this operation may potentially be // relatively slow, O(length) func (b *BitSet) DeleteAt(i uint) *BitSet { // the index of the slice element where we'll delete a bit deleteAtElement := i >> log2WordSize // generate a mask for the data that needs to be shifted right // within that slice element that gets modified dataMask := ^((uint64(1) << wordsIndex(i)) - 1) // extract the data that we'll shift right from the slice element data := b.set[deleteAtElement] & dataMask // set the masked area to 0 while leaving the rest as it is b.set[deleteAtElement] &= ^dataMask // shift the previously extracted data to the right and then // set it in the previously masked area b.set[deleteAtElement] |= (data >> 1) & dataMask // loop over all the consecutive slice elements to copy each // lowest bit into the highest position of the previous element, // then shift the entire content to the right by 1 for i := int(deleteAtElement) + 1; i < len(b.set); i++ { b.set[i-1] |= (b.set[i] & 1) << 63 b.set[i] >>= 1 } b.length = b.length - 1 return b } // NextSet returns the next bit set from the specified index, // including possibly the current index // along with an error code (true = valid, false = no set bit found) // for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} // // Users concerned with performance may want to use NextSetMany to // retrieve several values at once. func (b *BitSet) NextSet(i uint) (uint, bool) { x := int(i >> log2WordSize) if x >= len(b.set) { return 0, false } w := b.set[x] w = w >> wordsIndex(i) if w != 0 { return i + trailingZeroes64(w), true } x++ // bounds check elimination in the loop if x < 0 { return 0, false } for x < len(b.set) { if b.set[x] != 0 { return uint(x)*wordSize + trailingZeroes64(b.set[x]), true } x++ } return 0, false } // NextSetMany returns many next bit sets from the specified index, // including possibly the current index and up to cap(buffer). // If the returned slice has len zero, then no more set bits were found // // buffer := make([]uint, 256) // this should be reused // j := uint(0) // j, buffer = bitmap.NextSetMany(j, buffer) // for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) { // for k := range buffer { // do something with buffer[k] // } // j += 1 // } // // It is possible to retrieve all set bits as follow: // // indices := make([]uint, bitmap.Count()) // bitmap.NextSetMany(0, indices) // // However if bitmap.Count() is large, it might be preferable to // use several calls to NextSetMany, for performance reasons. func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { myanswer := buffer capacity := cap(buffer) x := int(i >> log2WordSize) if x >= len(b.set) || capacity == 0 { return 0, myanswer[:0] } skip := wordsIndex(i) word := b.set[x] >> skip myanswer = myanswer[:capacity] size := int(0) for word != 0 { r := trailingZeroes64(word) t := word & ((^word) + 1) myanswer[size] = r + i size++ if size == capacity { goto End } word = word ^ t } x++ for idx, word := range b.set[x:] { for word != 0 { r := trailingZeroes64(word) t := word & ((^word) + 1) myanswer[size] = r + (uint(x+idx) << 6) size++ if size == capacity { goto End } word = word ^ t } } End: if size > 0 { return myanswer[size-1], myanswer[:size] } return 0, myanswer[:0] } // NextClear returns the next clear bit from the specified index, // including possibly the current index // along with an error code (true = valid, false = no bit found i.e. all bits are set) func (b *BitSet) NextClear(i uint) (uint, bool) { x := int(i >> log2WordSize) if x >= len(b.set) { return 0, false } w := b.set[x] w = w >> wordsIndex(i) wA := allBits >> wordsIndex(i) index := i + trailingZeroes64(^w) if w != wA && index < b.length { return index, true } x++ // bounds check elimination in the loop if x < 0 { return 0, false } for x < len(b.set) { if b.set[x] != allBits { index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) if index < b.length { return index, true } } x++ } return 0, false } // ClearAll clears the entire BitSet func (b *BitSet) ClearAll() *BitSet { if b != nil && b.set != nil { for i := range b.set { b.set[i] = 0 } } return b } // SetAll sets the entire BitSet func (b *BitSet) SetAll() *BitSet { if b != nil && b.set != nil { for i := range b.set { b.set[i] = allBits } b.cleanLastWord() } return b } // wordCount returns the number of words used in a bit set func (b *BitSet) wordCount() int { return wordsNeededUnbound(b.length) } // Clone this BitSet func (b *BitSet) Clone() *BitSet { c := New(b.length) if b.set != nil { // Clone should not modify current object copy(c.set, b.set) } return c } // Copy into a destination BitSet using the Go array copy semantics: // the number of bits copied is the minimum of the number of bits in the current // BitSet (Len()) and the destination Bitset. // We return the number of bits copied in the destination BitSet. func (b *BitSet) Copy(c *BitSet) (count uint) { if c == nil { return } if b.set != nil { // Copy should not modify current object copy(c.set, b.set) } count = c.length if b.length < c.length { count = b.length } // Cleaning the last word is needed to keep the invariant that other functions, such as Count, require // that any bits in the last word that would exceed the length of the bitmask are set to 0. c.cleanLastWord() return } // CopyFull copies into a destination BitSet such that the destination is // identical to the source after the operation, allocating memory if necessary. func (b *BitSet) CopyFull(c *BitSet) { if c == nil { return } c.length = b.length if len(b.set) == 0 { if c.set != nil { c.set = c.set[:0] } } else { if cap(c.set) < len(b.set) { c.set = make([]uint64, len(b.set)) } else { c.set = c.set[:len(b.set)] } copy(c.set, b.set) } } // Count (number of set bits). // Also known as "popcount" or "population count". func (b *BitSet) Count() uint { if b != nil && b.set != nil { return uint(popcntSlice(b.set)) } return 0 } // Equal tests the equivalence of two BitSets. // False if they are of different sizes, otherwise true // only if all the same bits are set func (b *BitSet) Equal(c *BitSet) bool { if c == nil || b == nil { return c == b } if b.length != c.length { return false } if b.length == 0 { // if they have both length == 0, then could have nil set return true } wn := b.wordCount() // bounds check elimination if wn <= 0 { return true } _ = b.set[wn-1] _ = c.set[wn-1] for p := 0; p < wn; p++ { if c.set[p] != b.set[p] { return false } } return true } func panicIfNull(b *BitSet) { if b == nil { panic(Error("BitSet must not be null")) } } // Difference of base set and other set // This is the BitSet equivalent of &^ (and not) func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { panicIfNull(b) panicIfNull(compare) result = b.Clone() // clone b (in case b is bigger than compare) l := compare.wordCount() if l > b.wordCount() { l = b.wordCount() } for i := 0; i < l; i++ { result.set[i] = b.set[i] &^ compare.set[i] } return } // DifferenceCardinality computes the cardinality of the differnce func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) l := compare.wordCount() if l > b.wordCount() { l = b.wordCount() } cnt := uint64(0) cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) cnt += popcntSlice(b.set[l:]) return uint(cnt) } // InPlaceDifference computes the difference of base set and other set // This is the BitSet equivalent of &^ (and not) func (b *BitSet) InPlaceDifference(compare *BitSet) { panicIfNull(b) panicIfNull(compare) l := compare.wordCount() if l > b.wordCount() { l = b.wordCount() } if l <= 0 { return } // bounds check elimination data, cmpData := b.set, compare.set _ = data[l-1] _ = cmpData[l-1] for i := 0; i < l; i++ { data[i] &^= cmpData[i] } } // Convenience function: return two bitsets ordered by // increasing length. Note: neither can be nil func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { if a.length <= b.length { ap, bp = a, b } else { ap, bp = b, a } return } // Intersection of base set and other set // This is the BitSet equivalent of & (and) func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { panicIfNull(b) panicIfNull(compare) b, compare = sortByLength(b, compare) result = New(b.length) for i, word := range b.set { result.set[i] = word & compare.set[i] } return } // IntersectionCardinality computes the cardinality of the union func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) b, compare = sortByLength(b, compare) cnt := popcntAndSlice(b.set, compare.set) return uint(cnt) } // InPlaceIntersection destructively computes the intersection of // base set and the compare set. // This is the BitSet equivalent of & (and) func (b *BitSet) InPlaceIntersection(compare *BitSet) { panicIfNull(b) panicIfNull(compare) l := compare.wordCount() if l > b.wordCount() { l = b.wordCount() } if l > 0 { // bounds check elimination data, cmpData := b.set, compare.set _ = data[l-1] _ = cmpData[l-1] for i := 0; i < l; i++ { data[i] &= cmpData[i] } } if l >= 0 { for i := l; i < len(b.set); i++ { b.set[i] = 0 } } if compare.length > 0 { if compare.length-1 >= b.length { b.extendSet(compare.length - 1) } } } // Union of base set and other set // This is the BitSet equivalent of | (or) func (b *BitSet) Union(compare *BitSet) (result *BitSet) { panicIfNull(b) panicIfNull(compare) b, compare = sortByLength(b, compare) result = compare.Clone() for i, word := range b.set { result.set[i] = word | compare.set[i] } return } // UnionCardinality computes the cardinality of the uniton of the base set // and the compare set. func (b *BitSet) UnionCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) b, compare = sortByLength(b, compare) cnt := popcntOrSlice(b.set, compare.set) if len(compare.set) > len(b.set) { cnt += popcntSlice(compare.set[len(b.set):]) } return uint(cnt) } // InPlaceUnion creates the destructive union of base set and compare set. // This is the BitSet equivalent of | (or). func (b *BitSet) InPlaceUnion(compare *BitSet) { panicIfNull(b) panicIfNull(compare) l := compare.wordCount() if l > b.wordCount() { l = b.wordCount() } if compare.length > 0 && compare.length-1 >= b.length { b.extendSet(compare.length - 1) } if l > 0 { // bounds check elimination data, cmpData := b.set, compare.set _ = data[l-1] _ = cmpData[l-1] for i := 0; i < l; i++ { data[i] |= cmpData[i] } } if len(compare.set) > l { for i := l; i < len(compare.set); i++ { b.set[i] = compare.set[i] } } } // SymmetricDifference of base set and other set // This is the BitSet equivalent of ^ (xor) func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { panicIfNull(b) panicIfNull(compare) b, compare = sortByLength(b, compare) // compare is bigger, so clone it result = compare.Clone() for i, word := range b.set { result.set[i] = word ^ compare.set[i] } return } // SymmetricDifferenceCardinality computes the cardinality of the symmetric difference func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) b, compare = sortByLength(b, compare) cnt := popcntXorSlice(b.set, compare.set) if len(compare.set) > len(b.set) { cnt += popcntSlice(compare.set[len(b.set):]) } return uint(cnt) } // InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set // This is the BitSet equivalent of ^ (xor) func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { panicIfNull(b) panicIfNull(compare) l := compare.wordCount() if l > b.wordCount() { l = b.wordCount() } if compare.length > 0 && compare.length-1 >= b.length { b.extendSet(compare.length - 1) } if l > 0 { // bounds check elimination data, cmpData := b.set, compare.set _ = data[l-1] _ = cmpData[l-1] for i := 0; i < l; i++ { data[i] ^= cmpData[i] } } if len(compare.set) > l { for i := l; i < len(compare.set); i++ { b.set[i] = compare.set[i] } } } // Is the length an exact multiple of word sizes? func (b *BitSet) isLenExactMultiple() bool { return wordsIndex(b.length) == 0 } // Clean last word by setting unused bits to 0 func (b *BitSet) cleanLastWord() { if !b.isLenExactMultiple() { b.set[len(b.set)-1] &= allBits >> (wordSize - wordsIndex(b.length)) } } // Complement computes the (local) complement of a bitset (up to length bits) func (b *BitSet) Complement() (result *BitSet) { panicIfNull(b) result = New(b.length) for i, word := range b.set { result.set[i] = ^word } result.cleanLastWord() return } // All returns true if all bits are set, false otherwise. Returns true for // empty sets. func (b *BitSet) All() bool { panicIfNull(b) return b.Count() == b.length } // None returns true if no bit is set, false otherwise. Returns true for // empty sets. func (b *BitSet) None() bool { panicIfNull(b) if b != nil && b.set != nil { for _, word := range b.set { if word > 0 { return false } } } return true } // Any returns true if any bit is set, false otherwise func (b *BitSet) Any() bool { panicIfNull(b) return !b.None() } // IsSuperSet returns true if this is a superset of the other set func (b *BitSet) IsSuperSet(other *BitSet) bool { l := other.wordCount() if b.wordCount() < l { l = b.wordCount() } for i, word := range other.set[:l] { if b.set[i]&word != word { return false } } return popcntSlice(other.set[l:]) == 0 } // IsStrictSuperSet returns true if this is a strict superset of the other set func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { return b.Count() > other.Count() && b.IsSuperSet(other) } // DumpAsBits dumps a bit set as a string of bits. Following the usual convention in Go, // the least significant bits are printed last (index 0 is at the end of the string). func (b *BitSet) DumpAsBits() string { if b.set == nil { return "." } buffer := bytes.NewBufferString("") i := len(b.set) - 1 for ; i >= 0; i-- { fmt.Fprintf(buffer, "%064b.", b.set[i]) } return buffer.String() } // BinaryStorageSize returns the binary storage requirements (see WriteTo) in bytes. func (b *BitSet) BinaryStorageSize() int { return int(wordBytes + wordBytes*uint(b.wordCount())) } func readUint64Array(reader io.Reader, data []uint64) error { length := len(data) bufferSize := 128 buffer := make([]byte, bufferSize*int(wordBytes)) for i := 0; i < length; i += bufferSize { end := i + bufferSize if end > length { end = length buffer = buffer[:wordBytes*uint(end-i)] } chunk := data[i:end] if _, err := io.ReadFull(reader, buffer); err != nil { return err } for i := range chunk { chunk[i] = uint64(binaryOrder.Uint64(buffer[8*i:])) } } return nil } func writeUint64Array(writer io.Writer, data []uint64) error { bufferSize := 128 buffer := make([]byte, bufferSize*int(wordBytes)) for i := 0; i < len(data); i += bufferSize { end := i + bufferSize if end > len(data) { end = len(data) buffer = buffer[:wordBytes*uint(end-i)] } chunk := data[i:end] for i, x := range chunk { binaryOrder.PutUint64(buffer[8*i:], x) } _, err := writer.Write(buffer) if err != nil { return err } } return nil } // WriteTo writes a BitSet to a stream. The format is: // 1. uint64 length // 2. []uint64 set // Upon success, the number of bytes written is returned. // // Performance: if this function is used to write to a disk or network // connection, it might be beneficial to wrap the stream in a bufio.Writer. // E.g., // // f, err := os.Create("myfile") // w := bufio.NewWriter(f) func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { length := uint64(b.length) // Write length err := binary.Write(stream, binaryOrder, &length) if err != nil { // Upon failure, we do not guarantee that we // return the number of bytes written. return int64(0), err } err = writeUint64Array(stream, b.set[:b.wordCount()]) if err != nil { // Upon failure, we do not guarantee that we // return the number of bytes written. return int64(wordBytes), err } return int64(b.BinaryStorageSize()), nil } // ReadFrom reads a BitSet from a stream written using WriteTo // The format is: // 1. uint64 length // 2. []uint64 set // Upon success, the number of bytes read is returned. // If the current BitSet is not large enough to hold the data, // it is extended. In case of error, the BitSet is either // left unchanged or made empty if the error occurs too late // to preserve the content. // // Performance: if this function is used to read from a disk or network // connection, it might be beneficial to wrap the stream in a bufio.Reader. // E.g., // // f, err := os.Open("myfile") // r := bufio.NewReader(f) func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { var length uint64 err := binary.Read(stream, binaryOrder, &length) if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return 0, err } newlength := uint(length) if uint64(newlength) != length { return 0, errors.New("unmarshalling error: type mismatch") } nWords := wordsNeeded(uint(newlength)) if cap(b.set) >= nWords { b.set = b.set[:nWords] } else { b.set = make([]uint64, nWords) } b.length = newlength err = readUint64Array(stream, b.set) if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } // We do not want to leave the BitSet partially filled as // it is error prone. b.set = b.set[:0] b.length = 0 return 0, err } return int64(b.BinaryStorageSize()), nil } // MarshalBinary encodes a BitSet into a binary form and returns the result. func (b *BitSet) MarshalBinary() ([]byte, error) { var buf bytes.Buffer _, err := b.WriteTo(&buf) if err != nil { return []byte{}, err } return buf.Bytes(), err } // UnmarshalBinary decodes the binary form generated by MarshalBinary. func (b *BitSet) UnmarshalBinary(data []byte) error { buf := bytes.NewReader(data) _, err := b.ReadFrom(buf) return err } // MarshalJSON marshals a BitSet as a JSON structure func (b BitSet) MarshalJSON() ([]byte, error) { buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) _, err := b.WriteTo(buffer) if err != nil { return nil, err } // URLEncode all bytes return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes())) } // UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON func (b *BitSet) UnmarshalJSON(data []byte) error { // Unmarshal as string var s string err := json.Unmarshal(data, &s) if err != nil { return err } // URLDecode string buf, err := base64Encoding.DecodeString(s) if err != nil { return err } _, err = b.ReadFrom(bytes.NewReader(buf)) return err } // Rank returns the nunber of set bits up to and including the index // that are set in the bitset. // See https://en.wikipedia.org/wiki/Ranking#Ranking_in_statistics func (b *BitSet) Rank(index uint) uint { if index >= b.length { return b.Count() } leftover := (index + 1) & 63 answer := uint(popcntSlice(b.set[:(index+1)>>6])) if leftover != 0 { answer += uint(popcount(b.set[(index+1)>>6] << (64 - leftover))) } return answer } // Select returns the index of the jth set bit, where j is the argument. // The caller is responsible to ensure that 0 <= j < Count(): when j is // out of range, the function returns the length of the bitset (b.length). // // Note that this function differs in convention from the Rank function which // returns 1 when ranking the smallest value. We follow the conventional // textbook definition of Select and Rank. func (b *BitSet) Select(index uint) uint { leftover := index for idx, word := range b.set { w := uint(popcount(word)) if w > leftover { return uint(idx)*64 + select64(word, leftover) } leftover -= w } return b.length } bitset-1.13.0/bitset_benchmark_test.go000066400000000000000000000336641454232453300200010ustar00rootroot00000000000000// Copyright 2014 Will Fitzgerald. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file tests bit sets package bitset import ( "bytes" "fmt" "math/rand" "testing" ) func BenchmarkSet(b *testing.B) { b.StopTimer() r := rand.New(rand.NewSource(0)) sz := 100000 s := New(uint(sz)) b.StartTimer() for i := 0; i < b.N; i++ { s.Set(uint(r.Int31n(int32(sz)))) } } func BenchmarkGetTest(b *testing.B) { b.StopTimer() r := rand.New(rand.NewSource(0)) sz := 100000 s := New(uint(sz)) b.StartTimer() for i := 0; i < b.N; i++ { s.Test(uint(r.Int31n(int32(sz)))) } } func BenchmarkSetExpand(b *testing.B) { b.StopTimer() sz := uint(100000) b.StartTimer() for i := 0; i < b.N; i++ { var s BitSet s.Set(sz) } } // go test -bench=Count func BenchmarkCount(b *testing.B) { b.StopTimer() s := New(100000) for i := 0; i < 100000; i += 100 { s.Set(uint(i)) } b.StartTimer() for i := 0; i < b.N; i++ { s.Count() } } // go test -bench=Iterate func BenchmarkIterate(b *testing.B) { b.StopTimer() s := New(10000) for i := 0; i < 10000; i += 3 { s.Set(uint(i)) } b.StartTimer() for j := 0; j < b.N; j++ { c := uint(0) for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { c++ } } } // go test -bench=SparseIterate func BenchmarkSparseIterate(b *testing.B) { b.StopTimer() s := New(100000) for i := 0; i < 100000; i += 30 { s.Set(uint(i)) } b.StartTimer() for j := 0; j < b.N; j++ { c := uint(0) for i, e := s.NextSet(0); e; i, e = s.NextSet(i + 1) { c++ } } } // go test -bench=BitsetOps func BenchmarkBitsetOps(b *testing.B) { // let's not write into s inside the benchmarks s := New(100000) for i := 0; i < 100000; i += 100 { s.Set(uint(i)) } cpy := s.Clone() b.Run("Equal", func(b *testing.B) { for i := 0; i < b.N; i++ { s.Equal(cpy) } }) b.Run("FlipRange", func(b *testing.B) { s = s.Clone() b.ResetTimer() for i := 0; i < b.N; i++ { s.FlipRange(0, 100000) } }) b.Run("NextSet", func(b *testing.B) { s = New(100000) b.ResetTimer() for i := 0; i < b.N; i++ { s.NextSet(0) } }) b.Run("NextClear", func(b *testing.B) { s = New(100000) s.FlipRange(0, 100000) b.ResetTimer() for i := 0; i < b.N; i++ { s.NextClear(0) } }) b.Run("DifferenceCardinality", func(b *testing.B) { empty := New(100000) b.ResetTimer() for i := 0; i < b.N; i++ { s.DifferenceCardinality(empty) } }) b.Run("InPlaceDifference", func(b *testing.B) { s = s.Clone() b.ResetTimer() for i := 0; i < b.N; i++ { s.InPlaceDifference(cpy) } }) b.Run("InPlaceUnion", func(b *testing.B) { s = s.Clone() b.ResetTimer() for i := 0; i < b.N; i++ { s.InPlaceUnion(cpy) } }) b.Run("InPlaceIntersection", func(b *testing.B) { s = s.Clone() b.ResetTimer() for i := 0; i < b.N; i++ { s.InPlaceIntersection(cpy) } }) b.Run("InPlaceSymmetricDifference", func(b *testing.B) { s = s.Clone() b.ResetTimer() for i := 0; i < b.N; i++ { s.InPlaceSymmetricDifference(cpy) } }) } // go test -bench=LemireCreate // see http://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ func BenchmarkLemireCreate(b *testing.B) { for i := 0; i < b.N; i++ { bitmap := New(0) // we force dynamic memory allocation for v := uint(0); v <= 100000000; v += 100 { bitmap.Set(v) } } } // go test -bench=LemireCount // see http://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ func BenchmarkLemireCount(b *testing.B) { bitmap := New(100000000) for v := uint(0); v <= 100000000; v += 100 { bitmap.Set(v) } b.ResetTimer() sum := uint(0) for i := 0; i < b.N; i++ { sum += bitmap.Count() } if sum == 0 { // added just to fool ineffassign return } } // go test -bench=LemireIterate // see http://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ func BenchmarkLemireIterate(b *testing.B) { bitmap := New(100000000) for v := uint(0); v <= 100000000; v += 100 { bitmap.Set(v) } b.ResetTimer() sum := uint(0) for i := 0; i < b.N; i++ { for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { sum++ } } if sum == 0 { // added just to fool ineffassign return } } // go test -bench=LemireIterateb // see http://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ func BenchmarkLemireIterateb(b *testing.B) { bitmap := New(100000000) for v := uint(0); v <= 100000000; v += 100 { bitmap.Set(v) } b.ResetTimer() sum := uint(0) for i := 0; i < b.N; i++ { for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { sum += j } } if sum == 0 { // added just to fool ineffassign return } } // go test -bench=BenchmarkLemireIterateManyb // see http://lemire.me/blog/2016/09/22/swift-versus-java-the-bitset-performance-test/ func BenchmarkLemireIterateManyb(b *testing.B) { bitmap := New(100000000) for v := uint(0); v <= 100000000; v += 100 { bitmap.Set(v) } buffer := make([]uint, 256) b.ResetTimer() sum := uint(0) for i := 0; i < b.N; i++ { j := uint(0) j, buffer = bitmap.NextSetMany(j, buffer) for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { for k := range buffer { sum += buffer[k] } j++ } } if sum == 0 { // added just to fool ineffassign return } } func setRnd(bits []uint64, halfings int) { var rnd = rand.NewSource(0).(rand.Source64) for i := range bits { bits[i] = 0xFFFFFFFFFFFFFFFF for j := 0; j < halfings; j++ { bits[i] &= rnd.Uint64() } } } // go test -bench=BenchmarkFlorianUekermannIterateMany func BenchmarkFlorianUekermannIterateMany(b *testing.B) { var input = make([]uint64, 68) setRnd(input, 4) var bitmap = From(input) buffer := make([]uint, 256) b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { var last, batch = bitmap.NextSetMany(0, buffer) for len(batch) > 0 { for _, idx := range batch { checksum += idx } last, batch = bitmap.NextSetMany(last+1, batch) } } if checksum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannIterateManyReg(b *testing.B) { var input = make([]uint64, 68) setRnd(input, 4) var bitmap = From(input) b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { checksum += j } } if checksum == 0 { // added just to fool ineffassign return } } // function provided by FlorianUekermann func good(set []uint64) (checksum uint) { for wordIdx, word := range set { var wordIdx = uint(wordIdx * 64) for word != 0 { var bitIdx = uint(trailingZeroes64(word)) word ^= 1 << bitIdx var index = wordIdx + bitIdx checksum += index } } return checksum } func BenchmarkFlorianUekermannIterateManyComp(b *testing.B) { var input = make([]uint64, 68) setRnd(input, 4) b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { checksum += good(input) } if checksum == 0 { // added just to fool ineffassign return } } /////// Mid density // go test -bench=BenchmarkFlorianUekermannLowDensityIterateMany func BenchmarkFlorianUekermannLowDensityIterateMany(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 50000; i++ { input[rnd.Uint64()%1000000] = 1 } var bitmap = From(input) buffer := make([]uint, 256) b.ResetTimer() var sum = uint(0) for i := 0; i < b.N; i++ { j := uint(0) j, buffer = bitmap.NextSetMany(j, buffer) for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { for k := range buffer { sum += buffer[k] } j++ } } if sum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannLowDensityIterateManyReg(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 50000; i++ { input[rnd.Uint64()%1000000] = 1 } var bitmap = From(input) b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { checksum += j } } if checksum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannLowDensityIterateManyComp(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 50000; i++ { input[rnd.Uint64()%1000000] = 1 } b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { checksum += good(input) } if checksum == 0 { // added just to fool ineffassign return } } /////// Mid density // go test -bench=BenchmarkFlorianUekermannMidDensityIterateMany func BenchmarkFlorianUekermannMidDensityIterateMany(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 3000000; i++ { input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) } var bitmap = From(input) buffer := make([]uint, 256) b.ResetTimer() sum := uint(0) for i := 0; i < b.N; i++ { j := uint(0) j, buffer = bitmap.NextSetMany(j, buffer) for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { for k := range buffer { sum += buffer[k] } j++ } } if sum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannMidDensityIterateManyReg(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 3000000; i++ { input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) } var bitmap = From(input) b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { checksum += j } } if checksum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannMidDensityIterateManyComp(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 3000000; i++ { input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) } b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { checksum += good(input) } if checksum == 0 { // added just to fool ineffassign return } } ////////// High density func BenchmarkFlorianUekermannMidStrongDensityIterateMany(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 20000000; i++ { input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) } var bitmap = From(input) buffer := make([]uint, 256) b.ResetTimer() sum := uint(0) for i := 0; i < b.N; i++ { j := uint(0) j, buffer = bitmap.NextSetMany(j, buffer) for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j, buffer) { for k := range buffer { sum += buffer[k] } j++ } } if sum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannMidStrongDensityIterateManyReg(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 20000000; i++ { input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) } var bitmap = From(input) b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { for j, e := bitmap.NextSet(0); e; j, e = bitmap.NextSet(j + 1) { checksum += j } } if checksum == 0 { // added just to fool ineffassign return } } func BenchmarkFlorianUekermannMidStrongDensityIterateManyComp(b *testing.B) { var input = make([]uint64, 1000000) var rnd = rand.NewSource(0).(rand.Source64) for i := 0; i < 20000000; i++ { input[rnd.Uint64()%1000000] |= uint64(1) << (rnd.Uint64() % 64) } b.ResetTimer() var checksum = uint(0) for i := 0; i < b.N; i++ { checksum += good(input) } if checksum == 0 { // added just to fool ineffassign return } } func BenchmarkBitsetReadWrite(b *testing.B) { s := New(100000) for i := 0; i < 100000; i += 100 { s.Set(uint(i)) } buffer := bytes.Buffer{} temp := New(100000) b.ResetTimer() for i := 0; i < b.N; i++ { s.WriteTo(&buffer) temp.ReadFrom(&buffer) buffer.Reset() } } func BenchmarkIsSuperSet(b *testing.B) { new := func(len int, density float64) *BitSet { r := rand.New(rand.NewSource(42)) bs := New(uint(len)) for i := 0; i < len; i++ { bs.SetTo(uint(i), r.Float64() < density) } return bs } bench := func(name string, lenS, lenSS int, density float64, overrideS, overrideSS map[int]bool, f func(*BitSet, *BitSet) bool) { s := new(lenS, density) ss := new(lenSS, density) for i, v := range overrideS { s.SetTo(uint(i), v) } for i, v := range overrideSS { ss.SetTo(uint(i), v) } b.Run(name, func(b *testing.B) { for i := 0; i < b.N; i++ { _ = f(ss, s) } }) } f := func(ss, s *BitSet) bool { return ss.IsSuperSet(s) } fStrict := func(ss, s *BitSet) bool { return ss.IsStrictSuperSet(s) } for _, len := range []int{1, 10, 100, 1000, 10000, 100000} { density := 0.5 bench(fmt.Sprintf("equal, len=%d", len), len, len, density, nil, nil, f) bench(fmt.Sprintf("equal, len=%d, strict", len), len, len, density, nil, nil, fStrict) } for _, density := range []float64{0, 0.05, 0.2, 0.8, 0.95, 1} { len := 10000 bench(fmt.Sprintf("equal, density=%.2f", density), len, len, density, nil, nil, f) bench(fmt.Sprintf("equal, density=%.2f, strict", density), len, len, density, nil, nil, fStrict) } for _, diff := range []int{0, 100, 1000, 9999} { len := 10000 density := 0.5 overrideS := map[int]bool{diff: true} overrideSS := map[int]bool{diff: false} bench(fmt.Sprintf("subset, len=%d, diff=%d", len, diff), len, len, density, overrideS, overrideSS, f) bench(fmt.Sprintf("subset, len=%d, diff=%d, strict", len, diff), len, len, density, overrideS, overrideSS, fStrict) } for _, diff := range []int{0, 100, 1000, 9999} { len := 10000 density := 0.5 overrideS := map[int]bool{diff: false} overrideSS := map[int]bool{diff: true} bench(fmt.Sprintf("superset, len=%d, diff=%d", len, diff), len, len, density, overrideS, overrideSS, f) bench(fmt.Sprintf("superset, len=%d, diff=%d, strict", len, diff), len, len, density, overrideS, overrideSS, fStrict) } } bitset-1.13.0/bitset_test.go000066400000000000000000001251301454232453300157550ustar00rootroot00000000000000// Copyright 2014 Will Fitzgerald. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file tests bit sets package bitset import ( "bytes" "compress/gzip" "encoding" "encoding/base64" "encoding/binary" "encoding/json" "errors" "fmt" "io" "math" "math/rand" "strconv" "testing" ) func TestStringer(t *testing.T) { v := New(0) for i := uint(0); i < 10; i++ { v.Set(i) } if v.String() != "{0,1,2,3,4,5,6,7,8,9}" { t.Error("bad string output") } } func TestStringLong(t *testing.T) { v := New(0) for i := uint(0); i < 262145; i++ { v.Set(i) } str := v.String() if len(str) != 1723903 { t.Error("Unexpected string length: ", len(str)) } } func TestEmptyBitSet(t *testing.T) { defer func() { if r := recover(); r != nil { t.Error("A zero-length bitset should be fine") } }() b := New(0) if b.Len() != 0 { t.Errorf("Empty set should have capacity 0, not %d", b.Len()) } } func TestZeroValueBitSet(t *testing.T) { defer func() { if r := recover(); r != nil { t.Error("A zero-length bitset should be fine") } }() var b BitSet if b.Len() != 0 { t.Errorf("Empty set should have capacity 0, not %d", b.Len()) } } func TestBitSetNew(t *testing.T) { v := New(16) if v.Test(0) { t.Errorf("Unable to make a bit set and read its 0th value.") } } func TestBitSetHuge(t *testing.T) { v := New(uint(math.MaxUint32)) if v.Test(0) { t.Errorf("Unable to make a huge bit set and read its 0th value.") } } func TestLen(t *testing.T) { v := New(1000) if v.Len() != 1000 { t.Errorf("Len should be 1000, but is %d.", v.Len()) } } func TestLenIsNumberOfBitsNotBytes(t *testing.T) { var b BitSet if b.Len() != 0 { t.Errorf("empty bitset should have Len 0, got %v", b.Len()) } b.Set(0) if b.Len() != 1 { t.Errorf("bitset with first bit set should have Len 1, got %v", b.Len()) } b.Set(8) if b.Len() != 9 { t.Errorf("bitset with 0th and 8th bit set should have Len 9, got %v", b.Len()) } b.Set(1) if b.Len() != 9 { t.Errorf("bitset with 0th, 1st and 8th bit set should have Len 9, got %v", b.Len()) } } func ExampleBitSet_Len() { var b BitSet b.Set(8) fmt.Println("len", b.Len()) fmt.Println("count", b.Count()) // Output: // len 9 // count 1 } func TestBitSetIsClear(t *testing.T) { v := New(1000) for i := uint(0); i < 1000; i++ { if v.Test(i) { t.Errorf("Bit %d is set, and it shouldn't be.", i) } } } func TestExendOnBoundary(t *testing.T) { v := New(32) defer func() { if r := recover(); r != nil { t.Error("Border out of index error should not have caused a panic") } }() v.Set(32) } func TestExceedCap(t *testing.T) { defer func() { if r := recover(); r == nil { t.Error("Set to capacity should have caused a panic") } }() NumHosts := uint(32768) bmp := New(NumHosts) bmp.ClearAll() d := Cap() bmp.Set(d) } func TestExpand(t *testing.T) { v := New(0) defer func() { if r := recover(); r != nil { t.Error("Expansion should not have caused a panic") } }() for i := uint(0); i < 1000; i++ { v.Set(i) } } func TestBitSetAndGet(t *testing.T) { v := New(1000) v.Set(100) if !v.Test(100) { t.Errorf("Bit %d is clear, and it shouldn't be.", 100) } } func TestNextClear(t *testing.T) { v := New(1000) v.Set(0).Set(1) next, found := v.NextClear(0) if !found || next != 2 { t.Errorf("Found next clear bit as %d, it should have been 2", next) } v = New(1000) for i := uint(0); i < 66; i++ { v.Set(i) } next, found = v.NextClear(0) if !found || next != 66 { t.Errorf("Found next clear bit as %d, it should have been 66", next) } v = New(1000) for i := uint(0); i < 64; i++ { v.Set(i) } v.Clear(45) v.Clear(52) next, found = v.NextClear(10) if !found || next != 45 { t.Errorf("Found next clear bit as %d, it should have been 45", next) } v = New(1000) for i := uint(0); i < 128; i++ { v.Set(i) } v.Clear(73) v.Clear(99) next, found = v.NextClear(10) if !found || next != 73 { t.Errorf("Found next clear bit as %d, it should have been 73", next) } next, found = v.NextClear(72) if !found || next != 73 { t.Errorf("Found next clear bit as %d, it should have been 73", next) } next, found = v.NextClear(73) if !found || next != 73 { t.Errorf("Found next clear bit as %d, it should have been 73", next) } next, found = v.NextClear(74) if !found || next != 99 { t.Errorf("Found next clear bit as %d, it should have been 73", next) } v = New(128) next, found = v.NextClear(0) if !found || next != 0 { t.Errorf("Found next clear bit as %d, it should have been 0", next) } for i := uint(0); i < 128; i++ { v.Set(i) } _, found = v.NextClear(0) if found { t.Errorf("There are not clear bits") } b := new(BitSet) c, d := b.NextClear(1) if c != 0 || d { t.Error("Unexpected values") return } v = New(100) for i := uint(0); i != 100; i++ { v.Set(i) } next, found = v.NextClear(0) if found || next != 0 { t.Errorf("Found next clear bit as %d, it should have return (0, false)", next) } } func TestIterate(t *testing.T) { v := New(10000) v.Set(0) v.Set(1) v.Set(2) data := make([]uint, 3) c := 0 for i, e := v.NextSet(0); e; i, e = v.NextSet(i + 1) { data[c] = i c++ } if data[0] != 0 { t.Errorf("bug 0") } if data[1] != 1 { t.Errorf("bug 1") } if data[2] != 2 { t.Errorf("bug 2") } v.Set(10) v.Set(2000) data = make([]uint, 5) c = 0 for i, e := v.NextSet(0); e; i, e = v.NextSet(i + 1) { data[c] = i c++ } if data[0] != 0 { t.Errorf("bug 0") } if data[1] != 1 { t.Errorf("bug 1") } if data[2] != 2 { t.Errorf("bug 2") } if data[3] != 10 { t.Errorf("bug 3") } if data[4] != 2000 { t.Errorf("bug 4") } } func TestSetTo(t *testing.T) { v := New(1000) v.SetTo(100, true) if !v.Test(100) { t.Errorf("Bit %d is clear, and it shouldn't be.", 100) } v.SetTo(100, false) if v.Test(100) { t.Errorf("Bit %d is set, and it shouldn't be.", 100) } } func TestChain(t *testing.T) { if !New(1000).Set(100).Set(99).Clear(99).Test(100) { t.Errorf("Bit %d is clear, and it shouldn't be.", 100) } } func TestOutOfBoundsLong(t *testing.T) { v := New(64) defer func() { if r := recover(); r != nil { t.Error("Long distance out of index error should not have caused a panic") } }() v.Set(1000) } func TestOutOfBoundsClose(t *testing.T) { v := New(65) defer func() { if r := recover(); r != nil { t.Error("Local out of index error should not have caused a panic") } }() v.Set(66) } func TestCount(t *testing.T) { tot := uint(64*4 + 11) // just some multi unit64 number v := New(tot) checkLast := true for i := uint(0); i < tot; i++ { sz := uint(v.Count()) if sz != i { t.Errorf("Count reported as %d, but it should be %d", sz, i) checkLast = false break } v.Set(i) } if checkLast { sz := uint(v.Count()) if sz != tot { t.Errorf("After all bits set, size reported as %d, but it should be %d", sz, tot) } } } // test setting every 3rd bit, just in case something odd is happening func TestCount2(t *testing.T) { tot := uint(64*4 + 11) // just some multi unit64 number v := New(tot) for i := uint(0); i < tot; i += 3 { sz := uint(v.Count()) if sz != i/3 { t.Errorf("Count reported as %d, but it should be %d", sz, i) break } v.Set(i) } } // nil tests func TestNullTest(t *testing.T) { var v *BitSet defer func() { if r := recover(); r == nil { t.Error("Checking bit of null reference should have caused a panic") } }() v.Test(66) } func TestNullSet(t *testing.T) { var v *BitSet defer func() { if r := recover(); r == nil { t.Error("Setting bit of null reference should have caused a panic") } }() v.Set(66) } func TestNullClear(t *testing.T) { var v *BitSet defer func() { if r := recover(); r == nil { t.Error("Clearning bit of null reference should have caused a panic") } }() v.Clear(66) } func TestNullCount(t *testing.T) { var v *BitSet defer func() { if r := recover(); r != nil { t.Error("Counting null reference should not have caused a panic") } }() cnt := v.Count() if cnt != 0 { t.Errorf("Count reported as %d, but it should be 0", cnt) } } func TestPanicDifferenceBNil(t *testing.T) { var b *BitSet var compare = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil First should should have caused a panic") } }() b.Difference(compare) } func TestPanicDifferenceCompareNil(t *testing.T) { var compare *BitSet var b = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil Second should should have caused a panic") } }() b.Difference(compare) } func TestPanicUnionBNil(t *testing.T) { var b *BitSet var compare = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil First should should have caused a panic") } }() b.Union(compare) } func TestPanicUnionCompareNil(t *testing.T) { var compare *BitSet var b = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil Second should should have caused a panic") } }() b.Union(compare) } func TestPanicIntersectionBNil(t *testing.T) { var b *BitSet var compare = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil First should should have caused a panic") } }() b.Intersection(compare) } func TestPanicIntersectionCompareNil(t *testing.T) { var compare *BitSet var b = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil Second should should have caused a panic") } }() b.Intersection(compare) } func TestPanicSymmetricDifferenceBNil(t *testing.T) { var b *BitSet var compare = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil First should should have caused a panic") } }() b.SymmetricDifference(compare) } func TestPanicSymmetricDifferenceCompareNil(t *testing.T) { var compare *BitSet var b = New(10) defer func() { if r := recover(); r == nil { t.Error("Nil Second should should have caused a panic") } }() b.SymmetricDifference(compare) } func TestPanicComplementBNil(t *testing.T) { var b *BitSet defer func() { if r := recover(); r == nil { t.Error("Nil should should have caused a panic") } }() b.Complement() } func TestPanicAnytBNil(t *testing.T) { var b *BitSet defer func() { if r := recover(); r == nil { t.Error("Nil should should have caused a panic") } }() b.Any() } func TestPanicNonetBNil(t *testing.T) { var b *BitSet defer func() { if r := recover(); r == nil { t.Error("Nil should should have caused a panic") } }() b.None() } func TestPanicAlltBNil(t *testing.T) { var b *BitSet defer func() { if r := recover(); r == nil { t.Error("Nil should should have caused a panic") } }() b.All() } func TestAll(t *testing.T) { v := New(0) if !v.All() { t.Error("Empty sets should return true on All()") } v = New(2) v.SetTo(0, true) v.SetTo(1, true) if !v.All() { t.Error("Non-empty sets with all bits set should return true on All()") } v = New(2) if v.All() { t.Error("Non-empty sets with no bits set should return false on All()") } v = New(2) v.SetTo(0, true) if v.All() { t.Error("Non-empty sets with some bits set should return false on All()") } } func TestShrink(t *testing.T) { bs := New(10) bs.Set(0) bs.Shrink(63) if !bs.Test(0) { t.Error("0 should be set") return } b := New(0) b.Set(0) b.Set(1) b.Set(2) b.Set(3) b.Set(64) b.Compact() if !b.Test(0) { t.Error("0 should be set") return } if !b.Test(1) { t.Error("1 should be set") return } if !b.Test(2) { t.Error("2 should be set") return } if !b.Test(3) { t.Error("3 should be set") return } if !b.Test(64) { t.Error("64 should be set") return } b.Shrink(2) if !b.Test(0) { t.Error("0 should be set") return } if !b.Test(1) { t.Error("1 should be set") return } if !b.Test(2) { t.Error("2 should be set") return } if b.Test(3) { t.Error("3 should not be set") return } if b.Test(64) { t.Error("64 should not be set") return } b.Set(24) b.Shrink(100) if !b.Test(24) { t.Error("24 should be set") return } b.Set(127) b.Set(128) b.Set(129) b.Compact() if !b.Test(127) { t.Error("127 should be set") return } if !b.Test(128) { t.Error("128 should be set") return } if !b.Test(129) { t.Error("129 be set") return } b.Shrink(128) if !b.Test(127) { t.Error("127 should be set") return } if !b.Test(128) { t.Error("128 should be set") return } if b.Test(129) { t.Error("129 should not be set") return } b.Set(129) b.Shrink(129) if !b.Test(129) { t.Error("129 should be set") return } b.Set(1000) b.Set(2000) b.Set(3000) b.Shrink(3000) if len(b.set) != 3000/64+1 { t.Error("Wrong length of BitSet.set") return } if !b.Test(3000) { t.Error("3000 should be set") return } b.Shrink(2000) if len(b.set) != 2000/64+1 { t.Error("Wrong length of BitSet.set") return } if b.Test(3000) { t.Error("3000 should not be set") return } if !b.Test(2000) { t.Error("2000 should be set") return } if !b.Test(1000) { t.Error("1000 should be set") return } if !b.Test(24) { t.Error("24 should be set") return } b = New(110) b.Set(80) b.Shrink(70) for _, word := range b.set { if word != 0 { t.Error("word should be 0", word) } } } func TestInsertAtWithSet(t *testing.T) { b := New(0) b.Set(0) b.Set(1) b.Set(63) b.Set(64) b.Set(65) b.InsertAt(3) if !b.Test(0) { t.Error("0 should be set") return } if !b.Test(1) { t.Error("1 should be set") return } if b.Test(3) { t.Error("3 should not be set") return } if !b.Test(64) { t.Error("64 should be set") return } if !b.Test(65) { t.Error("65 should be set") return } if !b.Test(66) { t.Error("66 should be set") return } } func TestInsertAt(t *testing.T) { type testCase struct { input []string insertIdx uint expected []string } testCases := []testCase{ { input: []string{ "1111111111111111111111111111111111111111111111111111111111111111", }, insertIdx: uint(62), expected: []string{ "1011111111111111111111111111111111111111111111111111111111111111", "0000000000000000000000000000000000000000000000000000000000000001", }, }, { input: []string{ "1111111111111111111111111111111111111111111111111111111111111111", }, insertIdx: uint(63), expected: []string{ "0111111111111111111111111111111111111111111111111111111111111111", "0000000000000000000000000000000000000000000000000000000000000001", }, }, { input: []string{ "1111111111111111111111111111111111111111111111111111111111111111", }, insertIdx: uint(0), expected: []string{ "1111111111111111111111111111111111111111111111111111111111111110", "0000000000000000000000000000000000000000000000000000000000000001", }, }, { input: []string{ "1111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111111111111", }, insertIdx: uint(70), expected: []string{ "1111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111110111111", "1111111111111111111111111111111111111111111111111111111111111111", "0000000000000000000000000000000000000000000000000000000000000001", }, }, { input: []string{ "1111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111111110000", }, insertIdx: uint(70), expected: []string{ "1111111111111111111111111111111111111111111111111111111111111111", "1111111111111111111111111111111111111111111111111111111110111111", "1111111111111111111111111111111111111111111111111111111111100001", "0000000000000000000000000000000000000000000000000000000000000001", }, }, { input: []string{ "1111111111111111111111111111111111111111111111111111111111110000", }, insertIdx: uint(10), expected: []string{ "1111111111111111111111111111111111111111111111111111101111110000", "0000000000000000000000000000000000000000000000000000000000000001", }, }, } for _, tc := range testCases { var input []uint64 for _, inputElement := range tc.input { parsed, _ := strconv.ParseUint(inputElement, 2, 64) input = append(input, parsed) } var expected []uint64 for _, expectedElement := range tc.expected { parsed, _ := strconv.ParseUint(expectedElement, 2, 64) expected = append(expected, parsed) } b := From(input) b.InsertAt(tc.insertIdx) if len(b.set) != len(expected) { t.Error("Length of sets should be equal") return } for i := range b.set { if b.set[i] != expected[i] { t.Error("Unexpected results found in set") return } } } } func TestNone(t *testing.T) { v := New(0) if !v.None() { t.Error("Empty sets should return true on None()") } v = New(2) v.SetTo(0, true) v.SetTo(1, true) if v.None() { t.Error("Non-empty sets with all bits set should return false on None()") } v = New(2) if !v.None() { t.Error("Non-empty sets with no bits set should return true on None()") } v = New(2) v.SetTo(0, true) if v.None() { t.Error("Non-empty sets with some bits set should return false on None()") } v = new(BitSet) if !v.None() { t.Error("Empty sets should return true on None()") } } func TestEqual(t *testing.T) { a := New(100) b := New(99) c := New(100) if a.Equal(b) { t.Error("Sets of different sizes should be not be equal") } if !a.Equal(c) { t.Error("Two empty sets of the same size should be equal") } a.Set(99) c.Set(0) if a.Equal(c) { t.Error("Two sets with differences should not be equal") } c.Set(99) a.Set(0) if !a.Equal(c) { t.Error("Two sets with the same bits set should be equal") } if a.Equal(nil) { t.Error("The sets should be different") } a = New(0) b = New(0) if !a.Equal(b) { t.Error("Two empty set should be equal") } var x *BitSet var y *BitSet z := New(0) if !x.Equal(y) { t.Error("Two nil bitsets should be equal") } if x.Equal(z) { t.Error("Nil receiver bitset should not be equal to non-nil bitset") } } func TestUnion(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) b.Set(i - 1) } for i := uint(100); i < 200; i++ { b.Set(i) } if a.UnionCardinality(b) != 200 { t.Errorf("Union should have 200 bits set, but had %d", a.UnionCardinality(b)) } if a.UnionCardinality(b) != b.UnionCardinality(a) { t.Errorf("Union should be symmetric") } c := a.Union(b) d := b.Union(a) if c.Count() != 200 { t.Errorf("Union should have 200 bits set, but had %d", c.Count()) } if !c.Equal(d) { t.Errorf("Union should be symmetric") } } func TestInPlaceUnion(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) b.Set(i - 1) } for i := uint(100); i < 200; i++ { b.Set(i) } c := a.Clone() c.InPlaceUnion(b) d := b.Clone() d.InPlaceUnion(a) if c.Count() != 200 { t.Errorf("Union should have 200 bits set, but had %d", c.Count()) } if d.Count() != 200 { t.Errorf("Union should have 200 bits set, but had %d", d.Count()) } if !c.Equal(d) { t.Errorf("Union should be symmetric") } } func TestIntersection(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) b.Set(i - 1).Set(i) } for i := uint(100); i < 200; i++ { b.Set(i) } if a.IntersectionCardinality(b) != 50 { t.Errorf("Intersection should have 50 bits set, but had %d", a.IntersectionCardinality(b)) } if a.IntersectionCardinality(b) != b.IntersectionCardinality(a) { t.Errorf("Intersection should be symmetric") } c := a.Intersection(b) d := b.Intersection(a) if c.Count() != 50 { t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) } if !c.Equal(d) { t.Errorf("Intersection should be symmetric") } } func TestInplaceIntersection(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) b.Set(i - 1).Set(i) } for i := uint(100); i < 200; i++ { b.Set(i) } c := a.Clone() c.InPlaceIntersection(b) d := b.Clone() d.InPlaceIntersection(a) if c.Count() != 50 { t.Errorf("Intersection should have 50 bits set, but had %d", c.Count()) } if d.Count() != 50 { t.Errorf("Intersection should have 50 bits set, but had %d", d.Count()) } if !c.Equal(d) { t.Errorf("Intersection should be symmetric") } } func TestDifference(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) b.Set(i - 1) } for i := uint(100); i < 200; i++ { b.Set(i) } if a.DifferenceCardinality(b) != 50 { t.Errorf("a-b Difference should have 50 bits set, but had %d", a.DifferenceCardinality(b)) } if b.DifferenceCardinality(a) != 150 { t.Errorf("b-a Difference should have 150 bits set, but had %d", b.DifferenceCardinality(a)) } c := a.Difference(b) d := b.Difference(a) if c.Count() != 50 { t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) } if d.Count() != 150 { t.Errorf("b-a Difference should have 150 bits set, but had %d", d.Count()) } if c.Equal(d) { t.Errorf("Difference, here, should not be symmetric") } } func TestInPlaceDifference(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) b.Set(i - 1) } for i := uint(100); i < 200; i++ { b.Set(i) } c := a.Clone() c.InPlaceDifference(b) d := b.Clone() d.InPlaceDifference(a) if c.Count() != 50 { t.Errorf("a-b Difference should have 50 bits set, but had %d", c.Count()) } if d.Count() != 150 { t.Errorf("b-a Difference should have 150 bits set, but had %d", d.Count()) } if c.Equal(d) { t.Errorf("Difference, here, should not be symmetric") } } func TestSymmetricDifference(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) // 01010101010 ... 0000000 b.Set(i - 1).Set(i) // 11111111111111111000000 } for i := uint(100); i < 200; i++ { b.Set(i) } if a.SymmetricDifferenceCardinality(b) != 150 { t.Errorf("a^b Difference should have 150 bits set, but had %d", a.SymmetricDifferenceCardinality(b)) } if b.SymmetricDifferenceCardinality(a) != 150 { t.Errorf("b^a Difference should have 150 bits set, but had %d", b.SymmetricDifferenceCardinality(a)) } c := a.SymmetricDifference(b) d := b.SymmetricDifference(a) if c.Count() != 150 { t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) } if d.Count() != 150 { t.Errorf("b^a Difference should have 150 bits set, but had %d", d.Count()) } if !c.Equal(d) { t.Errorf("SymmetricDifference should be symmetric") } } func TestInPlaceSymmetricDifference(t *testing.T) { a := New(100) b := New(200) for i := uint(1); i < 100; i += 2 { a.Set(i) // 01010101010 ... 0000000 b.Set(i - 1).Set(i) // 11111111111111111000000 } for i := uint(100); i < 200; i++ { b.Set(i) } c := a.Clone() c.InPlaceSymmetricDifference(b) d := b.Clone() d.InPlaceSymmetricDifference(a) if c.Count() != 150 { t.Errorf("a^b Difference should have 150 bits set, but had %d", c.Count()) } if d.Count() != 150 { t.Errorf("b^a Difference should have 150 bits set, but had %d", d.Count()) } if !c.Equal(d) { t.Errorf("SymmetricDifference should be symmetric") } } func TestComplement(t *testing.T) { a := New(50) b := a.Complement() if b.Count() != 50 { t.Errorf("Complement failed, size should be 50, but was %d", b.Count()) } a = New(50) a.Set(10).Set(20).Set(42) b = a.Complement() if b.Count() != 47 { t.Errorf("Complement failed, size should be 47, but was %d", b.Count()) } } func TestIsSuperSet(t *testing.T) { test := func(name string, lenS, lenSS int, overrideS, overrideSS map[int]bool, want, wantStrict bool) { t.Run(name, func(t *testing.T) { s := New(uint(lenS)) ss := New(uint(lenSS)) l := lenS if lenSS < lenS { l = lenSS } r := rand.New(rand.NewSource(42)) for i := 0; i < l; i++ { bit := r.Intn(2) == 1 s.SetTo(uint(i), bit) ss.SetTo(uint(i), bit) } for i, v := range overrideS { s.SetTo(uint(i), v) } for i, v := range overrideSS { ss.SetTo(uint(i), v) } if got := ss.IsSuperSet(s); got != want { t.Errorf("IsSuperSet() = %v, want %v", got, want) } if got := ss.IsStrictSuperSet(s); got != wantStrict { t.Errorf("IsStrictSuperSet() = %v, want %v", got, wantStrict) } }) } test("empty", 0, 0, nil, nil, true, false) test("empty vs non-empty", 0, 100, nil, nil, true, false) test("non-empty vs empty", 100, 0, nil, nil, true, false) test("equal", 100, 100, nil, nil, true, false) test("set is shorter, subset", 100, 200, map[int]bool{50: true}, map[int]bool{50: false}, false, false) test("set is shorter, equal", 100, 200, nil, nil, true, false) test("set is shorter, superset", 100, 200, map[int]bool{50: false}, map[int]bool{50: true}, true, true) test("set is shorter, neither", 100, 200, map[int]bool{50: true}, map[int]bool{50: false, 150: true}, false, false) test("set is longer, subset", 200, 100, map[int]bool{50: true}, map[int]bool{50: false}, false, false) test("set is longer, equal", 200, 100, nil, nil, true, false) test("set is longer, superset", 200, 100, nil, map[int]bool{150: true}, true, true) test("set is longer, neither", 200, 100, map[int]bool{50: false, 150: true}, map[int]bool{50: true}, false, false) } func TestDumpAsBits(t *testing.T) { a := New(10).Set(10) astr := "0000000000000000000000000000000000000000000000000000010000000000." if a.DumpAsBits() != astr { t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", astr, a.DumpAsBits()) } var b BitSet // zero value (b.set == nil) bstr := "." if b.DumpAsBits() != bstr { t.Errorf("DumpAsBits failed, output should be \"%s\" but was \"%s\"", bstr, b.DumpAsBits()) } } func TestMarshalUnmarshalBinary(t *testing.T) { a := New(1010).Set(10).Set(1001) b := new(BitSet) copyBinary(t, a, b) // BitSets must be equal after marshalling and unmarshalling if !a.Equal(b) { t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) return } aSetBit := uint(128) a = New(256).Set(aSetBit) aExpectedMarshaledSize := 8 /* length: uint64 */ + 4*8 /* set : [4]uint64 */ aMarshaled, err := a.MarshalBinary() if err != nil || aExpectedMarshaledSize != len(aMarshaled) || aExpectedMarshaledSize != a.BinaryStorageSize() { t.Error("MarshalBinary failed to produce expected (", aExpectedMarshaledSize, ") number of bytes") return } shiftAmount := uint(72) // https://github.com/bits-and-blooms/bitset/issues/114 for i := uint(0); i < shiftAmount; i++ { a.DeleteAt(0) } aExpectedMarshaledSize = 8 /* length: uint64 */ + 3*8 /* set : [3]uint64 */ aMarshaled, err = a.MarshalBinary() if err != nil || aExpectedMarshaledSize != len(aMarshaled) || aExpectedMarshaledSize != a.BinaryStorageSize() { t.Error("MarshalBinary failed to produce expected (", aExpectedMarshaledSize, ") number of bytes") return } copyBinary(t, a, b) if b.Len() != 256-shiftAmount || !b.Test(aSetBit-shiftAmount) { t.Error("Shifted bitset is not copied correctly") } } func TestMarshalUnmarshalBinaryByLittleEndian(t *testing.T) { LittleEndian() defer func() { // Revert when done. binaryOrder = binary.BigEndian }() a := New(1010).Set(10).Set(1001) b := new(BitSet) copyBinary(t, a, b) // BitSets must be equal after marshalling and unmarshalling if !a.Equal(b) { t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) return } } func copyBinary(t *testing.T, from encoding.BinaryMarshaler, to encoding.BinaryUnmarshaler) { data, err := from.MarshalBinary() if err != nil { t.Errorf(err.Error()) return } err = to.UnmarshalBinary(data) if err != nil { t.Errorf(err.Error()) return } } func TestMarshalUnmarshalJSON(t *testing.T) { t.Run("value", func(t *testing.T) { a := BitSet{} a.Set(10).Set(1001) data, err := json.Marshal(a) if err != nil { t.Errorf(err.Error()) return } b := new(BitSet) err = json.Unmarshal(data, b) if err != nil { t.Errorf(err.Error()) return } // Bitsets must be equal after marshalling and unmarshalling if !a.Equal(b) { t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) return } }) t.Run("pointer", func(t *testing.T) { a := New(1010).Set(10).Set(1001) data, err := json.Marshal(a) if err != nil { t.Errorf(err.Error()) return } b := new(BitSet) err = json.Unmarshal(data, b) if err != nil { t.Errorf(err.Error()) return } // Bitsets must be equal after marshalling and unmarshalling if !a.Equal(b) { t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) return } }) } func TestMarshalUnmarshalJSONWithTrailingData(t *testing.T) { a := New(1010).Set(10).Set(1001) data, err := json.Marshal(a) if err != nil { t.Errorf(err.Error()) return } // appending some noise data = data[:len(data)-3] // remove " data = append(data, []byte(`AAAAAAAAAA"`)...) b := new(BitSet) err = json.Unmarshal(data, b) if err != nil { t.Errorf(err.Error()) return } // Bitsets must be equal after marshalling and unmarshalling // Do not over-reading when unmarshalling if !a.Equal(b) { t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) return } } func TestMarshalUnmarshalJSONByStdEncoding(t *testing.T) { Base64StdEncoding() a := New(1010).Set(10).Set(1001) data, err := json.Marshal(a) if err != nil { t.Errorf(err.Error()) return } b := new(BitSet) err = json.Unmarshal(data, b) if err != nil { t.Errorf(err.Error()) return } // Bitsets must be equal after marshalling and unmarshalling if !a.Equal(b) { t.Error("Bitsets are not equal:\n\t", a.DumpAsBits(), "\n\t", b.DumpAsBits()) return } } func TestSafeSet(t *testing.T) { b := new(BitSet) c := b.safeSet() outType := fmt.Sprintf("%T", c) expType := "[]uint64" if outType != expType { t.Error("Expecting type: ", expType, ", gotf:", outType) return } if len(c) != 0 { t.Error("The slice should be empty") return } } func TestSetBitsetFrom(t *testing.T) { u := []uint64{2, 3, 5, 7, 11} b := new(BitSet) b.SetBitsetFrom(u) outType := fmt.Sprintf("%T", b) expType := "*bitset.BitSet" if outType != expType { t.Error("Expecting type: ", expType, ", gotf:", outType) return } } func TestIssue116(t *testing.T) { a := []uint64{2, 3, 5, 7, 11} b := []uint64{2, 3, 5, 7, 11, 0, 1} bitset1 := FromWithLength(320, a) bitset2 := FromWithLength(320, b) if !bitset1.Equal(bitset2) || !bitset2.Equal(bitset1) { t.Error("Bitsets should be equal irrespective of the underlying capacity") } } func TestFrom(t *testing.T) { u := []uint64{2, 3, 5, 7, 11} b := From(u) outType := fmt.Sprintf("%T", b) expType := "*bitset.BitSet" if outType != expType { t.Error("Expecting type: ", expType, ", gotf:", outType) return } } func TestBytes(t *testing.T) { b := new(BitSet) c := b.Bytes() outType := fmt.Sprintf("%T", c) expType := "[]uint64" if outType != expType { t.Error("Expecting type: ", expType, ", gotf:", outType) return } if len(c) != 0 { t.Error("The slice should be empty") return } } func TestCap(t *testing.T) { c := Cap() if c <= 0 { t.Error("The uint capacity should be >= 0") return } } func TestWordsNeededLong(t *testing.T) { i := Cap() out := wordsNeeded(i) if out <= 0 { t.Error("Unexpected value: ", out) return } } func TestTestTooLong(t *testing.T) { b := new(BitSet) if b.Test(1) { t.Error("Unexpected value: true") return } } func TestClearTooLong(t *testing.T) { b := new(BitSet) c := b.Clear(1) if b != c { t.Error("Unexpected value") return } } func TestClearAll(t *testing.T) { u := []uint64{2, 3, 5, 7, 11} b := From(u) c := b.ClearAll() if c.length != 320 { t.Error("Unexpected length: ", b.length) return } if c.Test(0) || c.Test(1) || c.Test(2) || c.Test(3) || c.Test(4) || c.Test(5) { t.Error("All bits should be unset") return } } func TestRankSelect(t *testing.T) { u := []uint{2, 3, 5, 7, 11, 700, 1500} b := BitSet{} for _, v := range u { b.Set(v) } if b.Rank(5) != 3 { t.Error("Unexpected rank") return } if b.Rank(6) != 3 { t.Error("Unexpected rank") return } if b.Rank(1500) != 7 { t.Error("Unexpected rank") return } if b.Select(0) != 2 { t.Error("Unexpected select") return } if b.Select(1) != 3 { t.Error("Unexpected select") return } if b.Select(2) != 5 { t.Error("Unexpected select") return } if b.Select(5) != 700 { t.Error("Unexpected select") return } } func TestFlip(t *testing.T) { b := new(BitSet) c := b.Flip(11) if c.length != 12 { t.Error("Unexpected value: ", c.length) return } d := c.Flip(7) if d.length != 12 { t.Error("Unexpected value: ", d.length) return } } func TestFlipRange(t *testing.T) { b := new(BitSet) b.Set(1).Set(3).Set(5).Set(7).Set(9).Set(11).Set(13).Set(15) c := b.FlipRange(4, 25) if c.length != 25 { t.Error("Unexpected value: ", c.length) return } d := c.FlipRange(8, 24) if d.length != 25 { t.Error("Unexpected value: ", d.length) return } // for i := uint(0); i < 256; i++ { for j := uint(0); j <= i; j++ { bits := New(i) bits.FlipRange(0, j) c := bits.Count() if c != j { t.Error("Unexpected value: ", c, " expected: ", j) return } } } } func TestCopy(t *testing.T) { a := New(10) if a.Copy(nil) != 0 { t.Error("No values should be copied") return } a = New(10) b := New(20) if a.Copy(b) != 10 { t.Error("Unexpected value") return } } func TestCopyUnaligned(t *testing.T) { a := New(16) a.FlipRange(0, 16) b := New(1) a.Copy(b) if b.Count() > b.Len() { t.Errorf("targets copied set count (%d) should never be larger than target's length (%d)", b.Count(), b.Len()) } if !b.Test(0) { t.Errorf("first bit should still be set in copy: %+v", b) } // Test a more complex scenario with a mix of bits set in the unaligned space to verify no bits are lost. a = New(32) a.Set(0).Set(3).Set(4).Set(16).Set(17).Set(29).Set(31) b = New(19) a.Copy(b) const expectedCount = 5 if b.Count() != expectedCount { t.Errorf("targets copied set count: %d, want %d", b.Count(), expectedCount) } if !(b.Test(0) && b.Test(3) && b.Test(4) && b.Test(16) && b.Test(17)) { t.Errorf("expected set bits are not set: %+v", b) } } func TestCopyFull(t *testing.T) { a := New(10) b := &BitSet{} a.CopyFull(b) if b.length != a.length || len(b.set) != len(a.set) { t.Error("Expected full length copy") return } for i, v := range a.set { if v != b.set[i] { t.Error("Unexpected value") return } } } func TestNextSetError(t *testing.T) { b := new(BitSet) c, d := b.NextSet(1) if c != 0 || d { t.Error("Unexpected values") return } } func TestDeleteWithBitStrings(t *testing.T) { type testCase struct { input []string deleteIdx uint expected []string } testCases := []testCase{ { input: []string{ "1110000000000000000000000000000000000000000000000000000000000001", }, deleteIdx: uint(63), expected: []string{ "0110000000000000000000000000000000000000000000000000000000000001", }, }, { input: []string{ "1000000000000000000000000000000000000000000000000000000000010101", }, deleteIdx: uint(0), expected: []string{ "0100000000000000000000000000000000000000000000000000000000001010", }, }, { input: []string{ "0000000000000000000000000000000000000000000000000000000000111000", }, deleteIdx: uint(4), expected: []string{ "0000000000000000000000000000000000000000000000000000000000011000", }, }, { input: []string{ "1000000000000000000000000000000000000000000000000000000000000001", "1010000000000000000000000000000000000000000000000000000000000001", }, deleteIdx: uint(63), expected: []string{ "1000000000000000000000000000000000000000000000000000000000000001", "0101000000000000000000000000000000000000000000000000000000000000", }, }, { input: []string{ "1000000000000000000000000000000000000000000000000000000000000000", "1000000000000000000000000000000000000000000000000000000000000001", "1000000000000000000000000000000000000000000000000000000000000001", }, deleteIdx: uint(64), expected: []string{ "1000000000000000000000000000000000000000000000000000000000000000", "1100000000000000000000000000000000000000000000000000000000000000", "0100000000000000000000000000000000000000000000000000000000000000", }, }, { input: []string{ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", }, deleteIdx: uint(256), expected: []string{ "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000", }, }, } for _, tc := range testCases { var input []uint64 for _, inputElement := range tc.input { parsed, _ := strconv.ParseUint(inputElement, 2, 64) input = append(input, parsed) } var expected []uint64 for _, expectedElement := range tc.expected { parsed, _ := strconv.ParseUint(expectedElement, 2, 64) expected = append(expected, parsed) } b := From(input) b.DeleteAt(tc.deleteIdx) if len(b.set) != len(expected) { t.Errorf("Length of sets expected to be %d, but was %d", len(expected), len(b.set)) return } for i := range b.set { if b.set[i] != expected[i] { t.Errorf("Unexpected output\nExpected: %b\nGot: %b", expected[i], b.set[i]) return } } } } func TestDeleteWithBitSetInstance(t *testing.T) { length := uint(256) bitSet := New(length) // the indexes that get set in the bit set indexesToSet := []uint{0, 1, 126, 127, 128, 129, 170, 171, 200, 201, 202, 203, 255} // the position we delete from the bitset deleteAt := uint(127) // the indexes that we expect to be set after the delete expectedToBeSet := []uint{0, 1, 126, 127, 128, 169, 170, 199, 200, 201, 202, 254} expected := make(map[uint]struct{}) for _, index := range expectedToBeSet { expected[index] = struct{}{} } for _, index := range indexesToSet { bitSet.Set(index) } bitSet.DeleteAt(deleteAt) for i := uint(0); i < length; i++ { if _, ok := expected[i]; ok { if !bitSet.Test(i) { t.Errorf("Expected index %d to be set, but wasn't", i) } } else { if bitSet.Test(i) { t.Errorf("Expected index %d to not be set, but was", i) } } } } func TestWriteTo(t *testing.T) { const length = 9585 const oneEvery = 97 addBuf := []byte(`12345678`) bs := New(length) // Add some bits for i := uint(0); i < length; i += oneEvery { bs = bs.Set(i) } var buf bytes.Buffer n, err := bs.WriteTo(&buf) if err != nil { t.Fatal(err) } wantSz := buf.Len() // Size of the serialized data in bytes. if n != int64(wantSz) { t.Errorf("want write size to be %d, got %d", wantSz, n) } buf.Write(addBuf) // Add additional data on stream. // Generate test input for regression tests: if false { gzout := bytes.NewBuffer(nil) gz, err := gzip.NewWriterLevel(gzout, 9) if err != nil { t.Fatal(err) } gz.Write(buf.Bytes()) gz.Close() t.Log("Encoded:", base64.StdEncoding.EncodeToString(gzout.Bytes())) } // Read back. bs = New(length) n, err = bs.ReadFrom(&buf) if err != nil { t.Fatal(err) } if n != int64(wantSz) { t.Errorf("want read size to be %d, got %d", wantSz, n) } // Check bits for i := uint(0); i < length; i += oneEvery { if !bs.Test(i) { t.Errorf("bit %d was not set", i) } } more, err := io.ReadAll(&buf) if err != nil { t.Fatal(err) } if !bytes.Equal(more, addBuf) { t.Fatalf("extra mismatch. got %v, want %v", more, addBuf) } } type inCompleteRetBufReader struct { returnEvery int64 reader io.Reader offset int64 } func (ir *inCompleteRetBufReader) Read(b []byte) (n int, err error) { if ir.returnEvery > 0 { maxRead := ir.returnEvery - (ir.offset % ir.returnEvery) if len(b) > int(maxRead) { b = b[:maxRead] } } n, err = ir.reader.Read(b) ir.offset += int64(n) return } func TestReadFrom(t *testing.T) { addBuf := []byte(`12345678`) // Bytes after stream tests := []struct { length uint oneEvery uint input string // base64+gzipped wantErr error returnEvery int64 }{ { length: 9585, oneEvery: 97, input: "H4sIAAAAAAAC/2IAA9VCCM3AyMDAwMSACVgYGBg4sIgLMDAwKGARd2BgYGjAFB41noDx6IAJajw64IAajw4UoMajg4ZR4/EaP5pQh1g+MDQyNjE1M7cABAAA//9W5OoOwAQAAA==", returnEvery: 127, }, { length: 1337, oneEvery: 42, input: "H4sIAAAAAAAC/2IAA1ZLBgYWEIPRAUQKgJkMcCZYisEBzkSSYkSTYqCxAYZGxiamZuYWgAAAAP//D0wyWbgAAAA=", }, { length: 1337, // Truncated input. oneEvery: 42, input: "H4sIAAAAAAAC/2IAA9VCCM3AyMDAwARmAQIAAP//vR3xdRkAAAA=", wantErr: io.ErrUnexpectedEOF, }, { length: 1337, // Empty input. oneEvery: 42, input: "H4sIAAAAAAAC/wEAAP//AAAAAAAAAAA=", wantErr: io.ErrUnexpectedEOF, }, } for i, test := range tests { t.Run(fmt.Sprint(i), func(t *testing.T) { fatalErr := func(err error) { t.Helper() if err != nil { t.Fatal(err) } } var buf bytes.Buffer b, err := base64.StdEncoding.DecodeString(test.input) fatalErr(err) gz, err := gzip.NewReader(bytes.NewBuffer(b)) fatalErr(err) _, err = io.Copy(&buf, gz) fatalErr(err) fatalErr(gz.Close()) bs := New(test.length) _, err = bs.ReadFrom(&inCompleteRetBufReader{returnEvery: test.returnEvery, reader: &buf}) if err != nil { if errors.Is(err, test.wantErr) { // Correct, nothing more we can test. return } t.Fatalf("did not get expected error %v, got %v", test.wantErr, err) } else { if test.wantErr != nil { t.Fatalf("did not get expected error %v", test.wantErr) } } fatalErr(err) // Test if correct bits are set. for i := uint(0); i < test.length; i++ { want := i%test.oneEvery == 0 got := bs.Test(i) if want != got { t.Errorf("bit %d was %v, should be %v", i, got, want) } } more, err := io.ReadAll(&buf) fatalErr(err) if !bytes.Equal(more, addBuf) { t.Errorf("extra mismatch. got %v, want %v", more, addBuf) } }) } } func TestSetAll(t *testing.T) { test := func(name string, bs *BitSet, want uint) { t.Run(name, func(t *testing.T) { bs.SetAll() if bs.Count() != want { t.Errorf("expected %d bits to be set, got %d", want, bs.Count()) } }) } test("nil", nil, 0) for _, length := range []uint{0, 1, 10, 63, 64, 65, 100, 640} { test(fmt.Sprintf("length %d", length), New(length), length) } } bitset-1.13.0/go.mod000066400000000000000000000000621454232453300141770ustar00rootroot00000000000000module github.com/bits-and-blooms/bitset go 1.16 bitset-1.13.0/go.sum000066400000000000000000000000001454232453300142140ustar00rootroot00000000000000bitset-1.13.0/popcnt.go000066400000000000000000000017741454232453300147360ustar00rootroot00000000000000package bitset // bit population count, take from // https://code.google.com/p/go/issues/detail?id=4988#c11 // credit: https://code.google.com/u/arnehormann/ func popcount(x uint64) (n uint64) { x -= (x >> 1) & 0x5555555555555555 x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 x += x >> 4 x &= 0x0f0f0f0f0f0f0f0f x *= 0x0101010101010101 return x >> 56 } func popcntSliceGo(s []uint64) uint64 { cnt := uint64(0) for _, x := range s { cnt += popcount(x) } return cnt } func popcntMaskSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { cnt += popcount(s[i] &^ m[i]) } return cnt } func popcntAndSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { cnt += popcount(s[i] & m[i]) } return cnt } func popcntOrSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { cnt += popcount(s[i] | m[i]) } return cnt } func popcntXorSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { cnt += popcount(s[i] ^ m[i]) } return cnt } bitset-1.13.0/popcnt_19.go000066400000000000000000000023471454232453300152440ustar00rootroot00000000000000//go:build go1.9 // +build go1.9 package bitset import "math/bits" func popcntSlice(s []uint64) uint64 { var cnt int for _, x := range s { cnt += bits.OnesCount64(x) } return uint64(cnt) } func popcntMaskSlice(s, m []uint64) uint64 { var cnt int // this explicit check eliminates a bounds check in the loop if len(m) < len(s) { panic("mask slice is too short") } for i := range s { cnt += bits.OnesCount64(s[i] &^ m[i]) } return uint64(cnt) } func popcntAndSlice(s, m []uint64) uint64 { var cnt int // this explicit check eliminates a bounds check in the loop if len(m) < len(s) { panic("mask slice is too short") } for i := range s { cnt += bits.OnesCount64(s[i] & m[i]) } return uint64(cnt) } func popcntOrSlice(s, m []uint64) uint64 { var cnt int // this explicit check eliminates a bounds check in the loop if len(m) < len(s) { panic("mask slice is too short") } for i := range s { cnt += bits.OnesCount64(s[i] | m[i]) } return uint64(cnt) } func popcntXorSlice(s, m []uint64) uint64 { var cnt int // this explicit check eliminates a bounds check in the loop if len(m) < len(s) { panic("mask slice is too short") } for i := range s { cnt += bits.OnesCount64(s[i] ^ m[i]) } return uint64(cnt) } bitset-1.13.0/popcnt_amd64.go000066400000000000000000000022761454232453300157270ustar00rootroot00000000000000//go:build !go1.9 && amd64 && !appengine // +build !go1.9,amd64,!appengine package bitset // *** the following functions are defined in popcnt_amd64.s //go:noescape func hasAsm() bool // useAsm is a flag used to select the GO or ASM implementation of the popcnt function var useAsm = hasAsm() //go:noescape func popcntSliceAsm(s []uint64) uint64 //go:noescape func popcntMaskSliceAsm(s, m []uint64) uint64 //go:noescape func popcntAndSliceAsm(s, m []uint64) uint64 //go:noescape func popcntOrSliceAsm(s, m []uint64) uint64 //go:noescape func popcntXorSliceAsm(s, m []uint64) uint64 func popcntSlice(s []uint64) uint64 { if useAsm { return popcntSliceAsm(s) } return popcntSliceGo(s) } func popcntMaskSlice(s, m []uint64) uint64 { if useAsm { return popcntMaskSliceAsm(s, m) } return popcntMaskSliceGo(s, m) } func popcntAndSlice(s, m []uint64) uint64 { if useAsm { return popcntAndSliceAsm(s, m) } return popcntAndSliceGo(s, m) } func popcntOrSlice(s, m []uint64) uint64 { if useAsm { return popcntOrSliceAsm(s, m) } return popcntOrSliceGo(s, m) } func popcntXorSlice(s, m []uint64) uint64 { if useAsm { return popcntXorSliceAsm(s, m) } return popcntXorSliceGo(s, m) } bitset-1.13.0/popcnt_amd64.s000066400000000000000000000033241454232453300155570ustar00rootroot00000000000000// +build !go1.9 // +build amd64,!appengine TEXT ·hasAsm(SB),4,$0-1 MOVQ $1, AX CPUID SHRQ $23, CX ANDQ $1, CX MOVB CX, ret+0(FP) RET #define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 TEXT ·popcntSliceAsm(SB),4,$0-32 XORQ AX, AX MOVQ s+0(FP), SI MOVQ s_len+8(FP), CX TESTQ CX, CX JZ popcntSliceEnd popcntSliceLoop: BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX ADDQ DX, AX ADDQ $8, SI LOOP popcntSliceLoop popcntSliceEnd: MOVQ AX, ret+24(FP) RET TEXT ·popcntMaskSliceAsm(SB),4,$0-56 XORQ AX, AX MOVQ s+0(FP), SI MOVQ s_len+8(FP), CX TESTQ CX, CX JZ popcntMaskSliceEnd MOVQ m+24(FP), DI popcntMaskSliceLoop: MOVQ (DI), DX NOTQ DX ANDQ (SI), DX POPCNTQ_DX_DX ADDQ DX, AX ADDQ $8, SI ADDQ $8, DI LOOP popcntMaskSliceLoop popcntMaskSliceEnd: MOVQ AX, ret+48(FP) RET TEXT ·popcntAndSliceAsm(SB),4,$0-56 XORQ AX, AX MOVQ s+0(FP), SI MOVQ s_len+8(FP), CX TESTQ CX, CX JZ popcntAndSliceEnd MOVQ m+24(FP), DI popcntAndSliceLoop: MOVQ (DI), DX ANDQ (SI), DX POPCNTQ_DX_DX ADDQ DX, AX ADDQ $8, SI ADDQ $8, DI LOOP popcntAndSliceLoop popcntAndSliceEnd: MOVQ AX, ret+48(FP) RET TEXT ·popcntOrSliceAsm(SB),4,$0-56 XORQ AX, AX MOVQ s+0(FP), SI MOVQ s_len+8(FP), CX TESTQ CX, CX JZ popcntOrSliceEnd MOVQ m+24(FP), DI popcntOrSliceLoop: MOVQ (DI), DX ORQ (SI), DX POPCNTQ_DX_DX ADDQ DX, AX ADDQ $8, SI ADDQ $8, DI LOOP popcntOrSliceLoop popcntOrSliceEnd: MOVQ AX, ret+48(FP) RET TEXT ·popcntXorSliceAsm(SB),4,$0-56 XORQ AX, AX MOVQ s+0(FP), SI MOVQ s_len+8(FP), CX TESTQ CX, CX JZ popcntXorSliceEnd MOVQ m+24(FP), DI popcntXorSliceLoop: MOVQ (DI), DX XORQ (SI), DX POPCNTQ_DX_DX ADDQ DX, AX ADDQ $8, SI ADDQ $8, DI LOOP popcntXorSliceLoop popcntXorSliceEnd: MOVQ AX, ret+48(FP) RET bitset-1.13.0/popcnt_amd64_test.go000066400000000000000000000042531454232453300167630ustar00rootroot00000000000000//go:build !go1.9 && amd64 && !appengine // +build !go1.9,amd64,!appengine // This file tests the popcnt funtions package bitset import ( "testing" ) func TestPopcntSliceCond(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} oldUseAsm := useAsm defer func() { useAsm = oldUseAsm }() useAsm = false resGo := popcntSlice(s) useAsm = (true && oldUseAsm) resAsm := popcntSlice(s) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestPopcntMaskSliceCond(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} oldUseAsm := useAsm defer func() { useAsm = oldUseAsm }() useAsm = false resGo := popcntMaskSlice(s, m) useAsm = (true && oldUseAsm) resAsm := popcntMaskSlice(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestPopcntAndSliceCond(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} oldUseAsm := useAsm defer func() { useAsm = oldUseAsm }() useAsm = false resGo := popcntAndSlice(s, m) useAsm = (true && oldUseAsm) resAsm := popcntAndSlice(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestPopcntOrSliceCond(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} oldUseAsm := useAsm defer func() { useAsm = oldUseAsm }() useAsm = false resGo := popcntOrSlice(s, m) useAsm = (true && oldUseAsm) resAsm := popcntOrSlice(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestPopcntXorSliceCond(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} oldUseAsm := useAsm defer func() { useAsm = oldUseAsm }() useAsm = false resGo := popcntXorSlice(s, m) useAsm = (true && oldUseAsm) resAsm := popcntXorSlice(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } bitset-1.13.0/popcnt_cmp_test.go000066400000000000000000000033011454232453300166200ustar00rootroot00000000000000//go:build !go1.9 && amd64 && !appengine // +build !go1.9,amd64,!appengine // This file tests the popcnt funtions package bitset import ( "testing" ) func TestComparePopcntSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} resGo := popcntSliceGo(s) resAsm := popcntSliceAsm(s) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestComparePopcntMaskSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} resGo := popcntMaskSliceGo(s, m) resAsm := popcntMaskSliceAsm(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestComparePopcntAndSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} resGo := popcntAndSliceGo(s, m) resAsm := popcntAndSliceAsm(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestComparePopcntOrSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} resGo := popcntOrSliceGo(s, m) resAsm := popcntOrSliceAsm(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } func TestComparePopcntXorSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} resGo := popcntXorSliceGo(s, m) resAsm := popcntXorSliceAsm(s, m) if resGo != resAsm { t.Errorf("The implementations are different: GO %d != ASM %d", resGo, resAsm) } } bitset-1.13.0/popcnt_generic.go000066400000000000000000000007411454232453300164230ustar00rootroot00000000000000//go:build !go1.9 && (!amd64 || appengine) // +build !go1.9 // +build !amd64 appengine package bitset func popcntSlice(s []uint64) uint64 { return popcntSliceGo(s) } func popcntMaskSlice(s, m []uint64) uint64 { return popcntMaskSliceGo(s, m) } func popcntAndSlice(s, m []uint64) uint64 { return popcntAndSliceGo(s, m) } func popcntOrSlice(s, m []uint64) uint64 { return popcntOrSliceGo(s, m) } func popcntXorSlice(s, m []uint64) uint64 { return popcntXorSliceGo(s, m) } bitset-1.13.0/popcnt_go18_test.go000066400000000000000000000024631454232453300166270ustar00rootroot00000000000000// This file tests the popcnt funtions package bitset import ( "testing" ) func TestPopcntSliceGo(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} res := popcntSliceGo(s) const l uint64 = 27 if res != l { t.Errorf("Wrong popcount %d != %d", res, l) } } func TestPopcntMaskSliceGo(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntMaskSliceGo(s, m) const l uint64 = 9 if res != l { t.Errorf("Wrong mask %d != %d", res, l) } } func TestPopcntAndSliceGo(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntAndSliceGo(s, m) const l uint64 = 18 if res != l { t.Errorf("Wrong And %d != %d", res, l) } } func TestPopcntOrSliceGo(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntOrSliceGo(s, m) const l uint64 = 50 if res != l { t.Errorf("Wrong OR %d != %d", res, l) } } func TestPopcntXorSliceGo(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntXorSliceGo(s, m) const l uint64 = 32 if res != l { t.Errorf("Wrong OR %d != %d", res, l) } } bitset-1.13.0/popcnt_test.go000066400000000000000000000024371454232453300157720ustar00rootroot00000000000000// This file tests the popcnt funtions package bitset import ( "testing" ) func TestPopcntSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} res := popcntSlice(s) const l uint64 = 27 if res != l { t.Errorf("Wrong popcount %d != %d", res, l) } } func TestPopcntMaskSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntMaskSlice(s, m) const l uint64 = 9 if res != l { t.Errorf("Wrong mask %d != %d", res, l) } } func TestPopcntAndSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntAndSlice(s, m) const l uint64 = 18 if res != l { t.Errorf("Wrong And %d != %d", res, l) } } func TestPopcntOrSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntOrSlice(s, m) const l uint64 = 50 if res != l { t.Errorf("Wrong OR %d != %d", res, l) } } func TestPopcntXorSlice(t *testing.T) { s := []uint64{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} m := []uint64{31, 37, 41, 43, 47, 53, 59, 61, 67, 71} res := popcntXorSlice(s, m) const l uint64 = 32 if res != l { t.Errorf("Wrong OR %d != %d", res, l) } } bitset-1.13.0/select.go000066400000000000000000000011641454232453300147030ustar00rootroot00000000000000package bitset func select64(w uint64, j uint) uint { seen := 0 // Divide 64bit part := w & 0xFFFFFFFF n := uint(popcount(part)) if n <= j { part = w >> 32 seen += 32 j -= n } ww := part // Divide 32bit part = ww & 0xFFFF n = uint(popcount(part)) if n <= j { part = ww >> 16 seen += 16 j -= n } ww = part // Divide 16bit part = ww & 0xFF n = uint(popcount(part)) if n <= j { part = ww >> 8 seen += 8 j -= n } ww = part // Lookup in final byte counter := 0 for ; counter < 8; counter++ { j -= uint((ww >> counter) & 1) if j+1 == 0 { break } } return uint(seen + counter) } bitset-1.13.0/trailing_zeros_18.go000066400000000000000000000006541454232453300167720ustar00rootroot00000000000000//go:build !go1.9 // +build !go1.9 package bitset var deBruijn = [...]byte{ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, } func trailingZeroes64(v uint64) uint { return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58]) } bitset-1.13.0/trailing_zeros_19.go000066400000000000000000000002251454232453300167650ustar00rootroot00000000000000//go:build go1.9 // +build go1.9 package bitset import "math/bits" func trailingZeroes64(v uint64) uint { return uint(bits.TrailingZeros64(v)) }