// dnlib: See LICENSE.txt for more info using System; using System.Diagnostics; using System.Threading; using dnlib.DotNet; namespace dnlib.Utils { /// /// A readonly list that gets initialized lazily /// /// Any class type [DebuggerDisplay("Count = {Length}")] sealed class SimpleLazyList where T : class { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] readonly T[] elements; [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly Func readElementByRID; [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly uint length; /// /// Gets the length of this list /// public uint Length => length; /// /// Access the list /// /// Index /// The element or null if is invalid public T this[uint index] { get { if (index >= length) return null; if (elements[index] is null) Interlocked.CompareExchange(ref elements[index], readElementByRID(index + 1), null); return elements[index]; } } /// /// Constructor /// /// Length of the list /// Delegate instance that lazily reads an element. It might /// be called more than once for each rid in rare cases. It must never return /// null. public SimpleLazyList(uint length, Func readElementByRID) { this.length = length; this.readElementByRID = readElementByRID; elements = new T[length]; } } /// /// A readonly list that gets initialized lazily /// /// Any class type [DebuggerDisplay("Count = {Length}")] sealed class SimpleLazyList2 where T : class, IContainsGenericParameter2 { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] readonly T[] elements; [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly Func readElementByRID; [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly uint length; /// /// Gets the length of this list /// public uint Length => length; /// /// Access the list /// /// Index /// Generic parameter context /// The element or null if is invalid public T this[uint index, GenericParamContext gpContext] { get { if (index >= length) return null; if (elements[index] is null) { var elem = readElementByRID(index + 1, gpContext); // Don't cache it if it contains GPs since each GP could hold a reference // to the type/method context. These GPs can't be shared. if (elem.ContainsGenericParameter) return elem; Interlocked.CompareExchange(ref elements[index], elem, null); } return elements[index]; } } /// /// Constructor /// /// Length of the list /// Delegate instance that lazily reads an element. It might /// be called more than once for each rid. It must never return null. public SimpleLazyList2(uint length, Func readElementByRID) { this.length = length; this.readElementByRID = readElementByRID; elements = new T[length]; } } }