using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace CustomCollections;
///
/// 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.
///
///
internal class HashedList : IList, ICollection, IEnumerable, 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 HashIndex = new Dictionary();
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);
}
}
///
/// 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).
///
///
///
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 AsReadOnly()
{
return new ReadOnlyCollection(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 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 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();
}
}