| File: System\Reflection\TypeLoading\General\Ecma\MetadataTable.cs | Web Access |
| Project: src\runtime\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Metadata; using System.Threading; namespace System.Reflection.TypeLoading.Ecma { /// <summary> /// Thread-safe interning table for objects that map 1-1 with ECMA tokens. /// /// The key type is hard-coded to EntityHandle. /// The "T" type is the value type (e.g. RoTypeDefinition objects) /// The "C" type is an optional context value passed through the factory methods (so we don't to allocate a closure each time.) /// </summary> internal sealed class MetadataTable<T, C> where T : class { private readonly T?[] _table; public MetadataTable(int count) { Count = count; _table = new T?[count]; } public T GetOrAdd(EntityHandle handle, C context, Func<EntityHandle, C, T> factory) { Debug.Assert(!handle.IsNil); Debug.Assert(factory != null); int index = handle.GetToken().GetTokenRowNumber() - 1; T?[] table = _table; T? result = Volatile.Read(ref table[index]); if (result != null) return result; T newValue = factory(handle, context); return Interlocked.CompareExchange(ref table[index], newValue, null) ?? newValue; } public int Count { get; } /// <summary> /// Return a read-only enumeration of the table (safe to hand back to app code.) /// </summary> public IEnumerable<T?> EnumerateValues(int skip = 0) { for (int i = skip; i < _table.Length; i++) { yield return _table[i]; } } /// <summary> /// Return a newly allocated array containing the contents (safe to hand back to app code.) /// </summary> public TOut[] ToArray<TOut>(int skip = 0) { TOut[] newArray = new TOut[Count - skip]; Array.Copy(_table, skip, newArray, 0, newArray.Length); return newArray; } } }