mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[chore] update go-structr and go-mangler to no longer rely on modern-go/reflect2 (#3026)
* updates go-structr and go-mangler to no longer rely on modern-go/reflect2 (*phew* now we're go1.23 safe) * update go-structr version * bump go-structr to improve memory usage (v. slightly) in certain conditions
This commit is contained in:
28
vendor/codeberg.org/gruf/go-structr/cache.go
generated
vendored
28
vendor/codeberg.org/gruf/go-structr/cache.go
generated
vendored
@@ -194,8 +194,7 @@ func (c *Cache[T]) Put(values ...T) {
|
||||
// Store all passed values.
|
||||
for i := range values {
|
||||
c.store_value(
|
||||
nil,
|
||||
Key{},
|
||||
nil, "",
|
||||
values[i],
|
||||
)
|
||||
}
|
||||
@@ -302,9 +301,9 @@ func (c *Cache[T]) LoadOne(index *Index, key Key, load func() (T, error)) (T, er
|
||||
// the provided value, so it is
|
||||
// safe for us to return as-is.
|
||||
if err != nil {
|
||||
c.store_error(index, key, err)
|
||||
c.store_error(index, key.key, err)
|
||||
} else {
|
||||
c.store_value(index, key, val)
|
||||
c.store_value(index, key.key, val)
|
||||
}
|
||||
|
||||
// Done with lock.
|
||||
@@ -388,8 +387,7 @@ func (c *Cache[T]) Load(index *Index, keys []Key, load func([]Key) ([]T, error))
|
||||
// Store all uncached values.
|
||||
for i := range uncached {
|
||||
c.store_value(
|
||||
nil,
|
||||
Key{},
|
||||
nil, "",
|
||||
uncached[i],
|
||||
)
|
||||
}
|
||||
@@ -511,6 +509,11 @@ func (c *Cache[T]) Trim(perc float64) {
|
||||
c.delete(item)
|
||||
}
|
||||
|
||||
// Compact index data stores.
|
||||
for i := range c.indices {
|
||||
c.indices[i].data.Compact()
|
||||
}
|
||||
|
||||
// Done with lock.
|
||||
c.mutex.Unlock()
|
||||
}
|
||||
@@ -535,10 +538,9 @@ func (c *Cache[T]) Debug() map[string]any {
|
||||
m["indices"] = indices
|
||||
for i := range c.indices {
|
||||
var n uint64
|
||||
c.indices[i].data.Iter(func(_ string, l *list) (stop bool) {
|
||||
for _, l := range c.indices[i].data.m {
|
||||
n += uint64(l.len)
|
||||
return
|
||||
})
|
||||
}
|
||||
indices[c.indices[i].name] = n
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
@@ -553,7 +555,7 @@ func (c *Cache[T]) Cap() int {
|
||||
return m
|
||||
}
|
||||
|
||||
func (c *Cache[T]) store_value(index *Index, key Key, value T) {
|
||||
func (c *Cache[T]) store_value(index *Index, key string, value T) {
|
||||
// Alloc new index item.
|
||||
item := new_indexed_item()
|
||||
if cap(item.indexed) < len(c.indices) {
|
||||
@@ -569,7 +571,7 @@ func (c *Cache[T]) store_value(index *Index, key Key, value T) {
|
||||
|
||||
if index != nil {
|
||||
// Append item to index.
|
||||
index.append(key.key, item)
|
||||
index.append(key, item)
|
||||
}
|
||||
|
||||
// Get ptr to value data.
|
||||
@@ -619,7 +621,7 @@ func (c *Cache[T]) store_value(index *Index, key Key, value T) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache[T]) store_error(index *Index, key Key, err error) {
|
||||
func (c *Cache[T]) store_error(index *Index, key string, err error) {
|
||||
if index == nil {
|
||||
// nothing we
|
||||
// can do here.
|
||||
@@ -639,7 +641,7 @@ func (c *Cache[T]) store_error(index *Index, key Key, err error) {
|
||||
item.data = err
|
||||
|
||||
// Append item to index.
|
||||
index.append(key.key, item)
|
||||
index.append(key, item)
|
||||
|
||||
// Add item to main lru list.
|
||||
c.lru.push_front(&item.elem)
|
||||
|
50
vendor/codeberg.org/gruf/go-structr/index.go
generated
vendored
50
vendor/codeberg.org/gruf/go-structr/index.go
generated
vendored
@@ -7,8 +7,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-byteutil"
|
||||
|
||||
"github.com/dolthub/swiss"
|
||||
)
|
||||
|
||||
// IndexConfig defines config variables
|
||||
@@ -72,7 +70,7 @@ type Index struct {
|
||||
// index_entry{} which also contains the exact
|
||||
// key each result is stored under. the hash map
|
||||
// only keys by the xxh3 hash checksum for speed.
|
||||
data *swiss.Map[string, *list]
|
||||
data hashmap
|
||||
|
||||
// struct fields encompassed by
|
||||
// keys (+ hashes) of this index.
|
||||
@@ -93,8 +91,12 @@ func (i *Index) Name() string {
|
||||
// the type of lookup this Index uses in cache.
|
||||
// NOTE: panics on incorrect no. parts / types given.
|
||||
func (i *Index) Key(parts ...any) Key {
|
||||
ptrs := make([]unsafe.Pointer, len(parts))
|
||||
for x, part := range parts {
|
||||
ptrs[x] = eface_data(part)
|
||||
}
|
||||
buf := new_buffer()
|
||||
key := i.key(buf, parts)
|
||||
key := i.key(buf, ptrs)
|
||||
free_buffer(buf)
|
||||
return Key{
|
||||
raw: parts,
|
||||
@@ -109,7 +111,11 @@ func (i *Index) Keys(parts ...[]any) []Key {
|
||||
keys := make([]Key, 0, len(parts))
|
||||
buf := new_buffer()
|
||||
for _, parts := range parts {
|
||||
key := i.key(buf, parts)
|
||||
ptrs := make([]unsafe.Pointer, len(parts))
|
||||
for x, part := range parts {
|
||||
ptrs[x] = eface_data(part)
|
||||
}
|
||||
key := i.key(buf, ptrs)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
@@ -160,8 +166,9 @@ func (i *Index) init(t reflect.Type, cfg IndexConfig, cap int) {
|
||||
i.fields[x] = find_field(t, names)
|
||||
}
|
||||
|
||||
// Initialize index_entry list store.
|
||||
i.data = swiss.NewMap[string, *list](uint32(cap))
|
||||
// Initialize store for
|
||||
// index_entry lists.
|
||||
i.data.init(cap)
|
||||
}
|
||||
|
||||
// get_one will fetch one indexed item under key.
|
||||
@@ -203,7 +210,7 @@ func (i *Index) get(key string, hook func(*indexed_item)) {
|
||||
}
|
||||
|
||||
// key uses hasher to generate Key{} from given raw parts.
|
||||
func (i *Index) key(buf *byteutil.Buffer, parts []any) string {
|
||||
func (i *Index) key(buf *byteutil.Buffer, parts []unsafe.Pointer) string {
|
||||
if len(parts) != len(i.fields) {
|
||||
panicf("incorrect number key parts: want=%d received=%d",
|
||||
len(i.fields),
|
||||
@@ -332,33 +339,6 @@ func (i *Index) delete_entry(entry *index_entry) {
|
||||
entry.item.drop_index(entry)
|
||||
}
|
||||
|
||||
// compact will reduce the size of underlying
|
||||
// index map if the cap vastly exceeds len.
|
||||
func (i *Index) compact() {
|
||||
|
||||
// Maximum load factor before
|
||||
// 'swiss' allocates new hmap:
|
||||
// maxLoad = 7 / 8
|
||||
//
|
||||
// So we apply the inverse/2, once
|
||||
// $maxLoad/2 % of hmap is empty we
|
||||
// compact the map to drop buckets.
|
||||
len := i.data.Count()
|
||||
cap := i.data.Capacity()
|
||||
if cap-len > (cap*7)/(8*2) {
|
||||
|
||||
// Create a new map only as big as required.
|
||||
data := swiss.NewMap[string, *list](uint32(len))
|
||||
i.data.Iter(func(k string, v *list) (stop bool) {
|
||||
data.Put(k, v)
|
||||
return false
|
||||
})
|
||||
|
||||
// Set new map.
|
||||
i.data = data
|
||||
}
|
||||
}
|
||||
|
||||
// index_entry represents a single entry
|
||||
// in an Index{}, where it will be accessible
|
||||
// by Key{} pointing to a containing list{}.
|
||||
|
59
vendor/codeberg.org/gruf/go-structr/map.go
generated
vendored
Normal file
59
vendor/codeberg.org/gruf/go-structr/map.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package structr
|
||||
|
||||
type hashmap struct {
|
||||
m map[string]*list
|
||||
n int
|
||||
}
|
||||
|
||||
func (m *hashmap) init(cap int) {
|
||||
m.m = make(map[string]*list, cap)
|
||||
m.n = cap
|
||||
}
|
||||
|
||||
func (m *hashmap) Get(key string) (*list, bool) {
|
||||
list, ok := m.m[key]
|
||||
return list, ok
|
||||
}
|
||||
|
||||
func (m *hashmap) Put(key string, list *list) {
|
||||
m.m[key] = list
|
||||
if n := len(m.m); n > m.n {
|
||||
m.n = n
|
||||
}
|
||||
}
|
||||
|
||||
func (m *hashmap) Delete(key string) {
|
||||
delete(m.m, key)
|
||||
}
|
||||
|
||||
func (m *hashmap) Compact() {
|
||||
// Noop when hashmap size
|
||||
// is too small to matter.
|
||||
if m.n < 2048 {
|
||||
return
|
||||
}
|
||||
|
||||
// Difference between maximum map
|
||||
// size and the current map size.
|
||||
diff := m.n - len(m.m)
|
||||
|
||||
// Maximum load factor before
|
||||
// runtime allocates new hmap:
|
||||
// maxLoad = 13 / 16
|
||||
//
|
||||
// So we apply the inverse/2, once
|
||||
// $maxLoad/2 % of hmap is empty we
|
||||
// compact the map to drop buckets.
|
||||
if 2*16*diff > m.n*13 {
|
||||
|
||||
// Create new map only big as required.
|
||||
m2 := make(map[string]*list, len(m.m))
|
||||
for k, v := range m.m {
|
||||
m2[k] = v
|
||||
}
|
||||
|
||||
// Set new.
|
||||
m.m = m2
|
||||
m.n = len(m2)
|
||||
}
|
||||
}
|
9
vendor/codeberg.org/gruf/go-structr/queue.go
generated
vendored
9
vendor/codeberg.org/gruf/go-structr/queue.go
generated
vendored
@@ -214,10 +214,9 @@ func (q *Queue[T]) Debug() map[string]any {
|
||||
m["indices"] = indices
|
||||
for i := range q.indices {
|
||||
var n uint64
|
||||
q.indices[i].data.Iter(func(_ string, l *list) (stop bool) {
|
||||
for _, l := range q.indices[i].data.m {
|
||||
n += uint64(l.len)
|
||||
return
|
||||
})
|
||||
}
|
||||
indices[q.indices[i].name] = n
|
||||
}
|
||||
q.mutex.Unlock()
|
||||
@@ -331,8 +330,8 @@ func (q *Queue[T]) delete(item *indexed_item) {
|
||||
// Drop this index_entry.
|
||||
index.delete_entry(entry)
|
||||
|
||||
// Check compact.
|
||||
index.compact()
|
||||
// Check compact map.
|
||||
index.data.Compact()
|
||||
}
|
||||
|
||||
// Drop entry from queue list.
|
||||
|
5
vendor/codeberg.org/gruf/go-structr/queue_ctx.go
generated
vendored
5
vendor/codeberg.org/gruf/go-structr/queue_ctx.go
generated
vendored
@@ -73,10 +73,9 @@ func (q *QueueCtx[T]) Debug() map[string]any {
|
||||
m["indices"] = indices
|
||||
for i := range q.indices {
|
||||
var n uint64
|
||||
q.indices[i].data.Iter(func(_ string, l *list) (stop bool) {
|
||||
for _, l := range q.indices[i].data.m {
|
||||
n += uint64(l.len)
|
||||
return
|
||||
})
|
||||
}
|
||||
indices[q.indices[i].name] = n
|
||||
}
|
||||
q.mutex.Unlock()
|
||||
|
58
vendor/codeberg.org/gruf/go-structr/runtime.go
generated
vendored
58
vendor/codeberg.org/gruf/go-structr/runtime.go
generated
vendored
@@ -8,18 +8,13 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"codeberg.org/gruf/go-mangler"
|
||||
"github.com/modern-go/reflect2"
|
||||
)
|
||||
|
||||
// struct_field contains pre-prepared type
|
||||
// information about a struct's field member,
|
||||
// including memory offset and hash function.
|
||||
type struct_field struct {
|
||||
|
||||
// type2 contains the reflect2
|
||||
// type information for this field,
|
||||
// used in repacking it as eface.
|
||||
type2 reflect2.Type
|
||||
rtype reflect.Type
|
||||
|
||||
// offsets defines whereabouts in
|
||||
// memory this field is located.
|
||||
@@ -109,25 +104,27 @@ func find_field(t reflect.Type, names []string) (sfield struct_field) {
|
||||
t = field.Type
|
||||
}
|
||||
|
||||
// Get field type as reflect2.
|
||||
sfield.type2 = reflect2.Type2(t)
|
||||
// Set final type.
|
||||
sfield.rtype = t
|
||||
|
||||
// Find mangler for field type.
|
||||
sfield.mangle = mangler.Get(t)
|
||||
|
||||
// Set possible zero value and its string.
|
||||
sfield.zero = sfield.type2.UnsafeNew()
|
||||
i := sfield.type2.UnsafeIndirect(sfield.zero)
|
||||
sfield.zerostr = string(sfield.mangle(nil, i))
|
||||
// Get new zero value data ptr.
|
||||
v := reflect.New(t).Elem()
|
||||
zptr := eface_data(v.Interface())
|
||||
zstr := sfield.mangle(nil, zptr)
|
||||
sfield.zerostr = string(zstr)
|
||||
sfield.zero = zptr
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// extract_fields extracts given structfields from the provided value type,
|
||||
// this is done using predetermined struct field memory offset locations.
|
||||
func extract_fields(ptr unsafe.Pointer, fields []struct_field) []any {
|
||||
// Prepare slice of field ifaces.
|
||||
ifaces := make([]any, len(fields))
|
||||
func extract_fields(ptr unsafe.Pointer, fields []struct_field) []unsafe.Pointer {
|
||||
// Prepare slice of field value pointers.
|
||||
ptrs := make([]unsafe.Pointer, len(fields))
|
||||
for i, field := range fields {
|
||||
|
||||
// loop scope.
|
||||
@@ -136,10 +133,7 @@ func extract_fields(ptr unsafe.Pointer, fields []struct_field) []any {
|
||||
for _, offset := range field.offsets {
|
||||
// Dereference any ptrs to offset.
|
||||
fptr = deref(fptr, offset.derefs)
|
||||
|
||||
if fptr == nil {
|
||||
// Use zero value.
|
||||
fptr = field.zero
|
||||
break
|
||||
}
|
||||
|
||||
@@ -148,11 +142,31 @@ func extract_fields(ptr unsafe.Pointer, fields []struct_field) []any {
|
||||
offset.offset)
|
||||
}
|
||||
|
||||
// Repack value data ptr as empty interface.
|
||||
ifaces[i] = field.type2.UnsafeIndirect(fptr)
|
||||
}
|
||||
if like_ptr(field.rtype) && fptr != nil {
|
||||
// Further dereference value ptr.
|
||||
fptr = *(*unsafe.Pointer)(fptr)
|
||||
}
|
||||
|
||||
return ifaces
|
||||
if fptr == nil {
|
||||
// Use zero value.
|
||||
fptr = field.zero
|
||||
}
|
||||
|
||||
ptrs[i] = fptr
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
// like_ptr returns whether type's kind is ptr-like.
|
||||
func like_ptr(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Pointer,
|
||||
reflect.Map,
|
||||
reflect.Chan,
|
||||
reflect.Func:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// deref will dereference ptr 'n' times (or until nil).
|
||||
|
8
vendor/codeberg.org/gruf/go-structr/util.go
generated
vendored
8
vendor/codeberg.org/gruf/go-structr/util.go
generated
vendored
@@ -1,5 +1,7 @@
|
||||
package structr
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// once only executes 'fn' once.
|
||||
func once(fn func()) func() {
|
||||
var once int32
|
||||
@@ -11,3 +13,9 @@ func once(fn func()) func() {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
// eface_data returns the data ptr from an empty interface.
|
||||
func eface_data(a any) unsafe.Pointer {
|
||||
type eface struct{ _, data unsafe.Pointer }
|
||||
return (*eface)(unsafe.Pointer(&a)).data
|
||||
}
|
||||
|
Reference in New Issue
Block a user