context: /*  This file is part of Chummer5a.
   *
   *  Chummer5a is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  Chummer5a is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with Chummer5a.  If not, see <http://www.gnu.org/licenses/>.
   *
   *  You can obtain the full source code for Chummer5a at
   *  https://github.com/chummer5a/chummer5a
   */
  
  using System;
  using System.Collections;
  using System.Collections.Concurrent;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading.Tasks;
  
  namespace Chummer
  {
      /// <summary>
      /// A version of Dictionary that is paired with a ReaderWriterLock.
      /// In theory, this dictionary can be faster in serial contexts than ConcurrentDictionary.
      /// Because ReadWriterLock allows parallel reads and only locks out writes, it's also faster than using a simple setup with the lock keyword.
      /// However, for mass parallel writes, use ConcurrentDictionary instead because locking the entire dictionary when accessing keys is not good for performance.
      /// </summary>
      /// <typeparam name="TKey">Key to use for the dictionary.</typeparam>
      /// <typeparam name="TValue">Values to use for the dictionary.</typeparam>
      public sealed class LockingDictionary<TKey, TValue> : IDictionary, IDictionary<TKey, TValue>, IAsyncReadOnlyDictionary<TKey, TValue>, IProducerConsumerCollection<KeyValuePair<TKey, TValue>>, IHasLockObject
      {
          private readonly Dictionary<TKey, TValue> _dicData;
          public AsyncFriendlyReaderWriterLock LockObject { get; } = new AsyncFriendlyReaderWriterLock();
  
          public LockingDictionary()
          {
              _dicData = new Dictionary<TKey, TValue>();
          }
  
          public LockingDictionary(int capacity)
          {
              _dicData = new Dictionary<TKey, TValue>(capacity);
          }
  
          public LockingDictionary(IDictionary<TKey, TValue> dictionary)
          {
              _dicData = new Dictionary<TKey, TValue>(dictionary);
          }
  
          public LockingDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
          {
              _dicData = new Dictionary<TKey, TValue>(dictionary, comparer);
          }
  
          public LockingDictionary(IEqualityComparer<TKey> comparer)
          {
              _dicData = new Dictionary<TKey, TValue>(comparer);
          }
          
          /// <inheritdoc />
          public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
          {
              LockingEnumerator<KeyValuePair<TKey, TValue>> objReturn = LockingEnumerator<KeyValuePair<TKey, TValue>>.Get(this);
              objReturn.SetEnumerator(_dicData.GetEnumerator());
              return objReturn;
          }
  
          /// <inheritdoc />
          IEnumerator IEnumerable.GetEnumerator()
          {
              LockingDictionaryEnumerator objReturn = LockingDictionaryEnumerator.Get(this);
              objReturn.SetEnumerator(_dicData.GetEnumerator());
              return objReturn;
          }
  
          /// <inheritdoc />
          IDictionaryEnumerator IDictionary.GetEnumerator()
          {
              LockingDictionaryEnumerator objReturn = LockingDictionaryEnumerator.Get(this);
              objReturn.SetEnumerator(_dicData.GetEnumerator());
              return objReturn;
          }
          
          public async ValueTask<IEnumerator<KeyValuePair<TKey, TValue>>> GetEnumeratorAsync()
          {
              LockingEnumerator<KeyValuePair<TKey, TValue>> objReturn = await LockingEnumerator<KeyValuePair<TKey, TValue>>.GetAsync(this);
              objReturn.SetEnumerator(_dicData.GetEnumerator());
              return objReturn;
          }
  
          /// <inheritdoc />
          public void Add(KeyValuePair<TKey, TValue> item)
          {
              using (LockObject.EnterWriteLock())
                  _dicData.Add(item.Key, item.Value);
          }
  
          public async ValueTask AddAsync(KeyValuePair<TKey, TValue> item)
          {
              IAsyncDisposable objLocker = await LockObject.EnterWriteLockAsync().ConfigureAwait(false);
              try
              {
                  _dicData.Add(item.Key, item.Value);
              }
              finally
              {
                  await objLocker.DisposeAsync().ConfigureAwait(false);
              }
          }
  
          /// <inheritdoc />
          public bool Contains(object key)
          {
              return ContainsKey((TKey)key);
          }
  
          /// <inheritdoc />
          public void Add(object key, object value)
          {
              Add((TKey)key, (TValue)value);
          }
  
          public ValueTask AddAsync(object key, object value)
          {
              return AddAsync((TKey)key, (TValue)value);
          }
  
          /// <inheritdoc cref="IDictionary{TKey, TValue}.Clear" />
          public void Clear()
          {
              using (LockObject.EnterWriteLock())
                  _dicData.Clear();
          }
  
          /// <inheritdoc cref="IDictionary{TKey, TValue}.Clear" />
          public async ValueTask ClearAsync()
          {
              IAsyncDisposable objLocker = await LockObject.EnterWriteLockAsync().ConfigureAwait(false);
              try
              {
                  _dicData.Clear();
              }
              finally
              {
                  await objLocker.DisposeAsync().ConfigureAwait(false);
              }
          }
  
          /// <inheritdoc />
          public bool Contains(KeyValuePair<TKey, TValue> item)
          {
              using (EnterReadLock.Enter(LockObject))
                  return _dicData.Contains(item);
          }
  
          public async ValueTask<bool> ContainsAsync(KeyValuePair<TKey, TValue> item)
          {
              using (await EnterReadLock.EnterAsync(LockObject))
                  return _dicData.Contains(item);
          }
  
          /// <inheritdoc cref="ICollection.CopyTo" />
          public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
          {
              using (EnterReadLock.Enter(LockObject))
              {
                  foreach (KeyValuePair<TKey, TValue> kvpItem in _dicData)
                  {
                      array[arrayIndex] = kvpItem;
                      ++arrayIndex;
                  }
              }
          }
  
          /// <inheritdoc />
          public void CopyTo(Array array, int index)
          {
              using (EnterReadLock.Enter(LockObject))
              {
                  foreach (KeyValuePair<TKey, TValue> kvpItem in _dicData)
                  {
                      array.SetValue(kvpItem, index);
                      ++index;
                  }
              }
          }
  
          /// <inheritdoc cref="ICollection.CopyTo" />
          public async ValueTask CopyToAsync(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
          {
              using (await EnterReadLock.EnterAsync(LockObject))
              {
                  foreach (KeyValuePair<TKey, TValue> kvpItem in _dicData)
                  {
                      array[arrayIndex] = kvpItem;
                      ++arrayIndex;
                  }
              }
          }
  
          /// <inheritdoc cref="ICollection.CopyTo" />
          public async ValueTask CopyToAsync(Array array, int index)
          {
              using (await EnterReadLock.EnterAsync(LockObject))
              {
                  foreach (KeyValuePair<TKey, TValue> kvpItem in _dicData)
                  {
                      array.SetValue(kvpItem, index);
                      ++index;
                  }
              }
          }
  
          /// <inheritdoc />
          public KeyValuePair<TKey, TValue>[] ToArray()
          {
              using (EnterReadLock.Enter(LockObject))
              {
                  KeyValuePair<TKey, TValue>[] akvpReturn = new KeyValuePair<TKey, TValue>[_dicData.Count];
                  int i = 0;
                  foreach (KeyValuePair<TKey, TValue> kvpLoop in _dicData)
                  {
                      akvpReturn[i] = kvpLoop;
                      ++i;
                  }
                  return akvpReturn;
              }
          }
  
          public async ValueTask<KeyValuePair<TKey, TValue>[]> ToArrayAsync()
          {
              using (await EnterReadLock.EnterAsync(LockObject))
              {
                  KeyValuePair<TKey, TValue>[] akvpReturn = new KeyValuePair<TKey, TValue>[_dicData.Count];
                  int i = 0;
                  foreach (KeyValuePair<TKey, TValue> kvpLoop in _dicData)
                  {
                      akvpReturn[i] = kvpLoop;
                      ++i;
                  }
                  return akvpReturn;
              }
          }
  
          /// <inheritdoc />
          public bool Remove(KeyValuePair<TKey, TValue> item)
          {
              // Immediately enter a write lock to prevent attempted reads until we have either removed the item we want to remove or failed to do so
              using (LockObject.EnterWriteLock())
              {
                  return _dicData.TryGetValue(item.Key, out TValue objValue) && objValue.Equals(item.Value)
                                                                             && _dicData.Remove(item.Key);
              }
          }
  
          /// <inheritdoc />
          public bool Remove(TKey key)
          {
              using (LockObject.EnterWriteLock())
                  return _dicData.Remove(key);
          }
  
          /// <inheritdoc />
          public void Remove(object key)
          {
              Remove((TKey)key);
          }
          
          public async ValueTask<bool> RemoveAsync(KeyValuePair<TKey, TValue> item)
          {
              // Immediately enter a write lock to prevent attempted reads until we have either removed the item we want to remove or failed to do so
              IAsyncDisposable objLocker = await LockObject.EnterWriteLockAsync().ConfigureAwait(false);
              try
              {
                  return _dicData.TryGetValue(item.Key, out TValue objValue) && objValue.Equals(item.Value)
                                                                             && _dicData.Remove(item.Key);
              }
              finally
              {
                  await objLocker.DisposeAsync().ConfigureAwait(false);
              }
          }
          
          public async ValueTask<bool> RemoveAsync(TKey key)
          {
              IAsyncDisposable objLocker = await LockObject.EnterWriteLockAsync().ConfigureAwait(false);
              try
              {
                  return _dicData.Remove(key);
              }
              finally
              {
                  await objLocker.DisposeAsync().ConfigureAwait(false);
              }
          }
          
          public ValueTask<bool> RemoveAsync(object key)
          {
              return RemoveAsync((TKey)key);
          }
  
          public bool TryRemove(TKey key, out TValue value)
          {
              // Immediately enter a write lock to prevent attempted reads until we have either removed the item we want to remove or failed to do so
              using (LockObject.EnterWriteLock())
                  return _dicData.TryGetValue(key, out value) && _dicData.Remove(key);
          }
  
          public async ValueTask<Tuple<bool, TValue>> TryRemoveAsync(TKey key)
          {
              // Immediately enter a write lock to prevent attempted reads until we have either removed the item we want to remove or failed to do so
              IAsyncDisposable objLocker = await LockObject.EnterWriteLockAsync().ConfigureAwait(false);
              try
              {
                  bool blnSuccess = _dicData.TryGetValue(key, out TValue value) && _dicData.Remove(key);
                  return new Tuple<bool, TValue>(blnSuccess, value);
              }
              finally
              {
                  await objLocker.DisposeAsync().ConfigureAwait(false);
              }
          }
  
          /// <inheritdoc />
          public bool TryTake(out KeyValuePair<TKey, TValue> item)
          {
              bool blnTakeSuccessful = false;
              TKey objKeyToTake = default;
              TValue objValue = default;
              // Immediately enter a write lock to prevent attempted reads until we have either taken the item we want to take or failed to do so
              using (LockObject.EnterWriteLock())
              {
  
gt:                 if (_dicData.Count > 0)