wabbajack/Wabbajack.Common/LazyCache.cs

40 lines
1.2 KiB
C#
Raw Normal View History

2021-09-27 12:42:46 +00:00
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
2021-10-23 16:51:17 +00:00
namespace Wabbajack.Common;
/// <summary>
/// Represents a cache where values are created on-the-fly when they are found missing.
/// Creating a value locks the cache entry so that each key/value pair is only created once.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TVal"></typeparam>
public class LazyCache<TKey, TArg, TVal>
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
private readonly ConcurrentDictionary<TKey, AsyncLazy<TVal>> _data;
private readonly Func<TArg, TKey> _selector;
private readonly Func<TArg, Task<TVal>> _valueFactory;
public LazyCache(Func<TArg, TKey> selector, Func<TArg, Task<TVal>> valueFactory)
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
_selector = selector;
_valueFactory = valueFactory;
_data = new ConcurrentDictionary<TKey, AsyncLazy<TVal>>();
}
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
public async ValueTask<TVal> Get(TArg lookup)
{
var key = _selector(lookup);
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
while (true)
2021-09-27 12:42:46 +00:00
{
2021-10-23 16:51:17 +00:00
if (_data.TryGetValue(key, out var found))
return await found.Value;
2021-09-27 12:42:46 +00:00
2021-10-23 16:51:17 +00:00
var value = new AsyncLazy<TVal>(() => _valueFactory(lookup));
if (_data.TryAdd(key, value))
return await value.Value;
2021-09-27 12:42:46 +00:00
}
}
}