// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Threading; #pragma warning disable CA1000 // Do not declare static members on generic types namespace Analyzer.Utilities.PooledObjects { /// <summary> /// <see cref="ConcurrentDictionary{TKey, TValue}"/> that can be recycled via an object pool. /// </summary> internal sealed class PooledConcurrentDictionary<K, V> : ConcurrentDictionary<K, V>, IDisposable where K : notnull { private readonly ObjectPool<PooledConcurrentDictionary<K, V>>? _pool; private PooledConcurrentDictionary(ObjectPool<PooledConcurrentDictionary<K, V>>? pool) { _pool = pool; } private PooledConcurrentDictionary(ObjectPool<PooledConcurrentDictionary<K, V>>? pool, IEqualityComparer<K> keyComparer) : base(keyComparer) { _pool = pool; } public void Dispose() => Free(CancellationToken.None); public void Free(CancellationToken cancellationToken) { // Do not free in presence of cancellation. // See https://github.com/dotnet/roslyn/issues/46859 for details. if (cancellationToken.IsCancellationRequested) { return; } this.Clear(); _pool?.Free(this, cancellationToken); } // global pool private static readonly ObjectPool<PooledConcurrentDictionary<K, V>> s_poolInstance = CreatePool(); private static readonly ConcurrentDictionary<IEqualityComparer<K>, ObjectPool<PooledConcurrentDictionary<K, V>>> s_poolInstancesByComparer = new(); // if someone needs to create a pool; public static ObjectPool<PooledConcurrentDictionary<K, V>> CreatePool(IEqualityComparer<K>? keyComparer = null) { ObjectPool<PooledConcurrentDictionary<K, V>>? pool = null; pool = new ObjectPool<PooledConcurrentDictionary<K, V>>(() => keyComparer != null ? new PooledConcurrentDictionary<K, V>(pool, keyComparer) : new PooledConcurrentDictionary<K, V>(pool), 128); return pool; } public static PooledConcurrentDictionary<K, V> GetInstance(IEqualityComparer<K>? keyComparer = null) { var pool = keyComparer == null ? s_poolInstance : s_poolInstancesByComparer.GetOrAdd(keyComparer, CreatePool); var instance = pool.Allocate(); Debug.Assert(instance.IsEmpty); return instance; } public static PooledConcurrentDictionary<K, V> GetInstance(IEnumerable<KeyValuePair<K, V>> initializer, IEqualityComparer<K>? keyComparer = null) { var instance = GetInstance(keyComparer); foreach (var kvp in initializer) { var added = instance.TryAdd(kvp.Key, kvp.Value); Debug.Assert(added); } return instance; } } } |