gotosocial/vendor/codeberg.org/gruf/go-structr/util.go
kim 07207e71e9
[performance] cache library performance enhancements (updates go-structr => v0.2.0) (#2575)
* update go-structr => v0.2.0

* update readme

* whoops, fix the link
2024-01-26 12:14:10 +00:00

99 lines
2.1 KiB
Go

package structr
import (
"fmt"
"reflect"
"sync"
"unicode"
"unicode/utf8"
"github.com/zeebo/xxh3"
)
// findField will search for a struct field with given set of names, where names is a len > 0 slice of names account for nesting.
func findField(t reflect.Type, names []string, allowZero bool) (sfield structfield, ok bool) {
var (
// isExported returns whether name is exported
// from a package; can be func or struct field.
isExported = func(name string) bool {
r, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(r)
}
// popName pops the next name from
// the provided slice of field names.
popName = func() string {
// Pop next name.
name := names[0]
names = names[1:]
// Ensure valid name.
if !isExported(name) {
panicf("field is not exported: %s", name)
}
return name
}
// field is the iteratively searched-for
// struct field value in below loop.
field reflect.StructField
)
for len(names) > 0 {
// Pop next name.
name := popName()
// Follow any ptrs leading to field.
for t.Kind() == reflect.Pointer {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
// The end type after following ptrs must be struct.
panicf("field %s is not struct (ptr): %s", t, name)
}
// Look for next field by name.
field, ok = t.FieldByName(name)
if !ok {
return
}
// Append next set of indices required to reach field.
sfield.index = append(sfield.index, field.Index...)
// Set the next type.
t = field.Type
}
// Get final type hash func.
sfield.hasher = hasher(t)
return
}
// panicf provides a panic with string formatting.
func panicf(format string, args ...any) {
panic(fmt.Sprintf(format, args...))
}
// hashPool provides a memory pool of xxh3
// hasher objects used indexing field vals.
var hashPool sync.Pool
// gethashbuf fetches hasher from memory pool.
func getHasher() *xxh3.Hasher {
v := hashPool.Get()
if v == nil {
v = new(xxh3.Hasher)
}
return v.(*xxh3.Hasher)
}
// putHasher replaces hasher in memory pool.
func putHasher(h *xxh3.Hasher) {
h.Reset()
hashPool.Put(h)
}