/Mono.Collections.Generic/Collection.cs
C# | 418 lines | 315 code | 94 blank | 9 comment | 34 complexity | bd6b47aeb5287076339069a0364d6a6b MD5 | raw file
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 11using System; 12using System.Collections; 13using System.Collections.Generic; 14 15using Mono.Cecil; 16 17namespace Mono.Collections.Generic { 18 19 public class Collection<T> : IList<T>, IList { 20 21 internal T [] items; 22 internal int size; 23 int version; 24 25 public int Count { 26 get { return size; } 27 } 28 29 public T this [int index] { 30 get { 31 if (index >= size) 32 throw new ArgumentOutOfRangeException (); 33 34 return items [index]; 35 } 36 set { 37 CheckIndex (index); 38 if (index == size) 39 throw new ArgumentOutOfRangeException (); 40 41 OnSet (value, index); 42 43 items [index] = value; 44 } 45 } 46 47 public int Capacity { 48 get { return items.Length; } 49 set { 50 if (value < 0 || value < size) 51 throw new ArgumentOutOfRangeException (); 52 53 Resize (value); 54 } 55 } 56 57 bool ICollection<T>.IsReadOnly { 58 get { return false; } 59 } 60 61 bool IList.IsFixedSize { 62 get { return false; } 63 } 64 65 bool IList.IsReadOnly { 66 get { return false; } 67 } 68 69 object IList.this [int index] { 70 get { return this [index]; } 71 set { 72 CheckIndex (index); 73 74 try { 75 this [index] = (T) value; 76 return; 77 } catch (InvalidCastException) { 78 } catch (NullReferenceException) { 79 } 80 81 throw new ArgumentException (); 82 } 83 } 84 85 int ICollection.Count { 86 get { return Count; } 87 } 88 89 bool ICollection.IsSynchronized { 90 get { return false; } 91 } 92 93 object ICollection.SyncRoot { 94 get { return this; } 95 } 96 97 public Collection () 98 { 99 items = Empty<T>.Array; 100 } 101 102 public Collection (int capacity) 103 { 104 if (capacity < 0) 105 throw new ArgumentOutOfRangeException (); 106 107 items = capacity == 0 108 ? Empty<T>.Array 109 : new T [capacity]; 110 } 111 112 public Collection (ICollection<T> items) 113 { 114 if (items == null) 115 throw new ArgumentNullException ("items"); 116 117 this.items = new T [items.Count]; 118 items.CopyTo (this.items, 0); 119 this.size = this.items.Length; 120 } 121 122 public void Add (T item) 123 { 124 if (size == items.Length) 125 Grow (1); 126 127 OnAdd (item, size); 128 129 items [size++] = item; 130 version++; 131 } 132 133 public bool Contains (T item) 134 { 135 return IndexOf (item) != -1; 136 } 137 138 public int IndexOf (T item) 139 { 140 return Array.IndexOf (items, item, 0, size); 141 } 142 143 public void Insert (int index, T item) 144 { 145 CheckIndex (index); 146 if (size == items.Length) 147 Grow (1); 148 149 OnInsert (item, index); 150 151 Shift (index, 1); 152 items [index] = item; 153 version++; 154 } 155 156 public void RemoveAt (int index) 157 { 158 if (index < 0 || index >= size) 159 throw new ArgumentOutOfRangeException (); 160 161 var item = items [index]; 162 163 OnRemove (item, index); 164 165 Shift (index, -1); 166 version++; 167 } 168 169 public bool Remove (T item) 170 { 171 var index = IndexOf (item); 172 if (index == -1) 173 return false; 174 175 OnRemove (item, index); 176 177 Shift (index, -1); 178 version++; 179 180 return true; 181 } 182 183 public void Clear () 184 { 185 OnClear (); 186 187 Array.Clear (items, 0, size); 188 size = 0; 189 version++; 190 } 191 192 public void CopyTo (T [] array, int arrayIndex) 193 { 194 Array.Copy (items, 0, array, arrayIndex, size); 195 } 196 197 public T [] ToArray () 198 { 199 var array = new T [size]; 200 Array.Copy (items, 0, array, 0, size); 201 return array; 202 } 203 204 void CheckIndex (int index) 205 { 206 if (index < 0 || index > size) 207 throw new ArgumentOutOfRangeException (); 208 } 209 210 void Shift (int start, int delta) 211 { 212 if (delta < 0) 213 start -= delta; 214 215 if (start < size) 216 Array.Copy (items, start, items, start + delta, size - start); 217 218 size += delta; 219 220 if (delta < 0) 221 Array.Clear (items, size, -delta); 222 } 223 224 protected virtual void OnAdd (T item, int index) 225 { 226 } 227 228 protected virtual void OnInsert (T item, int index) 229 { 230 } 231 232 protected virtual void OnSet (T item, int index) 233 { 234 } 235 236 protected virtual void OnRemove (T item, int index) 237 { 238 } 239 240 protected virtual void OnClear () 241 { 242 } 243 244 internal virtual void Grow (int desired) 245 { 246 int new_size = size + desired; 247 if (new_size <= items.Length) 248 return; 249 250 const int default_capacity = 4; 251 252 new_size = System.Math.Max ( 253 System.Math.Max (items.Length * 2, default_capacity), 254 new_size); 255 256 Resize (new_size); 257 } 258 259 protected void Resize (int new_size) 260 { 261 if (new_size == size) 262 return; 263 if (new_size < size) 264 throw new ArgumentOutOfRangeException (); 265 266 items = items.Resize (new_size); 267 } 268 269 int IList.Add (object value) 270 { 271 try { 272 Add ((T) value); 273 return size - 1; 274 } catch (InvalidCastException) { 275 } catch (NullReferenceException) { 276 } 277 278 throw new ArgumentException (); 279 } 280 281 void IList.Clear () 282 { 283 Clear (); 284 } 285 286 bool IList.Contains (object value) 287 { 288 return ((IList) this).IndexOf (value) > -1; 289 } 290 291 int IList.IndexOf (object value) 292 { 293 try { 294 return IndexOf ((T) value); 295 } catch (InvalidCastException) { 296 } catch (NullReferenceException) { 297 } 298 299 return -1; 300 } 301 302 void IList.Insert (int index, object value) 303 { 304 CheckIndex (index); 305 306 try { 307 Insert (index, (T) value); 308 return; 309 } catch (InvalidCastException) { 310 } catch (NullReferenceException) { 311 } 312 313 throw new ArgumentException (); 314 } 315 316 void IList.Remove (object value) 317 { 318 try { 319 Remove ((T) value); 320 } catch (InvalidCastException) { 321 } catch (NullReferenceException) { 322 } 323 } 324 325 void IList.RemoveAt (int index) 326 { 327 RemoveAt (index); 328 } 329 330 void ICollection.CopyTo (Array array, int index) 331 { 332 Array.Copy (items, 0, array, index, size); 333 } 334 335 public Enumerator GetEnumerator () 336 { 337 return new Enumerator (this); 338 } 339 340 IEnumerator IEnumerable.GetEnumerator () 341 { 342 return new Enumerator (this); 343 } 344 345 IEnumerator<T> IEnumerable<T>.GetEnumerator () 346 { 347 return new Enumerator (this); 348 } 349 350 public struct Enumerator : IEnumerator<T>, IDisposable { 351 352 Collection<T> collection; 353 T current; 354 355 int next; 356 readonly int version; 357 358 public T Current { 359 get { return current; } 360 } 361 362 object IEnumerator.Current { 363 get { 364 CheckState (); 365 366 if (next <= 0) 367 throw new InvalidOperationException (); 368 369 return current; 370 } 371 } 372 373 internal Enumerator (Collection<T> collection) 374 : this () 375 { 376 this.collection = collection; 377 this.version = collection.version; 378 } 379 380 public bool MoveNext () 381 { 382 CheckState (); 383 384 if (next < 0) 385 return false; 386 387 if (next < collection.size) { 388 current = collection.items [next++]; 389 return true; 390 } 391 392 next = -1; 393 return false; 394 } 395 396 public void Reset () 397 { 398 CheckState (); 399 400 next = 0; 401 } 402 403 void CheckState () 404 { 405 if (collection == null) 406 throw new ObjectDisposedException (GetType ().FullName); 407 408 if (version != collection.version) 409 throw new InvalidOperationException (); 410 } 411 412 public void Dispose () 413 { 414 collection = null; 415 } 416 } 417 } 418}