404 lines
9.3 KiB
C#
404 lines
9.3 KiB
C#
//
|
|
// Author:
|
|
// Jb Evain (jbevain@gmail.com)
|
|
//
|
|
// Copyright (c) 2008 - 2015 Jb Evain
|
|
// Copyright (c) 2008 - 2011 Novell, Inc.
|
|
//
|
|
// Licensed under the MIT/X11 license.
|
|
//
|
|
|
|
using MonoFN.Cecil;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace MonoFN.Collections.Generic
|
|
{
|
|
public class Collection<T> : IList<T>, IList
|
|
{
|
|
internal T[] items;
|
|
internal int size;
|
|
private int version;
|
|
public int Count
|
|
{
|
|
get { return size; }
|
|
}
|
|
public T this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index >= size)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
return items[index];
|
|
}
|
|
set
|
|
{
|
|
CheckIndex(index);
|
|
if (index == size)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
OnSet(value, index);
|
|
|
|
items[index] = value;
|
|
}
|
|
}
|
|
public int Capacity
|
|
{
|
|
get { return items.Length; }
|
|
set
|
|
{
|
|
if (value < 0 || value < size)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
Resize(value);
|
|
}
|
|
}
|
|
bool ICollection<T>.IsReadOnly
|
|
{
|
|
get { return false; }
|
|
}
|
|
bool IList.IsFixedSize
|
|
{
|
|
get { return false; }
|
|
}
|
|
bool IList.IsReadOnly
|
|
{
|
|
get { return false; }
|
|
}
|
|
object IList.this[int index]
|
|
{
|
|
get { return this[index]; }
|
|
set
|
|
{
|
|
CheckIndex(index);
|
|
|
|
try
|
|
{
|
|
this[index] = (T)value;
|
|
return;
|
|
}
|
|
catch (InvalidCastException) { }
|
|
catch (NullReferenceException) { }
|
|
|
|
throw new ArgumentException();
|
|
}
|
|
}
|
|
int ICollection.Count
|
|
{
|
|
get { return Count; }
|
|
}
|
|
bool ICollection.IsSynchronized
|
|
{
|
|
get { return false; }
|
|
}
|
|
object ICollection.SyncRoot
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
public Collection()
|
|
{
|
|
items = Empty<T>.Array;
|
|
}
|
|
|
|
public Collection(int capacity)
|
|
{
|
|
if (capacity < 0)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
items = capacity == 0 ? Empty<T>.Array : new T [capacity];
|
|
}
|
|
|
|
public Collection(ICollection<T> items)
|
|
{
|
|
if (items == null)
|
|
throw new ArgumentNullException("items");
|
|
|
|
this.items = new T [items.Count];
|
|
items.CopyTo(this.items, 0);
|
|
size = this.items.Length;
|
|
}
|
|
|
|
public void Add(T item)
|
|
{
|
|
if (size == items.Length)
|
|
Grow(1);
|
|
|
|
OnAdd(item, size);
|
|
|
|
items[size++] = item;
|
|
version++;
|
|
}
|
|
|
|
public bool Contains(T item)
|
|
{
|
|
return IndexOf(item) != -1;
|
|
}
|
|
|
|
public int IndexOf(T item)
|
|
{
|
|
return Array.IndexOf(items, item, 0, size);
|
|
}
|
|
|
|
public void Insert(int index, T item)
|
|
{
|
|
CheckIndex(index);
|
|
if (size == items.Length)
|
|
Grow(1);
|
|
|
|
OnInsert(item, index);
|
|
|
|
Shift(index, 1);
|
|
items[index] = item;
|
|
version++;
|
|
}
|
|
|
|
public void RemoveAt(int index)
|
|
{
|
|
if (index < 0 || index >= size)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
T item = items[index];
|
|
|
|
OnRemove(item, index);
|
|
|
|
Shift(index, -1);
|
|
version++;
|
|
}
|
|
|
|
public bool Remove(T item)
|
|
{
|
|
int index = IndexOf(item);
|
|
if (index == -1)
|
|
return false;
|
|
|
|
OnRemove(item, index);
|
|
|
|
Shift(index, -1);
|
|
version++;
|
|
|
|
return true;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
OnClear();
|
|
|
|
Array.Clear(items, 0, size);
|
|
size = 0;
|
|
version++;
|
|
}
|
|
|
|
public void CopyTo(T[] array, int arrayIndex)
|
|
{
|
|
Array.Copy(items, 0, array, arrayIndex, size);
|
|
}
|
|
|
|
public T[] ToArray()
|
|
{
|
|
T[] array = new T [size];
|
|
Array.Copy(items, 0, array, 0, size);
|
|
return array;
|
|
}
|
|
|
|
private void CheckIndex(int index)
|
|
{
|
|
if (index < 0 || index > size)
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
private void Shift(int start, int delta)
|
|
{
|
|
if (delta < 0)
|
|
start -= delta;
|
|
|
|
if (start < size)
|
|
Array.Copy(items, start, items, start + delta, size - start);
|
|
|
|
size += delta;
|
|
|
|
if (delta < 0)
|
|
Array.Clear(items, size, -delta);
|
|
}
|
|
|
|
protected virtual void OnAdd(T item, int index) { }
|
|
protected virtual void OnInsert(T item, int index) { }
|
|
protected virtual void OnSet(T item, int index) { }
|
|
protected virtual void OnRemove(T item, int index) { }
|
|
protected virtual void OnClear() { }
|
|
|
|
internal virtual void Grow(int desired)
|
|
{
|
|
int new_size = size + desired;
|
|
if (new_size <= items.Length)
|
|
return;
|
|
|
|
const int default_capacity = 4;
|
|
|
|
new_size = Math.Max(Math.Max(items.Length * 2, default_capacity), new_size);
|
|
|
|
Resize(new_size);
|
|
}
|
|
|
|
protected void Resize(int new_size)
|
|
{
|
|
if (new_size == size)
|
|
return;
|
|
if (new_size < size)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
items = items.Resize(new_size);
|
|
}
|
|
|
|
int IList.Add(object value)
|
|
{
|
|
try
|
|
{
|
|
Add((T)value);
|
|
return size - 1;
|
|
}
|
|
catch (InvalidCastException) { }
|
|
catch (NullReferenceException) { }
|
|
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
void IList.Clear()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
bool IList.Contains(object value)
|
|
{
|
|
return ((IList)this).IndexOf(value) > -1;
|
|
}
|
|
|
|
int IList.IndexOf(object value)
|
|
{
|
|
try
|
|
{
|
|
return IndexOf((T)value);
|
|
}
|
|
catch (InvalidCastException) { }
|
|
catch (NullReferenceException) { }
|
|
|
|
return -1;
|
|
}
|
|
|
|
void IList.Insert(int index, object value)
|
|
{
|
|
CheckIndex(index);
|
|
|
|
try
|
|
{
|
|
Insert(index, (T)value);
|
|
return;
|
|
}
|
|
catch (InvalidCastException) { }
|
|
catch (NullReferenceException) { }
|
|
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
void IList.Remove(object value)
|
|
{
|
|
try
|
|
{
|
|
Remove((T)value);
|
|
}
|
|
catch (InvalidCastException) { }
|
|
catch (NullReferenceException) { }
|
|
}
|
|
|
|
void IList.RemoveAt(int index)
|
|
{
|
|
RemoveAt(index);
|
|
}
|
|
|
|
void ICollection.CopyTo(Array array, int index)
|
|
{
|
|
Array.Copy(items, 0, array, index, size);
|
|
}
|
|
|
|
public Enumerator GetEnumerator()
|
|
{
|
|
return new(this);
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return new Enumerator(this);
|
|
}
|
|
|
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
{
|
|
return new Enumerator(this);
|
|
}
|
|
|
|
public struct Enumerator : IEnumerator<T>, IDisposable
|
|
{
|
|
private Collection<T> collection;
|
|
private int next;
|
|
private readonly int version;
|
|
public T Current { get; private set; }
|
|
object IEnumerator.Current
|
|
{
|
|
get
|
|
{
|
|
CheckState();
|
|
|
|
if (next <= 0)
|
|
throw new InvalidOperationException();
|
|
|
|
return Current;
|
|
}
|
|
}
|
|
|
|
internal Enumerator(Collection<T> collection) : this()
|
|
{
|
|
this.collection = collection;
|
|
version = collection.version;
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
CheckState();
|
|
|
|
if (next < 0)
|
|
return false;
|
|
|
|
if (next < collection.size)
|
|
{
|
|
Current = collection.items[next++];
|
|
return true;
|
|
}
|
|
|
|
next = -1;
|
|
return false;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
CheckState();
|
|
|
|
next = 0;
|
|
}
|
|
|
|
private void CheckState()
|
|
{
|
|
if (collection == null)
|
|
throw new ObjectDisposedException(GetType().FullName);
|
|
|
|
if (version != collection.version)
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
collection = null;
|
|
}
|
|
}
|
|
}
|
|
} |