fix xsrf and added nonce

This commit is contained in:
ston1th 2025-10-15 22:51:08 +02:00
commit 809627b538
208 changed files with 7166 additions and 4278 deletions

View file

@ -69,6 +69,13 @@ func main() {
}
```
If you have Go 1.23 or better, you can iterate over the set bits like so:
```go
for i := range b.EachSet() {}
```
Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc
@ -157,3 +164,13 @@ Before committing the code, please check if it passes tests, has adequate covera
go test
go test -cover
```
## Stars
[![Star History Chart](https://api.star-history.com/svg?repos=bits-and-blooms/bitset&type=Date)](https://www.star-history.com/#bits-and-blooms/bitset&Date)
## Further reading
<p>Mastering Programming: From Testing to Performance in Go</p>
<div><a href="https://www.amazon.com/dp/B0FMPGSWR5"><img style="margin-left: auto; margin-right: auto;" src="https://m.media-amazon.com/images/I/61feneHS7kL._SL1499_.jpg" alt="" width="250px" /></a></div>

View file

@ -905,7 +905,9 @@ func (b *BitSet) DifferenceCardinality(compare *BitSet) uint {
l = b.wordCount()
}
cnt := uint64(0)
cnt += popcntMaskSlice(b.set[:l], compare.set[:l])
if l > 0 {
cnt += popcntMaskSlice(b.set[:l], compare.set[:l])
}
cnt += popcntSlice(b.set[l:])
return uint(cnt)
}
@ -960,6 +962,9 @@ func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
func (b *BitSet) IntersectionCardinality(compare *BitSet) uint {
panicIfNull(b)
panicIfNull(compare)
if b.length == 0 || compare.length == 0 {
return 0
}
b, compare = sortByLength(b, compare)
cnt := popcntAndSlice(b.set, compare.set)
return uint(cnt)
@ -1016,7 +1021,10 @@ func (b *BitSet) UnionCardinality(compare *BitSet) uint {
panicIfNull(b)
panicIfNull(compare)
b, compare = sortByLength(b, compare)
cnt := popcntOrSlice(b.set, compare.set)
cnt := uint64(0)
if len(b.set) > 0 {
cnt += popcntOrSlice(b.set, compare.set)
}
if len(compare.set) > len(b.set) {
cnt += popcntSlice(compare.set[len(b.set):])
}
@ -1071,7 +1079,10 @@ func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint {
panicIfNull(b)
panicIfNull(compare)
b, compare = sortByLength(b, compare)
cnt := popcntXorSlice(b.set, compare.set)
cnt := uint64(0)
if len(b.set) > 0 {
cnt += popcntXorSlice(b.set, compare.set)
}
if len(compare.set) > len(b.set) {
cnt += popcntSlice(compare.set[len(b.set):])
}
@ -1385,16 +1396,36 @@ func (b *BitSet) UnmarshalJSON(data []byte) error {
// Rank returns the number 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()
func (b *BitSet) Rank(index uint) (rank uint) {
index++ // Rank is up to and including
// needed more than once
length := len(b.set)
// TODO: built-in min requires go1.21 or later
// idx := min(int(index>>6), len(b.set))
idx := int(index >> 6)
if idx > length {
idx = length
}
leftover := (index + 1) & 63
answer := uint(popcntSlice(b.set[:(index+1)>>6]))
if leftover != 0 {
answer += uint(bits.OnesCount64(b.set[(index+1)>>6] << (64 - leftover)))
// sum up the popcounts until idx ...
// TODO: cannot range over idx (...): requires go1.22 or later
// for j := range idx {
for j := 0; j < idx; j++ {
if w := b.set[j]; w != 0 {
rank += uint(bits.OnesCount64(w))
}
}
return answer
// ... plus partial word at idx,
// make Rank inlineable and faster in the end
// don't test index&63 != 0, just add, less branching
if idx < length {
rank += uint(bits.OnesCount64(b.set[idx] << (64 - index&63)))
}
return
}
// Select returns the index of the jth set bit, where j is the argument.
@ -1418,18 +1449,13 @@ func (b *BitSet) Select(index uint) uint {
// top detects the top bit set
func (b *BitSet) top() (uint, bool) {
panicIfNull(b)
idx := len(b.set) - 1
for ; idx >= 0 && b.set[idx] == 0; idx-- {
for idx := len(b.set) - 1; idx >= 0; idx-- {
if word := b.set[idx]; word != 0 {
return uint(idx<<log2WordSize+bits.Len64(word)) - 1, true
}
}
// no set bits
if idx < 0 {
return 0, false
}
return uint(idx*wordSize+bits.Len64(b.set[idx])) - 1, true
return 0, false
}
// ShiftLeft shifts the bitset like << operation would do.
@ -1458,7 +1484,7 @@ func (b *BitSet) ShiftLeft(bits uint) {
dst := b.set
// not using extendSet() to avoid unneeded data copying
nsize := wordsNeeded(top + bits)
nsize := wordsNeeded(top + bits + 1)
if len(b.set) < nsize {
dst = make([]uint64, nsize)
}
@ -1505,7 +1531,7 @@ func (b *BitSet) ShiftRight(bits uint) {
return
}
if bits >= top {
if bits > top {
b.set = make([]uint64, wordsNeeded(b.length))
return
}

View file

@ -0,0 +1,23 @@
//go:build go1.23
// +build go1.23
package bitset
import (
"iter"
"math/bits"
)
func (b *BitSet) EachSet() iter.Seq[uint] {
return func(yield func(uint) bool) {
for wordIndex, word := range b.set {
idx := 0
for trail := bits.TrailingZeros64(word); trail != 64; trail = bits.TrailingZeros64(word >> idx) {
if !yield(uint(wordIndex<<log2WordSize + idx + trail)) {
return
}
idx += trail + 1
}
}
}
}

View file

@ -2,58 +2,51 @@ package bitset
import "math/bits"
func popcntSlice(s []uint64) uint64 {
var cnt int
func popcntSlice(s []uint64) (cnt uint64) {
for _, x := range s {
cnt += bits.OnesCount64(x)
cnt += uint64(bits.OnesCount64(x))
}
return uint64(cnt)
return
}
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")
}
func popcntMaskSlice(s, m []uint64) (cnt uint64) {
// The next line is to help the bounds checker, it matters!
_ = m[len(s)-1] // BCE
for i := range s {
cnt += bits.OnesCount64(s[i] &^ m[i])
cnt += uint64(bits.OnesCount64(s[i] &^ m[i]))
}
return uint64(cnt)
return
}
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")
}
// popcntAndSlice computes the population count of the AND of two slices.
// It assumes that len(m) >= len(s) > 0.
func popcntAndSlice(s, m []uint64) (cnt uint64) {
// The next line is to help the bounds checker, it matters!
_ = m[len(s)-1] // BCE
for i := range s {
cnt += bits.OnesCount64(s[i] & m[i])
cnt += uint64(bits.OnesCount64(s[i] & m[i]))
}
return uint64(cnt)
return
}
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")
}
// popcntOrSlice computes the population count of the OR of two slices.
// It assumes that len(m) >= len(s) > 0.
func popcntOrSlice(s, m []uint64) (cnt uint64) {
// The next line is to help the bounds checker, it matters!
_ = m[len(s)-1] // BCE
for i := range s {
cnt += bits.OnesCount64(s[i] | m[i])
cnt += uint64(bits.OnesCount64(s[i] | m[i]))
}
return uint64(cnt)
return
}
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")
}
// popcntXorSlice computes the population count of the XOR of two slices.
// It assumes that len(m) >= len(s) > 0.
func popcntXorSlice(s, m []uint64) (cnt uint64) {
// The next line is to help the bounds checker, it matters!
_ = m[len(s)-1] // BCE
for i := range s {
cnt += bits.OnesCount64(s[i] ^ m[i])
cnt += uint64(bits.OnesCount64(s[i] ^ m[i]))
}
return uint64(cnt)
return
}