15 public class Node : IDisposable {
23 public T
Item {
get;
protected internal set; }
26 public static bool operator <(Node left, Node right) => left.Owner.CompareItem(left, right) < 0;
29 public static bool operator <=(Node left, Node right) => left.Owner.CompareItem(left, right) <= 0;
32 public static bool operator >(
Node left,
Node right) => left.Owner.CompareItem(left, right) > 0;
35 public static bool operator >=(
Node left,
Node right) => left.Owner.CompareItem(left, right) >= 0;
46 Owner.DeactivateItem(
this);
49 reverseLookup?.Remove(
this);
55 nodeForNext.Next = Next;
56 if (
Owner == Home.recycleBin)
return this;
57 Owner.DeactivateItem(
this);
62 private static readonly
Node nodeForNext =
new Node();
68 public override string ToString() => $
"{Owner,25} << {Home,-25}:: {Item}";
80 #region Private create, deactivation and activation support 81 private static Func<T> CallConstructor() {
82 var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
83 var constructor = typeof(T).GetConstructor(flags, null, Type.EmptyTypes, null);
84 if (constructor == null)
return null;
85 return () => (T) constructor.Invoke(parameters: null);
88 private static MethodInfo DefaultMethod(
string name, Type[] parameters) {
89 var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
90 return typeof(T).GetMethod(name, flags, null, CallingConventions.HasThis, parameters, null);
93 private static readonly Type[] comparisonParameters = {typeof(T), typeof(T)};
95 private static Action<Node> DefaultActivation(
string name) {
96 var method = DefaultMethod(name, Type.EmptyTypes);
97 if (method == null)
return null;
98 return node => method.Invoke(node.Item, null);
101 private static Func<Node, Node, int> GetDefaultCompareItem() {
102 var method = DefaultMethod(
"CompareItem", comparisonParameters);
103 if (method == null)
return (node, other) => 0;
105 orderedDynamic =
true;
106 return (node, other) => (int) method.Invoke(node.Item,
new object[] {node.Item, other.Item});
109 private static Func<T> GetDefaultCreateItem() {
110 var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
112 var method = typeof(T).GetMethod(
"CreateItem", flags, null, CallingConventions.Standard, Type.EmptyTypes, null);
114 if (method != null)
return () => (T) method.Invoke(null, null);
116 return CallConstructor() ?? (() =>
default);
119 private static Action<Node> GetDefaultDeactivateItem() => DefaultActivation(
"DeactivateItem") ?? (node => { });
121 private static Action<Node> GetDefaultReactivateItem() => DefaultActivation(
"ReactivateItem") ?? (node => { });
123 private static bool orderedStatic;
124 private static bool orderedDynamic;
125 private bool ordered = orderedStatic || orderedDynamic;
126 private static int ordinal;
129 #region Public List Creation and Destruction 132 Name =
string.IsNullOrWhiteSpace(name) ? $
"{typeof(T).Name}-{++ordinal}" : name;
159 orderedStatic =
true;
160 compareItemStatic = value;
164 private static Func<Node, Node, int> compareItemStatic = GetDefaultCompareItem();
168 private get {
return compareItem; }
170 orderedDynamic = ordered =
true;
175 private Func<Node, Node, int> compareItem = (left, right) => compareItemStatic(left, right);
180 if (recycleBin == null)
return;
182 while (recycleBin.First != null) recycleBin.First.Destroy();
183 recycleBin.First = recycleBin.Last = null;
188 reverseLookup = null;
194 #region Node Creation and Movement 198 reverseLookup?.
Remove(node.Item).
Add(item, node);
214 if (reverseLookup == null) {
215 reverseLookup =
new Map();
216 for (var node =
First; node != null; node = node.Next) reverseLookup.
Add(node.Item, node);
219 return reverseLookup?[item].
Value as Node;
225 private static Map reverseLookup;
227 private Node NewNode(T item) {
228 Node newNode =
new Node() {Item = item, Owner =
this, Home =
this};
229 reverseLookup?.
Add(item, newNode);
233 private Node Insert(Node nodeToInsert) {
234 if (
DebugMode) DebugMessage(nodeToInsert);
236 Unlink(nodeToInsert);
238 nodeToInsert.Owner =
this;
244 while (nodeToInsert > after) {
245 if ((after = after.Next) == null) {
247 Last.Next = nodeToInsert;
248 return Last = nodeToInsert;
253 nodeToInsert.Next = after;
256 if (after.Previous != null) after.
Previous.Next = nodeToInsert;
259 if (
Last == null)
Last = nodeToInsert;
264 private Node Append(Node nodeToAppend) {
265 if (
DebugMode) DebugMessage(nodeToAppend,
"end of ");
267 Unlink(nodeToAppend);
269 nodeToAppend.Owner =
this;
273 Last.Next = nodeToAppend;
278 private void Unlink(Node node) {
279 if (node == node.Owner.First) { node.
Owner.First = node.Next; }
else if (node == node.Owner.Last) {
280 node.Owner.Last = node.Previous;
281 }
else if ((node.Previous == null) && (node.Next == null))
return;
285 if (node.Previous != null) node.Previous.Next = node.Next;
286 if (node.Next != null) node.Next.Previous = node.Previous;
288 node.Previous = node.Next = null;
297 private bool isRecycleBin;
315 public int Count {
get;
private set; }
318 public Node
Push(T item) =>
Add(item);
321 public Node
Push(Node node) => node.
MoveTo(
this);
325 if (
First == null)
return default;
333 if (
Last == null)
return default;
345 private void DebugMessage(Node node,
string append =
"") =>
348 ? $
"**** LinkedList: Add to {this}" 349 : $
"**** LinkedList: move {node.Owner} to {append}{this}");
352 public string Dump(
int maxEntriesToDump = 1000) {
353 var builder =
new StringBuilder();
356 for (Node node =
First; (node != null) && (maxEntriesToDump-- > 0); node = node.Next) {
357 builder.AppendLine($
"{++line}:\t{node}");
360 return builder.ToString();
365 string count = recycleBin != null ? $
"({Count}/{recycleBin.Count})" : $
"({Count})";
366 return $
"{Name} {count,8}";
Node MoveTo(LinkedList< T > to)
Move Node to Another List
Node GetRecycledOrNew()
Get a node and item either recycled or created new.
T Pop()
Retrieve the first list item - Node.Recycle
LinkedList< T > RecycleBin
List for Unused Nodes
static bool operator>=(Node left, Node right)
Node comparison Operator
static Action< Node > DeactivateItemStatic
Called before an item is returned to recycling
void Destroy()
Dispose of a Node Forever
override string ToString()
static bool operator>(Node left, Node right)
Node comparison Operator
Func< T > CreateItem
Item Creation and Preparation when new() is not enough
T Pull()
Pull the last item from the list
void Dispose()
For the rare times we need to clear a linked list
override string ToString()
LinkedList - a different perspective
Node GetRecycledOrNew()
Retrieve a node - either from recycling or creating it anew
Map Add(object key, object value=null)
Add a map or set entry
static bool DebugMode
Debug mode logs changes
Node MoveToEndOf(LinkedList< T > to)
Move Node to Another List
Node Second
Second item in the list or null
string Dump(int maxEntriesToDump=1000)
Return list contents as a string
Node Push(T item)
Add an item to the list
Node Recycle()
Deactivate an entry and put the containing node in the recycling bin
Node Add(T t)
Fetch an unused node and use it as the container for the provided new item
static Action< Node > ReactivateItemStatic
Actor we can create if reactivation requires additional code
LinkedList< T > Owner
List that currently owns this node is called Owner. It is changed by MoveTo Home is the list in which...
Node ReverseLookup(T item)
For node disposal using reverse lookup
void Destroy()
For the rare times we need to clear a linked list
Node Push(T t)
Fetch an unused node and use it as the container for the provided new item
int Count
Calculate number of items in a list
Node Last
Last Node in List or null
Map Remove(object key, bool dispose=true)
Remove an entry, optionally calling Dispose()
string Name
Linked List Name
T Item
Item can be value type (int, float ... struct) or object (class instance)
Node First
First Node in List or null
Action< Node > ReactivateItem
Prepare an idle item for reuse
Node Add(T item)
Add an Item to a List
LinkedList(string name=null)
Get an instance of this type of linked list
static Func< Node, Node, int > CompareItemStatic
Used to insert items into the correct location for sorted lists
object Value
Last value found (null for failure)
static Func< T > CreateItemStatic
Item Creation and Preparation when new() is not enough
Func< Node, Node, int > CompareItem
Used to insert items into the correct location for sorted lists
Action< Node > DeactivateItem
For Deactivation when Dispose() is not enough