using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; namespace ARMeilleure.IntermediateRepresentation { /// /// Represents a efficient linked list that stores the pointer on the object directly and does not allocate. /// /// Type of the list items class IntrusiveList where T : IEquatable, IIntrusiveListNode { /// /// First item of the list, or null if empty. /// public T First { get; private set; } /// /// Last item of the list, or null if empty. /// public T Last { get; private set; } /// /// Total number of items on the list. /// public int Count { get; private set; } /// /// Initializes a new instance of the class. /// /// is not pointer sized. public IntrusiveList() { if (Unsafe.SizeOf() != IntPtr.Size) { throw new ArgumentException("T must be a reference type or a pointer sized struct."); } } /// /// Adds a item as the first item of the list. /// /// Item to be added [MethodImpl(MethodImplOptions.AggressiveInlining)] public T AddFirst(T newNode) { if (!EqualsNull(First)) { return AddBefore(First, newNode); } else { Debug.Assert(EqualsNull(newNode.ListPrevious)); Debug.Assert(EqualsNull(newNode.ListNext)); Debug.Assert(EqualsNull(Last)); First = newNode; Last = newNode; Debug.Assert(Count == 0); Count = 1; return newNode; } } /// /// Adds a item as the last item of the list. /// /// Item to be added [MethodImpl(MethodImplOptions.AggressiveInlining)] public T AddLast(T newNode) { if (!EqualsNull(Last)) { return AddAfter(Last, newNode); } else { Debug.Assert(EqualsNull(newNode.ListPrevious)); Debug.Assert(EqualsNull(newNode.ListNext)); Debug.Assert(EqualsNull(First)); First = newNode; Last = newNode; Debug.Assert(Count == 0); Count = 1; return newNode; } } /// /// Adds a item before a existing item on the list. /// /// Item on the list that will succeed the new item /// Item to be added /// New item [MethodImpl(MethodImplOptions.AggressiveInlining)] public T AddBefore(T node, T newNode) { Debug.Assert(EqualsNull(newNode.ListPrevious)); Debug.Assert(EqualsNull(newNode.ListNext)); newNode.ListPrevious = node.ListPrevious; newNode.ListNext = node; node.ListPrevious = newNode; if (!EqualsNull(newNode.ListPrevious)) { newNode.ListPrevious.ListNext = newNode; } if (Equals(First, node)) { First = newNode; } Count++; return newNode; } /// /// Adds a item after a existing item on the list. /// /// Item on the list that will preceed the new item /// Item to be added /// New item [MethodImpl(MethodImplOptions.AggressiveInlining)] public T AddAfter(T node, T newNode) { Debug.Assert(EqualsNull(newNode.ListPrevious)); Debug.Assert(EqualsNull(newNode.ListNext)); newNode.ListPrevious = node; newNode.ListNext = node.ListNext; node.ListNext = newNode; if (!EqualsNull(newNode.ListNext)) { newNode.ListNext.ListPrevious = newNode; } if (Equals(Last, node)) { Last = newNode; } Count++; return newNode; } /// /// Removes a item from the list. /// /// The item to be removed [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Remove(T node) { if (!EqualsNull(node.ListPrevious)) { node.ListPrevious.ListNext = node.ListNext; } else { Debug.Assert(Equals(First, node)); First = node.ListNext; } if (!EqualsNull(node.ListNext)) { node.ListNext.ListPrevious = node.ListPrevious; } else { Debug.Assert(Equals(Last, node)); Last = node.ListPrevious; } node.ListPrevious = default; node.ListNext = default; Count--; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool EqualsNull(T a) { return EqualityComparer.Default.Equals(a, default); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool Equals(T a, T b) { return EqualityComparer.Default.Equals(a, b); } } }