/// <summary> /// Detaches the node's tail, clears the node's value, and releases the node to the pool. /// /// Note: Nodes should generally not be released one at a time as it will incur much greater overhead than batching releases using LinkedHeadTail<T>s. /// </summary> public void TrimAndDispose() { value = default(T); lock (poolLock) { next = pool; pool = this; } }
/// <summary> /// Returns a Slinq that enumerates the values contained in the list. /// Ownership of the nodes contained in the list is transferred to the Slinq. When the Slinq is disposed, the nodes will be added to the /// disposal queue. /// </summary> public Slinq <T, LinkedContext <T> > SlinqAndDispose() { var slinq = LinkedContext <T> .Slinq(this, true); head = null; tail = null; count = 0; return(slinq); }
/// <summary> /// Releases the head of the list to the node pool. /// The list must be well formed when calling this method or the program will enter an invalid state, resulting in unspecified behaviour. /// </summary> public void Dispose() { if (head != null) { head.Dispose(); } head = null; tail = null; count = 0; }
/// <summary> /// Adds the head of the list to the disposal queue. /// The list must be well formed when calling this method or the program will enter an invalid state, resulting in unspecified behaviour. /// </summary> public void DisposeInBackground() { if (head != null) { head.DisposeInBackground(); } head = null; tail = null; count = 0; }
/// <summary> /// Appends the specified value to the value list for the specified key. If the key was previously unmapped it is appended to the key /// list. /// Calling this method transfers ownership of the specified node and any linked nodes to the lookup. /// </summary> public void Add(K key, Linked <T> value) { LinkedHeadTail <T> values; if (!dictionary.TryGetValue(key, out values)) { keys.Append(key); } values.Append(value); dictionary[key] = values; }
/// <summary> /// Adds the nodes in the list to the specified lookup using the specified key selector. /// /// Ownership of the nodes contained in this list is transerred to the lookup. /// </summary> public Lookup <K, T> AddTo <K, P>(Lookup <K, T> lookup, DelegateFunc <T, P, K> selector, P parameter) { while (head != null) { var node = head; head = head.next; node.next = null; lookup.Add(selector(node.value, parameter), node); } tail = null; count = 0; return(lookup); }
/// <summary> /// Adds the nodes in the list to the specified lookup using the specified key selector. /// Ownership of the nodes contained in this list is transerred to the lookup. /// </summary> public Lookup <K, T> AddTo <K>(Lookup <K, T> lookup, Func <T, K> selector) { while (head != null) { var node = head; head = head.next; node.next = null; lookup.Add(selector(node.value), node); } tail = null; count = 0; return(lookup); }
/// <summary> /// Appends a pooled node with with specified value to the end of the list. /// </summary> public void Append(T value) { var node = Linked <T> .Borrow(value); if (head == null) { head = node; } else { tail.next = node; } tail = node; ++count; }
/// <summary> /// Appends the specified list to the end of this list. /// This list and the specified list must be well formed when calling this method or the program will enter an invalid state, resulting in /// unspecified behaviour. /// Calling this method will invalidate the specified list and any variables containing its nodes. /// </summary> public void Append(LinkedHeadTail <T> other) { if (other.count == 0) { // noop } else if (head == null) { head = other.head; tail = other.tail; count = other.count; } else { tail.next = other.head; tail = other.tail; count += other.count; } }
/// <summary> /// Traverses the node list that starts with this node, clears the value of each node, and releases the resulting node list to the pool. /// </summary> public void Dispose() { var dt = default(T); value = dt; var runner = this; while (runner.next != null) { runner = runner.next; runner.value = dt; } lock (poolLock) { runner.next = pool; pool = this; } }
/// <summary> /// Returns a pooled list node with the specified value. /// </summary> public static Linked <T> Borrow(T value) { Linked <T> node; lock (poolLock) { if (pool == null) { node = new Linked <T>(); } else { node = pool; pool = pool.next; node.next = null; } } node.value = value; return(node); }
private static bool DetectResetLoop(Linked <T> head) { Linked <T> slow = head, prefFast = head, fast = head; while (slow != null && fast?.next != null) { slow = slow.next; prefFast = fast.next; fast = prefFast.next; if (slow == fast) { // remove loop // prefFast.next = null; Debug.Log("Detect Loop"); return(true); } } return(false); }
/// <summary> /// Returns a list that starts with the specified node. /// The constructor will traverse the node links to set the tail and count fields. /// If the specified node is null, the resulting list will be empty. /// </summary> public LinkedHeadTail(Linked <T> head) { if (head == null) { this.head = null; tail = null; count = 0; } else { this.head = head; tail = head; count = 1; while (tail.next != null) { tail = tail.next; ++count; } } }
/// <summary> /// Appends the specified node to the end of the list. /// The node links will be traversed to determine the new tail and count. /// If the specified node is null, the list will not be modified. /// </summary> public void Append(Linked <T> node) { if (node != null) { if (head == null) { head = node; } else { tail.next = node; } tail = node; ++count; while (tail.next != null) { tail = tail.next; ++count; } } }
/// <summary> /// Sorts the lookup's keys using the specified comparison and ordering. /// This method uses an introspective merge sort algorithm that will optimally sort rather than split lists with 3 or fewer nodes. /// </summary> public Lookup <K, T> SortKeys(Comparison <K> comparison, bool ascending) { keys = Linked.Sort(keys, comparison, ascending); return(this); }
/// <summary> /// Returns a list containing a single node with the specified value. /// </summary> public LinkedHeadTail(T value) : this(Linked <T> .Borrow(value)) { }