#if NEED_LINKEDLIST_SHIM using System; using System.Diagnostics; namespace KcpSharp.NetstandardShim { internal class LinkedList { // This LinkedList is a doubly-Linked circular list. internal LinkedListNode? head; internal int count; internal int version; public int Count { get { return count; } } public LinkedListNode? First { get { return head; } } public LinkedListNode? Last { get { return head == null ? null : head.prev; } } public void AddAfter(LinkedListNode node, LinkedListNode newNode) { ValidateNode(node); ValidateNewNode(newNode); InternalInsertNodeBefore(node.next!, newNode); newNode.list = this; } public void AddBefore(LinkedListNode node, LinkedListNode newNode) { ValidateNode(node); ValidateNewNode(newNode); InternalInsertNodeBefore(node, newNode); newNode.list = this; if (node == head) { head = newNode; } } public void AddFirst(LinkedListNode node) { ValidateNewNode(node); if (head == null) { InternalInsertNodeToEmptyList(node); } else { InternalInsertNodeBefore(head, node); head = node; } node.list = this; } public void AddLast(LinkedListNode node) { ValidateNewNode(node); if (head == null) { InternalInsertNodeToEmptyList(node); } else { InternalInsertNodeBefore(head, node); } node.list = this; } public void Clear() { LinkedListNode? current = head; while (current != null) { LinkedListNode temp = current; current = current.Next; // use Next the instead of "next", otherwise it will loop forever temp.Invalidate(); } head = null; count = 0; version++; } public void Remove(LinkedListNode node) { ValidateNode(node); InternalRemoveNode(node); } public void RemoveFirst() { if (head == null) { throw new InvalidOperationException(); } InternalRemoveNode(head); } private void InternalInsertNodeBefore(LinkedListNode node, LinkedListNode newNode) { newNode.next = node; newNode.prev = node.prev; node.prev!.next = newNode; node.prev = newNode; version++; count++; } private void InternalInsertNodeToEmptyList(LinkedListNode newNode) { Debug.Assert(head == null && count == 0, "LinkedList must be empty when this method is called!"); newNode.next = newNode; newNode.prev = newNode; head = newNode; version++; count++; } internal void InternalRemoveNode(LinkedListNode node) { Debug.Assert(node.list == this, "Deleting the node from another list!"); Debug.Assert(head != null, "This method shouldn't be called on empty list!"); if (node.next == node) { Debug.Assert(count == 1 && head == node, "this should only be true for a list with only one node"); head = null; } else { node.next!.prev = node.prev; node.prev!.next = node.next; if (head == node) { head = node.next; } } node.Invalidate(); count--; version++; } internal static void ValidateNewNode(LinkedListNode node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (node.list != null) { throw new InvalidOperationException(); } } internal void ValidateNode(LinkedListNode node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (node.list != this) { throw new InvalidOperationException(); } } } // Note following class is not serializable since we customized the serialization of LinkedList. internal sealed class LinkedListNode { internal LinkedList? list; internal LinkedListNode? next; internal LinkedListNode? prev; internal T item; public LinkedListNode(T value) { item = value; } public LinkedListNode? Next { get { return next == null || next == list!.head ? null : next; } } public LinkedListNode? Previous { get { return prev == null || this == list!.head ? null : prev; } } /// Gets a reference to the value held by the node. public ref T ValueRef => ref item; internal void Invalidate() { list = null; next = null; prev = null; } } } #endif