2022-02-28 15:32:19 -07:00
|
|
|
// run
|
2021-12-12 12:08:59 -07:00
|
|
|
|
|
|
|
// Copyright 2021 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
type AnyCacher[T any] interface {
|
|
|
|
// Get an item from the cache. Returns the item or nil, and a bool indicating
|
|
|
|
// whether the key was found.
|
|
|
|
Get(k string) (T, bool)
|
|
|
|
// Add an item to the cache, replacing any existing item.
|
|
|
|
Set(k string, x T)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Item ...
|
|
|
|
type Item[T any] struct {
|
|
|
|
Object T
|
|
|
|
}
|
|
|
|
|
|
|
|
// AnyCache implements AnyCacher
|
|
|
|
type AnyCache[T any] struct {
|
|
|
|
*anyCache[T]
|
|
|
|
}
|
|
|
|
|
|
|
|
type anyCache[T any] struct {
|
|
|
|
items map[string]Item[T]
|
|
|
|
janitor *janitor[T] // Needed for the failure in the issue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set adds an item to the cache, replacing any existing item.
|
|
|
|
func (c *anyCache[T]) Set(k string, x T) {
|
|
|
|
c.items[k] = Item[T]{
|
|
|
|
Object: x,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get gets an item from the cache. Returns the item or nil, and a bool indicating
|
|
|
|
// whether the key was found.
|
|
|
|
func (c *anyCache[T]) Get(k string) (T, bool) {
|
|
|
|
// "Inlining" of get and Expired
|
|
|
|
item, found := c.items[k]
|
|
|
|
if !found {
|
|
|
|
var ret T
|
|
|
|
return ret, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return item.Object, true
|
|
|
|
}
|
|
|
|
|
|
|
|
type janitor[T any] struct {
|
|
|
|
stop chan bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newAnyCache[T any](m map[string]Item[T]) *anyCache[T] {
|
|
|
|
c := &anyCache[T]{
|
|
|
|
items: m,
|
|
|
|
}
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAny[T any](...) returns a new AnyCache[T].
|
|
|
|
func NewAny[T any]() *AnyCache[T] {
|
|
|
|
items := make(map[string]Item[T])
|
|
|
|
return &AnyCache[T]{newAnyCache(items)}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAnyCacher[T any](...) returns an AnyCacher[T] interface.
|
|
|
|
func NewAnyCacher[T any]() AnyCacher[T] {
|
|
|
|
return NewAny[T]()
|
|
|
|
}
|
|
|
|
|
|
|
|
type MyStruct struct {
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Create a generic cache.
|
|
|
|
// All items are cached as interface{} so they need to be cast back to their
|
|
|
|
// original type when retrieved.
|
|
|
|
// Failure in issue doesn't happen with 'any' replaced by 'interface{}'
|
|
|
|
c := NewAnyCacher[any]()
|
|
|
|
|
|
|
|
myStruct := &MyStruct{"MySuperStruct"}
|
|
|
|
|
|
|
|
c.Set("MySuperStruct", myStruct)
|
|
|
|
|
|
|
|
myRawCachedStruct, found := c.Get("MySuperStruct")
|
|
|
|
|
|
|
|
if found {
|
|
|
|
// Casting the retrieved object back to its original type
|
|
|
|
myCachedStruct := myRawCachedStruct.(*MyStruct)
|
|
|
|
fmt.Printf("%s", myCachedStruct.Name)
|
|
|
|
} else {
|
|
|
|
fmt.Printf("Error: MySuperStruct not found in cache")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output:
|
|
|
|
// MySuperStruct
|
|
|
|
}
|