diff --git a/BitFaster.Caching/SingletonCache.cs b/BitFaster.Caching/SingletonCache.cs index a4f7bba4..4baeb620 100644 --- a/BitFaster.Caching/SingletonCache.cs +++ b/BitFaster.Caching/SingletonCache.cs @@ -7,89 +7,88 @@ namespace BitFaster.Caching { - /// - /// Cache a single value for each key, and maintain in memory only the values that have been acquired - /// but not yet released. - /// - /// The type of the key. - /// The type of the value. - public class SingletonCache - where TValue : new() - { - private readonly ConcurrentDictionary> cache; + /// + /// Cache a single value for each key, and maintain in memory only the values that have been acquired + /// but not yet released. + /// + /// The type of the key. + /// The type of the value. + public class SingletonCache + { + private readonly ConcurrentDictionary> cache; - public SingletonCache() - { - this.cache = new ConcurrentDictionary>(); - } + public SingletonCache() + { + this.cache = new ConcurrentDictionary>(); + } - public SingletonCache(int concurrencyLevel, int capacity, IEqualityComparer comparer) - { - this.cache = new ConcurrentDictionary>(concurrencyLevel, capacity, comparer); - } + public SingletonCache(int concurrencyLevel, int capacity, IEqualityComparer comparer) + { + this.cache = new ConcurrentDictionary>(concurrencyLevel, capacity, comparer); + } - public Handle Acquire(TKey key) - { - var refCount = this.cache.AddOrUpdate(key, - (_) => new ReferenceCount(new TValue()), - (_, existingRefCount) => existingRefCount.IncrementCopy()); + public Handle Acquire(TKey key, Func valueFactory) + { + var refCount = this.cache.AddOrUpdate(key, + (_) => new ReferenceCount(valueFactory(_)), + (_, existingRefCount) => existingRefCount.IncrementCopy()); - return new Handle(key, refCount.Value, this); - } + return new Handle(key, refCount.Value, this); + } - private void Release(TKey key) - { - while (true) - { - var oldRefCount = this.cache[key]; - var newRefCount = oldRefCount.DecrementCopy(); - if (this.cache.TryUpdate(key, newRefCount, oldRefCount)) - { - if (newRefCount.Count == 0) - { - // This will remove from dictionary only if key and the value with ReferenceCount (== 0) matches (under a lock) - if (((IDictionary>)this.cache).Remove(new KeyValuePair>(key, newRefCount))) - { - if (newRefCount.Value is IDisposable d) - { - d.Dispose(); - } - } - } - break; - } - } - } + private void Release(TKey key) + { + while (true) + { + var oldRefCount = this.cache[key]; + var newRefCount = oldRefCount.DecrementCopy(); + if (this.cache.TryUpdate(key, newRefCount, oldRefCount)) + { + if (newRefCount.Count == 0) + { + // This will remove from dictionary only if key and the value with ReferenceCount (== 0) matches (under a lock) + if (((IDictionary>)this.cache).Remove(new KeyValuePair>(key, newRefCount))) + { + if (newRefCount.Value is IDisposable d) + { + d.Dispose(); + } + } + } + break; + } + } + } - public sealed class Handle : IDisposable - { - private TKey key; - private TValue value; - private SingletonCache cache; + public sealed class Handle : IDisposable + { + private TKey key; + private TValue value; + private SingletonCache cache; - public Handle(TKey key, TValue value, SingletonCache cache) - { - this.key = key; - this.value = value; - this.cache = cache; - } + public Handle(TKey key, TValue value, SingletonCache cache) + { + this.key = key; + this.value = value; + this.cache = cache; + } - public TValue Value - { - get - { - return this.value; - } - } + public TValue Value + { + get + { + return this.value; + } + } - public void Dispose() - { - if (this.cache != null) - { - this.cache.Release(this.key); - this.cache = null; - } - } - } - } + public void Dispose() + { + if (this.cache != null) + { + this.cache.Release(this.key); + this.cache = null; + } + } + } + } } diff --git a/BitFaster.Caching/SingletonCacheExtensions.cs b/BitFaster.Caching/SingletonCacheExtensions.cs new file mode 100644 index 00000000..7d4ca461 --- /dev/null +++ b/BitFaster.Caching/SingletonCacheExtensions.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BitFaster.Caching +{ + public static class SingletonCacheExtensions + { + public static SingletonCache.Handle Acquire(this SingletonCache cache, TKey key) + where TValue : new() + { + return cache.Acquire(key, _ => new TValue()); + } + } +}