IntrusiveList.cs 6.0 KB

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