157 lines
3.2 KiB
Go
157 lines
3.2 KiB
Go
package models
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
)
|
|
|
|
// TagKeysSet provides set operations for combining Tags.
|
|
type TagKeysSet struct {
|
|
i int
|
|
keys [2][][]byte
|
|
tmp [][]byte
|
|
}
|
|
|
|
// Clear removes all the elements of TagKeysSet and ensures all internal
|
|
// buffers are reset.
|
|
func (set *TagKeysSet) Clear() {
|
|
set.clear(set.keys[0])
|
|
set.clear(set.keys[1])
|
|
set.clear(set.tmp)
|
|
set.i = 0
|
|
set.keys[0] = set.keys[0][:0]
|
|
}
|
|
|
|
func (set *TagKeysSet) clear(b [][]byte) {
|
|
b = b[:cap(b)]
|
|
for i := range b {
|
|
b[i] = nil
|
|
}
|
|
}
|
|
|
|
// KeysBytes returns the merged keys in lexicographical order.
|
|
// The slice is valid until the next call to UnionKeys, UnionBytes or Reset.
|
|
func (set *TagKeysSet) KeysBytes() [][]byte {
|
|
return set.keys[set.i&1]
|
|
}
|
|
|
|
// Keys returns a copy of the merged keys in lexicographical order.
|
|
func (set *TagKeysSet) Keys() []string {
|
|
keys := set.KeysBytes()
|
|
s := make([]string, 0, len(keys))
|
|
for i := range keys {
|
|
s = append(s, string(keys[i]))
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (set *TagKeysSet) String() string {
|
|
var s []string
|
|
for _, k := range set.KeysBytes() {
|
|
s = append(s, string(k))
|
|
}
|
|
return strings.Join(s, ",")
|
|
}
|
|
|
|
// IsSupersetKeys returns true if the TagKeysSet is a superset of all the keys
|
|
// contained in other.
|
|
func (set *TagKeysSet) IsSupersetKeys(other Tags) bool {
|
|
keys := set.keys[set.i&1]
|
|
i, j := 0, 0
|
|
for i < len(keys) && j < len(other) {
|
|
if cmp := bytes.Compare(keys[i], other[j].Key); cmp > 0 {
|
|
return false
|
|
} else if cmp == 0 {
|
|
j++
|
|
}
|
|
i++
|
|
}
|
|
|
|
return j == len(other)
|
|
}
|
|
|
|
// IsSupersetBytes returns true if the TagKeysSet is a superset of all the keys
|
|
// in other.
|
|
// Other must be lexicographically sorted or the results are undefined.
|
|
func (set *TagKeysSet) IsSupersetBytes(other [][]byte) bool {
|
|
keys := set.keys[set.i&1]
|
|
i, j := 0, 0
|
|
for i < len(keys) && j < len(other) {
|
|
if cmp := bytes.Compare(keys[i], other[j]); cmp > 0 {
|
|
return false
|
|
} else if cmp == 0 {
|
|
j++
|
|
}
|
|
i++
|
|
}
|
|
|
|
return j == len(other)
|
|
}
|
|
|
|
// UnionKeys updates the set so that it is the union of itself and all the
|
|
// keys contained in other.
|
|
func (set *TagKeysSet) UnionKeys(other Tags) {
|
|
if set.IsSupersetKeys(other) {
|
|
return
|
|
}
|
|
|
|
if l := len(other); cap(set.tmp) < l {
|
|
set.tmp = make([][]byte, l)
|
|
} else {
|
|
set.tmp = set.tmp[:l]
|
|
}
|
|
|
|
for i := range other {
|
|
set.tmp[i] = other[i].Key
|
|
}
|
|
|
|
set.merge(set.tmp)
|
|
}
|
|
|
|
// UnionBytes updates the set so that it is the union of itself and all the
|
|
// keys contained in other.
|
|
// Other must be lexicographically sorted or the results are undefined.
|
|
func (set *TagKeysSet) UnionBytes(other [][]byte) {
|
|
if set.IsSupersetBytes(other) {
|
|
return
|
|
}
|
|
|
|
set.merge(other)
|
|
}
|
|
|
|
func (set *TagKeysSet) merge(in [][]byte) {
|
|
keys := set.keys[set.i&1]
|
|
l := len(keys) + len(in)
|
|
set.i = (set.i + 1) & 1
|
|
keya := set.keys[set.i&1]
|
|
if cap(keya) < l {
|
|
keya = make([][]byte, 0, l)
|
|
} else {
|
|
keya = keya[:0]
|
|
}
|
|
|
|
i, j := 0, 0
|
|
for i < len(keys) && j < len(in) {
|
|
ki, kj := keys[i], in[j]
|
|
if cmp := bytes.Compare(ki, kj); cmp < 0 {
|
|
i++
|
|
} else if cmp > 0 {
|
|
ki = kj
|
|
j++
|
|
} else {
|
|
i++
|
|
j++
|
|
}
|
|
|
|
keya = append(keya, ki)
|
|
}
|
|
|
|
if i < len(keys) {
|
|
keya = append(keya, keys[i:]...)
|
|
} else if j < len(in) {
|
|
keya = append(keya, in[j:]...)
|
|
}
|
|
|
|
set.keys[set.i&1] = keya
|
|
}
|