diff options
author | 2024-01-19 12:57:29 +0000 | |
---|---|---|
committer | 2024-01-19 12:57:29 +0000 | |
commit | 7ec1e1332e7d04e74451acef18b41f389722b698 (patch) | |
tree | 9c69eca7fc664ab5564279a2e065dfd5c2ddd17b /vendor/codeberg.org/gruf/go-structr/util.go | |
parent | [chore] chore rationalise http return codes for activitypub handlers (#2540) (diff) | |
download | gotosocial-7ec1e1332e7d04e74451acef18b41f389722b698.tar.xz |
[performance] overhaul struct (+ result) caching library for simplicity, performance and multiple-result lookups (#2535)
* rewrite cache library as codeberg.org/gruf/go-structr, implement in gotosocial
* use actual go-structr release version (not just commit hash)
* revert go toolchain changes (damn you go for auto changing this)
* fix go mod woes
* ensure %w is used in calls to errs.Appendf()
* fix error checking
* fix possible panic
* remove unnecessary start/stop functions, move to main Cache{} struct, add note regarding which caches require start/stop
* fix copy-paste artifact... :innocent:
* fix all comment copy-paste artifacts
* remove dropID() function, now we can just use slices.DeleteFunc()
* use util.Deduplicate() instead of collate(), move collate to util
* move orderByIDs() to util package and "generify"
* add a util.DeleteIf() function, use this to delete entries on failed population
* use slices.DeleteFunc() instead of util.DeleteIf() (i had the logic mixed up in my head somehow lol)
* add note about how collate differs from deduplicate
Diffstat (limited to 'vendor/codeberg.org/gruf/go-structr/util.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-structr/util.go | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-structr/util.go b/vendor/codeberg.org/gruf/go-structr/util.go new file mode 100644 index 000000000..d8f227baf --- /dev/null +++ b/vendor/codeberg.org/gruf/go-structr/util.go @@ -0,0 +1,118 @@ +package structr + +import ( + "fmt" + "reflect" + "sync" + "unicode" + "unicode/utf8" + + "codeberg.org/gruf/go-byteutil" + "codeberg.org/gruf/go-mangler" +) + +// 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 mangler func. + sfield.mangler = mangler.Get(t) + + if allowZero { + var buf []byte + + // Allocate field instance. + v := reflect.New(field.Type) + v = v.Elem() + + // Serialize this zero value into buf. + buf = sfield.mangler(buf, v.Interface()) + + // Set zero value str. + sfield.zero = string(buf) + } + + return +} + +// panicf provides a panic with string formatting. +func panicf(format string, args ...any) { + panic(fmt.Sprintf(format, args...)) +} + +// bufpool provides a memory pool of byte +// buffers used when encoding key types. +var bufPool sync.Pool + +// getBuf fetches buffer from memory pool. +func getBuf() *byteutil.Buffer { + v := bufPool.Get() + if v == nil { + buf := new(byteutil.Buffer) + buf.B = make([]byte, 0, 512) + v = buf + } + return v.(*byteutil.Buffer) +} + +// putBuf replaces buffer in memory pool. +func putBuf(buf *byteutil.Buffer) { + if buf.Cap() > int(^uint16(0)) { + return // drop large bufs + } + buf.Reset() + bufPool.Put(buf) +} |