Files
2026-08-27 10:56:38 -06:00

82 lines
1.9 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Threading;
using Microsoft.Cci;
namespace Microsoft.CodeAnalysis.CodeGen;
internal sealed class TokenMap
{
private readonly ConcurrentDictionary<IReferenceOrISignature, uint> _itemIdentityToToken = new ConcurrentDictionary<IReferenceOrISignature, uint>();
private object[] _items = Array.Empty<object>();
private int _count;
internal TokenMap()
{
}
public uint GetOrAddTokenFor(IReference item, out bool referenceAdded)
{
if (_itemIdentityToToken.TryGetValue(new IReferenceOrISignature(item), out var value))
{
referenceAdded = false;
return value;
}
return AddItem(new IReferenceOrISignature(item), out referenceAdded);
}
public uint GetOrAddTokenFor(ISignature item, out bool referenceAdded)
{
if (_itemIdentityToToken.TryGetValue(new IReferenceOrISignature(item), out var value))
{
referenceAdded = false;
return value;
}
return AddItem(new IReferenceOrISignature(item), out referenceAdded);
}
private uint AddItem(IReferenceOrISignature item, out bool referenceAdded)
{
uint value;
lock (_itemIdentityToToken)
{
if (!_itemIdentityToToken.TryGetValue(item, out value))
{
value = (uint)_count;
referenceAdded = _itemIdentityToToken.TryAdd(item, value);
int num = (int)(value + 1);
object[] array = _items;
if (array.Length > num)
{
array[value] = item.AsObject();
}
else
{
Array.Resize(ref array, Math.Max(8, num * 2));
array[value] = item.AsObject();
Volatile.Write(ref _items, array);
}
Volatile.Write(ref _count, num);
}
else
{
referenceAdded = false;
}
}
return value;
}
public object GetItem(uint token)
{
return _items[token];
}
public ReadOnlySpan<object> GetAllItems()
{
int length = Volatile.Read(in _count);
return new ReadOnlySpan<object>(Volatile.Read(in _items), 0, length);
}
}