// Copyright 2025 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 fips140cache provides a weak map that associates the lifetime of // values with the lifetime of keys. // // It can be used to associate a precomputed value (such as an internal/fips140 // PrivateKey value, which in FIPS 140-3 mode may have required an expensive // pairwise consistency test) with a type that doesn't have private fields (such // as an ed25519.PrivateKey), or that can't be safely modified because it may be // concurrently copied (such as an ecdsa.PrivateKey). package fips140cache import ( "runtime" "sync" "weak" ) type Cache[K, V any] struct { m sync.Map } // Get returns the result of new, for an associated key k. // // If Get was called with k before and didn't return an error, Get may return // the same value it returned from the previous call if check returns true on // it. If check returns false, Get will call new again and return the result. // // The cache is evicted some time after k becomes unreachable. func (c *Cache[K, V]) Get(k *K, new func() (*V, error), check func(*V) bool) (*V, error) { p := weak.Make(k) if cached, ok := c.m.Load(p); ok { v := cached.(*V) if check(v) { return v, nil } } v, err := new() if err != nil { return nil, err } if _, present := c.m.Swap(p, v); !present { runtime.AddCleanup(k, c.evict, p) } return v, nil } func (c *Cache[K, V]) evict(p weak.Pointer[K]) { c.m.Delete(p) }