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);
}
}
}