From fbafd68cd11404708d7124fb0a9246e04f7131e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20=C5=A0t=C3=A1gl?= Date: Wed, 8 Jan 2025 17:51:40 +0100 Subject: [PATCH] make cache DRY --- FastCloner/Code/FastClonerCache.cs | 77 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/FastCloner/Code/FastClonerCache.cs b/FastCloner/Code/FastClonerCache.cs index cc0b3dc..3f8860c 100644 --- a/FastCloner/Code/FastClonerCache.cs +++ b/FastCloner/Code/FastClonerCache.cs @@ -4,46 +4,18 @@ namespace FastCloner.Code; internal static class FastClonerCache { - private static readonly ConcurrentDictionary> classCache = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary> structCache = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary> deepClassToCache = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary> shallowClassToCache = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary, Lazy> typeConvertCache = new ConcurrentDictionary, Lazy>(); - - public static object? GetOrAddClass(Type type, Func valueFactory) - { - Lazy lazy = classCache.GetOrAdd(type, t => new Lazy(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication)); - return lazy.Value; - } - - public static object GetOrAddStructAsObject(Type type, Func valueFactory) - { - Lazy lazy = structCache.GetOrAdd(type, t => new Lazy(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication)); - return lazy.Value; - } - - public static object GetOrAddDeepClassTo(Type type, Func valueFactory) - { - Lazy lazy = deepClassToCache.GetOrAdd(type, t => new Lazy(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication)); - return lazy.Value; - } - - public static object GetOrAddShallowClassTo(Type type, Func valueFactory) - { - Lazy lazy = shallowClassToCache.GetOrAdd(type, t => new Lazy(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication)); - return lazy.Value; - } + private static readonly ClrCache classCache = new ClrCache(); + private static readonly ClrCache structCache = new ClrCache(); + private static readonly ClrCache deepClassToCache = new ClrCache(); + private static readonly ClrCache shallowClassToCache = new ClrCache(); + private static readonly ConcurrentLazyCache typeConvertCache = new ConcurrentLazyCache(); - public static T GetOrAddConvertor(Type from, Type to, Func adder) - { - Tuple key = new Tuple(from, to); - Lazy lazy = typeConvertCache.GetOrAdd(key, tuple => new Lazy(() => adder(tuple.Item1, tuple.Item2), LazyThreadSafetyMode.ExecutionAndPublication)); - return (T)lazy.Value; - } + public static object? GetOrAddClass(Type type, Func valueFactory) => classCache.GetOrAdd(type, valueFactory); + public static object GetOrAddStructAsObject(Type type, Func valueFactory) => structCache.GetOrAdd(type, valueFactory); + public static object GetOrAddDeepClassTo(Type type, Func valueFactory) => deepClassToCache.GetOrAdd(type, valueFactory); + public static object GetOrAddShallowClassTo(Type type, Func valueFactory) => shallowClassToCache.GetOrAdd(type, valueFactory); + public static T GetOrAddConvertor(Type from, Type to, Func valueFactory) => (T)typeConvertCache.GetOrAdd(from, to, (f, t) => valueFactory(f, t)); - /// - /// This method can be used when we switch between safe / unsafe variants (for testing) - /// public static void ClearCache() { classCache.Clear(); @@ -52,4 +24,31 @@ public static void ClearCache() shallowClassToCache.Clear(); typeConvertCache.Clear(); } -} \ No newline at end of file + + private class ClrCache + { + private readonly ConcurrentDictionary> cache = new ConcurrentDictionary>(); + + public TValue GetOrAdd(Type type, Func valueFactory) + { + Lazy lazy = cache.GetOrAdd(type, t => new Lazy(() => valueFactory(t), LazyThreadSafetyMode.ExecutionAndPublication)); + return lazy.Value; + } + + public void Clear() => cache.Clear(); + } + + private class ConcurrentLazyCache + { + private readonly ConcurrentDictionary, Lazy> cache = []; + + public TValue GetOrAdd(Type from, Type to, Func valueFactory) + { + Tuple key = new Tuple(from, to); + Lazy lazy = cache.GetOrAdd(key, tuple => new Lazy(() => valueFactory(tuple.Item1, tuple.Item2), LazyThreadSafetyMode.ExecutionAndPublication)); + return lazy.Value; + } + + public void Clear() => cache.Clear(); + } +}