update vendor
This commit is contained in:
parent
824f46979b
commit
8675bc4b7a
328 changed files with 27166 additions and 6537 deletions
1
vendor/github.com/RoaringBitmap/roaring/.drone.yml
generated
vendored
1
vendor/github.com/RoaringBitmap/roaring/.drone.yml
generated
vendored
|
|
@ -11,7 +11,6 @@ steps:
|
|||
commands:
|
||||
- go get -t
|
||||
- go test
|
||||
- go test -race -run TestConcurrent*
|
||||
- go build -tags appengine
|
||||
- go test -tags appengine
|
||||
- GOARCH=386 go build
|
||||
|
|
|
|||
107
vendor/github.com/RoaringBitmap/roaring/Makefile
generated
vendored
107
vendor/github.com/RoaringBitmap/roaring/Makefile
generated
vendored
|
|
@ -1,107 +0,0 @@
|
|||
.PHONY: help all test format fmtcheck vet lint qa deps clean nuke ser fetch-real-roaring-datasets
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Display general help about this command
|
||||
help:
|
||||
@echo ""
|
||||
@echo "The following commands are available:"
|
||||
@echo ""
|
||||
@echo " make qa : Run all the tests"
|
||||
@echo " make test : Run the unit tests"
|
||||
@echo ""
|
||||
@echo " make format : Format the source code"
|
||||
@echo " make fmtcheck : Check if the source code has been formatted"
|
||||
@echo " make vet : Check for suspicious constructs"
|
||||
@echo " make lint : Check for style errors"
|
||||
@echo ""
|
||||
@echo " make deps : Get the dependencies"
|
||||
@echo " make clean : Remove any build artifact"
|
||||
@echo " make nuke : Deletes any intermediate file"
|
||||
@echo ""
|
||||
@echo " make fuzz-smat : Fuzzy testing with smat"
|
||||
@echo " make fuzz-stream : Fuzzy testing with stream deserialization"
|
||||
@echo " make fuzz-buffer : Fuzzy testing with buffer deserialization"
|
||||
@echo ""
|
||||
|
||||
# Alias for help target
|
||||
all: help
|
||||
test:
|
||||
go test
|
||||
go test -race -run TestConcurrent*
|
||||
# Format the source code
|
||||
format:
|
||||
@find ./ -type f -name "*.go" -exec gofmt -w {} \;
|
||||
|
||||
# Check if the source code has been formatted
|
||||
fmtcheck:
|
||||
@mkdir -p target
|
||||
@find ./ -type f -name "*.go" -exec gofmt -d {} \; | tee target/format.diff
|
||||
@test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; }
|
||||
|
||||
# Check for syntax errors
|
||||
vet:
|
||||
GOPATH=$(GOPATH) go vet ./...
|
||||
|
||||
# Check for style errors
|
||||
lint:
|
||||
GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint ./...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Alias to run all quality-assurance checks
|
||||
qa: fmtcheck test vet lint
|
||||
|
||||
# --- INSTALL ---
|
||||
|
||||
# Get the dependencies
|
||||
deps:
|
||||
GOPATH=$(GOPATH) go get github.com/stretchr/testify
|
||||
GOPATH=$(GOPATH) go get github.com/bits-and-blooms/bitset
|
||||
GOPATH=$(GOPATH) go get github.com/golang/lint/golint
|
||||
GOPATH=$(GOPATH) go get github.com/mschoch/smat
|
||||
GOPATH=$(GOPATH) go get github.com/dvyukov/go-fuzz/go-fuzz
|
||||
GOPATH=$(GOPATH) go get github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||
GOPATH=$(GOPATH) go get github.com/glycerine/go-unsnap-stream
|
||||
GOPATH=$(GOPATH) go get github.com/philhofer/fwd
|
||||
GOPATH=$(GOPATH) go get github.com/jtolds/gls
|
||||
|
||||
fuzz-smat:
|
||||
go test -tags=gofuzz -run=TestGenerateSmatCorpus
|
||||
go-fuzz-build -func FuzzSmat github.com/RoaringBitmap/roaring
|
||||
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||
|
||||
|
||||
fuzz-stream:
|
||||
go-fuzz-build -func FuzzSerializationStream github.com/RoaringBitmap/roaring
|
||||
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||
|
||||
|
||||
fuzz-buffer:
|
||||
go-fuzz-build -func FuzzSerializationBuffer github.com/RoaringBitmap/roaring
|
||||
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||
|
||||
# Remove any build artifact
|
||||
clean:
|
||||
GOPATH=$(GOPATH) go clean ./...
|
||||
|
||||
# Deletes any intermediate file
|
||||
nuke:
|
||||
rm -rf ./target
|
||||
GOPATH=$(GOPATH) go clean -i ./...
|
||||
|
||||
cover:
|
||||
go test -coverprofile=coverage.out
|
||||
go tool cover -html=coverage.out
|
||||
|
||||
fetch-real-roaring-datasets:
|
||||
# pull github.com/RoaringBitmap/real-roaring-datasets -> testdata/real-roaring-datasets
|
||||
git submodule init
|
||||
git submodule update
|
||||
16
vendor/github.com/RoaringBitmap/roaring/README.md
generated
vendored
16
vendor/github.com/RoaringBitmap/roaring/README.md
generated
vendored
|
|
@ -1,5 +1,7 @@
|
|||
roaring [](https://godoc.org/github.com/RoaringBitmap/roaring/roaring64) [](https://goreportcard.com/report/github.com/RoaringBitmap/roaring)
|
||||
[](https://cloud.drone.io/RoaringBitmap/roaring)
|
||||
# roaring
|
||||
|
||||
[](https://godoc.org/github.com/RoaringBitmap/roaring) [](https://goreportcard.com/report/github.com/RoaringBitmap/roaring)
|
||||
|
||||

|
||||

|
||||

|
||||
|
|
@ -8,7 +10,7 @@ roaring [][druid], [LinkedIn Pinot][pinot], [Netflix Atlas][atlas], [Apache Spark][spark], [OpenSearchServer][opensearchserver], [anacrolix/torrent][anacrolix/torrent], [Whoosh][whoosh], [Pilosa][pilosa], [Microsoft Visual Studio Team Services (VSTS)][vsts], and eBay's [Apache Kylin][kylin]. The YouTube SQL Engine, [Google Procella](https://research.google/pubs/pub48388/), uses Roaring bitmaps for indexing.
|
||||
[Elasticsearch][elasticsearch], [Apache Druid (Incubating)][druid], [LinkedIn Pinot][pinot], [Netflix Atlas][atlas], [Apache Spark][spark], [OpenSearchServer][opensearchserver], [anacrolix/torrent][anacrolix/torrent], [Whoosh][whoosh], [Redpanda](https://github.com/redpanda-data/redpanda), [Pilosa][pilosa], [Microsoft Visual Studio Team Services (VSTS)][vsts], and eBay's [Apache Kylin][kylin]. The YouTube SQL Engine, [Google Procella](https://research.google/pubs/pub48388/), uses Roaring bitmaps for indexing.
|
||||
|
||||
[lucene]: https://lucene.apache.org/
|
||||
[solr]: https://lucene.apache.org/solr/
|
||||
|
|
@ -31,17 +33,17 @@ Roaring bitmaps are found to work well in many important applications:
|
|||
|
||||
The ``roaring`` Go library is used by
|
||||
* [anacrolix/torrent]
|
||||
* [runv](https://github.com/hyperhq/runv)
|
||||
* [InfluxDB](https://www.influxdata.com)
|
||||
* [Pilosa](https://www.pilosa.com/)
|
||||
* [Bleve](http://www.blevesearch.com)
|
||||
* [Weaviate](https://github.com/weaviate/weaviate)
|
||||
* [lindb](https://github.com/lindb/lindb)
|
||||
* [Elasticell](https://github.com/deepfabric/elasticell)
|
||||
* [SourceGraph](https://github.com/sourcegraph/sourcegraph)
|
||||
* [M3](https://github.com/m3db/m3)
|
||||
* [trident](https://github.com/NetApp/trident)
|
||||
* [Husky](https://www.datadoghq.com/blog/engineering/introducing-husky/)
|
||||
|
||||
* [FrostDB](https://github.com/polarsignals/frostdb)
|
||||
|
||||
This library is used in production in several systems, it is part of the [Awesome Go collection](https://awesome-go.com).
|
||||
|
||||
|
|
@ -99,7 +101,7 @@ whether you like it or not. That can become very wasteful.
|
|||
|
||||
This being said, there are definitively cases where attempting to use compressed bitmaps is wasteful.
|
||||
For example, if you have a small universe size. E.g., your bitmaps represent sets of integers
|
||||
from [0,n) where n is small (e.g., n=64 or n=128). If you are able to uncompressed BitSet and
|
||||
from [0,n) where n is small (e.g., n=64 or n=128). If you can use uncompressed BitSet and
|
||||
it does not blow up your memory usage, then compressed bitmaps are probably not useful
|
||||
to you. In fact, if you do not need compression, then a BitSet offers remarkable speed.
|
||||
|
||||
|
|
@ -134,7 +136,7 @@ There is a big problem with these formats however that can hurt you badly in som
|
|||
|
||||
Roaring solves this problem. It works in the following manner. It divides the data into chunks of 2<sup>16</sup> integers
|
||||
(e.g., [0, 2<sup>16</sup>), [2<sup>16</sup>, 2 x 2<sup>16</sup>), ...). Within a chunk, it can use an uncompressed bitmap, a simple list of integers,
|
||||
or a list of runs. Whatever format it uses, they all allow you to check for the present of any one value quickly
|
||||
or a list of runs. Whatever format it uses, they all allow you to check for the presence of any one value quickly
|
||||
(e.g., with a binary search). The net result is that Roaring can compute many operations much faster than run-length-encoded
|
||||
formats like WAH, EWAH, Concise... Maybe surprisingly, Roaring also generally offers better compression ratios.
|
||||
|
||||
|
|
|
|||
63
vendor/github.com/RoaringBitmap/roaring/arraycontainer.go
generated
vendored
63
vendor/github.com/RoaringBitmap/roaring/arraycontainer.go
generated
vendored
|
|
@ -17,8 +17,17 @@ func (ac *arrayContainer) String() string {
|
|||
}
|
||||
|
||||
func (ac *arrayContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) int {
|
||||
if i < 0 {
|
||||
panic("negative index")
|
||||
}
|
||||
if len(ac.content) == 0 {
|
||||
return i
|
||||
}
|
||||
_ = x[len(ac.content)-1+i]
|
||||
_ = ac.content[len(ac.content)-1]
|
||||
for k := 0; k < len(ac.content); k++ {
|
||||
x[k+i] = uint32(ac.content[k]) | mask
|
||||
x[k+i] =
|
||||
uint32(ac.content[k]) | mask
|
||||
}
|
||||
return i + len(ac.content)
|
||||
}
|
||||
|
|
@ -655,10 +664,54 @@ func (ac *arrayContainer) iandNot(a container) container {
|
|||
}
|
||||
|
||||
func (ac *arrayContainer) iandNotRun16(rc *runContainer16) container {
|
||||
rcb := rc.toBitmapContainer()
|
||||
acb := ac.toBitmapContainer()
|
||||
acb.iandNotBitmapSurely(rcb)
|
||||
*ac = *(acb.toArrayContainer())
|
||||
// Fast path: if either the array container or the run container is empty, the result is the array.
|
||||
if ac.isEmpty() || rc.isEmpty() {
|
||||
// Empty
|
||||
return ac
|
||||
}
|
||||
// Fast path: if the run container is full, the result is empty.
|
||||
if rc.isFull() {
|
||||
ac.content = ac.content[:0]
|
||||
return ac
|
||||
}
|
||||
current_run := 0
|
||||
// All values in [start_run, end_end] are part of the run
|
||||
start_run := rc.iv[current_run].start
|
||||
end_end := start_run + rc.iv[current_run].length
|
||||
// We are going to read values in the array at index i, and we are
|
||||
// going to write them at index pos. So we do in-place processing.
|
||||
// We always have that pos <= i by construction. So we can either
|
||||
// overwrite a value just read, or a value that was previous read.
|
||||
pos := 0
|
||||
i := 0
|
||||
for ; i < len(ac.content); i++ {
|
||||
if ac.content[i] < start_run {
|
||||
// the value in the array appears before the run [start_run, end_end]
|
||||
ac.content[pos] = ac.content[i]
|
||||
pos++
|
||||
} else if ac.content[i] <= end_end {
|
||||
// nothing to do, the value is in the array but also in the run.
|
||||
} else {
|
||||
// We have the value in the array after the run. We cannot tell
|
||||
// whether we need to keep it or not. So let us move to another run.
|
||||
if current_run+1 < len(rc.iv) {
|
||||
current_run++
|
||||
start_run = rc.iv[current_run].start
|
||||
end_end = start_run + rc.iv[current_run].length
|
||||
i-- // retry with the same i
|
||||
} else {
|
||||
// We have exhausted the number of runs. We can keep the rest of the values
|
||||
// from i to len(ac.content) - 1 inclusively.
|
||||
break // We are done, the rest of the array will be kept
|
||||
}
|
||||
}
|
||||
}
|
||||
for ; i < len(ac.content); i++ {
|
||||
ac.content[pos] = ac.content[i]
|
||||
pos++
|
||||
}
|
||||
// We 'shink' the slice.
|
||||
ac.content = ac.content[:pos]
|
||||
return ac
|
||||
}
|
||||
|
||||
|
|
|
|||
63
vendor/github.com/RoaringBitmap/roaring/bitmapcontainer.go
generated
vendored
63
vendor/github.com/RoaringBitmap/roaring/bitmapcontainer.go
generated
vendored
|
|
@ -888,13 +888,67 @@ func (bc *bitmapContainer) iandNot(a container) container {
|
|||
}
|
||||
|
||||
func (bc *bitmapContainer) iandNotArray(ac *arrayContainer) container {
|
||||
acb := ac.toBitmapContainer()
|
||||
return bc.iandNotBitmapSurely(acb)
|
||||
if ac.isEmpty() || bc.isEmpty() {
|
||||
// Nothing to do.
|
||||
return bc
|
||||
}
|
||||
|
||||
// Word by word, we remove the elements in ac from bc. The approach is to build
|
||||
// a mask of the elements to remove, and then apply it to the bitmap.
|
||||
wordIdx := uint16(0)
|
||||
mask := uint64(0)
|
||||
for i, v := range ac.content {
|
||||
if v/64 != wordIdx {
|
||||
// Flush the current word.
|
||||
if i != 0 {
|
||||
// We're removing bits that are set in the mask and in the current word.
|
||||
// To figure out the cardinality change, we count the number of bits that
|
||||
// are set in the mask and in the current word.
|
||||
mask &= bc.bitmap[wordIdx]
|
||||
bc.bitmap[wordIdx] &= ^mask
|
||||
bc.cardinality -= int(popcount(mask))
|
||||
}
|
||||
|
||||
wordIdx = v / 64
|
||||
mask = 0
|
||||
}
|
||||
mask |= 1 << (v % 64)
|
||||
}
|
||||
|
||||
// Flush the last word.
|
||||
mask &= bc.bitmap[wordIdx]
|
||||
bc.bitmap[wordIdx] &= ^mask
|
||||
bc.cardinality -= int(popcount(mask))
|
||||
|
||||
if bc.getCardinality() <= arrayDefaultMaxSize {
|
||||
return bc.toArrayContainer()
|
||||
}
|
||||
return bc
|
||||
}
|
||||
|
||||
func (bc *bitmapContainer) iandNotRun16(rc *runContainer16) container {
|
||||
rcb := rc.toBitmapContainer()
|
||||
return bc.iandNotBitmapSurely(rcb)
|
||||
if rc.isEmpty() || bc.isEmpty() {
|
||||
// Nothing to do.
|
||||
return bc
|
||||
}
|
||||
|
||||
wordRangeStart := rc.iv[0].start / 64
|
||||
wordRangeEnd := (rc.iv[len(rc.iv)-1].last()) / 64 // inclusive
|
||||
|
||||
cardinalityChange := popcntSlice(bc.bitmap[wordRangeStart : wordRangeEnd+1]) // before cardinality - after cardinality (for word range)
|
||||
|
||||
for _, iv := range rc.iv {
|
||||
resetBitmapRange(bc.bitmap, int(iv.start), int(iv.last())+1)
|
||||
}
|
||||
|
||||
cardinalityChange -= popcntSlice(bc.bitmap[wordRangeStart : wordRangeEnd+1])
|
||||
|
||||
bc.cardinality -= int(cardinalityChange)
|
||||
|
||||
if bc.getCardinality() <= arrayDefaultMaxSize {
|
||||
return bc.toArrayContainer()
|
||||
}
|
||||
return bc
|
||||
}
|
||||
|
||||
func (bc *bitmapContainer) andNotArray(value2 *arrayContainer) container {
|
||||
|
|
@ -1062,7 +1116,6 @@ func (bc *bitmapContainer) PrevSetBit(i int) int {
|
|||
|
||||
// reference the java implementation
|
||||
// https://github.com/RoaringBitmap/RoaringBitmap/blob/master/src/main/java/org/roaringbitmap/BitmapContainer.java#L875-L892
|
||||
//
|
||||
func (bc *bitmapContainer) numberOfRuns() int {
|
||||
if bc.cardinality == 0 {
|
||||
return 0
|
||||
|
|
|
|||
63
vendor/github.com/RoaringBitmap/roaring/internal/byte_input.go
generated
vendored
63
vendor/github.com/RoaringBitmap/roaring/internal/byte_input.go
generated
vendored
|
|
@ -10,6 +10,11 @@ type ByteInput interface {
|
|||
// Next returns a slice containing the next n bytes from the buffer,
|
||||
// advancing the buffer as if the bytes had been returned by Read.
|
||||
Next(n int) ([]byte, error)
|
||||
// NextReturnsSafeSlice returns true if Next() returns a safe slice as opposed
|
||||
// to a slice that points to an underlying buffer possibly owned by another system.
|
||||
// When NextReturnsSafeSlice returns false, the result from Next() should be copied
|
||||
// before it is modified (i.e., it is immutable).
|
||||
NextReturnsSafeSlice() bool
|
||||
// ReadUInt32 reads uint32 with LittleEndian order
|
||||
ReadUInt32() (uint32, error)
|
||||
// ReadUInt16 reads uint16 with LittleEndian order
|
||||
|
|
@ -42,6 +47,25 @@ type ByteBuffer struct {
|
|||
off int
|
||||
}
|
||||
|
||||
// NewByteBuffer creates a new ByteBuffer.
|
||||
func NewByteBuffer(buf []byte) *ByteBuffer {
|
||||
return &ByteBuffer{
|
||||
buf: buf,
|
||||
}
|
||||
}
|
||||
|
||||
var _ io.Reader = (*ByteBuffer)(nil)
|
||||
|
||||
// Read implements io.Reader.
|
||||
func (b *ByteBuffer) Read(p []byte) (int, error) {
|
||||
data, err := b.Next(len(p))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(p, data)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// Next returns a slice containing the next n bytes from the reader
|
||||
// If there are fewer bytes than the given n, io.ErrUnexpectedEOF will be returned
|
||||
func (b *ByteBuffer) Next(n int) ([]byte, error) {
|
||||
|
|
@ -57,6 +81,12 @@ func (b *ByteBuffer) Next(n int) ([]byte, error) {
|
|||
return data, nil
|
||||
}
|
||||
|
||||
// NextReturnsSafeSlice returns false since ByteBuffer might hold
|
||||
// an array owned by some other systems.
|
||||
func (b *ByteBuffer) NextReturnsSafeSlice() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ReadUInt32 reads uint32 with LittleEndian order
|
||||
func (b *ByteBuffer) ReadUInt32() (uint32, error) {
|
||||
if len(b.buf)-b.off < 4 {
|
||||
|
|
@ -109,26 +139,45 @@ func (b *ByteBuffer) Reset(buf []byte) {
|
|||
type ByteInputAdapter struct {
|
||||
r io.Reader
|
||||
readBytes int
|
||||
buf [4]byte
|
||||
}
|
||||
|
||||
var _ io.Reader = (*ByteInputAdapter)(nil)
|
||||
|
||||
// Read implements io.Reader.
|
||||
func (b *ByteInputAdapter) Read(buf []byte) (int, error) {
|
||||
m, err := io.ReadAtLeast(b.r, buf, len(buf))
|
||||
b.readBytes += m
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Next returns a slice containing the next n bytes from the buffer,
|
||||
// advancing the buffer as if the bytes had been returned by Read.
|
||||
func (b *ByteInputAdapter) Next(n int) ([]byte, error) {
|
||||
buf := make([]byte, n)
|
||||
m, err := io.ReadAtLeast(b.r, buf, n)
|
||||
b.readBytes += m
|
||||
_, err := b.Read(buf)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// NextReturnsSafeSlice returns true since ByteInputAdapter always returns a slice
|
||||
// allocated with make([]byte, ...)
|
||||
func (b *ByteInputAdapter) NextReturnsSafeSlice() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUInt32 reads uint32 with LittleEndian order
|
||||
func (b *ByteInputAdapter) ReadUInt32() (uint32, error) {
|
||||
buf, err := b.Next(4)
|
||||
|
||||
buf := b.buf[:4]
|
||||
_, err := b.Read(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -138,8 +187,8 @@ func (b *ByteInputAdapter) ReadUInt32() (uint32, error) {
|
|||
|
||||
// ReadUInt16 reads uint16 with LittleEndian order
|
||||
func (b *ByteInputAdapter) ReadUInt16() (uint16, error) {
|
||||
buf, err := b.Next(2)
|
||||
|
||||
buf := b.buf[:2]
|
||||
_, err := b.Read(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
|||
267
vendor/github.com/RoaringBitmap/roaring/roaring.go
generated
vendored
267
vendor/github.com/RoaringBitmap/roaring/roaring.go
generated
vendored
|
|
@ -13,6 +13,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/RoaringBitmap/roaring/internal"
|
||||
"github.com/bits-and-blooms/bitset"
|
||||
)
|
||||
|
||||
// Bitmap represents a compressed bitmap where you can add integers.
|
||||
|
|
@ -53,17 +54,186 @@ func (rb *Bitmap) ToBytes() ([]byte, error) {
|
|||
return rb.highlowcontainer.toBytes()
|
||||
}
|
||||
|
||||
const wordSize = uint64(64)
|
||||
const log2WordSize = uint64(6)
|
||||
const capacity = ^uint64(0)
|
||||
const bitmapContainerSize = (1 << 16) / 64 // bitmap size in words
|
||||
|
||||
// DenseSize returns the size of the bitmap when stored as a dense bitmap.
|
||||
func (rb *Bitmap) DenseSize() uint64 {
|
||||
if rb.highlowcontainer.size() == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
maximum := 1 + uint64(rb.Maximum())
|
||||
if maximum > (capacity - wordSize + 1) {
|
||||
return uint64(capacity >> log2WordSize)
|
||||
}
|
||||
|
||||
return uint64((maximum + (wordSize - 1)) >> log2WordSize)
|
||||
}
|
||||
|
||||
// ToDense returns a slice of uint64s representing the bitmap as a dense bitmap.
|
||||
// Useful to convert a roaring bitmap to a format that can be used by other libraries
|
||||
// like https://github.com/bits-and-blooms/bitset or https://github.com/kelindar/bitmap
|
||||
func (rb *Bitmap) ToDense() []uint64 {
|
||||
sz := rb.DenseSize()
|
||||
if sz == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bitmap := make([]uint64, sz)
|
||||
rb.WriteDenseTo(bitmap)
|
||||
return bitmap
|
||||
}
|
||||
|
||||
// FromDense creates a bitmap from a slice of uint64s representing the bitmap as a dense bitmap.
|
||||
// Useful to convert bitmaps from libraries like https://github.com/bits-and-blooms/bitset or
|
||||
// https://github.com/kelindar/bitmap into roaring bitmaps fast and with convenience.
|
||||
//
|
||||
// This function will not create any run containers, only array and bitmap containers. It's up to
|
||||
// the caller to call RunOptimize if they want to further compress the runs of consecutive values.
|
||||
//
|
||||
// When doCopy is true, the bitmap is copied into a new slice for each bitmap container.
|
||||
// This is useful when the bitmap is going to be modified after this function returns or if it's
|
||||
// undesirable to hold references to large bitmaps which the GC would not be able to collect.
|
||||
// One copy can still happen even when doCopy is false if the bitmap length is not divisible
|
||||
// by bitmapContainerSize.
|
||||
//
|
||||
// See also FromBitSet.
|
||||
func FromDense(bitmap []uint64, doCopy bool) *Bitmap {
|
||||
sz := (len(bitmap) + bitmapContainerSize - 1) / bitmapContainerSize // round up
|
||||
rb := &Bitmap{
|
||||
highlowcontainer: roaringArray{
|
||||
containers: make([]container, 0, sz),
|
||||
keys: make([]uint16, 0, sz),
|
||||
needCopyOnWrite: make([]bool, 0, sz),
|
||||
},
|
||||
}
|
||||
rb.FromDense(bitmap, doCopy)
|
||||
return rb
|
||||
}
|
||||
|
||||
// FromDense unmarshalls from a slice of uint64s representing the bitmap as a dense bitmap.
|
||||
// Useful to convert bitmaps from libraries like https://github.com/bits-and-blooms/bitset or
|
||||
// https://github.com/kelindar/bitmap into roaring bitmaps fast and with convenience.
|
||||
// Callers are responsible for ensuring that the bitmap is empty before calling this function.
|
||||
//
|
||||
// This function will not create any run containers, only array and bitmap containers. It is up to
|
||||
// the caller to call RunOptimize if they want to further compress the runs of consecutive values.
|
||||
//
|
||||
// When doCopy is true, the bitmap is copied into a new slice for each bitmap container.
|
||||
// This is useful when the bitmap is going to be modified after this function returns or if it's
|
||||
// undesirable to hold references to large bitmaps which the GC would not be able to collect.
|
||||
// One copy can still happen even when doCopy is false if the bitmap length is not divisible
|
||||
// by bitmapContainerSize.
|
||||
//
|
||||
// See FromBitSet.
|
||||
func (rb *Bitmap) FromDense(bitmap []uint64, doCopy bool) {
|
||||
if len(bitmap) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var k uint16
|
||||
const size = bitmapContainerSize
|
||||
|
||||
for len(bitmap) > 0 {
|
||||
hi := size
|
||||
if len(bitmap) < size {
|
||||
hi = len(bitmap)
|
||||
}
|
||||
|
||||
words := bitmap[:hi]
|
||||
count := int(popcntSlice(words))
|
||||
|
||||
switch {
|
||||
case count > arrayDefaultMaxSize:
|
||||
c := &bitmapContainer{cardinality: count, bitmap: words}
|
||||
cow := true
|
||||
|
||||
if doCopy || len(words) < size {
|
||||
c.bitmap = make([]uint64, size)
|
||||
copy(c.bitmap, words)
|
||||
cow = false
|
||||
}
|
||||
|
||||
rb.highlowcontainer.appendContainer(k, c, cow)
|
||||
|
||||
case count > 0:
|
||||
c := &arrayContainer{content: make([]uint16, count)}
|
||||
var pos, base int
|
||||
for _, w := range words {
|
||||
for w != 0 {
|
||||
t := w & -w
|
||||
c.content[pos] = uint16(base + int(popcount(t-1)))
|
||||
pos++
|
||||
w ^= t
|
||||
}
|
||||
base += 64
|
||||
}
|
||||
rb.highlowcontainer.appendContainer(k, c, false)
|
||||
}
|
||||
|
||||
bitmap = bitmap[hi:]
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
||||
// WriteDenseTo writes to a slice of uint64s representing the bitmap as a dense bitmap.
|
||||
// Callers are responsible for allocating enough space in the bitmap using DenseSize.
|
||||
// Useful to convert a roaring bitmap to a format that can be used by other libraries
|
||||
// like https://github.com/bits-and-blooms/bitset or https://github.com/kelindar/bitmap
|
||||
func (rb *Bitmap) WriteDenseTo(bitmap []uint64) {
|
||||
for i, ct := range rb.highlowcontainer.containers {
|
||||
hb := uint32(rb.highlowcontainer.keys[i]) << 16
|
||||
|
||||
switch c := ct.(type) {
|
||||
case *arrayContainer:
|
||||
for _, x := range c.content {
|
||||
n := int(hb | uint32(x))
|
||||
bitmap[n>>log2WordSize] |= uint64(1) << uint(x%64)
|
||||
}
|
||||
|
||||
case *bitmapContainer:
|
||||
copy(bitmap[int(hb)>>log2WordSize:], c.bitmap)
|
||||
|
||||
case *runContainer16:
|
||||
for j := range c.iv {
|
||||
start := uint32(c.iv[j].start)
|
||||
end := start + uint32(c.iv[j].length) + 1
|
||||
lo := int(hb|start) >> log2WordSize
|
||||
hi := int(hb|(end-1)) >> log2WordSize
|
||||
|
||||
if lo == hi {
|
||||
bitmap[lo] |= (^uint64(0) << uint(start%64)) &
|
||||
(^uint64(0) >> (uint(-end) % 64))
|
||||
continue
|
||||
}
|
||||
|
||||
bitmap[lo] |= ^uint64(0) << uint(start%64)
|
||||
for n := lo + 1; n < hi; n++ {
|
||||
bitmap[n] = ^uint64(0)
|
||||
}
|
||||
bitmap[hi] |= ^uint64(0) >> (uint(-end) % 64)
|
||||
}
|
||||
default:
|
||||
panic("unsupported container type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checksum computes a hash (currently FNV-1a) for a bitmap that is suitable for
|
||||
// using bitmaps as elements in hash sets or as keys in hash maps, as well as
|
||||
// generally quicker comparisons.
|
||||
// The implementation is biased towards efficiency in little endian machines, so
|
||||
// expect some extra CPU cycles and memory to be used if your machine is big endian.
|
||||
// Likewise, don't use this to verify integrity unless you're certain you'll load
|
||||
// the bitmap on a machine with the same endianess used to create it.
|
||||
// Likewise, do not use this to verify integrity unless you are certain you will load
|
||||
// the bitmap on a machine with the same endianess used to create it. (Thankfully
|
||||
// very few people use big endian machines these days.)
|
||||
func (rb *Bitmap) Checksum() uint64 {
|
||||
const (
|
||||
offset = 14695981039346656037
|
||||
prime = 1099511628211
|
||||
prime = 1099511628211
|
||||
)
|
||||
|
||||
var bytes []byte
|
||||
|
|
@ -106,6 +276,20 @@ func (rb *Bitmap) Checksum() uint64 {
|
|||
return hash
|
||||
}
|
||||
|
||||
// FromUnsafeBytes reads a serialized version of this bitmap from the byte buffer without copy.
|
||||
// It is the caller's responsibility to ensure that the input data is not modified and remains valid for the entire lifetime of this bitmap.
|
||||
// This method avoids small allocations but holds references to the input data buffer. It is GC-friendly, but it may consume more memory eventually.
|
||||
// The containers in the resulting bitmap are immutable containers tied to the provided byte array and they rely on
|
||||
// copy-on-write which means that modifying them creates copies. Thus FromUnsafeBytes is more likely to be appropriate for read-only use cases,
|
||||
// when the resulting bitmap can be considered immutable.
|
||||
//
|
||||
// See also the FromBuffer function.
|
||||
// See https://github.com/RoaringBitmap/roaring/pull/395 for more details.
|
||||
func (rb *Bitmap) FromUnsafeBytes(data []byte, cookieHeader ...byte) (p int64, err error) {
|
||||
stream := internal.NewByteBuffer(data)
|
||||
return rb.ReadFrom(stream)
|
||||
}
|
||||
|
||||
// ReadFrom reads a serialized version of this bitmap from stream.
|
||||
// The format is compatible with other RoaringBitmap
|
||||
// implementations (Java, C) and is documented here:
|
||||
|
|
@ -114,12 +298,18 @@ func (rb *Bitmap) Checksum() uint64 {
|
|||
// So add cookieHeader to accept the 4-byte data that has been read in roaring64.ReadFrom.
|
||||
// It is not necessary to pass cookieHeader when call roaring.ReadFrom to read the roaring32 data directly.
|
||||
func (rb *Bitmap) ReadFrom(reader io.Reader, cookieHeader ...byte) (p int64, err error) {
|
||||
stream := internal.ByteInputAdapterPool.Get().(*internal.ByteInputAdapter)
|
||||
stream.Reset(reader)
|
||||
stream, ok := reader.(internal.ByteInput)
|
||||
if !ok {
|
||||
byteInputAdapter := internal.ByteInputAdapterPool.Get().(*internal.ByteInputAdapter)
|
||||
byteInputAdapter.Reset(reader)
|
||||
stream = byteInputAdapter
|
||||
}
|
||||
|
||||
p, err = rb.highlowcontainer.readFrom(stream, cookieHeader...)
|
||||
internal.ByteInputAdapterPool.Put(stream)
|
||||
|
||||
if !ok {
|
||||
internal.ByteInputAdapterPool.Put(stream.(*internal.ByteInputAdapter))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -139,12 +329,17 @@ func (rb *Bitmap) ReadFrom(reader io.Reader, cookieHeader ...byte) (p int64, err
|
|||
// You should *not* change the copy-on-write status of the resulting
|
||||
// bitmaps (SetCopyOnWrite).
|
||||
//
|
||||
// Thus FromBuffer is more likely to be appropriate for read-only use cases,
|
||||
// when the resulting bitmap can be considered immutable.
|
||||
//
|
||||
// If buf becomes unavailable, then a bitmap created with
|
||||
// FromBuffer would be effectively broken. Furthermore, any
|
||||
// bitmap derived from this bitmap (e.g., via Or, And) might
|
||||
// also be broken. Thus, before making buf unavailable, you should
|
||||
// call CloneCopyOnWriteContainers on all such bitmaps.
|
||||
//
|
||||
// See also the FromUnsafeBytes function which can have better performance
|
||||
// in some cases.
|
||||
func (rb *Bitmap) FromBuffer(buf []byte) (p int64, err error) {
|
||||
stream := internal.ByteBufferPool.Get().(*internal.ByteBuffer)
|
||||
stream.Reset(buf)
|
||||
|
|
@ -194,6 +389,16 @@ func (rb *Bitmap) Clear() {
|
|||
rb.highlowcontainer.clear()
|
||||
}
|
||||
|
||||
// ToBitSet copies the content of the RoaringBitmap into a bitset.BitSet instance
|
||||
func (rb *Bitmap) ToBitSet() *bitset.BitSet {
|
||||
return bitset.From(rb.ToDense())
|
||||
}
|
||||
|
||||
// FromBitSet creates a new RoaringBitmap from a bitset.BitSet instance
|
||||
func FromBitSet(bitset *bitset.BitSet) *Bitmap {
|
||||
return FromDense(bitset.Bytes(), false)
|
||||
}
|
||||
|
||||
// ToArray creates a new slice containing all of the integers stored in the Bitmap in sorted order
|
||||
func (rb *Bitmap) ToArray() []uint32 {
|
||||
array := make([]uint32, rb.GetCardinality())
|
||||
|
|
@ -233,7 +438,7 @@ func BoundSerializedSizeInBytes(cardinality uint64, universeSize uint64) uint64
|
|||
contnbr := (universeSize + uint64(65535)) / uint64(65536)
|
||||
if contnbr > cardinality {
|
||||
contnbr = cardinality
|
||||
// we can't have more containers than we have values
|
||||
// we cannot have more containers than we have values
|
||||
}
|
||||
headermax := 8*contnbr + 4
|
||||
if 4 > (contnbr+7)/8 {
|
||||
|
|
@ -276,9 +481,9 @@ type intIterator struct {
|
|||
// This way, instead of making up-to 64k allocations per full iteration
|
||||
// we get a single allocation and simply reinitialize the appropriate
|
||||
// iterator and point to it in the generic `iter` member on each key bound.
|
||||
shortIter shortIterator
|
||||
runIter runIterator16
|
||||
bitmapIter bitmapContainerShortIterator
|
||||
shortIter shortIterator
|
||||
runIter runIterator16
|
||||
bitmapIter bitmapContainerShortIterator
|
||||
}
|
||||
|
||||
// HasNext returns true if there are more integers to iterate over
|
||||
|
|
@ -341,14 +546,13 @@ func (ii *intIterator) AdvanceIfNeeded(minval uint32) {
|
|||
// IntIterator is meant to allow you to iterate through the values of a bitmap, see Initialize(a *Bitmap)
|
||||
type IntIterator = intIterator
|
||||
|
||||
|
||||
// Initialize configures the existing iterator so that it can iterate through the values of
|
||||
// the provided bitmap.
|
||||
// The iteration results are undefined if the bitmap is modified (e.g., with Add or Remove).
|
||||
func (p *intIterator) Initialize(a *Bitmap) {
|
||||
p.pos = 0
|
||||
p.highlowcontainer = &a.highlowcontainer
|
||||
p.init()
|
||||
func (ii *intIterator) Initialize(a *Bitmap) {
|
||||
ii.pos = 0
|
||||
ii.highlowcontainer = &a.highlowcontainer
|
||||
ii.init()
|
||||
}
|
||||
|
||||
type intReverseIterator struct {
|
||||
|
|
@ -357,9 +561,9 @@ type intReverseIterator struct {
|
|||
iter shortIterable
|
||||
highlowcontainer *roaringArray
|
||||
|
||||
shortIter reverseIterator
|
||||
runIter runReverseIterator16
|
||||
bitmapIter reverseBitmapContainerShortIterator
|
||||
shortIter reverseIterator
|
||||
runIter runReverseIterator16
|
||||
bitmapIter reverseBitmapContainerShortIterator
|
||||
}
|
||||
|
||||
// HasNext returns true if there are more integers to iterate over
|
||||
|
|
@ -414,10 +618,10 @@ type IntReverseIterator = intReverseIterator
|
|||
// Initialize configures the existing iterator so that it can iterate through the values of
|
||||
// the provided bitmap.
|
||||
// The iteration results are undefined if the bitmap is modified (e.g., with Add or Remove).
|
||||
func (p *intReverseIterator) Initialize(a *Bitmap) {
|
||||
p.highlowcontainer = &a.highlowcontainer
|
||||
p.pos = a.highlowcontainer.size() - 1
|
||||
p.init()
|
||||
func (ii *intReverseIterator) Initialize(a *Bitmap) {
|
||||
ii.highlowcontainer = &a.highlowcontainer
|
||||
ii.pos = a.highlowcontainer.size() - 1
|
||||
ii.init()
|
||||
}
|
||||
|
||||
// ManyIntIterable allows you to iterate over the values in a Bitmap
|
||||
|
|
@ -434,9 +638,9 @@ type manyIntIterator struct {
|
|||
iter manyIterable
|
||||
highlowcontainer *roaringArray
|
||||
|
||||
shortIter shortIterator
|
||||
runIter runIterator16
|
||||
bitmapIter bitmapContainerManyIterator
|
||||
shortIter shortIterator
|
||||
runIter runIterator16
|
||||
bitmapIter bitmapContainerManyIterator
|
||||
}
|
||||
|
||||
func (ii *manyIntIterator) init() {
|
||||
|
|
@ -495,17 +699,16 @@ func (ii *manyIntIterator) NextMany64(hs64 uint64, buf []uint64) int {
|
|||
return n
|
||||
}
|
||||
|
||||
|
||||
// ManyIntIterator is meant to allow you to iterate through the values of a bitmap, see Initialize(a *Bitmap)
|
||||
type ManyIntIterator = manyIntIterator
|
||||
|
||||
// Initialize configures the existing iterator so that it can iterate through the values of
|
||||
// the provided bitmap.
|
||||
// The iteration results are undefined if the bitmap is modified (e.g., with Add or Remove).
|
||||
func (p *manyIntIterator) Initialize(a *Bitmap) {
|
||||
p.pos = 0
|
||||
p.highlowcontainer = &a.highlowcontainer
|
||||
p.init()
|
||||
func (ii *manyIntIterator) Initialize(a *Bitmap) {
|
||||
ii.pos = 0
|
||||
ii.highlowcontainer = &a.highlowcontainer
|
||||
ii.init()
|
||||
}
|
||||
|
||||
// String creates a string representation of the Bitmap
|
||||
|
|
@ -569,7 +772,7 @@ func (rb *Bitmap) Iterate(cb func(x uint32) bool) {
|
|||
// Iterator creates a new IntPeekable to iterate over the integers contained in the bitmap, in sorted order;
|
||||
// the iterator becomes invalid if the bitmap is modified (e.g., with Add or Remove).
|
||||
func (rb *Bitmap) Iterator() IntPeekable {
|
||||
p := new(intIterator)
|
||||
p := new(intIterator)
|
||||
p.Initialize(rb)
|
||||
return p
|
||||
}
|
||||
|
|
@ -847,7 +1050,7 @@ func (rb *Bitmap) Select(x uint32) (uint32, error) {
|
|||
return uint32(key)<<16 + uint32(c.selectInt(uint16(remaining))), nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("can't find %dth integer in a bitmap with only %d items", x, rb.GetCardinality())
|
||||
return 0, fmt.Errorf("cannot find %dth integer in a bitmap with only %d items", x, rb.GetCardinality())
|
||||
}
|
||||
|
||||
// And computes the intersection between two bitmaps and stores the result in the current bitmap
|
||||
|
|
|
|||
19
vendor/github.com/RoaringBitmap/roaring/roaringarray.go
generated
vendored
19
vendor/github.com/RoaringBitmap/roaring/roaringarray.go
generated
vendored
|
|
@ -4,8 +4,9 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/RoaringBitmap/roaring/internal"
|
||||
"io"
|
||||
|
||||
"github.com/RoaringBitmap/roaring/internal"
|
||||
)
|
||||
|
||||
type container interface {
|
||||
|
|
@ -112,9 +113,10 @@ func newRoaringArray() *roaringArray {
|
|||
// runOptimize compresses the element containers to minimize space consumed.
|
||||
// Q: how does this interact with copyOnWrite and needCopyOnWrite?
|
||||
// A: since we aren't changing the logical content, just the representation,
|
||||
// we don't bother to check the needCopyOnWrite bits. We replace
|
||||
// (possibly all) elements of ra.containers in-place with space
|
||||
// optimized versions.
|
||||
//
|
||||
// we don't bother to check the needCopyOnWrite bits. We replace
|
||||
// (possibly all) elements of ra.containers in-place with space
|
||||
// optimized versions.
|
||||
func (ra *roaringArray) runOptimize() {
|
||||
for i := range ra.containers {
|
||||
ra.containers[i] = ra.containers[i].toEfficientContainer()
|
||||
|
|
@ -465,9 +467,7 @@ func (ra *roaringArray) serializedSizeInBytes() uint64 {
|
|||
return answer
|
||||
}
|
||||
|
||||
//
|
||||
// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||
//
|
||||
func (ra *roaringArray) writeTo(w io.Writer) (n int64, err error) {
|
||||
hasRun := ra.hasRunCompression()
|
||||
isRunSizeInBytes := 0
|
||||
|
|
@ -544,15 +544,14 @@ func (ra *roaringArray) writeTo(w io.Writer) (n int64, err error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
//
|
||||
// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||
//
|
||||
func (ra *roaringArray) toBytes() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
_, err := ra.writeTo(&buf)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
// Reads a serialized roaringArray from a byte slice.
|
||||
func (ra *roaringArray) readFrom(stream internal.ByteInput, cookieHeader ...byte) (int64, error) {
|
||||
var cookie uint32
|
||||
var err error
|
||||
|
|
@ -567,6 +566,8 @@ func (ra *roaringArray) readFrom(stream internal.ByteInput, cookieHeader ...byte
|
|||
return stream.GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: %s", err)
|
||||
}
|
||||
}
|
||||
// If NextReturnsSafeSlice is false, then willNeedCopyOnWrite should be true
|
||||
willNeedCopyOnWrite := !stream.NextReturnsSafeSlice()
|
||||
|
||||
var size uint32
|
||||
var isRunBitmap []byte
|
||||
|
|
@ -631,7 +632,7 @@ func (ra *roaringArray) readFrom(stream internal.ByteInput, cookieHeader ...byte
|
|||
key := keycard[2*i]
|
||||
card := int(keycard[2*i+1]) + 1
|
||||
ra.keys[i] = key
|
||||
ra.needCopyOnWrite[i] = true
|
||||
ra.needCopyOnWrite[i] = willNeedCopyOnWrite
|
||||
|
||||
if isRunBitmap != nil && isRunBitmap[i/8]&(1<<(i%8)) != 0 {
|
||||
// run container
|
||||
|
|
|
|||
49
vendor/github.com/RoaringBitmap/roaring/runcontainer.go
generated
vendored
49
vendor/github.com/RoaringBitmap/roaring/runcontainer.go
generated
vendored
|
|
@ -47,6 +47,7 @@ import (
|
|||
// runContainer16 does run-length encoding of sets of
|
||||
// uint16 integers.
|
||||
type runContainer16 struct {
|
||||
// iv is a slice of sorted, non-overlapping, non-adjacent intervals.
|
||||
iv []interval16
|
||||
}
|
||||
|
||||
|
|
@ -253,10 +254,8 @@ func newRunContainer16FromBitmapContainer(bc *bitmapContainer) *runContainer16 {
|
|||
|
||||
}
|
||||
|
||||
//
|
||||
// newRunContainer16FromArray populates a new
|
||||
// runContainer16 from the contents of arr.
|
||||
//
|
||||
func newRunContainer16FromArray(arr *arrayContainer) *runContainer16 {
|
||||
// keep this in sync with newRunContainer16FromVals above
|
||||
|
||||
|
|
@ -834,24 +833,23 @@ func (rc *runContainer16) numIntervals() int {
|
|||
// If key is not already present, then whichInterval16 is
|
||||
// set as follows:
|
||||
//
|
||||
// a) whichInterval16 == len(rc.iv)-1 if key is beyond our
|
||||
// last interval16 in rc.iv;
|
||||
// a) whichInterval16 == len(rc.iv)-1 if key is beyond our
|
||||
// last interval16 in rc.iv;
|
||||
//
|
||||
// b) whichInterval16 == -1 if key is before our first
|
||||
// interval16 in rc.iv;
|
||||
// b) whichInterval16 == -1 if key is before our first
|
||||
// interval16 in rc.iv;
|
||||
//
|
||||
// c) whichInterval16 is set to the minimum index of rc.iv
|
||||
// which comes strictly before the key;
|
||||
// so rc.iv[whichInterval16].last < key,
|
||||
// and if whichInterval16+1 exists, then key < rc.iv[whichInterval16+1].start
|
||||
// (Note that whichInterval16+1 won't exist when
|
||||
// whichInterval16 is the last interval.)
|
||||
// c) whichInterval16 is set to the minimum index of rc.iv
|
||||
// which comes strictly before the key;
|
||||
// so rc.iv[whichInterval16].last < key,
|
||||
// and if whichInterval16+1 exists, then key < rc.iv[whichInterval16+1].start
|
||||
// (Note that whichInterval16+1 won't exist when
|
||||
// whichInterval16 is the last interval.)
|
||||
//
|
||||
// runContainer16.search always returns whichInterval16 < len(rc.iv).
|
||||
//
|
||||
// The search space is from startIndex to endxIndex. If endxIndex is set to zero, then there
|
||||
// no upper bound.
|
||||
//
|
||||
func (rc *runContainer16) searchRange(key int, startIndex int, endxIndex int) (whichInterval16 int, alreadyPresent bool, numCompares int) {
|
||||
n := int(len(rc.iv))
|
||||
if n == 0 {
|
||||
|
|
@ -937,21 +935,20 @@ func (rc *runContainer16) searchRange(key int, startIndex int, endxIndex int) (w
|
|||
// If key is not already present, then whichInterval16 is
|
||||
// set as follows:
|
||||
//
|
||||
// a) whichInterval16 == len(rc.iv)-1 if key is beyond our
|
||||
// last interval16 in rc.iv;
|
||||
// a) whichInterval16 == len(rc.iv)-1 if key is beyond our
|
||||
// last interval16 in rc.iv;
|
||||
//
|
||||
// b) whichInterval16 == -1 if key is before our first
|
||||
// interval16 in rc.iv;
|
||||
// b) whichInterval16 == -1 if key is before our first
|
||||
// interval16 in rc.iv;
|
||||
//
|
||||
// c) whichInterval16 is set to the minimum index of rc.iv
|
||||
// which comes strictly before the key;
|
||||
// so rc.iv[whichInterval16].last < key,
|
||||
// and if whichInterval16+1 exists, then key < rc.iv[whichInterval16+1].start
|
||||
// (Note that whichInterval16+1 won't exist when
|
||||
// whichInterval16 is the last interval.)
|
||||
// c) whichInterval16 is set to the minimum index of rc.iv
|
||||
// which comes strictly before the key;
|
||||
// so rc.iv[whichInterval16].last < key,
|
||||
// and if whichInterval16+1 exists, then key < rc.iv[whichInterval16+1].start
|
||||
// (Note that whichInterval16+1 won't exist when
|
||||
// whichInterval16 is the last interval.)
|
||||
//
|
||||
// runContainer16.search always returns whichInterval16 < len(rc.iv).
|
||||
//
|
||||
func (rc *runContainer16) search(key int) (whichInterval16 int, alreadyPresent bool, numCompares int) {
|
||||
return rc.searchRange(key, 0, 0)
|
||||
}
|
||||
|
|
@ -994,7 +991,6 @@ func newRunContainer16() *runContainer16 {
|
|||
|
||||
// newRunContainer16CopyIv creates a run container, initializing
|
||||
// with a copy of the supplied iv slice.
|
||||
//
|
||||
func newRunContainer16CopyIv(iv []interval16) *runContainer16 {
|
||||
rc := &runContainer16{
|
||||
iv: make([]interval16, len(iv)),
|
||||
|
|
@ -1011,7 +1007,6 @@ func (rc *runContainer16) Clone() *runContainer16 {
|
|||
// newRunContainer16TakeOwnership returns a new runContainer16
|
||||
// backed by the provided iv slice, which we will
|
||||
// assume exclusive control over from now on.
|
||||
//
|
||||
func newRunContainer16TakeOwnership(iv []interval16) *runContainer16 {
|
||||
rc := &runContainer16{
|
||||
iv: iv,
|
||||
|
|
@ -2006,7 +2001,6 @@ func (rc *runContainer16) not(firstOfRange, endx int) container {
|
|||
// Current routine is correct but
|
||||
// makes 2 more passes through the arrays than should be
|
||||
// strictly necessary. Measure both ways though--this may not matter.
|
||||
//
|
||||
func (rc *runContainer16) Not(firstOfRange, endx int) *runContainer16 {
|
||||
|
||||
if firstOfRange > endx {
|
||||
|
|
@ -2329,7 +2323,6 @@ func runArrayUnionToRuns(rc *runContainer16, ac *arrayContainer) ([]interval16,
|
|||
// the backing array, and then you write
|
||||
// the answer at the beginning. What this
|
||||
// trick does is minimize memory allocations.
|
||||
//
|
||||
func (rc *runContainer16) lazyIOR(a container) container {
|
||||
// not lazy at the moment
|
||||
return rc.ior(a)
|
||||
|
|
|
|||
1
vendor/github.com/RoaringBitmap/roaring/serialization.go
generated
vendored
1
vendor/github.com/RoaringBitmap/roaring/serialization.go
generated
vendored
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
// writeTo for runContainer16 follows this
|
||||
// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||
//
|
||||
func (b *runContainer16) writeTo(stream io.Writer) (int, error) {
|
||||
buf := make([]byte, 2+4*len(b.iv))
|
||||
binary.LittleEndian.PutUint16(buf[0:], uint16(len(b.iv)))
|
||||
|
|
|
|||
94
vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
generated
vendored
94
vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
generated
vendored
|
|
@ -79,12 +79,12 @@ func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
|
|||
|
||||
// Deserialization code follows
|
||||
|
||||
////
|
||||
// //
|
||||
// These methods (byteSliceAsUint16Slice,...) do not make copies,
|
||||
// they are pointer-based (unsafe). The caller is responsible to
|
||||
// ensure that the input slice does not get garbage collected, deleted
|
||||
// or modified while you hold the returned slince.
|
||||
////
|
||||
// //
|
||||
func byteSliceAsUint16Slice(slice []byte) (result []uint16) { // here we create a new slice holder
|
||||
if len(slice)%2 != 0 {
|
||||
panic("Slice size should be divisible by 2")
|
||||
|
|
@ -295,7 +295,6 @@ func byteSliceAsBoolSlice(slice []byte) (result []bool) {
|
|||
// bitmap derived from this bitmap (e.g., via Or, And) might
|
||||
// also be broken. Thus, before making buf unavailable, you should
|
||||
// call CloneCopyOnWriteContainers on all such bitmaps.
|
||||
//
|
||||
func (rb *Bitmap) FrozenView(buf []byte) error {
|
||||
return rb.highlowcontainer.frozenView(buf)
|
||||
}
|
||||
|
|
@ -313,7 +312,7 @@ func (rb *Bitmap) FrozenView(buf []byte) error {
|
|||
* <typecodes> uint8_t[num_containers]
|
||||
* <header> uint32_t
|
||||
*
|
||||
* <header> is a 4-byte value which is a bit union of FROZEN_COOKIE (15 bits)
|
||||
* <header> is a 4-byte value which is a bit union of frozenCookie (15 bits)
|
||||
* and the number of containers (17 bits).
|
||||
*
|
||||
* <counts> stores number of elements for every container.
|
||||
|
|
@ -329,43 +328,50 @@ func (rb *Bitmap) FrozenView(buf []byte) error {
|
|||
* All members have their native alignments during deserilization except <header>,
|
||||
* which is not guaranteed to be aligned by 4 bytes.
|
||||
*/
|
||||
const FROZEN_COOKIE = 13766
|
||||
const frozenCookie = 13766
|
||||
|
||||
var (
|
||||
FrozenBitmapInvalidCookie = errors.New("header does not contain the FROZEN_COOKIE")
|
||||
FrozenBitmapBigEndian = errors.New("loading big endian frozen bitmaps is not supported")
|
||||
FrozenBitmapIncomplete = errors.New("input buffer too small to contain a frozen bitmap")
|
||||
FrozenBitmapOverpopulated = errors.New("too many containers")
|
||||
FrozenBitmapUnexpectedData = errors.New("spurious data in input")
|
||||
FrozenBitmapInvalidTypecode = errors.New("unrecognized typecode")
|
||||
FrozenBitmapBufferTooSmall = errors.New("buffer too small")
|
||||
// ErrFrozenBitmapInvalidCookie is returned when the header does not contain the frozenCookie.
|
||||
ErrFrozenBitmapInvalidCookie = errors.New("header does not contain the frozenCookie")
|
||||
// ErrFrozenBitmapBigEndian is returned when the header is big endian.
|
||||
ErrFrozenBitmapBigEndian = errors.New("loading big endian frozen bitmaps is not supported")
|
||||
// ErrFrozenBitmapIncomplete is returned when the buffer is too small to contain a frozen bitmap.
|
||||
ErrFrozenBitmapIncomplete = errors.New("input buffer too small to contain a frozen bitmap")
|
||||
// ErrFrozenBitmapOverpopulated is returned when the number of containers is too large.
|
||||
ErrFrozenBitmapOverpopulated = errors.New("too many containers")
|
||||
// ErrFrozenBitmapUnexpectedData is returned when the buffer contains unexpected data.
|
||||
ErrFrozenBitmapUnexpectedData = errors.New("spurious data in input")
|
||||
// ErrFrozenBitmapInvalidTypecode is returned when the typecode is invalid.
|
||||
ErrFrozenBitmapInvalidTypecode = errors.New("unrecognized typecode")
|
||||
// ErrFrozenBitmapBufferTooSmall is returned when the buffer is too small.
|
||||
ErrFrozenBitmapBufferTooSmall = errors.New("buffer too small")
|
||||
)
|
||||
|
||||
func (ra *roaringArray) frozenView(buf []byte) error {
|
||||
if len(buf) < 4 {
|
||||
return FrozenBitmapIncomplete
|
||||
return ErrFrozenBitmapIncomplete
|
||||
}
|
||||
|
||||
headerBE := binary.BigEndian.Uint32(buf[len(buf)-4:])
|
||||
if headerBE&0x7fff == FROZEN_COOKIE {
|
||||
return FrozenBitmapBigEndian
|
||||
if headerBE&0x7fff == frozenCookie {
|
||||
return ErrFrozenBitmapBigEndian
|
||||
}
|
||||
|
||||
header := binary.LittleEndian.Uint32(buf[len(buf)-4:])
|
||||
buf = buf[:len(buf)-4]
|
||||
|
||||
if header&0x7fff != FROZEN_COOKIE {
|
||||
return FrozenBitmapInvalidCookie
|
||||
if header&0x7fff != frozenCookie {
|
||||
return ErrFrozenBitmapInvalidCookie
|
||||
}
|
||||
|
||||
nCont := int(header >> 15)
|
||||
if nCont > (1 << 16) {
|
||||
return FrozenBitmapOverpopulated
|
||||
return ErrFrozenBitmapOverpopulated
|
||||
}
|
||||
|
||||
// 1 byte per type, 2 bytes per key, 2 bytes per count.
|
||||
if len(buf) < 5*nCont {
|
||||
return FrozenBitmapIncomplete
|
||||
return ErrFrozenBitmapIncomplete
|
||||
}
|
||||
|
||||
types := buf[len(buf)-nCont:]
|
||||
|
|
@ -390,12 +396,12 @@ func (ra *roaringArray) frozenView(buf []byte) error {
|
|||
nRun++
|
||||
nRunEl += int(counts[i])
|
||||
default:
|
||||
return FrozenBitmapInvalidTypecode
|
||||
return ErrFrozenBitmapInvalidTypecode
|
||||
}
|
||||
}
|
||||
|
||||
if len(buf) < (1<<13)*nBitmap+4*nRunEl+2*nArrayEl {
|
||||
return FrozenBitmapIncomplete
|
||||
return ErrFrozenBitmapIncomplete
|
||||
}
|
||||
|
||||
bitsetsArena := byteSliceAsUint64Slice(buf[:(1<<13)*nBitmap])
|
||||
|
|
@ -408,15 +414,15 @@ func (ra *roaringArray) frozenView(buf []byte) error {
|
|||
buf = buf[2*nArrayEl:]
|
||||
|
||||
if len(buf) != 0 {
|
||||
return FrozenBitmapUnexpectedData
|
||||
return ErrFrozenBitmapUnexpectedData
|
||||
}
|
||||
|
||||
var c container
|
||||
containersSz := int(unsafe.Sizeof(c))*nCont
|
||||
bitsetsSz := int(unsafe.Sizeof(bitmapContainer{}))*nBitmap
|
||||
arraysSz := int(unsafe.Sizeof(arrayContainer{}))*nArray
|
||||
runsSz := int(unsafe.Sizeof(runContainer16{}))*nRun
|
||||
needCOWSz := int(unsafe.Sizeof(true))*nCont
|
||||
containersSz := int(unsafe.Sizeof(c)) * nCont
|
||||
bitsetsSz := int(unsafe.Sizeof(bitmapContainer{})) * nBitmap
|
||||
arraysSz := int(unsafe.Sizeof(arrayContainer{})) * nArray
|
||||
runsSz := int(unsafe.Sizeof(runContainer16{})) * nRun
|
||||
needCOWSz := int(unsafe.Sizeof(true)) * nCont
|
||||
|
||||
bitmapArenaSz := containersSz + bitsetsSz + arraysSz + runsSz + needCOWSz
|
||||
bitmapArena := make([]byte, bitmapArenaSz)
|
||||
|
|
@ -475,9 +481,10 @@ func (ra *roaringArray) frozenView(buf []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (bm *Bitmap) GetFrozenSizeInBytes() uint64 {
|
||||
// GetFrozenSizeInBytes returns the size in bytes of the frozen bitmap.
|
||||
func (rb *Bitmap) GetFrozenSizeInBytes() uint64 {
|
||||
nBits, nArrayEl, nRunEl := uint64(0), uint64(0), uint64(0)
|
||||
for _, c := range bm.highlowcontainer.containers {
|
||||
for _, c := range rb.highlowcontainer.containers {
|
||||
switch v := c.(type) {
|
||||
case *bitmapContainer:
|
||||
nBits++
|
||||
|
|
@ -487,19 +494,21 @@ func (bm *Bitmap) GetFrozenSizeInBytes() uint64 {
|
|||
nRunEl += uint64(len(v.iv))
|
||||
}
|
||||
}
|
||||
return 4 + 5*uint64(len(bm.highlowcontainer.containers)) +
|
||||
return 4 + 5*uint64(len(rb.highlowcontainer.containers)) +
|
||||
(nBits << 13) + 2*nArrayEl + 4*nRunEl
|
||||
}
|
||||
|
||||
func (bm *Bitmap) Freeze() ([]byte, error) {
|
||||
sz := bm.GetFrozenSizeInBytes()
|
||||
// Freeze serializes the bitmap in the CRoaring's frozen format.
|
||||
func (rb *Bitmap) Freeze() ([]byte, error) {
|
||||
sz := rb.GetFrozenSizeInBytes()
|
||||
buf := make([]byte, sz)
|
||||
_, err := bm.FreezeTo(buf)
|
||||
_, err := rb.FreezeTo(buf)
|
||||
return buf, err
|
||||
}
|
||||
|
||||
func (bm *Bitmap) FreezeTo(buf []byte) (int, error) {
|
||||
containers := bm.highlowcontainer.containers
|
||||
// FreezeTo serializes the bitmap in the CRoaring's frozen format.
|
||||
func (rb *Bitmap) FreezeTo(buf []byte) (int, error) {
|
||||
containers := rb.highlowcontainer.containers
|
||||
nCont := len(containers)
|
||||
|
||||
nBits, nArrayEl, nRunEl := 0, 0, 0
|
||||
|
|
@ -516,7 +525,7 @@ func (bm *Bitmap) FreezeTo(buf []byte) (int, error) {
|
|||
|
||||
serialSize := 4 + 5*nCont + (1<<13)*nBits + 4*nRunEl + 2*nArrayEl
|
||||
if len(buf) < serialSize {
|
||||
return 0, FrozenBitmapBufferTooSmall
|
||||
return 0, ErrFrozenBitmapBufferTooSmall
|
||||
}
|
||||
|
||||
bitsArena := byteSliceAsUint64Slice(buf[:(1<<13)*nBits])
|
||||
|
|
@ -537,10 +546,10 @@ func (bm *Bitmap) FreezeTo(buf []byte) (int, error) {
|
|||
types := buf[:nCont]
|
||||
buf = buf[nCont:]
|
||||
|
||||
header := uint32(FROZEN_COOKIE | (nCont << 15))
|
||||
header := uint32(frozenCookie | (nCont << 15))
|
||||
binary.LittleEndian.PutUint32(buf[:4], header)
|
||||
|
||||
copy(keys, bm.highlowcontainer.keys[:])
|
||||
copy(keys, rb.highlowcontainer.keys[:])
|
||||
|
||||
for i, c := range containers {
|
||||
switch v := c.(type) {
|
||||
|
|
@ -567,11 +576,12 @@ func (bm *Bitmap) FreezeTo(buf []byte) (int, error) {
|
|||
return serialSize, nil
|
||||
}
|
||||
|
||||
func (bm *Bitmap) WriteFrozenTo(wr io.Writer) (int, error) {
|
||||
// WriteFrozenTo serializes the bitmap in the CRoaring's frozen format.
|
||||
func (rb *Bitmap) WriteFrozenTo(wr io.Writer) (int, error) {
|
||||
// FIXME: this is a naive version that iterates 4 times through the
|
||||
// containers and allocates 3*len(containers) bytes; it's quite likely
|
||||
// it can be done more efficiently.
|
||||
containers := bm.highlowcontainer.containers
|
||||
containers := rb.highlowcontainer.containers
|
||||
written := 0
|
||||
|
||||
for _, c := range containers {
|
||||
|
|
@ -610,7 +620,7 @@ func (bm *Bitmap) WriteFrozenTo(wr io.Writer) (int, error) {
|
|||
}
|
||||
}
|
||||
|
||||
n, err := wr.Write(uint16SliceAsByteSlice(bm.highlowcontainer.keys))
|
||||
n, err := wr.Write(uint16SliceAsByteSlice(rb.highlowcontainer.keys))
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
|
|
@ -642,7 +652,7 @@ func (bm *Bitmap) WriteFrozenTo(wr io.Writer) (int, error) {
|
|||
return written, err
|
||||
}
|
||||
|
||||
header := uint32(FROZEN_COOKIE | (len(containers) << 15))
|
||||
header := uint32(frozenCookie | (len(containers) << 15))
|
||||
if err := binary.Write(wr, binary.LittleEndian, header); err != nil {
|
||||
return written, err
|
||||
}
|
||||
|
|
|
|||
95
vendor/github.com/bits-and-blooms/bitset/README.md
generated
vendored
95
vendor/github.com/bits-and-blooms/bitset/README.md
generated
vendored
|
|
@ -7,6 +7,15 @@
|
|||
[](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-public-snapshot)
|
||||
* [torrent](https://github.com/anacrolix/torrent)
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
Package bitset implements bitsets, a mapping between non-negative integers and boolean values.
|
||||
|
|
@ -16,7 +25,7 @@ It provides methods for setting, clearing, flipping, and testing individual inte
|
|||
|
||||
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.
|
||||
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 automatically, but `Shrink` and `Compact` methods are available. 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.
|
||||
|
||||
|
|
@ -60,19 +69,83 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets.
|
||||
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
|
||||
|
||||
## 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 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](https://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring).
|
||||
|
||||
## Implementation Note
|
||||
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)
|
||||
```
|
||||
|
||||
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 `unit64`). If so, the version will be bumped.
|
||||
### Goroutine safety
|
||||
|
||||
In general, it's not safe to access the same BitSet using different goroutines--they are unsynchronized for performance.
|
||||
|
||||
Should you want to access a BitSet from more than one goroutine, you should provide synchronization. Typically this is done by using channels to pass the *BitSet around (in Go style; so there is only ever one owner), or by using `sync.Mutex` to serialize operations on BitSets.
|
||||
|
||||
## Installation
|
||||
|
||||
|
|
@ -91,3 +164,13 @@ Before committing the code, please check if it passes tests, has adequate covera
|
|||
go test
|
||||
go test -cover
|
||||
```
|
||||
|
||||
## Stars
|
||||
|
||||
|
||||
[](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>
|
||||
|
|
|
|||
5
vendor/github.com/bits-and-blooms/bitset/SECURITY.md
generated
vendored
Normal file
5
vendor/github.com/bits-and-blooms/bitset/SECURITY.md
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
You can report privately a vulnerability by email at daniel@lemire.me (current maintainer).
|
||||
1052
vendor/github.com/bits-and-blooms/bitset/bitset.go
generated
vendored
1052
vendor/github.com/bits-and-blooms/bitset/bitset.go
generated
vendored
File diff suppressed because it is too large
Load diff
23
vendor/github.com/bits-and-blooms/bitset/bitset_iter.go
generated
vendored
Normal file
23
vendor/github.com/bits-and-blooms/bitset/bitset_iter.go
generated
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8866
vendor/github.com/bits-and-blooms/bitset/pext.gen.go
generated
vendored
Normal file
8866
vendor/github.com/bits-and-blooms/bitset/pext.gen.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
61
vendor/github.com/bits-and-blooms/bitset/popcnt.go
generated
vendored
61
vendor/github.com/bits-and-blooms/bitset/popcnt.go
generated
vendored
|
|
@ -1,53 +1,52 @@
|
|||
package 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
|
||||
}
|
||||
import "math/bits"
|
||||
|
||||
func popcntSliceGo(s []uint64) uint64 {
|
||||
cnt := uint64(0)
|
||||
func popcntSlice(s []uint64) (cnt uint64) {
|
||||
for _, x := range s {
|
||||
cnt += popcount(x)
|
||||
cnt += uint64(bits.OnesCount64(x))
|
||||
}
|
||||
return cnt
|
||||
return
|
||||
}
|
||||
|
||||
func popcntMaskSliceGo(s, m []uint64) uint64 {
|
||||
cnt := uint64(0)
|
||||
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 += popcount(s[i] &^ m[i])
|
||||
cnt += uint64(bits.OnesCount64(s[i] &^ m[i]))
|
||||
}
|
||||
return cnt
|
||||
return
|
||||
}
|
||||
|
||||
func popcntAndSliceGo(s, m []uint64) uint64 {
|
||||
cnt := uint64(0)
|
||||
// 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 += popcount(s[i] & m[i])
|
||||
cnt += uint64(bits.OnesCount64(s[i] & m[i]))
|
||||
}
|
||||
return cnt
|
||||
return
|
||||
}
|
||||
|
||||
func popcntOrSliceGo(s, m []uint64) uint64 {
|
||||
cnt := uint64(0)
|
||||
// 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 += popcount(s[i] | m[i])
|
||||
cnt += uint64(bits.OnesCount64(s[i] | m[i]))
|
||||
}
|
||||
return cnt
|
||||
return
|
||||
}
|
||||
|
||||
func popcntXorSliceGo(s, m []uint64) uint64 {
|
||||
cnt := uint64(0)
|
||||
// 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 += popcount(s[i] ^ m[i])
|
||||
cnt += uint64(bits.OnesCount64(s[i] ^ m[i]))
|
||||
}
|
||||
return cnt
|
||||
return
|
||||
}
|
||||
|
|
|
|||
45
vendor/github.com/bits-and-blooms/bitset/popcnt_19.go
generated
vendored
45
vendor/github.com/bits-and-blooms/bitset/popcnt_19.go
generated
vendored
|
|
@ -1,45 +0,0 @@
|
|||
// +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
|
||||
for i := range s {
|
||||
cnt += bits.OnesCount64(s[i] &^ m[i])
|
||||
}
|
||||
return uint64(cnt)
|
||||
}
|
||||
|
||||
func popcntAndSlice(s, m []uint64) uint64 {
|
||||
var cnt int
|
||||
for i := range s {
|
||||
cnt += bits.OnesCount64(s[i] & m[i])
|
||||
}
|
||||
return uint64(cnt)
|
||||
}
|
||||
|
||||
func popcntOrSlice(s, m []uint64) uint64 {
|
||||
var cnt int
|
||||
for i := range s {
|
||||
cnt += bits.OnesCount64(s[i] | m[i])
|
||||
}
|
||||
return uint64(cnt)
|
||||
}
|
||||
|
||||
func popcntXorSlice(s, m []uint64) uint64 {
|
||||
var cnt int
|
||||
for i := range s {
|
||||
cnt += bits.OnesCount64(s[i] ^ m[i])
|
||||
}
|
||||
return uint64(cnt)
|
||||
}
|
||||
68
vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go
generated
vendored
68
vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go
generated
vendored
|
|
@ -1,68 +0,0 @@
|
|||
// +build !go1.9
|
||||
// +build 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)
|
||||
}
|
||||
104
vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s
generated
vendored
104
vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s
generated
vendored
|
|
@ -1,104 +0,0 @@
|
|||
// +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
|
||||
24
vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go
generated
vendored
24
vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go
generated
vendored
|
|
@ -1,24 +0,0 @@
|
|||
// +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)
|
||||
}
|
||||
47
vendor/github.com/bits-and-blooms/bitset/select.go
generated
vendored
Normal file
47
vendor/github.com/bits-and-blooms/bitset/select.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package bitset
|
||||
|
||||
import "math/bits"
|
||||
|
||||
func select64(w uint64, j uint) uint {
|
||||
seen := 0
|
||||
// Divide 64bit
|
||||
part := w & 0xFFFFFFFF
|
||||
n := uint(bits.OnesCount64(part))
|
||||
if n <= j {
|
||||
part = w >> 32
|
||||
seen += 32
|
||||
j -= n
|
||||
}
|
||||
ww := part
|
||||
|
||||
// Divide 32bit
|
||||
part = ww & 0xFFFF
|
||||
|
||||
n = uint(bits.OnesCount64(part))
|
||||
if n <= j {
|
||||
part = ww >> 16
|
||||
seen += 16
|
||||
j -= n
|
||||
}
|
||||
ww = part
|
||||
|
||||
// Divide 16bit
|
||||
part = ww & 0xFF
|
||||
n = uint(bits.OnesCount64(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)
|
||||
}
|
||||
14
vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go
generated
vendored
14
vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go
generated
vendored
|
|
@ -1,14 +0,0 @@
|
|||
// +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])
|
||||
}
|
||||
9
vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go
generated
vendored
9
vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go
generated
vendored
|
|
@ -1,9 +0,0 @@
|
|||
// +build go1.9
|
||||
|
||||
package bitset
|
||||
|
||||
import "math/bits"
|
||||
|
||||
func trailingZeroes64(v uint64) uint {
|
||||
return uint(bits.TrailingZeros64(v))
|
||||
}
|
||||
8
vendor/github.com/boombuler/barcode/barcode.go
generated
vendored
8
vendor/github.com/boombuler/barcode/barcode.go
generated
vendored
|
|
@ -1,6 +1,8 @@
|
|||
package barcode
|
||||
|
||||
import "image"
|
||||
import (
|
||||
"image"
|
||||
)
|
||||
|
||||
const (
|
||||
TypeAztec = "Aztec"
|
||||
|
|
@ -40,3 +42,7 @@ type BarcodeIntCS interface {
|
|||
Barcode
|
||||
CheckSum() int
|
||||
}
|
||||
|
||||
type BarcodeColor interface {
|
||||
ColorScheme() ColorScheme
|
||||
}
|
||||
|
|
|
|||
39
vendor/github.com/boombuler/barcode/color_scheme.go
generated
vendored
Normal file
39
vendor/github.com/boombuler/barcode/color_scheme.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package barcode
|
||||
|
||||
import "image/color"
|
||||
|
||||
// ColorScheme defines a structure for color schemes used in barcode rendering.
|
||||
// It includes the color model, background color, and foreground color.
|
||||
type ColorScheme struct {
|
||||
Model color.Model // Color model to be used (e.g., grayscale, RGB, RGBA)
|
||||
Background color.Color // Color of the background
|
||||
Foreground color.Color // Color of the foreground (e.g., bars in a barcode)
|
||||
}
|
||||
|
||||
// ColorScheme8 represents a color scheme with 8-bit grayscale colors.
|
||||
var ColorScheme8 = ColorScheme{
|
||||
Model: color.GrayModel,
|
||||
Background: color.Gray{Y: 255},
|
||||
Foreground: color.Gray{Y: 0},
|
||||
}
|
||||
|
||||
// ColorScheme16 represents a color scheme with 16-bit grayscale colors.
|
||||
var ColorScheme16 = ColorScheme{
|
||||
Model: color.Gray16Model,
|
||||
Background: color.White,
|
||||
Foreground: color.Black,
|
||||
}
|
||||
|
||||
// ColorScheme24 represents a color scheme with 24-bit RGB colors.
|
||||
var ColorScheme24 = ColorScheme{
|
||||
Model: color.RGBAModel,
|
||||
Background: color.RGBA{255, 255, 255, 255},
|
||||
Foreground: color.RGBA{0, 0, 0, 255},
|
||||
}
|
||||
|
||||
// ColorScheme32 represents a color scheme with 32-bit RGBA colors, which is similar to ColorScheme24 but typically includes alpha for transparency.
|
||||
var ColorScheme32 = ColorScheme{
|
||||
Model: color.RGBAModel,
|
||||
Background: color.RGBA{255, 255, 255, 255},
|
||||
Foreground: color.RGBA{0, 0, 0, 255},
|
||||
}
|
||||
16
vendor/github.com/boombuler/barcode/qr/encoder.go
generated
vendored
16
vendor/github.com/boombuler/barcode/qr/encoder.go
generated
vendored
|
|
@ -54,8 +54,8 @@ func (e Encoding) String() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// Encode returns a QR barcode with the given content, error correction level and uses the given encoding
|
||||
func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.Barcode, error) {
|
||||
// Encode returns a QR barcode with the given content and color scheme, error correction level and uses the given encoding
|
||||
func EncodeWithColor(content string, level ErrorCorrectionLevel, mode Encoding, color barcode.ColorScheme) (barcode.Barcode, error) {
|
||||
bits, vi, err := mode.getEncoder()(content, level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -63,19 +63,23 @@ func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.
|
|||
|
||||
blocks := splitToBlocks(bits.IterateBytes(), vi)
|
||||
data := blocks.interleave(vi)
|
||||
result := render(data, vi)
|
||||
result := render(data, vi, color)
|
||||
result.content = content
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func render(data []byte, vi *versionInfo) *qrcode {
|
||||
func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.Barcode, error) {
|
||||
return EncodeWithColor(content, level, mode, barcode.ColorScheme16)
|
||||
}
|
||||
|
||||
func render(data []byte, vi *versionInfo, color barcode.ColorScheme) *qrcode {
|
||||
dim := vi.modulWidth()
|
||||
results := make([]*qrcode, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
results[i] = newBarcode(dim)
|
||||
results[i] = newBarCodeWithColor(dim, color)
|
||||
}
|
||||
|
||||
occupied := newBarcode(dim)
|
||||
occupied := newBarCodeWithColor(dim, color)
|
||||
|
||||
setAll := func(x int, y int, val bool) {
|
||||
occupied.Set(x, y, true)
|
||||
|
|
|
|||
18
vendor/github.com/boombuler/barcode/qr/qrcode.go
generated
vendored
18
vendor/github.com/boombuler/barcode/qr/qrcode.go
generated
vendored
|
|
@ -13,6 +13,7 @@ type qrcode struct {
|
|||
dimension int
|
||||
data *utils.BitList
|
||||
content string
|
||||
color barcode.ColorScheme
|
||||
}
|
||||
|
||||
func (qr *qrcode) Content() string {
|
||||
|
|
@ -24,7 +25,11 @@ func (qr *qrcode) Metadata() barcode.Metadata {
|
|||
}
|
||||
|
||||
func (qr *qrcode) ColorModel() color.Model {
|
||||
return color.Gray16Model
|
||||
return qr.color.Model
|
||||
}
|
||||
|
||||
func (c *qrcode) ColorScheme() barcode.ColorScheme {
|
||||
return c.color
|
||||
}
|
||||
|
||||
func (qr *qrcode) Bounds() image.Rectangle {
|
||||
|
|
@ -33,9 +38,9 @@ func (qr *qrcode) Bounds() image.Rectangle {
|
|||
|
||||
func (qr *qrcode) At(x, y int) color.Color {
|
||||
if qr.Get(x, y) {
|
||||
return color.Black
|
||||
return qr.color.Foreground
|
||||
}
|
||||
return color.White
|
||||
return qr.color.Background
|
||||
}
|
||||
|
||||
func (qr *qrcode) Get(x, y int) bool {
|
||||
|
|
@ -158,9 +163,14 @@ func (qr *qrcode) calcPenaltyRule4() uint {
|
|||
return uint(math.Min(floor, ceil) * 10)
|
||||
}
|
||||
|
||||
func newBarcode(dim int) *qrcode {
|
||||
func newBarCodeWithColor(dim int, color barcode.ColorScheme) *qrcode {
|
||||
res := new(qrcode)
|
||||
res.dimension = dim
|
||||
res.data = utils.NewBitList(dim * dim)
|
||||
res.color = color
|
||||
return res
|
||||
}
|
||||
|
||||
func newBarcode(dim int) *qrcode {
|
||||
return newBarCodeWithColor(dim, barcode.ColorScheme16)
|
||||
}
|
||||
|
|
|
|||
27
vendor/github.com/boombuler/barcode/scaledbarcode.go
generated
vendored
27
vendor/github.com/boombuler/barcode/scaledbarcode.go
generated
vendored
|
|
@ -49,11 +49,22 @@ func (bc *intCSscaledBC) CheckSum() int {
|
|||
|
||||
// Scale returns a resized barcode with the given width and height.
|
||||
func Scale(bc Barcode, width, height int) (Barcode, error) {
|
||||
var fill color.Color
|
||||
if v, ok := bc.(BarcodeColor); ok {
|
||||
fill = v.ColorScheme().Background
|
||||
} else {
|
||||
fill = color.White
|
||||
}
|
||||
return ScaleWithFill(bc, width, height, fill)
|
||||
}
|
||||
|
||||
// Scale returns a resized barcode with the given width, height and fill color.
|
||||
func ScaleWithFill(bc Barcode, width, height int, fill color.Color) (Barcode, error) {
|
||||
switch bc.Metadata().Dimensions {
|
||||
case 1:
|
||||
return scale1DCode(bc, width, height)
|
||||
return scale1DCode(bc, width, height, fill)
|
||||
case 2:
|
||||
return scale2DCode(bc, width, height)
|
||||
return scale2DCode(bc, width, height, fill)
|
||||
}
|
||||
|
||||
return nil, errors.New("unsupported barcode format")
|
||||
|
|
@ -72,7 +83,7 @@ func newScaledBC(wrapped Barcode, wrapperFunc wrapFunc, rect image.Rectangle) Ba
|
|||
return result
|
||||
}
|
||||
|
||||
func scale2DCode(bc Barcode, width, height int) (Barcode, error) {
|
||||
func scale2DCode(bc Barcode, width, height int, fill color.Color) (Barcode, error) {
|
||||
orgBounds := bc.Bounds()
|
||||
orgWidth := orgBounds.Max.X - orgBounds.Min.X
|
||||
orgHeight := orgBounds.Max.Y - orgBounds.Min.Y
|
||||
|
|
@ -87,12 +98,12 @@ func scale2DCode(bc Barcode, width, height int) (Barcode, error) {
|
|||
|
||||
wrap := func(x, y int) color.Color {
|
||||
if x < offsetX || y < offsetY {
|
||||
return color.White
|
||||
return fill
|
||||
}
|
||||
x = (x - offsetX) / factor
|
||||
y = (y - offsetY) / factor
|
||||
if x >= orgWidth || y >= orgHeight {
|
||||
return color.White
|
||||
return fill
|
||||
}
|
||||
return bc.At(x, y)
|
||||
}
|
||||
|
|
@ -104,7 +115,7 @@ func scale2DCode(bc Barcode, width, height int) (Barcode, error) {
|
|||
), nil
|
||||
}
|
||||
|
||||
func scale1DCode(bc Barcode, width, height int) (Barcode, error) {
|
||||
func scale1DCode(bc Barcode, width, height int, fill color.Color) (Barcode, error) {
|
||||
orgBounds := bc.Bounds()
|
||||
orgWidth := orgBounds.Max.X - orgBounds.Min.X
|
||||
factor := int(float64(width) / float64(orgWidth))
|
||||
|
|
@ -116,12 +127,12 @@ func scale1DCode(bc Barcode, width, height int) (Barcode, error) {
|
|||
|
||||
wrap := func(x, y int) color.Color {
|
||||
if x < offsetX {
|
||||
return color.White
|
||||
return fill
|
||||
}
|
||||
x = (x - offsetX) / factor
|
||||
|
||||
if x >= orgWidth {
|
||||
return color.White
|
||||
return fill
|
||||
}
|
||||
return bc.At(x, 0)
|
||||
}
|
||||
|
|
|
|||
25
vendor/github.com/boombuler/barcode/utils/base1dcode.go
generated
vendored
25
vendor/github.com/boombuler/barcode/utils/base1dcode.go
generated
vendored
|
|
@ -12,6 +12,7 @@ type base1DCode struct {
|
|||
*BitList
|
||||
kind string
|
||||
content string
|
||||
color barcode.ColorScheme
|
||||
}
|
||||
|
||||
type base1DCodeIntCS struct {
|
||||
|
|
@ -28,7 +29,11 @@ func (c *base1DCode) Metadata() barcode.Metadata {
|
|||
}
|
||||
|
||||
func (c *base1DCode) ColorModel() color.Model {
|
||||
return color.Gray16Model
|
||||
return c.color.Model
|
||||
}
|
||||
|
||||
func (c *base1DCode) ColorScheme() barcode.ColorScheme {
|
||||
return c.color
|
||||
}
|
||||
|
||||
func (c *base1DCode) Bounds() image.Rectangle {
|
||||
|
|
@ -37,9 +42,9 @@ func (c *base1DCode) Bounds() image.Rectangle {
|
|||
|
||||
func (c *base1DCode) At(x, y int) color.Color {
|
||||
if c.GetBit(x) {
|
||||
return color.Black
|
||||
return c.color.Foreground
|
||||
}
|
||||
return color.White
|
||||
return c.color.Background
|
||||
}
|
||||
|
||||
func (c *base1DCodeIntCS) CheckSum() int {
|
||||
|
|
@ -48,10 +53,20 @@ func (c *base1DCodeIntCS) CheckSum() int {
|
|||
|
||||
// New1DCodeIntCheckSum creates a new 1D barcode where the bars are represented by the bits in the bars BitList
|
||||
func New1DCodeIntCheckSum(codeKind, content string, bars *BitList, checksum int) barcode.BarcodeIntCS {
|
||||
return &base1DCodeIntCS{base1DCode{bars, codeKind, content}, checksum}
|
||||
return &base1DCodeIntCS{base1DCode{bars, codeKind, content, barcode.ColorScheme16}, checksum}
|
||||
}
|
||||
|
||||
// New1DCodeIntCheckSum creates a new 1D barcode where the bars are represented by the bits in the bars BitList
|
||||
func New1DCodeIntCheckSumWithColor(codeKind, content string, bars *BitList, checksum int, color barcode.ColorScheme) barcode.BarcodeIntCS {
|
||||
return &base1DCodeIntCS{base1DCode{bars, codeKind, content, color}, checksum}
|
||||
}
|
||||
|
||||
// New1DCode creates a new 1D barcode where the bars are represented by the bits in the bars BitList
|
||||
func New1DCode(codeKind, content string, bars *BitList) barcode.Barcode {
|
||||
return &base1DCode{bars, codeKind, content}
|
||||
return &base1DCode{bars, codeKind, content, barcode.ColorScheme16}
|
||||
}
|
||||
|
||||
// New1DCode creates a new 1D barcode where the bars are represented by the bits in the bars BitList
|
||||
func New1DCodeWithColor(codeKind, content string, bars *BitList, color barcode.ColorScheme) barcode.Barcode {
|
||||
return &base1DCode{bars, codeKind, content, color}
|
||||
}
|
||||
|
|
|
|||
62
vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go
generated
vendored
Normal file
62
vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package md2man
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/russross/blackfriday/v2"
|
||||
)
|
||||
|
||||
func fmtListFlags(flags blackfriday.ListType) string {
|
||||
knownFlags := []struct {
|
||||
name string
|
||||
flag blackfriday.ListType
|
||||
}{
|
||||
{"ListTypeOrdered", blackfriday.ListTypeOrdered},
|
||||
{"ListTypeDefinition", blackfriday.ListTypeDefinition},
|
||||
{"ListTypeTerm", blackfriday.ListTypeTerm},
|
||||
{"ListItemContainsBlock", blackfriday.ListItemContainsBlock},
|
||||
{"ListItemBeginningOfList", blackfriday.ListItemBeginningOfList},
|
||||
{"ListItemEndOfList", blackfriday.ListItemEndOfList},
|
||||
}
|
||||
|
||||
var f []string
|
||||
for _, kf := range knownFlags {
|
||||
if flags&kf.flag != 0 {
|
||||
f = append(f, kf.name)
|
||||
flags &^= kf.flag
|
||||
}
|
||||
}
|
||||
if flags != 0 {
|
||||
f = append(f, fmt.Sprintf("Unknown(%#x)", flags))
|
||||
}
|
||||
return strings.Join(f, "|")
|
||||
}
|
||||
|
||||
type debugDecorator struct {
|
||||
blackfriday.Renderer
|
||||
}
|
||||
|
||||
func depth(node *blackfriday.Node) int {
|
||||
d := 0
|
||||
for n := node.Parent; n != nil; n = n.Parent {
|
||||
d++
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *debugDecorator) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
|
||||
fmt.Fprintf(os.Stderr, "%s%s %v %v\n",
|
||||
strings.Repeat(" ", depth(node)),
|
||||
map[bool]string{true: "+", false: "-"}[entering],
|
||||
node,
|
||||
fmtListFlags(node.ListFlags))
|
||||
var b strings.Builder
|
||||
status := d.Renderer.RenderNode(io.MultiWriter(&b, w), node, entering)
|
||||
if b.Len() > 0 {
|
||||
fmt.Fprintf(os.Stderr, ">> %q\n", b.String())
|
||||
}
|
||||
return status
|
||||
}
|
||||
14
vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
generated
vendored
14
vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
generated
vendored
|
|
@ -1,14 +1,24 @@
|
|||
// Package md2man aims in converting markdown into roff (man pages).
|
||||
package md2man
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/russross/blackfriday/v2"
|
||||
)
|
||||
|
||||
// Render converts a markdown document into a roff formatted document.
|
||||
func Render(doc []byte) []byte {
|
||||
renderer := NewRoffRenderer()
|
||||
var r blackfriday.Renderer = renderer
|
||||
if v, _ := strconv.ParseBool(os.Getenv("MD2MAN_DEBUG")); v {
|
||||
r = &debugDecorator{Renderer: r}
|
||||
}
|
||||
|
||||
return blackfriday.Run(doc,
|
||||
[]blackfriday.Option{blackfriday.WithRenderer(renderer),
|
||||
blackfriday.WithExtensions(renderer.GetExtensions())}...)
|
||||
[]blackfriday.Option{
|
||||
blackfriday.WithRenderer(r),
|
||||
blackfriday.WithExtensions(renderer.GetExtensions()),
|
||||
}...)
|
||||
}
|
||||
|
|
|
|||
222
vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
generated
vendored
222
vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
generated
vendored
|
|
@ -1,6 +1,8 @@
|
|||
package md2man
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
|
@ -12,68 +14,72 @@ import (
|
|||
// roffRenderer implements the blackfriday.Renderer interface for creating
|
||||
// roff format (manpages) from markdown text
|
||||
type roffRenderer struct {
|
||||
extensions blackfriday.Extensions
|
||||
listCounters []int
|
||||
firstHeader bool
|
||||
firstDD bool
|
||||
listDepth int
|
||||
}
|
||||
|
||||
const (
|
||||
titleHeader = ".TH "
|
||||
topLevelHeader = "\n\n.SH "
|
||||
secondLevelHdr = "\n.SH "
|
||||
otherHeader = "\n.SS "
|
||||
crTag = "\n"
|
||||
emphTag = "\\fI"
|
||||
emphCloseTag = "\\fP"
|
||||
strongTag = "\\fB"
|
||||
strongCloseTag = "\\fP"
|
||||
breakTag = "\n.br\n"
|
||||
paraTag = "\n.PP\n"
|
||||
hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n"
|
||||
linkTag = "\n\\[la]"
|
||||
linkCloseTag = "\\[ra]"
|
||||
codespanTag = "\\fB\\fC"
|
||||
codespanCloseTag = "\\fR"
|
||||
codeTag = "\n.PP\n.RS\n\n.nf\n"
|
||||
codeCloseTag = "\n.fi\n.RE\n"
|
||||
quoteTag = "\n.PP\n.RS\n"
|
||||
quoteCloseTag = "\n.RE\n"
|
||||
listTag = "\n.RS\n"
|
||||
listCloseTag = "\n.RE\n"
|
||||
dtTag = "\n.TP\n"
|
||||
dd2Tag = "\n"
|
||||
tableStart = "\n.TS\nallbox;\n"
|
||||
tableEnd = ".TE\n"
|
||||
tableCellStart = "T{\n"
|
||||
tableCellEnd = "\nT}\n"
|
||||
titleHeader = ".TH "
|
||||
topLevelHeader = "\n\n.SH "
|
||||
secondLevelHdr = "\n.SH "
|
||||
otherHeader = "\n.SS "
|
||||
crTag = "\n"
|
||||
emphTag = "\\fI"
|
||||
emphCloseTag = "\\fP"
|
||||
strongTag = "\\fB"
|
||||
strongCloseTag = "\\fP"
|
||||
breakTag = "\n.br\n"
|
||||
paraTag = "\n.PP\n"
|
||||
hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n"
|
||||
linkTag = "\n\\[la]"
|
||||
linkCloseTag = "\\[ra]"
|
||||
codespanTag = "\\fB"
|
||||
codespanCloseTag = "\\fR"
|
||||
codeTag = "\n.EX\n"
|
||||
codeCloseTag = ".EE\n" // Do not prepend a newline character since code blocks, by definition, include a newline already (or at least as how blackfriday gives us on).
|
||||
quoteTag = "\n.PP\n.RS\n"
|
||||
quoteCloseTag = "\n.RE\n"
|
||||
listTag = "\n.RS\n"
|
||||
listCloseTag = ".RE\n"
|
||||
dtTag = "\n.TP\n"
|
||||
dd2Tag = "\n"
|
||||
tableStart = "\n.TS\nallbox;\n"
|
||||
tableEnd = ".TE\n"
|
||||
tableCellStart = "T{\n"
|
||||
tableCellEnd = "\nT}"
|
||||
tablePreprocessor = `'\" t`
|
||||
)
|
||||
|
||||
// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
|
||||
// from markdown
|
||||
func NewRoffRenderer() *roffRenderer { // nolint: golint
|
||||
var extensions blackfriday.Extensions
|
||||
|
||||
extensions |= blackfriday.NoIntraEmphasis
|
||||
extensions |= blackfriday.Tables
|
||||
extensions |= blackfriday.FencedCode
|
||||
extensions |= blackfriday.SpaceHeadings
|
||||
extensions |= blackfriday.Footnotes
|
||||
extensions |= blackfriday.Titleblock
|
||||
extensions |= blackfriday.DefinitionLists
|
||||
return &roffRenderer{
|
||||
extensions: extensions,
|
||||
}
|
||||
func NewRoffRenderer() *roffRenderer {
|
||||
return &roffRenderer{}
|
||||
}
|
||||
|
||||
// GetExtensions returns the list of extensions used by this renderer implementation
|
||||
func (r *roffRenderer) GetExtensions() blackfriday.Extensions {
|
||||
return r.extensions
|
||||
func (*roffRenderer) GetExtensions() blackfriday.Extensions {
|
||||
return blackfriday.NoIntraEmphasis |
|
||||
blackfriday.Tables |
|
||||
blackfriday.FencedCode |
|
||||
blackfriday.SpaceHeadings |
|
||||
blackfriday.Footnotes |
|
||||
blackfriday.Titleblock |
|
||||
blackfriday.DefinitionLists
|
||||
}
|
||||
|
||||
// RenderHeader handles outputting the header at document start
|
||||
func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) {
|
||||
// We need to walk the tree to check if there are any tables.
|
||||
// If there are, we need to enable the roff table preprocessor.
|
||||
ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
|
||||
if node.Type == blackfriday.Table {
|
||||
out(w, tablePreprocessor+"\n")
|
||||
return blackfriday.Terminate
|
||||
}
|
||||
return blackfriday.GoToNext
|
||||
})
|
||||
|
||||
// disable hyphenation
|
||||
out(w, ".nh\n")
|
||||
}
|
||||
|
|
@ -86,12 +92,27 @@ func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) {
|
|||
// RenderNode is called for each node in a markdown document; based on the node
|
||||
// type the equivalent roff output is sent to the writer
|
||||
func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
|
||||
|
||||
var walkAction = blackfriday.GoToNext
|
||||
walkAction := blackfriday.GoToNext
|
||||
|
||||
switch node.Type {
|
||||
case blackfriday.Text:
|
||||
escapeSpecialChars(w, node.Literal)
|
||||
// Special case: format the NAME section as required for proper whatis parsing.
|
||||
// Refer to the lexgrog(1) and groff_man(7) manual pages for details.
|
||||
if node.Parent != nil &&
|
||||
node.Parent.Type == blackfriday.Paragraph &&
|
||||
node.Parent.Prev != nil &&
|
||||
node.Parent.Prev.Type == blackfriday.Heading &&
|
||||
node.Parent.Prev.FirstChild != nil &&
|
||||
bytes.EqualFold(node.Parent.Prev.FirstChild.Literal, []byte("NAME")) {
|
||||
before, after, found := bytesCut(node.Literal, []byte(" - "))
|
||||
escapeSpecialChars(w, before)
|
||||
if found {
|
||||
out(w, ` \- `)
|
||||
escapeSpecialChars(w, after)
|
||||
}
|
||||
} else {
|
||||
escapeSpecialChars(w, node.Literal)
|
||||
}
|
||||
case blackfriday.Softbreak:
|
||||
out(w, crTag)
|
||||
case blackfriday.Hardbreak:
|
||||
|
|
@ -109,9 +130,16 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
|
|||
out(w, strongCloseTag)
|
||||
}
|
||||
case blackfriday.Link:
|
||||
if !entering {
|
||||
out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag)
|
||||
// Don't render the link text for automatic links, because this
|
||||
// will only duplicate the URL in the roff output.
|
||||
// See https://daringfireball.net/projects/markdown/syntax#autolink
|
||||
if !bytes.Equal(node.LinkData.Destination, node.FirstChild.Literal) {
|
||||
out(w, string(node.FirstChild.Literal))
|
||||
}
|
||||
// Hyphens in a link must be escaped to avoid word-wrap in the rendered man page.
|
||||
escapedLink := strings.ReplaceAll(string(node.LinkData.Destination), "-", "\\-")
|
||||
out(w, linkTag+escapedLink+linkCloseTag)
|
||||
walkAction = blackfriday.SkipChildren
|
||||
case blackfriday.Image:
|
||||
// ignore images
|
||||
walkAction = blackfriday.SkipChildren
|
||||
|
|
@ -122,14 +150,25 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
|
|||
case blackfriday.Document:
|
||||
break
|
||||
case blackfriday.Paragraph:
|
||||
// roff .PP markers break lists
|
||||
if r.listDepth > 0 {
|
||||
return blackfriday.GoToNext
|
||||
}
|
||||
if entering {
|
||||
out(w, paraTag)
|
||||
if r.listDepth > 0 {
|
||||
// roff .PP markers break lists
|
||||
if node.Prev != nil { // continued paragraph
|
||||
if node.Prev.Type == blackfriday.List && node.Prev.ListFlags&blackfriday.ListTypeDefinition == 0 {
|
||||
out(w, ".IP\n")
|
||||
} else {
|
||||
out(w, crTag)
|
||||
}
|
||||
}
|
||||
} else if node.Prev != nil && node.Prev.Type == blackfriday.Heading {
|
||||
out(w, crTag)
|
||||
} else {
|
||||
out(w, paraTag)
|
||||
}
|
||||
} else {
|
||||
out(w, crTag)
|
||||
if node.Next == nil || node.Next.Type != blackfriday.List {
|
||||
out(w, crTag)
|
||||
}
|
||||
}
|
||||
case blackfriday.BlockQuote:
|
||||
if entering {
|
||||
|
|
@ -160,6 +199,11 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
|
|||
r.handleTableCell(w, node, entering)
|
||||
case blackfriday.HTMLSpan:
|
||||
// ignore other HTML tags
|
||||
case blackfriday.HTMLBlock:
|
||||
if bytes.HasPrefix(node.Literal, []byte("<!--")) {
|
||||
break // ignore comments, no warning
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
|
||||
default:
|
||||
fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
|
||||
}
|
||||
|
|
@ -187,6 +231,10 @@ func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, enteri
|
|||
func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) {
|
||||
openTag := listTag
|
||||
closeTag := listCloseTag
|
||||
if (entering && r.listDepth == 0) || (!entering && r.listDepth == 1) {
|
||||
openTag = crTag
|
||||
closeTag = ""
|
||||
}
|
||||
if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
|
||||
// tags for definition lists handled within Item node
|
||||
openTag = ""
|
||||
|
|
@ -215,23 +263,25 @@ func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering
|
|||
} else if node.ListFlags&blackfriday.ListTypeTerm != 0 {
|
||||
// DT (definition term): line just before DD (see below).
|
||||
out(w, dtTag)
|
||||
r.firstDD = true
|
||||
} else if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
|
||||
// DD (definition description): line that starts with ": ".
|
||||
//
|
||||
// We have to distinguish between the first DD and the
|
||||
// subsequent ones, as there should be no vertical
|
||||
// whitespace between the DT and the first DD.
|
||||
if r.firstDD {
|
||||
r.firstDD = false
|
||||
} else {
|
||||
out(w, dd2Tag)
|
||||
if node.Prev != nil && node.Prev.ListFlags&(blackfriday.ListTypeTerm|blackfriday.ListTypeDefinition) == blackfriday.ListTypeDefinition {
|
||||
if node.Prev.Type == blackfriday.Item &&
|
||||
node.Prev.LastChild != nil &&
|
||||
node.Prev.LastChild.Type == blackfriday.List &&
|
||||
node.Prev.LastChild.ListFlags&blackfriday.ListTypeDefinition == 0 {
|
||||
out(w, ".IP\n")
|
||||
} else {
|
||||
out(w, dd2Tag)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out(w, ".IP \\(bu 2\n")
|
||||
}
|
||||
} else {
|
||||
out(w, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +304,7 @@ func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, ente
|
|||
start = "\t"
|
||||
}
|
||||
if node.IsHeader {
|
||||
start += codespanTag
|
||||
start += strongTag
|
||||
} else if nodeLiteralSize(node) > 30 {
|
||||
start += tableCellStart
|
||||
}
|
||||
|
|
@ -262,13 +312,12 @@ func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, ente
|
|||
} else {
|
||||
var end string
|
||||
if node.IsHeader {
|
||||
end = codespanCloseTag
|
||||
end = strongCloseTag
|
||||
} else if nodeLiteralSize(node) > 30 {
|
||||
end = tableCellEnd
|
||||
}
|
||||
if node.Next == nil && end != tableCellEnd {
|
||||
// Last cell: need to carriage return if we are at the end of the
|
||||
// header row and content isn't wrapped in a "tablecell"
|
||||
if node.Next == nil {
|
||||
// Last cell: need to carriage return if we are at the end of the header row.
|
||||
end += crTag
|
||||
}
|
||||
out(w, end)
|
||||
|
|
@ -306,10 +355,32 @@ func countColumns(node *blackfriday.Node) int {
|
|||
}
|
||||
|
||||
func out(w io.Writer, output string) {
|
||||
io.WriteString(w, output) // nolint: errcheck
|
||||
io.WriteString(w, output) //nolint:errcheck
|
||||
}
|
||||
|
||||
func escapeSpecialChars(w io.Writer, text []byte) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(text))
|
||||
|
||||
// count the number of lines in the text
|
||||
// we need to know this to avoid adding a newline after the last line
|
||||
n := bytes.Count(text, []byte{'\n'})
|
||||
idx := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
dt := scanner.Bytes()
|
||||
if idx < n {
|
||||
idx++
|
||||
dt = append(dt, '\n')
|
||||
}
|
||||
escapeSpecialCharsLine(w, dt)
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func escapeSpecialCharsLine(w io.Writer, text []byte) {
|
||||
for i := 0; i < len(text); i++ {
|
||||
// escape initial apostrophe or period
|
||||
if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') {
|
||||
|
|
@ -323,7 +394,7 @@ func escapeSpecialChars(w io.Writer, text []byte) {
|
|||
i++
|
||||
}
|
||||
if i > org {
|
||||
w.Write(text[org:i]) // nolint: errcheck
|
||||
w.Write(text[org:i]) //nolint:errcheck
|
||||
}
|
||||
|
||||
// escape a character
|
||||
|
|
@ -331,6 +402,15 @@ func escapeSpecialChars(w io.Writer, text []byte) {
|
|||
break
|
||||
}
|
||||
|
||||
w.Write([]byte{'\\', text[i]}) // nolint: errcheck
|
||||
w.Write([]byte{'\\', text[i]}) //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
// bytesCut is a copy of [bytes.Cut] to provide compatibility with go1.17
|
||||
// and older. We can remove this once we drop support for go1.17 and older.
|
||||
func bytesCut(s, sep []byte) (before, after []byte, found bool) {
|
||||
if i := bytes.Index(s, sep); i >= 0 {
|
||||
return s[:i], s[i+len(sep):], true
|
||||
}
|
||||
return s, nil, false
|
||||
}
|
||||
|
|
|
|||
7
vendor/github.com/golang/snappy/README
generated
vendored
7
vendor/github.com/golang/snappy/README
generated
vendored
|
|
@ -1,8 +1,13 @@
|
|||
The Snappy compression format in the Go programming language.
|
||||
|
||||
To download and install from source:
|
||||
To use as a library:
|
||||
$ go get github.com/golang/snappy
|
||||
|
||||
To use as a binary:
|
||||
$ go install github.com/golang/snappy/cmd/snappytool@latest
|
||||
$ cat decoded | ~/go/bin/snappytool -e > encoded
|
||||
$ cat encoded | ~/go/bin/snappytool -d > decoded
|
||||
|
||||
Unless otherwise noted, the Snappy-Go source files are distributed
|
||||
under the BSD-style license found in the LICENSE file.
|
||||
|
||||
|
|
|
|||
4
vendor/github.com/golang/snappy/encode_arm64.s
generated
vendored
4
vendor/github.com/golang/snappy/encode_arm64.s
generated
vendored
|
|
@ -27,7 +27,7 @@
|
|||
// The unusual register allocation of local variables, such as R10 for the
|
||||
// source pointer, matches the allocation used at the call site in encodeBlock,
|
||||
// which makes it easier to manually inline this function.
|
||||
TEXT ·emitLiteral(SB), NOSPLIT, $32-56
|
||||
TEXT ·emitLiteral(SB), NOSPLIT, $40-56
|
||||
MOVD dst_base+0(FP), R8
|
||||
MOVD lit_base+24(FP), R10
|
||||
MOVD lit_len+32(FP), R3
|
||||
|
|
@ -261,7 +261,7 @@ extendMatchEnd:
|
|||
// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An
|
||||
// extra 64 bytes, to call other functions, and an extra 64 bytes, to spill
|
||||
// local variables (registers) during calls gives 32768 + 64 + 64 = 32896.
|
||||
TEXT ·encodeBlock(SB), 0, $32896-56
|
||||
TEXT ·encodeBlock(SB), 0, $32904-56
|
||||
MOVD dst_base+0(FP), R8
|
||||
MOVD src_base+24(FP), R7
|
||||
MOVD src_len+32(FP), R14
|
||||
|
|
|
|||
20
vendor/github.com/gorilla/mux/.editorconfig
generated
vendored
Normal file
20
vendor/github.com/gorilla/mux/.editorconfig
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
; https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
eclint_indent_style = unset
|
||||
1
vendor/github.com/gorilla/mux/.gitignore
generated
vendored
Normal file
1
vendor/github.com/gorilla/mux/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
coverage.coverprofile
|
||||
8
vendor/github.com/gorilla/mux/AUTHORS
generated
vendored
8
vendor/github.com/gorilla/mux/AUTHORS
generated
vendored
|
|
@ -1,8 +0,0 @@
|
|||
# This is the official list of gorilla/mux authors for copyright purposes.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Google LLC (https://opensource.google.com/)
|
||||
Kamil Kisielk <kamil@kamilkisiel.net>
|
||||
Matt Silverlock <matt@eatsleeprepeat.net>
|
||||
Rodrigo Moraes (https://github.com/moraes)
|
||||
2
vendor/github.com/gorilla/mux/LICENSE
generated
vendored
2
vendor/github.com/gorilla/mux/LICENSE
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved.
|
||||
Copyright (c) 2023 The Gorilla Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
|
|||
34
vendor/github.com/gorilla/mux/Makefile
generated
vendored
Normal file
34
vendor/github.com/gorilla/mux/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '')
|
||||
GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
|
||||
GO_SEC=$(shell which gosec 2> /dev/null || echo '')
|
||||
GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
|
||||
GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '')
|
||||
GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint:
|
||||
$(if $(GO_LINT), ,go install $(GO_LINT_URI))
|
||||
@echo "##### Running golangci-lint"
|
||||
golangci-lint run -v
|
||||
|
||||
.PHONY: gosec
|
||||
gosec:
|
||||
$(if $(GO_SEC), ,go install $(GO_SEC_URI))
|
||||
@echo "##### Running gosec"
|
||||
gosec ./...
|
||||
|
||||
.PHONY: govulncheck
|
||||
govulncheck:
|
||||
$(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI))
|
||||
@echo "##### Running govulncheck"
|
||||
govulncheck ./...
|
||||
|
||||
.PHONY: verify
|
||||
verify: golangci-lint gosec govulncheck
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@echo "##### Running tests"
|
||||
go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./...
|
||||
63
vendor/github.com/gorilla/mux/README.md
generated
vendored
63
vendor/github.com/gorilla/mux/README.md
generated
vendored
|
|
@ -1,12 +1,12 @@
|
|||
# gorilla/mux
|
||||
|
||||
[](https://godoc.org/github.com/gorilla/mux)
|
||||
[](https://circleci.com/gh/gorilla/mux)
|
||||
[](https://sourcegraph.com/github.com/gorilla/mux?badge)
|
||||

|
||||
[](https://codecov.io/github/gorilla/mux)
|
||||
[](https://godoc.org/github.com/gorilla/mux)
|
||||
[](https://sourcegraph.com/github.com/gorilla/mux?badge)
|
||||
|
||||

|
||||
|
||||
https://www.gorillatoolkit.org/pkg/mux
|
||||

|
||||
|
||||
Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
|
||||
their respective handler.
|
||||
|
|
@ -247,32 +247,25 @@ type spaHandler struct {
|
|||
// file located at the index path on the SPA handler will be served. This
|
||||
// is suitable behavior for serving an SPA (single page application).
|
||||
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// get the absolute path to prevent directory traversal
|
||||
path, err := filepath.Abs(r.URL.Path)
|
||||
if err != nil {
|
||||
// if we failed to get the absolute path respond with a 400 bad request
|
||||
// and stop
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Join internally call path.Clean to prevent directory traversal
|
||||
path := filepath.Join(h.staticPath, r.URL.Path)
|
||||
|
||||
// prepend the path with the path to the static directory
|
||||
path = filepath.Join(h.staticPath, path)
|
||||
|
||||
// check whether a file exists at the given path
|
||||
_, err = os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
// file does not exist, serve index.html
|
||||
// check whether a file exists or is a directory at the given path
|
||||
fi, err := os.Stat(path)
|
||||
if os.IsNotExist(err) || fi.IsDir() {
|
||||
// file does not exist or path is a directory, serve index.html
|
||||
http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath))
|
||||
return
|
||||
} else if err != nil {
|
||||
// if we got an error (that wasn't that the file doesn't exist) stating the
|
||||
// file, return a 500 internal server error and stop
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, use http.FileServer to serve the static dir
|
||||
if err != nil {
|
||||
// if we got an error (that wasn't that the file doesn't exist) stating the
|
||||
// file, return a 500 internal server error and stop
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, use http.FileServer to serve the static file
|
||||
http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
|
|
@ -375,6 +368,19 @@ url, err := r.Get("article").URL("subdomain", "news",
|
|||
"id", "42")
|
||||
```
|
||||
|
||||
To find all the required variables for a given route when calling `URL()`, the method `GetVarNames()` is available:
|
||||
```go
|
||||
r := mux.NewRouter()
|
||||
r.Host("{domain}").
|
||||
Path("/{group}/{item_id}").
|
||||
Queries("some_data1", "{some_data1}").
|
||||
Queries("some_data2", "{some_data2}").
|
||||
Name("article")
|
||||
|
||||
// Will print [domain group item_id some_data1 some_data2] <nil>
|
||||
fmt.Println(r.Get("article").GetVarNames())
|
||||
|
||||
```
|
||||
### Walking Routes
|
||||
|
||||
The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
|
||||
|
|
@ -572,7 +578,7 @@ func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler
|
|||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", handler)
|
||||
|
||||
amw := authenticationMiddleware{}
|
||||
amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
|
||||
amw.Populate()
|
||||
|
||||
r.Use(amw.Middleware)
|
||||
|
|
@ -758,7 +764,8 @@ func TestMetricsHandler(t *testing.T) {
|
|||
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
// Need to create a router that we can pass the request through so that the vars will be added to the context
|
||||
// To add the vars to the context,
|
||||
// we need to create a router through which we can pass the request.
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/metrics/{type}", MetricsHandler)
|
||||
router.ServeHTTP(rr, req)
|
||||
|
|
|
|||
25
vendor/github.com/gorilla/mux/doc.go
generated
vendored
25
vendor/github.com/gorilla/mux/doc.go
generated
vendored
|
|
@ -10,18 +10,18 @@ http.ServeMux, mux.Router matches incoming requests against a list of
|
|||
registered routes and calls a handler for the route that matches the URL
|
||||
or other conditions. The main features are:
|
||||
|
||||
* Requests can be matched based on URL host, path, path prefix, schemes,
|
||||
header and query values, HTTP methods or using custom matchers.
|
||||
* URL hosts, paths and query values can have variables with an optional
|
||||
regular expression.
|
||||
* Registered URLs can be built, or "reversed", which helps maintaining
|
||||
references to resources.
|
||||
* Routes can be used as subrouters: nested routes are only tested if the
|
||||
parent route matches. This is useful to define groups of routes that
|
||||
share common conditions like a host, a path prefix or other repeated
|
||||
attributes. As a bonus, this optimizes request matching.
|
||||
* It implements the http.Handler interface so it is compatible with the
|
||||
standard http.ServeMux.
|
||||
- Requests can be matched based on URL host, path, path prefix, schemes,
|
||||
header and query values, HTTP methods or using custom matchers.
|
||||
- URL hosts, paths and query values can have variables with an optional
|
||||
regular expression.
|
||||
- Registered URLs can be built, or "reversed", which helps maintaining
|
||||
references to resources.
|
||||
- Routes can be used as subrouters: nested routes are only tested if the
|
||||
parent route matches. This is useful to define groups of routes that
|
||||
share common conditions like a host, a path prefix or other repeated
|
||||
attributes. As a bonus, this optimizes request matching.
|
||||
- It implements the http.Handler interface so it is compatible with the
|
||||
standard http.ServeMux.
|
||||
|
||||
Let's start registering a couple of URL paths and handlers:
|
||||
|
||||
|
|
@ -301,6 +301,5 @@ A more complex authentication middleware, which maps session token to users, cou
|
|||
r.Use(amw.Middleware)
|
||||
|
||||
Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
|
||||
|
||||
*/
|
||||
package mux
|
||||
|
|
|
|||
16
vendor/github.com/gorilla/mux/mux.go
generated
vendored
16
vendor/github.com/gorilla/mux/mux.go
generated
vendored
|
|
@ -31,24 +31,26 @@ func NewRouter() *Router {
|
|||
// It implements the http.Handler interface, so it can be registered to serve
|
||||
// requests:
|
||||
//
|
||||
// var router = mux.NewRouter()
|
||||
// var router = mux.NewRouter()
|
||||
//
|
||||
// func main() {
|
||||
// http.Handle("/", router)
|
||||
// }
|
||||
// func main() {
|
||||
// http.Handle("/", router)
|
||||
// }
|
||||
//
|
||||
// Or, for Google App Engine, register it in a init() function:
|
||||
//
|
||||
// func init() {
|
||||
// http.Handle("/", router)
|
||||
// }
|
||||
// func init() {
|
||||
// http.Handle("/", router)
|
||||
// }
|
||||
//
|
||||
// This will send all incoming requests to the router.
|
||||
type Router struct {
|
||||
// Configurable Handler to be used when no route matches.
|
||||
// This can be used to render your own 404 Not Found errors.
|
||||
NotFoundHandler http.Handler
|
||||
|
||||
// Configurable Handler to be used when the request method does not match the route.
|
||||
// This can be used to render your own 405 Method Not Allowed errors.
|
||||
MethodNotAllowedHandler http.Handler
|
||||
|
||||
// Routes to be matched, in order.
|
||||
|
|
|
|||
10
vendor/github.com/gorilla/mux/regexp.go
generated
vendored
10
vendor/github.com/gorilla/mux/regexp.go
generated
vendored
|
|
@ -22,10 +22,10 @@ type routeRegexpOptions struct {
|
|||
type regexpType int
|
||||
|
||||
const (
|
||||
regexpTypePath regexpType = 0
|
||||
regexpTypeHost regexpType = 1
|
||||
regexpTypePrefix regexpType = 2
|
||||
regexpTypeQuery regexpType = 3
|
||||
regexpTypePath regexpType = iota
|
||||
regexpTypeHost
|
||||
regexpTypePrefix
|
||||
regexpTypeQuery
|
||||
)
|
||||
|
||||
// newRouteRegexp parses a route template and returns a routeRegexp,
|
||||
|
|
@ -195,7 +195,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
|||
|
||||
// url builds a URL part using the given values.
|
||||
func (r *routeRegexp) url(values map[string]string) (string, error) {
|
||||
urlValues := make([]interface{}, len(r.varsN), len(r.varsN))
|
||||
urlValues := make([]interface{}, len(r.varsN))
|
||||
for k, v := range r.varsN {
|
||||
value, ok := values[v]
|
||||
if !ok {
|
||||
|
|
|
|||
109
vendor/github.com/gorilla/mux/route.go
generated
vendored
109
vendor/github.com/gorilla/mux/route.go
generated
vendored
|
|
@ -64,8 +64,18 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
|||
match.MatchErr = nil
|
||||
}
|
||||
|
||||
matchErr = nil
|
||||
matchErr = nil // nolint:ineffassign
|
||||
return false
|
||||
} else {
|
||||
// Multiple routes may share the same path but use different HTTP methods. For instance:
|
||||
// Route 1: POST "/users/{id}".
|
||||
// Route 2: GET "/users/{id}", parameters: "id": "[0-9]+".
|
||||
//
|
||||
// The router must handle these cases correctly. For a GET request to "/users/abc" with "id" as "-2",
|
||||
// The router should return a "Not Found" error as no route fully matches this request.
|
||||
if match.MatchErr == ErrMethodMismatch {
|
||||
match.MatchErr = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -230,9 +240,9 @@ func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
|||
// Headers adds a matcher for request header values.
|
||||
// It accepts a sequence of key/value pairs to be matched. For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.Headers("Content-Type", "application/json",
|
||||
// "X-Requested-With", "XMLHttpRequest")
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// r.Headers("Content-Type", "application/json",
|
||||
// "X-Requested-With", "XMLHttpRequest")
|
||||
//
|
||||
// The above route will only match if both request header values match.
|
||||
// If the value is an empty string, it will match any value if the key is set.
|
||||
|
|
@ -255,9 +265,9 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
|
|||
// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
|
||||
// support. For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
||||
// "X-Requested-With", "XMLHttpRequest")
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// r.HeadersRegexp("Content-Type", "application/(text|json)",
|
||||
// "X-Requested-With", "XMLHttpRequest")
|
||||
//
|
||||
// The above route will only match if both the request header matches both regular expressions.
|
||||
// If the value is an empty string, it will match any value if the key is set.
|
||||
|
|
@ -283,10 +293,10 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route {
|
|||
//
|
||||
// For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.Host("www.example.com")
|
||||
// r.Host("{subdomain}.domain.com")
|
||||
// r.Host("{subdomain:[a-z]+}.domain.com")
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// r.Host("www.example.com")
|
||||
// r.Host("{subdomain}.domain.com")
|
||||
// r.Host("{subdomain:[a-z]+}.domain.com")
|
||||
//
|
||||
// Variable names must be unique in a given route. They can be retrieved
|
||||
// calling mux.Vars(request).
|
||||
|
|
@ -342,11 +352,11 @@ func (r *Route) Methods(methods ...string) *Route {
|
|||
//
|
||||
// For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.Path("/products/").Handler(ProductsHandler)
|
||||
// r.Path("/products/{key}").Handler(ProductsHandler)
|
||||
// r.Path("/articles/{category}/{id:[0-9]+}").
|
||||
// Handler(ArticleHandler)
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// r.Path("/products/").Handler(ProductsHandler)
|
||||
// r.Path("/products/{key}").Handler(ProductsHandler)
|
||||
// r.Path("/articles/{category}/{id:[0-9]+}").
|
||||
// Handler(ArticleHandler)
|
||||
//
|
||||
// Variable names must be unique in a given route. They can be retrieved
|
||||
// calling mux.Vars(request).
|
||||
|
|
@ -377,8 +387,8 @@ func (r *Route) PathPrefix(tpl string) *Route {
|
|||
// It accepts a sequence of key/value pairs. Values may define variables.
|
||||
// For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.Queries("foo", "bar", "id", "{id:[0-9]+}")
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// r.Queries("foo", "bar", "id", "{id:[0-9]+}")
|
||||
//
|
||||
// The above route will only match if the URL contains the defined queries
|
||||
// values, e.g.: ?foo=bar&id=42.
|
||||
|
|
@ -473,11 +483,11 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
|
|||
//
|
||||
// It will test the inner routes only if the parent route matched. For example:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// s := r.Host("www.example.com").Subrouter()
|
||||
// s.HandleFunc("/products/", ProductsHandler)
|
||||
// s.HandleFunc("/products/{key}", ProductHandler)
|
||||
// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// s := r.Host("www.example.com").Subrouter()
|
||||
// s.HandleFunc("/products/", ProductsHandler)
|
||||
// s.HandleFunc("/products/{key}", ProductHandler)
|
||||
// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
|
||||
//
|
||||
// Here, the routes registered in the subrouter won't be tested if the host
|
||||
// doesn't match.
|
||||
|
|
@ -497,36 +507,36 @@ func (r *Route) Subrouter() *Router {
|
|||
// It accepts a sequence of key/value pairs for the route variables. For
|
||||
// example, given this route:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
||||
// Name("article")
|
||||
// r := mux.NewRouter()
|
||||
// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
||||
// Name("article")
|
||||
//
|
||||
// ...a URL for it can be built using:
|
||||
//
|
||||
// url, err := r.Get("article").URL("category", "technology", "id", "42")
|
||||
// url, err := r.Get("article").URL("category", "technology", "id", "42")
|
||||
//
|
||||
// ...which will return an url.URL with the following path:
|
||||
//
|
||||
// "/articles/technology/42"
|
||||
// "/articles/technology/42"
|
||||
//
|
||||
// This also works for host variables:
|
||||
//
|
||||
// r := mux.NewRouter()
|
||||
// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
||||
// Host("{subdomain}.domain.com").
|
||||
// Name("article")
|
||||
// r := mux.NewRouter()
|
||||
// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
|
||||
// Host("{subdomain}.domain.com").
|
||||
// Name("article")
|
||||
//
|
||||
// // url.String() will be "http://news.domain.com/articles/technology/42"
|
||||
// url, err := r.Get("article").URL("subdomain", "news",
|
||||
// "category", "technology",
|
||||
// "id", "42")
|
||||
// // url.String() will be "http://news.domain.com/articles/technology/42"
|
||||
// url, err := r.Get("article").URL("subdomain", "news",
|
||||
// "category", "technology",
|
||||
// "id", "42")
|
||||
//
|
||||
// The scheme of the resulting url will be the first argument that was passed to Schemes:
|
||||
//
|
||||
// // url.String() will be "https://example.com"
|
||||
// r := mux.NewRouter()
|
||||
// url, err := r.Host("example.com")
|
||||
// .Schemes("https", "http").URL()
|
||||
// // url.String() will be "https://example.com"
|
||||
// r := mux.NewRouter().NewRoute()
|
||||
// url, err := r.Host("example.com")
|
||||
// .Schemes("https", "http").URL()
|
||||
//
|
||||
// All variables defined in the route are required, and their values must
|
||||
// conform to the corresponding patterns.
|
||||
|
|
@ -718,6 +728,25 @@ func (r *Route) GetHostTemplate() (string, error) {
|
|||
return r.regexp.host.template, nil
|
||||
}
|
||||
|
||||
// GetVarNames returns the names of all variables added by regexp matchers
|
||||
// These can be used to know which route variables should be passed into r.URL()
|
||||
func (r *Route) GetVarNames() ([]string, error) {
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
var varNames []string
|
||||
if r.regexp.host != nil {
|
||||
varNames = append(varNames, r.regexp.host.varsN...)
|
||||
}
|
||||
if r.regexp.path != nil {
|
||||
varNames = append(varNames, r.regexp.path.varsN...)
|
||||
}
|
||||
for _, regx := range r.regexp.queries {
|
||||
varNames = append(varNames, regx.varsN...)
|
||||
}
|
||||
return varNames, nil
|
||||
}
|
||||
|
||||
// prepareVars converts the route variable pairs into a map. If the route has a
|
||||
// BuildVarsFunc, it is invoked.
|
||||
func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
|
||||
|
|
|
|||
35
vendor/github.com/pquerna/otp/hotp/hotp.go
generated
vendored
35
vendor/github.com/pquerna/otp/hotp/hotp.go
generated
vendored
|
|
@ -57,6 +57,8 @@ type ValidateOpts struct {
|
|||
Digits otp.Digits
|
||||
// Algorithm to use for HMAC. Defaults to SHA1.
|
||||
Algorithm otp.Algorithm
|
||||
// Encoder to use for output code.
|
||||
Encoder otp.Encoder
|
||||
}
|
||||
|
||||
// GenerateCode creates a HOTP passcode given a counter and secret.
|
||||
|
|
@ -112,15 +114,34 @@ func GenerateCodeCustom(secret string, counter uint64, opts ValidateOpts) (passc
|
|||
(int(sum[offset+3]) & 0xff))
|
||||
|
||||
l := opts.Digits.Length()
|
||||
mod := int32(value % int64(math.Pow10(l)))
|
||||
switch opts.Encoder {
|
||||
case otp.EncoderDefault:
|
||||
mod := int32(value % int64(math.Pow10(l)))
|
||||
|
||||
if debug {
|
||||
fmt.Printf("offset=%v\n", offset)
|
||||
fmt.Printf("value=%v\n", value)
|
||||
fmt.Printf("mod'ed=%v\n", mod)
|
||||
if debug {
|
||||
fmt.Printf("offset=%v\n", offset)
|
||||
fmt.Printf("value=%v\n", value)
|
||||
fmt.Printf("mod'ed=%v\n", mod)
|
||||
}
|
||||
passcode = opts.Digits.Format(mod)
|
||||
case otp.EncoderSteam:
|
||||
// Define the character set used by Steam Guard codes.
|
||||
alphabet := []byte{
|
||||
'2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C',
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q',
|
||||
'R', 'T', 'V', 'W', 'X', 'Y',
|
||||
}
|
||||
radix := int64(len(alphabet))
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
digit := value % radix
|
||||
value /= radix
|
||||
c := alphabet[digit]
|
||||
passcode += string(c)
|
||||
}
|
||||
}
|
||||
|
||||
return opts.Digits.Format(mod), nil
|
||||
return
|
||||
}
|
||||
|
||||
// ValidateCustom validates an HOTP with customizable options. Most users should
|
||||
|
|
@ -194,7 +215,7 @@ func Generate(opts GenerateOpts) (*otp.Key, error) {
|
|||
v.Set("secret", b32NoPadding.EncodeToString(opts.Secret))
|
||||
} else {
|
||||
secret := make([]byte, opts.SecretSize)
|
||||
_, err := opts.Rand.Read(secret)
|
||||
_, err := io.ReadFull(opts.Rand, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
27
vendor/github.com/pquerna/otp/otp.go
generated
vendored
27
vendor/github.com/pquerna/otp/otp.go
generated
vendored
|
|
@ -154,12 +154,7 @@ func (k *Key) Digits() Digits {
|
|||
q := k.url.Query()
|
||||
|
||||
if u, err := strconv.ParseUint(q.Get("digits"), 10, 64); err == nil {
|
||||
switch u {
|
||||
case 8:
|
||||
return DigitsEight
|
||||
default:
|
||||
return DigitsSix
|
||||
}
|
||||
return Digits(u)
|
||||
}
|
||||
|
||||
// Six is the most common value.
|
||||
|
|
@ -183,6 +178,19 @@ func (k *Key) Algorithm() Algorithm {
|
|||
}
|
||||
}
|
||||
|
||||
// Encoder returns the encoder used or the default ("")
|
||||
func (k *Key) Encoder() Encoder {
|
||||
q := k.url.Query()
|
||||
|
||||
a := strings.ToLower(q.Get("encoder"))
|
||||
switch a {
|
||||
case "steam":
|
||||
return EncoderSteam
|
||||
default:
|
||||
return EncoderDefault
|
||||
}
|
||||
}
|
||||
|
||||
// URL returns the OTP URL as a string
|
||||
func (k *Key) URL() string {
|
||||
return k.url.String()
|
||||
|
|
@ -253,3 +261,10 @@ func (d Digits) Length() int {
|
|||
func (d Digits) String() string {
|
||||
return fmt.Sprintf("%d", d)
|
||||
}
|
||||
|
||||
type Encoder string
|
||||
|
||||
const (
|
||||
EncoderDefault Encoder = ""
|
||||
EncoderSteam Encoder = "steam"
|
||||
)
|
||||
|
|
|
|||
7
vendor/github.com/pquerna/otp/totp/totp.go
generated
vendored
7
vendor/github.com/pquerna/otp/totp/totp.go
generated
vendored
|
|
@ -73,6 +73,8 @@ type ValidateOpts struct {
|
|||
Digits otp.Digits
|
||||
// Algorithm to use for HMAC. Defaults to SHA1.
|
||||
Algorithm otp.Algorithm
|
||||
// Encoder to use for output code.
|
||||
Encoder otp.Encoder
|
||||
}
|
||||
|
||||
// GenerateCodeCustom takes a timepoint and produces a passcode using a
|
||||
|
|
@ -86,6 +88,7 @@ func GenerateCodeCustom(secret string, t time.Time, opts ValidateOpts) (passcode
|
|||
passcode, err = hotp.GenerateCodeCustom(secret, counter, hotp.ValidateOpts{
|
||||
Digits: opts.Digits,
|
||||
Algorithm: opts.Algorithm,
|
||||
Encoder: opts.Encoder,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -113,8 +116,8 @@ func ValidateCustom(passcode string, secret string, t time.Time, opts ValidateOp
|
|||
rv, err := hotp.ValidateCustom(passcode, counter, secret, hotp.ValidateOpts{
|
||||
Digits: opts.Digits,
|
||||
Algorithm: opts.Algorithm,
|
||||
Encoder: opts.Encoder,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -184,7 +187,7 @@ func Generate(opts GenerateOpts) (*otp.Key, error) {
|
|||
v.Set("secret", b32NoPadding.EncodeToString(opts.Secret))
|
||||
} else {
|
||||
secret := make([]byte, opts.SecretSize)
|
||||
_, err := opts.Rand.Read(secret)
|
||||
_, err := io.ReadFull(opts.Rand, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue