Skip to content

Commit

Permalink
make cache DRY
Browse files Browse the repository at this point in the history
  • Loading branch information
lofcz committed Jan 8, 2025
1 parent 513bf37 commit fbafd68
Showing 1 changed file with 38 additions and 39 deletions.
77 changes: 38 additions & 39 deletions FastCloner/Code/FastClonerCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,18 @@ namespace FastCloner.Code;

internal static class FastClonerCache
{
private static readonly ConcurrentDictionary<Type, Lazy<object?>> classCache = new ConcurrentDictionary<Type, Lazy<object?>>();
private static readonly ConcurrentDictionary<Type, Lazy<object>> structCache = new ConcurrentDictionary<Type, Lazy<object>>();
private static readonly ConcurrentDictionary<Type, Lazy<object>> deepClassToCache = new ConcurrentDictionary<Type, Lazy<object>>();
private static readonly ConcurrentDictionary<Type, Lazy<object>> shallowClassToCache = new ConcurrentDictionary<Type, Lazy<object>>();
private static readonly ConcurrentDictionary<Tuple<Type, Type>, Lazy<object>> typeConvertCache = new ConcurrentDictionary<Tuple<Type, Type>, Lazy<object>>();

public static object? GetOrAddClass(Type type, Func<Type, object?> valueFactory)
{
Lazy<object?> lazy = classCache.GetOrAdd(type, t => new Lazy<object?>(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication));
return lazy.Value;
}

public static object GetOrAddStructAsObject(Type type, Func<Type, object> valueFactory)
{
Lazy<object> lazy = structCache.GetOrAdd(type, t => new Lazy<object>(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication));
return lazy.Value;
}

public static object GetOrAddDeepClassTo(Type type, Func<Type, object> valueFactory)
{
Lazy<object> lazy = deepClassToCache.GetOrAdd(type, t => new Lazy<object>(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication));
return lazy.Value;
}

public static object GetOrAddShallowClassTo(Type type, Func<Type, object> valueFactory)
{
Lazy<object> lazy = shallowClassToCache.GetOrAdd(type, t => new Lazy<object>(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication));
return lazy.Value;
}
private static readonly ClrCache<object?> classCache = new ClrCache<object?>();
private static readonly ClrCache<object> structCache = new ClrCache<object>();
private static readonly ClrCache<object> deepClassToCache = new ClrCache<object>();
private static readonly ClrCache<object> shallowClassToCache = new ClrCache<object>();
private static readonly ConcurrentLazyCache<object> typeConvertCache = new ConcurrentLazyCache<object>();

public static T GetOrAddConvertor<T>(Type from, Type to, Func<Type, Type, T> adder)
{
Tuple<Type, Type> key = new Tuple<Type, Type>(from, to);
Lazy<object> lazy = typeConvertCache.GetOrAdd(key, tuple => new Lazy<object>(() => adder(tuple.Item1, tuple.Item2), LazyThreadSafetyMode.ExecutionAndPublication));
return (T)lazy.Value;
}
public static object? GetOrAddClass(Type type, Func<Type, object?> valueFactory) => classCache.GetOrAdd(type, valueFactory);
public static object GetOrAddStructAsObject(Type type, Func<Type, object> valueFactory) => structCache.GetOrAdd(type, valueFactory);
public static object GetOrAddDeepClassTo(Type type, Func<Type, object> valueFactory) => deepClassToCache.GetOrAdd(type, valueFactory);
public static object GetOrAddShallowClassTo(Type type, Func<Type, object> valueFactory) => shallowClassToCache.GetOrAdd(type, valueFactory);
public static T GetOrAddConvertor<T>(Type from, Type to, Func<Type, Type, T> valueFactory) => (T)typeConvertCache.GetOrAdd(from, to, (f, t) => valueFactory(f, t));

Check warning on line 17 in FastCloner/Code/FastClonerCache.cs

View workflow job for this annotation

GitHub Actions / build-and-test (9.0.101)

Possible null reference return.

/// <summary>
/// This method can be used when we switch between safe / unsafe variants (for testing)
/// </summary>
public static void ClearCache()
{
classCache.Clear();
Expand All @@ -52,4 +24,31 @@ public static void ClearCache()
shallowClassToCache.Clear();
typeConvertCache.Clear();
}
}

private class ClrCache<TValue>
{
private readonly ConcurrentDictionary<Type, Lazy<TValue>> cache = new ConcurrentDictionary<Type, Lazy<TValue>>();

public TValue GetOrAdd(Type type, Func<Type, TValue> valueFactory)
{
Lazy<TValue> lazy = cache.GetOrAdd(type, t => new Lazy<TValue>(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication));
return lazy.Value;
}

public void Clear() => cache.Clear();
}

private class ConcurrentLazyCache<TValue>
{
private readonly ConcurrentDictionary<Tuple<Type, Type>, Lazy<TValue>> cache = [];

public TValue GetOrAdd(Type from, Type to, Func<Type, Type, TValue> valueFactory)
{
Tuple<Type, Type> key = new Tuple<Type, Type>(from, to);
Lazy<TValue> lazy = cache.GetOrAdd(key, tuple => new Lazy<TValue>(() => valueFactory(tuple.Item1, tuple.Item2), LazyThreadSafetyMode.ExecutionAndPublication));
return lazy.Value;
}

public void Clear() => cache.Clear();
}
}

0 comments on commit fbafd68

Please sign in to comment.