Files
2026-03-30 20:11:57 +07:00

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;
}
}
}
}