github.com/LagrangeDev/LagrangeGo@v0.0.0-20240512064304-ad4a85e10cb4/client/internal/cache/base.go (about)

     1  package cache
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  
     7  	"github.com/LagrangeDev/LagrangeGo/client/entity"
     8  	"github.com/RomiChan/syncx"
     9  )
    10  
    11  type cacheType uint32
    12  
    13  const (
    14  	cacheTypeCache cacheType = 1 << iota
    15  	cacheTypeFriend
    16  	cacheTypeGroupInfo
    17  	cacheTypeGroupMember
    18  )
    19  
    20  func typenameof[T any]() string {
    21  	return reflect.ValueOf((*T)(nil)).Type().String()
    22  }
    23  
    24  var cacheTypesMap = map[string]cacheType{
    25  	typenameof[Cache]():              cacheTypeCache,
    26  	typenameof[entity.Friend]():      cacheTypeFriend,
    27  	typenameof[entity.Group]():       cacheTypeGroupInfo,
    28  	typenameof[entity.GroupMember](): cacheTypeGroupMember,
    29  }
    30  
    31  type Cache struct {
    32  	m         syncx.Map[uint64, unsafe.Pointer]
    33  	refreshed syncx.Map[cacheType, struct{}]
    34  }
    35  
    36  func hasRefreshed[T any](c *Cache) bool {
    37  	typ := cacheTypesMap[reflect.ValueOf((*T)(nil)).Type().String()]
    38  	if typ == 0 {
    39  		return false
    40  	}
    41  	_, ok := c.refreshed.Load(typ)
    42  	return ok
    43  }
    44  
    45  func refreshAllCacheOf[T any](c *Cache, newcache map[uint32]*T) {
    46  	typstr := reflect.ValueOf((*T)(nil)).Type().String()
    47  	typ := cacheTypesMap[typstr]
    48  	if typ == 0 {
    49  		return
    50  	}
    51  	c.refreshed.Store(typ, struct{}{})
    52  	key := uint64(typ) << 32
    53  	dellst := make([]uint64, 0, 64)
    54  	c.m.Range(func(k uint64, v unsafe.Pointer) bool {
    55  		if k&key != 0 {
    56  			if _, ok := newcache[uint32(k)]; !ok {
    57  				dellst = append(dellst, k)
    58  			}
    59  		}
    60  		return true
    61  	})
    62  	for k, v := range newcache {
    63  		c.m.Store(key|uint64(k), unsafe.Pointer(v))
    64  	}
    65  	for _, k := range dellst {
    66  		c.m.Delete(k)
    67  	}
    68  }
    69  
    70  func setCacheOf[T any](c *Cache, k uint32, v *T) {
    71  	typstr := reflect.ValueOf(v).Type().String()
    72  	typ := cacheTypesMap[typstr]
    73  	if typ == 0 {
    74  		return
    75  	}
    76  	key := uint64(typ)<<32 | uint64(k)
    77  	c.m.Store(key, unsafe.Pointer(v))
    78  }
    79  
    80  func getCacheOf[T any](c *Cache, k uint32) (v *T, ok bool) {
    81  	typstr := reflect.ValueOf(v).Type().String()
    82  	typ := cacheTypesMap[typstr]
    83  	if typ == 0 {
    84  		return
    85  	}
    86  	key := uint64(typ)<<32 | uint64(k)
    87  	unsafev, ok := c.m.Load(key)
    88  	if ok {
    89  		v = (*T)(unsafev)
    90  	}
    91  	return
    92  }
    93  
    94  func rangeCacheOf[T any](c *Cache, iter func(k uint32, v *T) bool) {
    95  	typ := cacheTypesMap[reflect.ValueOf((*T)(nil)).Type().String()]
    96  	if typ == 0 {
    97  		return
    98  	}
    99  	key := uint64(typ) << 32
   100  	c.m.Range(func(k uint64, v unsafe.Pointer) bool {
   101  		if k&key != 0 {
   102  			return iter(uint32(k), (*T)(v))
   103  		}
   104  		return true
   105  	})
   106  }