428 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			428 lines
		
	
	
		
			6.8 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;
 | |
| 		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;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |