Source file src/crypto/internal/fips140cache/cache.go
1 // Copyright 2025 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package fips140cache provides a weak map that associates the lifetime of 6 // values with the lifetime of keys. 7 // 8 // It can be used to associate a precomputed value (such as an internal/fips140 9 // PrivateKey value, which in FIPS 140-3 mode may have required an expensive 10 // pairwise consistency test) with a type that doesn't have private fields (such 11 // as an ed25519.PrivateKey), or that can't be safely modified because it may be 12 // concurrently copied (such as an ecdsa.PrivateKey). 13 package fips140cache 14 15 import ( 16 "runtime" 17 "sync" 18 "weak" 19 ) 20 21 type Cache[K, V any] struct { 22 m sync.Map 23 } 24 25 // Get returns the result of new, for an associated key k. 26 // 27 // If Get was called with k before and didn't return an error, Get may return 28 // the same value it returned from the previous call if check returns true on 29 // it. If check returns false, Get will call new again and return the result. 30 // 31 // The cache is evicted some time after k becomes unreachable. 32 func (c *Cache[K, V]) Get(k *K, new func() (*V, error), check func(*V) bool) (*V, error) { 33 p := weak.Make(k) 34 if cached, ok := c.m.Load(p); ok { 35 v := cached.(*V) 36 if check(v) { 37 return v, nil 38 } 39 } 40 v, err := new() 41 if err != nil { 42 return nil, err 43 } 44 if _, present := c.m.Swap(p, v); !present { 45 runtime.AddCleanup(k, c.evict, p) 46 } 47 return v, nil 48 } 49 50 func (c *Cache[K, V]) evict(p weak.Pointer[K]) { 51 c.m.Delete(p) 52 } 53