te
This commit is contained in:
parent
01151e679b
commit
57b2f0400e
265 changed files with 22828 additions and 6 deletions
353
Unused/CustomCollections/HashedList.cs
Normal file
353
Unused/CustomCollections/HashedList.cs
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace CustomCollections;
|
||||
|
||||
/// <summary>
|
||||
/// A doubly-linked list with a Dictionary index. Duplicate items are not allowed.
|
||||
/// -Add is O(1)
|
||||
/// -Contains is O(1)
|
||||
/// -Remove is O(1)
|
||||
/// -Get/set by index is O(n)
|
||||
/// -Insert is O(n)
|
||||
/// -RemoveAt is O(n)
|
||||
/// Additionally, a cached pointer (with associated index) is kept pointing to the last used index item.
|
||||
/// When looking up an item by index, the list is walked from the head, tail, or cached index pointer.
|
||||
/// Thus, doing multiple operations in index order is O(1) even without an enumerator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class HashedList<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable
|
||||
{
|
||||
private class ListNode
|
||||
{
|
||||
public ListNode Previous;
|
||||
|
||||
public ListNode Next;
|
||||
|
||||
public T Value;
|
||||
|
||||
public ListNode(T v, ListNode prev, ListNode nxt)
|
||||
{
|
||||
Previous = prev;
|
||||
Next = nxt;
|
||||
Value = v;
|
||||
}
|
||||
}
|
||||
|
||||
private ListNode Head;
|
||||
|
||||
private ListNode Tail;
|
||||
|
||||
private Dictionary<T, ListNode> HashIndex = new Dictionary<T, ListNode>();
|
||||
|
||||
private int ChangeMarker;
|
||||
|
||||
private bool IndexCacheValid;
|
||||
|
||||
private int IndexCache_Index;
|
||||
|
||||
private ListNode IndexCache_Value;
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index >= HashIndex.Count || index < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
return RunToIndex(index).Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index >= HashIndex.Count || index < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
if (HashIndex.ContainsKey(value))
|
||||
{
|
||||
throw new ArgumentException("Duplicate value");
|
||||
}
|
||||
ListNode listNode = RunToIndex(index);
|
||||
HashIndex.Remove(listNode.Value);
|
||||
listNode.Value = value;
|
||||
HashIndex.Add(value, listNode);
|
||||
ChangeMarker++;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => HashIndex.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public HashedList()
|
||||
{
|
||||
}
|
||||
|
||||
public HashedList(T[] arr)
|
||||
{
|
||||
foreach (T item in arr)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method gets the node corresponding to a particular index. To get there,
|
||||
/// the list is traversed from the head, tail, or cached index pointer (if valid).
|
||||
/// </summary>
|
||||
/// <param name="ind"></param>
|
||||
/// <returns></returns>
|
||||
private ListNode RunToIndex(int ind)
|
||||
{
|
||||
int num = HashIndex.Count / 2;
|
||||
if (IndexCacheValid)
|
||||
{
|
||||
if (ind > IndexCache_Index)
|
||||
{
|
||||
if (ind - IndexCache_Index < num)
|
||||
{
|
||||
ListNode listNode = IndexCache_Value;
|
||||
for (int i = IndexCache_Index; i < ind; i++)
|
||||
{
|
||||
listNode = listNode.Next;
|
||||
}
|
||||
IndexCache_Index = ind;
|
||||
IndexCache_Value = listNode;
|
||||
IndexCacheValid = true;
|
||||
return listNode;
|
||||
}
|
||||
}
|
||||
else if (IndexCache_Index - ind < num)
|
||||
{
|
||||
ListNode listNode2 = IndexCache_Value;
|
||||
for (int num2 = IndexCache_Index; num2 > ind; num2--)
|
||||
{
|
||||
listNode2 = listNode2.Previous;
|
||||
}
|
||||
IndexCache_Index = ind;
|
||||
IndexCache_Value = listNode2;
|
||||
IndexCacheValid = true;
|
||||
return listNode2;
|
||||
}
|
||||
}
|
||||
if (ind < num)
|
||||
{
|
||||
ListNode listNode3 = Head;
|
||||
for (int j = 0; j < ind; j++)
|
||||
{
|
||||
listNode3 = listNode3.Next;
|
||||
}
|
||||
if (listNode3 == null)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
IndexCache_Index = ind;
|
||||
IndexCache_Value = listNode3;
|
||||
IndexCacheValid = true;
|
||||
return listNode3;
|
||||
}
|
||||
ListNode listNode4 = Tail;
|
||||
for (int num3 = HashIndex.Count - 1; num3 > ind; num3--)
|
||||
{
|
||||
listNode4 = listNode4.Previous;
|
||||
}
|
||||
if (listNode4 == null)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
IndexCache_Index = ind;
|
||||
IndexCache_Value = listNode4;
|
||||
IndexCacheValid = true;
|
||||
return listNode4;
|
||||
}
|
||||
|
||||
private void RemoveNode(ListNode n)
|
||||
{
|
||||
if (n.Previous == null)
|
||||
{
|
||||
Head = n.Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
n.Previous.Next = n.Next;
|
||||
}
|
||||
if (n.Next == null)
|
||||
{
|
||||
Tail = n.Previous;
|
||||
}
|
||||
else
|
||||
{
|
||||
n.Next.Previous = n.Previous;
|
||||
}
|
||||
HashIndex.Remove(n.Value);
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<T> AsReadOnly()
|
||||
{
|
||||
return new ReadOnlyCollection<T>(this);
|
||||
}
|
||||
|
||||
public bool GetIfContains(T matchval, ref T outval)
|
||||
{
|
||||
if (HashIndex.ContainsKey(matchval))
|
||||
{
|
||||
outval = HashIndex[matchval].Value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
if (HashIndex.ContainsKey(item))
|
||||
{
|
||||
ListNode listNode = HashIndex[item];
|
||||
ListNode listNode2 = Head;
|
||||
for (int i = 0; i < HashIndex.Count; i++)
|
||||
{
|
||||
if (listNode2 == listNode)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
listNode2 = listNode2.Next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (index > HashIndex.Count || index < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
if (HashIndex.ContainsKey(item))
|
||||
{
|
||||
throw new ArgumentException("Duplicate value");
|
||||
}
|
||||
ListNode listNode;
|
||||
if (index == HashIndex.Count)
|
||||
{
|
||||
Add(item);
|
||||
listNode = HashIndex[item];
|
||||
}
|
||||
else if (index == 0)
|
||||
{
|
||||
listNode = new ListNode(item, null, Head);
|
||||
Head.Previous = listNode;
|
||||
Head = listNode;
|
||||
HashIndex.Add(item, listNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
ListNode listNode2 = RunToIndex(index - 1);
|
||||
listNode = (listNode2.Next = new ListNode(item, listNode2, listNode2.Next));
|
||||
listNode.Next.Previous = listNode;
|
||||
HashIndex.Add(item, listNode);
|
||||
}
|
||||
ChangeMarker++;
|
||||
IndexCache_Index = index;
|
||||
IndexCache_Value = listNode;
|
||||
IndexCacheValid = true;
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index >= HashIndex.Count || index < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
ListNode n = RunToIndex(index);
|
||||
RemoveNode(n);
|
||||
ChangeMarker++;
|
||||
IndexCacheValid = false;
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
ListNode listNode;
|
||||
if (HashIndex.Count == 0)
|
||||
{
|
||||
listNode = (Tail = (Head = new ListNode(item, null, null)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HashIndex.ContainsKey(item))
|
||||
{
|
||||
throw new ArgumentException("Duplicate value");
|
||||
}
|
||||
listNode = new ListNode(item, Tail, null);
|
||||
Tail.Next = listNode;
|
||||
Tail = listNode;
|
||||
}
|
||||
HashIndex.Add(item, listNode);
|
||||
ChangeMarker++;
|
||||
IndexCacheValid = false;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Head = null;
|
||||
Tail = null;
|
||||
HashIndex.Clear();
|
||||
ChangeMarker++;
|
||||
IndexCacheValid = false;
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return HashIndex.ContainsKey(item);
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
if (!HashIndex.ContainsKey(item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RemoveNode(HashIndex[item]);
|
||||
ChangeMarker++;
|
||||
IndexCacheValid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
int num = arrayIndex + HashIndex.Count;
|
||||
IEnumerator<T> enumerator = GetEnumerator();
|
||||
for (int i = arrayIndex; i < num; i++)
|
||||
{
|
||||
enumerator.MoveNext();
|
||||
array[i] = enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] array = new T[HashIndex.Count];
|
||||
CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
int startchangemarker = ChangeMarker;
|
||||
for (ListNode cur = Head; cur != null; cur = cur.Next)
|
||||
{
|
||||
yield return cur.Value;
|
||||
if (ChangeMarker != startchangemarker)
|
||||
{
|
||||
throw new Exception("Collection modified during enumeration");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue