The filtering logic has been streamlined, adding enhanced query support for filters involving tags, authors, kinds, and their combinations. Introduced new utility methods for deduplication, intersection, and sorting to improve efficiency in handling event serials. Adjusted indexing structures and encoding for better modularity and readability.
139 lines
3.2 KiB
Go
139 lines
3.2 KiB
Go
package helpers
|
|
|
|
import (
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"github.com/minio/sha256-simd"
|
|
"golang.org/x/exp/constraints"
|
|
)
|
|
|
|
const MAX_LOCKS = 50
|
|
|
|
var (
|
|
namedMutexPool = make([]sync.Mutex, MAX_LOCKS)
|
|
)
|
|
|
|
//go:noescape
|
|
//go:linkname memhash runtime.memhash
|
|
func memhash(p unsafe.Pointer, h, s uintptr) uintptr
|
|
|
|
func NamedLock(name string) (unlock func()) {
|
|
sptr := unsafe.StringData(name)
|
|
idx := uint64(memhash(unsafe.Pointer(sptr), 0, uintptr(len(name)))) % MAX_LOCKS
|
|
namedMutexPool[idx].Lock()
|
|
return namedMutexPool[idx].Unlock
|
|
}
|
|
|
|
func Similar[E constraints.Ordered](as, bs []E) bool {
|
|
if len(as) != len(bs) {
|
|
return false
|
|
}
|
|
|
|
for _, a := range as {
|
|
for _, b := range bs {
|
|
if b == a {
|
|
goto next
|
|
}
|
|
}
|
|
// didn't find a B that corresponded to the current A
|
|
return false
|
|
|
|
next:
|
|
continue
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// EscapeString for JSON encoding according to RFC8259.
|
|
// Also encloses result in quotation marks "".
|
|
func EscapeString(dst []byte, s string) []byte {
|
|
dst = append(dst, '"')
|
|
for i := 0; i < len(s); i++ {
|
|
c := s[i]
|
|
switch {
|
|
case c == '"':
|
|
// quotation mark
|
|
dst = append(dst, []byte{'\\', '"'}...)
|
|
case c == '\\':
|
|
// reverse solidus
|
|
dst = append(dst, []byte{'\\', '\\'}...)
|
|
case c >= 0x20:
|
|
// default, rest below are control chars
|
|
dst = append(dst, c)
|
|
case c == 0x08:
|
|
dst = append(dst, []byte{'\\', 'b'}...)
|
|
case c < 0x09:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '0', '0' + c}...)
|
|
case c == 0x09:
|
|
dst = append(dst, []byte{'\\', 't'}...)
|
|
case c == 0x0a:
|
|
dst = append(dst, []byte{'\\', 'n'}...)
|
|
case c == 0x0c:
|
|
dst = append(dst, []byte{'\\', 'f'}...)
|
|
case c == 0x0d:
|
|
dst = append(dst, []byte{'\\', 'r'}...)
|
|
case c < 0x10:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '0', 0x57 + c}...)
|
|
case c < 0x1a:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x20 + c}...)
|
|
case c < 0x20: // maybe default?
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x47 + c}...)
|
|
}
|
|
}
|
|
dst = append(dst, '"')
|
|
return dst
|
|
}
|
|
|
|
func ArePointerValuesEqual[V comparable](a *V, b *V) bool {
|
|
if a == nil && b == nil {
|
|
return true
|
|
}
|
|
if a != nil && b != nil {
|
|
return *a == *b
|
|
}
|
|
return false
|
|
}
|
|
|
|
func SubIdToSerial(subId string) int64 {
|
|
n := strings.Index(subId, ":")
|
|
if n < 0 || n > len(subId) {
|
|
return -1
|
|
}
|
|
serialId, _ := strconv.ParseInt(subId[0:n], 10, 64)
|
|
return serialId
|
|
}
|
|
|
|
func IsLowerHex(thing string) bool {
|
|
for _, charNumber := range thing {
|
|
if (charNumber >= 48 && charNumber <= 57) || (charNumber >= 97 && charNumber <= 102) {
|
|
continue
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Hash is a little helper generate a hash and return a slice instead of an
|
|
// array.
|
|
func Hash(in []byte) (out []byte) {
|
|
h := sha256.Sum256(in)
|
|
return h[:]
|
|
}
|
|
|
|
// RemoveDuplicates removes repeated items in any slice of comparable items. This would not be
|
|
// appropriate for pointers unless they were assembled from the same source where a pointer is
|
|
// equal to a unique reference to the content.
|
|
func RemoveDuplicates[T comparable](s []T) []T {
|
|
alreadySeen := make(map[T]struct{}, len(s))
|
|
return slices.DeleteFunc(s, func(val T) bool {
|
|
_, duplicate := alreadySeen[val]
|
|
alreadySeen[val] = struct{}{}
|
|
return duplicate
|
|
})
|
|
}
|