You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
418 lines
6.8 KiB
418 lines
6.8 KiB
// |
|
// 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 System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
|
|
using ILRuntime.Mono.Cecil; |
|
|
|
namespace ILRuntime.Mono.Collections.Generic { |
|
|
|
public class Collection<T> : IList<T>, IList { |
|
|
|
internal T [] items; |
|
internal int size; |
|
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); |
|
this.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 (); |
|
|
|
var item = items [index]; |
|
|
|
OnRemove (item, index); |
|
|
|
Shift (index, -1); |
|
version++; |
|
} |
|
|
|
public bool Remove (T item) |
|
{ |
|
var 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 () |
|
{ |
|
var array = new T [size]; |
|
Array.Copy (items, 0, array, 0, size); |
|
return array; |
|
} |
|
|
|
void CheckIndex (int index) |
|
{ |
|
if (index < 0 || index > size) |
|
throw new ArgumentOutOfRangeException (); |
|
} |
|
|
|
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 = System.Math.Max ( |
|
System.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 Enumerator (this); |
|
} |
|
|
|
IEnumerator IEnumerable.GetEnumerator () |
|
{ |
|
return new Enumerator (this); |
|
} |
|
|
|
IEnumerator<T> IEnumerable<T>.GetEnumerator () |
|
{ |
|
return new Enumerator (this); |
|
} |
|
|
|
public struct Enumerator : IEnumerator<T>, IDisposable { |
|
|
|
Collection<T> collection; |
|
T current; |
|
|
|
int next; |
|
readonly int version; |
|
|
|
public T Current { |
|
get { return current; } |
|
} |
|
|
|
object IEnumerator.Current { |
|
get { |
|
CheckState (); |
|
|
|
if (next <= 0) |
|
throw new InvalidOperationException (); |
|
|
|
return current; |
|
} |
|
} |
|
|
|
internal Enumerator (Collection<T> collection) |
|
: this () |
|
{ |
|
this.collection = collection; |
|
this.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; |
|
} |
|
|
|
void CheckState () |
|
{ |
|
if (collection == null) |
|
throw new ObjectDisposedException (GetType ().FullName); |
|
|
|
if (version != collection.version) |
|
throw new InvalidOperationException (); |
|
} |
|
|
|
public void Dispose () |
|
{ |
|
collection = null; |
|
} |
|
} |
|
} |
|
}
|
|
|