package nostr import ( "sync" "unsafe" "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 } // Escaping strings 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: 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 }