Collection.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using Mono.Cecil;
  14. namespace Mono.Collections.Generic {
  15. public class Collection<T> : IList<T>, IList {
  16. internal T [] items;
  17. internal int size;
  18. int version;
  19. public int Count {
  20. get { return size; }
  21. }
  22. public T this [int index] {
  23. get {
  24. if (index >= size)
  25. throw new ArgumentOutOfRangeException ();
  26. return items [index];
  27. }
  28. set {
  29. CheckIndex (index);
  30. if (index == size)
  31. throw new ArgumentOutOfRangeException ();
  32. OnSet (value, index);
  33. items [index] = value;
  34. }
  35. }
  36. public int Capacity {
  37. get { return items.Length; }
  38. set {
  39. if (value < 0 || value < size)
  40. throw new ArgumentOutOfRangeException ();
  41. Resize (value);
  42. }
  43. }
  44. bool ICollection<T>.IsReadOnly {
  45. get { return false; }
  46. }
  47. bool IList.IsFixedSize {
  48. get { return false; }
  49. }
  50. bool IList.IsReadOnly {
  51. get { return false; }
  52. }
  53. object IList.this [int index] {
  54. get { return this [index]; }
  55. set {
  56. CheckIndex (index);
  57. try {
  58. this [index] = (T) value;
  59. return;
  60. } catch (InvalidCastException) {
  61. } catch (NullReferenceException) {
  62. }
  63. throw new ArgumentException ();
  64. }
  65. }
  66. int ICollection.Count {
  67. get { return Count; }
  68. }
  69. bool ICollection.IsSynchronized {
  70. get { return false; }
  71. }
  72. object ICollection.SyncRoot {
  73. get { return this; }
  74. }
  75. public Collection ()
  76. {
  77. items = Empty<T>.Array;
  78. }
  79. public Collection (int capacity)
  80. {
  81. if (capacity < 0)
  82. throw new ArgumentOutOfRangeException ();
  83. items = new T [capacity];
  84. }
  85. public Collection (ICollection<T> items)
  86. {
  87. if (items == null)
  88. throw new ArgumentNullException ("items");
  89. this.items = new T [items.Count];
  90. items.CopyTo (this.items, 0);
  91. this.size = this.items.Length;
  92. }
  93. public void Add (T item)
  94. {
  95. if (size == items.Length)
  96. Grow (1);
  97. OnAdd (item, size);
  98. items [size++] = item;
  99. version++;
  100. }
  101. public bool Contains (T item)
  102. {
  103. return IndexOf (item) != -1;
  104. }
  105. public int IndexOf (T item)
  106. {
  107. return Array.IndexOf (items, item, 0, size);
  108. }
  109. public void Insert (int index, T item)
  110. {
  111. CheckIndex (index);
  112. if (size == items.Length)
  113. Grow (1);
  114. OnInsert (item, index);
  115. Shift (index, 1);
  116. items [index] = item;
  117. version++;
  118. }
  119. public void RemoveAt (int index)
  120. {
  121. if (index < 0 || index >= size)
  122. throw new ArgumentOutOfRangeException ();
  123. var item = items [index];
  124. OnRemove (item, index);
  125. Shift (index, -1);
  126. version++;
  127. }
  128. public bool Remove (T item)
  129. {
  130. var index = IndexOf (item);
  131. if (index == -1)
  132. return false;
  133. OnRemove (item, index);
  134. Shift (index, -1);
  135. version++;
  136. return true;
  137. }
  138. public void Clear ()
  139. {
  140. OnClear ();
  141. Array.Clear (items, 0, size);
  142. size = 0;
  143. version++;
  144. }
  145. public void CopyTo (T [] array, int arrayIndex)
  146. {
  147. Array.Copy (items, 0, array, arrayIndex, size);
  148. }
  149. public T [] ToArray ()
  150. {
  151. var array = new T [size];
  152. Array.Copy (items, 0, array, 0, size);
  153. return array;
  154. }
  155. void CheckIndex (int index)
  156. {
  157. if (index < 0 || index > size)
  158. throw new ArgumentOutOfRangeException ();
  159. }
  160. void Shift (int start, int delta)
  161. {
  162. if (delta < 0)
  163. start -= delta;
  164. if (start < size)
  165. Array.Copy (items, start, items, start + delta, size - start);
  166. size += delta;
  167. if (delta < 0)
  168. Array.Clear (items, size, -delta);
  169. }
  170. protected virtual void OnAdd (T item, int index)
  171. {
  172. }
  173. protected virtual void OnInsert (T item, int index)
  174. {
  175. }
  176. protected virtual void OnSet (T item, int index)
  177. {
  178. }
  179. protected virtual void OnRemove (T item, int index)
  180. {
  181. }
  182. protected virtual void OnClear ()
  183. {
  184. }
  185. internal virtual void Grow (int desired)
  186. {
  187. int new_size = size + desired;
  188. if (new_size <= items.Length)
  189. return;
  190. const int default_capacity = 4;
  191. new_size = System.Math.Max (
  192. System.Math.Max (items.Length * 2, default_capacity),
  193. new_size);
  194. Resize (new_size);
  195. }
  196. protected void Resize (int new_size)
  197. {
  198. if (new_size == size)
  199. return;
  200. if (new_size < size)
  201. throw new ArgumentOutOfRangeException ();
  202. items = items.Resize (new_size);
  203. }
  204. int IList.Add (object value)
  205. {
  206. try {
  207. Add ((T) value);
  208. return size - 1;
  209. } catch (InvalidCastException) {
  210. } catch (NullReferenceException) {
  211. }
  212. throw new ArgumentException ();
  213. }
  214. void IList.Clear ()
  215. {
  216. Clear ();
  217. }
  218. bool IList.Contains (object value)
  219. {
  220. return ((IList) this).IndexOf (value) > -1;
  221. }
  222. int IList.IndexOf (object value)
  223. {
  224. try {
  225. return IndexOf ((T) value);
  226. } catch (InvalidCastException) {
  227. } catch (NullReferenceException) {
  228. }
  229. return -1;
  230. }
  231. void IList.Insert (int index, object value)
  232. {
  233. CheckIndex (index);
  234. try {
  235. Insert (index, (T) value);
  236. return;
  237. } catch (InvalidCastException) {
  238. } catch (NullReferenceException) {
  239. }
  240. throw new ArgumentException ();
  241. }
  242. void IList.Remove (object value)
  243. {
  244. try {
  245. Remove ((T) value);
  246. } catch (InvalidCastException) {
  247. } catch (NullReferenceException) {
  248. }
  249. }
  250. void IList.RemoveAt (int index)
  251. {
  252. RemoveAt (index);
  253. }
  254. void ICollection.CopyTo (Array array, int index)
  255. {
  256. Array.Copy (items, 0, array, index, size);
  257. }
  258. public Enumerator GetEnumerator ()
  259. {
  260. return new Enumerator (this);
  261. }
  262. IEnumerator IEnumerable.GetEnumerator ()
  263. {
  264. return new Enumerator (this);
  265. }
  266. IEnumerator<T> IEnumerable<T>.GetEnumerator ()
  267. {
  268. return new Enumerator (this);
  269. }
  270. public struct Enumerator : IEnumerator<T>, IDisposable {
  271. Collection<T> collection;
  272. T current;
  273. int next;
  274. readonly int version;
  275. public T Current {
  276. get { return current; }
  277. }
  278. object IEnumerator.Current {
  279. get {
  280. CheckState ();
  281. if (next <= 0)
  282. throw new InvalidOperationException ();
  283. return current;
  284. }
  285. }
  286. internal Enumerator (Collection<T> collection)
  287. : this ()
  288. {
  289. this.collection = collection;
  290. this.version = collection.version;
  291. }
  292. public bool MoveNext ()
  293. {
  294. CheckState ();
  295. if (next < 0)
  296. return false;
  297. if (next < collection.size) {
  298. current = collection.items [next++];
  299. return true;
  300. }
  301. next = -1;
  302. return false;
  303. }
  304. public void Reset ()
  305. {
  306. CheckState ();
  307. next = 0;
  308. }
  309. void CheckState ()
  310. {
  311. if (collection == null)
  312. throw new ObjectDisposedException (GetType ().FullName);
  313. if (version != collection.version)
  314. throw new InvalidOperationException ();
  315. }
  316. public void Dispose ()
  317. {
  318. collection = null;
  319. }
  320. }
  321. }
  322. }