IntrusiveList.cs
  1  using System;
  2  using System.Collections.Generic;
  3  using System.Diagnostics;
  4  using System.Runtime.CompilerServices;
  5  
  6  namespace ARMeilleure.IntermediateRepresentation
  7  {
  8      /// <summary>
  9      /// Represents a efficient linked list that stores the pointer on the object directly and does not allocate.
 10      /// </summary>
 11      /// <typeparam name="T">Type of the list items</typeparam>
 12      class IntrusiveList<T> where T : IEquatable<T>, IIntrusiveListNode<T>
 13      {
 14          /// <summary>
 15          /// First item of the list, or null if empty.
 16          /// </summary>
 17          public T First { get; private set; }
 18  
 19          /// <summary>
 20          /// Last item of the list, or null if empty.
 21          /// </summary>
 22          public T Last { get; private set; }
 23  
 24          /// <summary>
 25          /// Total number of items on the list.
 26          /// </summary>
 27          public int Count { get; private set; }
 28  
 29          /// <summary>
 30          /// Initializes a new instance of the <see cref="IntrusiveList{T}"/> class.
 31          /// </summary>
 32          /// <exception cref="ArgumentException"><typeparamref name="T"/> is not pointer sized.</exception>
 33          public IntrusiveList()
 34          {
 35              if (Unsafe.SizeOf<T>() != IntPtr.Size)
 36              {
 37                  throw new ArgumentException("T must be a reference type or a pointer sized struct.");
 38              }
 39          }
 40  
 41          /// <summary>
 42          /// Adds a item as the first item of the list.
 43          /// </summary>
 44          /// <param name="newNode">Item to be added</param>
 45          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 46          public T AddFirst(T newNode)
 47          {
 48              if (!EqualsNull(First))
 49              {
 50                  return AddBefore(First, newNode);
 51              }
 52              else
 53              {
 54                  Debug.Assert(EqualsNull(newNode.ListPrevious));
 55                  Debug.Assert(EqualsNull(newNode.ListNext));
 56                  Debug.Assert(EqualsNull(Last));
 57  
 58                  First = newNode;
 59                  Last = newNode;
 60  
 61                  Debug.Assert(Count == 0);
 62  
 63                  Count = 1;
 64  
 65                  return newNode;
 66              }
 67          }
 68  
 69          /// <summary>
 70          /// Adds a item as the last item of the list.
 71          /// </summary>
 72          /// <param name="newNode">Item to be added</param>
 73          [MethodImpl(MethodImplOptions.AggressiveInlining)]
 74          public T AddLast(T newNode)
 75          {
 76              if (!EqualsNull(Last))
 77              {
 78                  return AddAfter(Last, newNode);
 79              }
 80              else
 81              {
 82                  Debug.Assert(EqualsNull(newNode.ListPrevious));
 83                  Debug.Assert(EqualsNull(newNode.ListNext));
 84                  Debug.Assert(EqualsNull(First));
 85  
 86                  First = newNode;
 87                  Last = newNode;
 88  
 89                  Debug.Assert(Count == 0);
 90  
 91                  Count = 1;
 92  
 93                  return newNode;
 94              }
 95          }
 96  
 97          /// <summary>
 98          /// Adds a item before a existing item on the list.
 99          /// </summary>
100          /// <param name="node">Item on the list that will succeed the new item</param>
101          /// <param name="newNode">Item to be added</param>
102          /// <returns>New item</returns>
103          [MethodImpl(MethodImplOptions.AggressiveInlining)]
104          public T AddBefore(T node, T newNode)
105          {
106              Debug.Assert(EqualsNull(newNode.ListPrevious));
107              Debug.Assert(EqualsNull(newNode.ListNext));
108  
109              newNode.ListPrevious = node.ListPrevious;
110              newNode.ListNext = node;
111  
112              node.ListPrevious = newNode;
113  
114              if (!EqualsNull(newNode.ListPrevious))
115              {
116                  newNode.ListPrevious.ListNext = newNode;
117              }
118  
119              if (Equals(First, node))
120              {
121                  First = newNode;
122              }
123  
124              Count++;
125  
126              return newNode;
127          }
128  
129          /// <summary>
130          /// Adds a item after a existing item on the list.
131          /// </summary>
132          /// <param name="node">Item on the list that will preceed the new item</param>
133          /// <param name="newNode">Item to be added</param>
134          /// <returns>New item</returns>
135          [MethodImpl(MethodImplOptions.AggressiveInlining)]
136          public T AddAfter(T node, T newNode)
137          {
138              Debug.Assert(EqualsNull(newNode.ListPrevious));
139              Debug.Assert(EqualsNull(newNode.ListNext));
140  
141              newNode.ListPrevious = node;
142              newNode.ListNext = node.ListNext;
143  
144              node.ListNext = newNode;
145  
146              if (!EqualsNull(newNode.ListNext))
147              {
148                  newNode.ListNext.ListPrevious = newNode;
149              }
150  
151              if (Equals(Last, node))
152              {
153                  Last = newNode;
154              }
155  
156              Count++;
157  
158              return newNode;
159          }
160  
161          /// <summary>
162          /// Removes a item from the list.
163          /// </summary>
164          /// <param name="node">The item to be removed</param>
165          [MethodImpl(MethodImplOptions.AggressiveInlining)]
166          public void Remove(T node)
167          {
168              if (!EqualsNull(node.ListPrevious))
169              {
170                  node.ListPrevious.ListNext = node.ListNext;
171              }
172              else
173              {
174                  Debug.Assert(Equals(First, node));
175  
176                  First = node.ListNext;
177              }
178  
179              if (!EqualsNull(node.ListNext))
180              {
181                  node.ListNext.ListPrevious = node.ListPrevious;
182              }
183              else
184              {
185                  Debug.Assert(Equals(Last, node));
186  
187                  Last = node.ListPrevious;
188              }
189  
190              node.ListPrevious = default;
191              node.ListNext = default;
192  
193              Count--;
194          }
195  
196          [MethodImpl(MethodImplOptions.AggressiveInlining)]
197          private static bool EqualsNull(T a)
198          {
199              return EqualityComparer<T>.Default.Equals(a, default);
200          }
201  
202          [MethodImpl(MethodImplOptions.AggressiveInlining)]
203          private static bool Equals(T a, T b)
204          {
205              return EqualityComparer<T>.Default.Equals(a, b);
206          }
207      }
208  }