summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2022-11-13 13:02:07 +0000
committerLibravatar GitHub <noreply@github.com>2022-11-13 14:02:07 +0100
commite8c733da3fd3448a8abc02127fdcc4f2db4af271 (patch)
treecc85a49e8aabc0202e30103a403cef2044b07f2d /vendor/codeberg.org/gruf/go-cache/v3/result/key.go
parent[documentation] Change default log path (#1030) (diff)
downloadgotosocial-e8c733da3fd3448a8abc02127fdcc4f2db4af271.tar.xz
[chore] bump go-cache to v3.1.7 to fix possible issues with zero value keys (#1038)
Signed-off-by: kim <grufwub@gmail.com> Signed-off-by: kim <grufwub@gmail.com>
Diffstat (limited to 'vendor/codeberg.org/gruf/go-cache/v3/result/key.go')
-rw-r--r--vendor/codeberg.org/gruf/go-cache/v3/result/key.go150
1 files changed, 91 insertions, 59 deletions
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/result/key.go b/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
index ec58e0ef9..0dc1276a5 100644
--- a/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
+++ b/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
@@ -12,22 +12,24 @@ import (
)
// structKeys provides convience methods for a list
-// of struct field combinations used for cache keys.
-type structKeys []keyFields
+// of structKey field combinations used for cache keys.
+type structKeys []structKey
-// get fetches the key-fields for given lookup (else, panics).
-func (sk structKeys) get(lookup string) *keyFields {
+// get fetches the structKey info for given lookup name (else, panics).
+func (sk structKeys) get(name string) *structKey {
for i := range sk {
- if sk[i].lookup == lookup {
+ if sk[i].name == name {
return &sk[i]
}
}
- panic("unknown lookup: \"" + lookup + "\"")
+ panic("unknown lookup: \"" + name + "\"")
}
-// generate will calculate the value string for each required
-// cache key as laid-out by the receiving structKeys{}.
-func (sk structKeys) generate(a any) []cacheKey {
+// generate will calculate and produce a slice of cache keys the given value
+// can be stored under in the, as determined by receiving struct keys.
+func (sk structKeys) generate(a any) []cachedKey {
+ var keys []cachedKey
+
// Get reflected value in order
// to access the struct fields
v := reflect.ValueOf(a)
@@ -40,9 +42,6 @@ func (sk structKeys) generate(a any) []cacheKey {
v = v.Elem()
}
- // Preallocate expected slice of keys
- keys := make([]cacheKey, len(sk))
-
// Acquire byte buffer
buf := bufpool.Get().(*byteutil.Buffer)
defer bufpool.Put(buf)
@@ -51,54 +50,63 @@ func (sk structKeys) generate(a any) []cacheKey {
// Reset buffer
buf.B = buf.B[:0]
- // Set the key-fields reference
- keys[i].fields = &sk[i]
+ // Append each field value to buffer.
+ for _, idx := range sk[i].fields {
+ fv := v.Field(idx)
+ fi := fv.Interface()
+ buf.B = mangler.Append(buf.B, fi)
+ buf.B = append(buf.B, '.')
+ }
+
+ // Drop last '.'
+ buf.Truncate(1)
- // Calculate cache-key value
- keys[i].populate(buf, v)
+ // Don't generate keys for zero values
+ if allowZero := sk[i].zero == ""; // nocollapse
+ !allowZero && buf.String() == sk[i].zero {
+ continue
+ }
+
+ // Append new cached key to slice
+ keys = append(keys, cachedKey{
+ key: &sk[i],
+ value: string(buf.B), // copy
+ })
}
return keys
}
-// cacheKey represents an actual cache key.
-type cacheKey struct {
+// cachedKey represents an actual cached key.
+type cachedKey struct {
+ // key is a reference to the structKey this
+ // cacheKey is representing. This is a shared
+ // reference and as such only the structKey.pkeys
+ // lookup map is expecting to be modified.
+ key *structKey
+
// value is the actual string representing
// this cache key for hashmap lookups.
value string
-
- // fieldsRO is a read-only slice (i.e. we should
- // NOT be modifying them, only using for reference)
- // of struct fields encapsulated by this cache key.
- fields *keyFields
-}
-
-// populate will calculate the cache key's value string for given
-// value's reflected information. Passed encoder is for string building.
-func (k *cacheKey) populate(buf *byteutil.Buffer, v reflect.Value) {
- // Append each field value to buffer.
- for _, idx := range k.fields.fields {
- fv := v.Field(idx)
- fi := fv.Interface()
- buf.B = mangler.Append(buf.B, fi)
- buf.B = append(buf.B, '.')
- }
-
- // Drop last '.'
- buf.Truncate(1)
-
- // Create string copy from buf
- k.value = string(buf.B)
}
-// keyFields represents a list of struct fields
-// encompassed in a single cache key, the string name
-// of the lookup, and the lookup map to primary keys.
-type keyFields struct {
- // lookup is the calculated (well, provided)
- // cache key lookup, consisting of dot sep'd
- // struct field names.
- lookup string
+// structKey represents a list of struct fields
+// encompassing a single cache key, the string name
+// of the lookup, the lookup map to primary cache
+// keys, and the key's possible zero value string.
+type structKey struct {
+ // name is the provided cache lookup name for
+ // this particular struct key, consisting of
+ // period ('.') separated struct field names.
+ name string
+
+ // zero is the possible zero value for this key.
+ // if set, this will _always_ be non-empty, as
+ // the mangled cache key will never be empty.
+ //
+ // i.e. zero = "" --> allow zero value keys
+ // zero != "" --> don't allow zero value keys
+ zero string
// fields is a slice of runtime struct field
// indices, of the fields encompassed by this key.
@@ -109,19 +117,20 @@ type keyFields struct {
pkeys map[string]int64
}
-// populate will populate this keyFields{} object's .fields member by determining
-// the field names from the given lookup, and querying given reflected type to get
-// the runtime field indices for each of the fields. this speeds-up future value lookups.
-func (kf *keyFields) populate(t reflect.Type) {
+// genStructKey will generate a structKey{} information object for user-given lookup
+// key information, and the receiving generic paramter's type information. Panics on error.
+func genStructKey(lk Lookup, t reflect.Type) structKey {
+ var zeros []any
+
// Split dot-separated lookup to get
// the individual struct field names
- names := strings.Split(kf.lookup, ".")
+ names := strings.Split(lk.Name, ".")
if len(names) == 0 {
panic("no key fields specified")
}
// Pre-allocate slice of expected length
- kf.fields = make([]int, len(names))
+ fields := make([]int, len(names))
for i, name := range names {
// Get field info for given name
@@ -136,13 +145,36 @@ func (kf *keyFields) populate(t reflect.Type) {
}
// Set the runtime field index
- kf.fields[i] = ft.Index[0]
+ fields[i] = ft.Index[0]
+
+ // Allocate new instance of field
+ v := reflect.New(ft.Type)
+ v = v.Elem()
+
+ if !lk.AllowZero {
+ // Append the zero value interface
+ zeros = append(zeros, v.Interface())
+ }
+ }
+
+ var zvalue string
+
+ if len(zeros) > 0 {
+ // Generate zero value string
+ zvalue = genKey(zeros...)
+ }
+
+ return structKey{
+ name: lk.Name,
+ zero: zvalue,
+ fields: fields,
+ pkeys: make(map[string]int64),
}
}
-// genkey generates a cache key for given key values.
-func genkey(parts ...any) string {
- if len(parts) < 1 {
+// genKey generates a cache key for given key values.
+func genKey(parts ...any) string {
+ if len(parts) == 0 {
// Panic to prevent annoying usecase
// where user forgets to pass lookup
// and instead only passes a key part,