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 }) }