mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-24 11:12:11 +00:00
167 lines
4.3 KiB
Go
167 lines
4.3 KiB
Go
|
// Copyright (C) MongoDB, Inc. 2017-present.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||
|
// not use this file except in compliance with the License. You may obtain
|
||
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
package bsoncodec
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"sync"
|
||
|
"sync/atomic"
|
||
|
)
|
||
|
|
||
|
// Runtime check that the kind encoder and decoder caches can store any valid
|
||
|
// reflect.Kind constant.
|
||
|
func init() {
|
||
|
if s := reflect.Kind(len(kindEncoderCache{}.entries)).String(); s != "kind27" {
|
||
|
panic("The capacity of kindEncoderCache is too small.\n" +
|
||
|
"This is due to a new type being added to reflect.Kind.")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// statically assert array size
|
||
|
var _ = (kindEncoderCache{}).entries[reflect.UnsafePointer]
|
||
|
var _ = (kindDecoderCache{}).entries[reflect.UnsafePointer]
|
||
|
|
||
|
type typeEncoderCache struct {
|
||
|
cache sync.Map // map[reflect.Type]ValueEncoder
|
||
|
}
|
||
|
|
||
|
func (c *typeEncoderCache) Store(rt reflect.Type, enc ValueEncoder) {
|
||
|
c.cache.Store(rt, enc)
|
||
|
}
|
||
|
|
||
|
func (c *typeEncoderCache) Load(rt reflect.Type) (ValueEncoder, bool) {
|
||
|
if v, _ := c.cache.Load(rt); v != nil {
|
||
|
return v.(ValueEncoder), true
|
||
|
}
|
||
|
return nil, false
|
||
|
}
|
||
|
|
||
|
func (c *typeEncoderCache) LoadOrStore(rt reflect.Type, enc ValueEncoder) ValueEncoder {
|
||
|
if v, loaded := c.cache.LoadOrStore(rt, enc); loaded {
|
||
|
enc = v.(ValueEncoder)
|
||
|
}
|
||
|
return enc
|
||
|
}
|
||
|
|
||
|
func (c *typeEncoderCache) Clone() *typeEncoderCache {
|
||
|
cc := new(typeEncoderCache)
|
||
|
c.cache.Range(func(k, v interface{}) bool {
|
||
|
if k != nil && v != nil {
|
||
|
cc.cache.Store(k, v)
|
||
|
}
|
||
|
return true
|
||
|
})
|
||
|
return cc
|
||
|
}
|
||
|
|
||
|
type typeDecoderCache struct {
|
||
|
cache sync.Map // map[reflect.Type]ValueDecoder
|
||
|
}
|
||
|
|
||
|
func (c *typeDecoderCache) Store(rt reflect.Type, dec ValueDecoder) {
|
||
|
c.cache.Store(rt, dec)
|
||
|
}
|
||
|
|
||
|
func (c *typeDecoderCache) Load(rt reflect.Type) (ValueDecoder, bool) {
|
||
|
if v, _ := c.cache.Load(rt); v != nil {
|
||
|
return v.(ValueDecoder), true
|
||
|
}
|
||
|
return nil, false
|
||
|
}
|
||
|
|
||
|
func (c *typeDecoderCache) LoadOrStore(rt reflect.Type, dec ValueDecoder) ValueDecoder {
|
||
|
if v, loaded := c.cache.LoadOrStore(rt, dec); loaded {
|
||
|
dec = v.(ValueDecoder)
|
||
|
}
|
||
|
return dec
|
||
|
}
|
||
|
|
||
|
func (c *typeDecoderCache) Clone() *typeDecoderCache {
|
||
|
cc := new(typeDecoderCache)
|
||
|
c.cache.Range(func(k, v interface{}) bool {
|
||
|
if k != nil && v != nil {
|
||
|
cc.cache.Store(k, v)
|
||
|
}
|
||
|
return true
|
||
|
})
|
||
|
return cc
|
||
|
}
|
||
|
|
||
|
// atomic.Value requires that all calls to Store() have the same concrete type
|
||
|
// so we wrap the ValueEncoder with a kindEncoderCacheEntry to ensure the type
|
||
|
// is always the same (since different concrete types may implement the
|
||
|
// ValueEncoder interface).
|
||
|
type kindEncoderCacheEntry struct {
|
||
|
enc ValueEncoder
|
||
|
}
|
||
|
|
||
|
type kindEncoderCache struct {
|
||
|
entries [reflect.UnsafePointer + 1]atomic.Value // *kindEncoderCacheEntry
|
||
|
}
|
||
|
|
||
|
func (c *kindEncoderCache) Store(rt reflect.Kind, enc ValueEncoder) {
|
||
|
if enc != nil && rt < reflect.Kind(len(c.entries)) {
|
||
|
c.entries[rt].Store(&kindEncoderCacheEntry{enc: enc})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *kindEncoderCache) Load(rt reflect.Kind) (ValueEncoder, bool) {
|
||
|
if rt < reflect.Kind(len(c.entries)) {
|
||
|
if ent, ok := c.entries[rt].Load().(*kindEncoderCacheEntry); ok {
|
||
|
return ent.enc, ent.enc != nil
|
||
|
}
|
||
|
}
|
||
|
return nil, false
|
||
|
}
|
||
|
|
||
|
func (c *kindEncoderCache) Clone() *kindEncoderCache {
|
||
|
cc := new(kindEncoderCache)
|
||
|
for i, v := range c.entries {
|
||
|
if val := v.Load(); val != nil {
|
||
|
cc.entries[i].Store(val)
|
||
|
}
|
||
|
}
|
||
|
return cc
|
||
|
}
|
||
|
|
||
|
// atomic.Value requires that all calls to Store() have the same concrete type
|
||
|
// so we wrap the ValueDecoder with a kindDecoderCacheEntry to ensure the type
|
||
|
// is always the same (since different concrete types may implement the
|
||
|
// ValueDecoder interface).
|
||
|
type kindDecoderCacheEntry struct {
|
||
|
dec ValueDecoder
|
||
|
}
|
||
|
|
||
|
type kindDecoderCache struct {
|
||
|
entries [reflect.UnsafePointer + 1]atomic.Value // *kindDecoderCacheEntry
|
||
|
}
|
||
|
|
||
|
func (c *kindDecoderCache) Store(rt reflect.Kind, dec ValueDecoder) {
|
||
|
if rt < reflect.Kind(len(c.entries)) {
|
||
|
c.entries[rt].Store(&kindDecoderCacheEntry{dec: dec})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *kindDecoderCache) Load(rt reflect.Kind) (ValueDecoder, bool) {
|
||
|
if rt < reflect.Kind(len(c.entries)) {
|
||
|
if ent, ok := c.entries[rt].Load().(*kindDecoderCacheEntry); ok {
|
||
|
return ent.dec, ent.dec != nil
|
||
|
}
|
||
|
}
|
||
|
return nil, false
|
||
|
}
|
||
|
|
||
|
func (c *kindDecoderCache) Clone() *kindDecoderCache {
|
||
|
cc := new(kindDecoderCache)
|
||
|
for i, v := range c.entries {
|
||
|
if val := v.Load(); val != nil {
|
||
|
cc.entries[i].Store(val)
|
||
|
}
|
||
|
}
|
||
|
return cc
|
||
|
}
|