You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
2.3 KiB
78 lines
2.3 KiB
5 years ago
|
// Copyright (c) Microsoft. All rights reserved.
|
||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||
|
#if !NET_4_6
|
||
|
using System.Threading;
|
||
|
using LinqInternal.Core;
|
||
|
|
||
|
namespace System.Dynamic.Utils
|
||
|
{
|
||
|
internal class CacheDict<TKey, TValue>
|
||
|
{
|
||
|
// cache size is always ^2.
|
||
|
// items are placed at [hash ^ mask]
|
||
|
// new item will displace previous one at the same location.
|
||
|
private readonly int _mask;
|
||
|
|
||
|
private readonly Entry[] _entries;
|
||
|
|
||
|
// class, to ensure atomic updates.
|
||
|
private sealed class Entry
|
||
|
{
|
||
|
internal readonly int Hash;
|
||
|
internal readonly TKey Key;
|
||
|
internal readonly TValue Value;
|
||
|
|
||
|
internal Entry(int hash, TKey key, TValue value)
|
||
|
{
|
||
|
Hash = hash;
|
||
|
Key = key;
|
||
|
Value = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a dictionary-like object used for caches.
|
||
|
/// </summary>
|
||
|
/// <param name="size">The maximum number of elements to store will be this number aligned to next ^2.</param>
|
||
|
internal CacheDict(int size)
|
||
|
{
|
||
|
var alignedSize = NumericHelper.NextPowerOf2(size - 1);
|
||
|
_mask = alignedSize - 1;
|
||
|
_entries = new Entry[alignedSize];
|
||
|
}
|
||
|
|
||
|
internal bool TryGetValue(TKey key, out TValue value)
|
||
|
{
|
||
|
var hash = key.GetHashCode();
|
||
|
var idx = hash & _mask;
|
||
|
|
||
|
var entry = Volatile.Read(ref _entries[idx]);
|
||
|
if (entry != null && entry.Hash == hash && entry.Key.Equals(key))
|
||
|
{
|
||
|
value = entry.Value;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
value = default(TValue);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
internal void Add(TKey key, TValue value)
|
||
|
{
|
||
|
var hash = key.GetHashCode();
|
||
|
var idx = hash & _mask;
|
||
|
|
||
|
var entry = Volatile.Read(ref _entries[idx]);
|
||
|
if (entry == null || entry.Hash != hash || !entry.Key.Equals(key))
|
||
|
{
|
||
|
Volatile.Write(ref _entries[idx], new Entry(hash, key, value));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal TValue this[TKey key]
|
||
|
{
|
||
|
set { Add(key, value); }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|