2 // System.Collections.Generic.List
5 // Ben Maurer (bmaurer@ximian.com)
6 // Martin Baulig (martin@ximian.com)
7 // Carlos Alberto Cortez (calberto.cortez@gmail.com)
9 // (C) 2004 Novell, Inc.
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Collections;
38 using System.Runtime.InteropServices;
40 namespace System.Collections.Generic
44 public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
50 const int DefaultCapacity = 4;
56 public List (IEnumerable <T> collection)
58 AddRange (collection);
61 public List (int capacity)
63 data = new T [capacity];
66 public void Add (T item)
69 Capacity = DefaultCapacity;
70 else if (size == data.Length)
71 Capacity = Math.Max (Capacity * 2, DefaultCapacity);
73 data [size ++] = item;
76 public void CheckRange (int idx, int count)
78 if (idx < 0 || count < 0 || idx > size - count)
79 throw new ArgumentOutOfRangeException ();
82 [MonoTODO ("PERFORMANCE: fix if it is an IList <T>")]
83 public void AddRange(IEnumerable<T> collection)
85 foreach (T t in collection)
89 public IList<T> AsReadOnly ()
91 return new ReadOnlyList<T>(this);
94 public int BinarySearch(T item)
96 return BinarySearch (item, Comparer <T>.Default);
99 public int BinarySearch(T item, IComparer<T> comparer)
101 return BinarySearch (0, size, item, comparer);
104 public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
106 CheckRange (index, count);
107 return Array.BinarySearch (data, index, size, item, comparer);
115 Array.Clear (data, 0, data.Length);
118 public bool Contains (T item)
120 return IndexOf (item) != -1;
123 public List <U> ConvertAll <U> (Converter<T, U> converter)
125 List <U> u = new List <U> (size);
127 foreach (T t in this)
128 u [i ++] = converter (t);
133 public void CopyTo (T [] array)
138 public void CopyTo (T [] array, int arrayIndex)
140 CopyTo (0, array, arrayIndex, size);
143 public void CopyTo (int index, T[] array, int arrayIndex, int count)
145 CheckRange (index, count);
146 Array.Copy (data, index, array, arrayIndex, count);
149 public bool Exists (Predicate<T> match)
151 foreach (T t in this)
158 public T Find (Predicate<T> match)
160 foreach (T t in this)
167 // Maybe we could make this faster. For example, you could
168 // make a bit set with stackalloc for which elements to copy
169 // then you could size the array correctly.
170 public List<T> FindAll (Predicate<T> match)
172 List <T> f = new List <T> ();
174 foreach (T t in this)
181 public int FindIndex (Predicate <T> match)
183 return FindIndex (0, match);
186 public int FindIndex (int startIndex, Predicate <T> match)
188 return FindIndex (startIndex, size - startIndex, match);
191 public int FindIndex (int startIndex, int count, Predicate <T> match)
193 CheckRange (startIndex, count);
195 for (int i = startIndex; i < startIndex + count; i ++)
196 if (match (data [i]))
202 public T FindLast (Predicate <T> match)
204 int i = FindLastIndex (match);
205 return i == -1 ? default (T) : this [i];
208 public int FindLastIndex (Predicate <T> match)
210 return FindLastIndex (0, match);
213 public int FindLastIndex (int startIndex, Predicate <T> match)
215 return FindLastIndex (startIndex, size - startIndex, match);
218 public int FindLastIndex (int startIndex, int count, Predicate <T> match)
220 CheckRange (startIndex, count);
221 for (int i = startIndex + count; i != startIndex;)
222 if (match (data [--i]))
228 public void ForEach (Action <T> action)
230 foreach (T t in this)
234 public Enumerator <T> GetEnumerator ()
236 return new Enumerator <T> (this);
240 public List <T> GetRange (int index, int count)
242 throw new NotImplementedException ();
245 public int IndexOf (T item)
247 return IndexOf (item, 0);
250 public int IndexOf (T item, int index)
252 return IndexOf (item, index, size - index);
255 public int IndexOf (T item, int index, int count)
257 CheckRange (index, count);
261 return Array.IndexOf (data, item, index, count);
264 void Shift (int start, int delta)
269 Array.Copy (data, start, data, start + delta, size - start);
274 public void Insert (int index, T item)
276 if ((uint) index < (uint) size)
277 throw new ArgumentOutOfRangeException ();
283 [MonoTODO ("Performance for collection")]
284 public void InsertRange (int index, IEnumerable<T> collection)
286 foreach (T t in collection)
287 Insert (index ++, t);
290 public int LastIndexOf (T item)
292 return LastIndexOf (item, 0);
295 public int LastIndexOf (T item, int index)
297 return LastIndexOf (item, index, size - index);
300 public int LastIndexOf (T item, int index, int count)
302 CheckRange (index, count);
306 return Array.LastIndexOf (data, item, index, count);
309 public bool Remove (T item)
311 int loc = IndexOf (item);
318 [MonoTODO ("I can make it faster than this...")]
319 public int RemoveAll (Predicate<T> match)
323 while ((index = FindIndex (index, match)) != -1) {
331 public void RemoveAt (int index)
333 RemoveRange (index, 1);
336 public void RemoveRange (int index, int count)
338 CheckRange (index, count);
339 Shift (index, -count);
342 public void Reverse ()
346 public void Reverse (int index, int count)
348 CheckRange (index, count);
349 Array.Reverse (data, index, count);
354 Sort (Comparer <T>.Default);
356 public void Sort (IComparer<T> comparer)
358 Sort (0, size, comparer);
363 public void Sort (Comparison<T> comparison)
365 throw new NotImplementedException ();
369 public void Sort (int index, int count, IComparer<T> comparer)
371 CheckRange (index, count);
372 throw new NotImplementedException ();
375 public T [] ToArray ()
377 T [] t = new T [size];
384 public void TrimToSize ()
389 public bool TrueForAll (Predicate <T> match)
391 foreach (T t in this)
398 public int Capacity {
401 return DefaultCapacity;
405 if ((uint) value < (uint) size)
406 throw new ArgumentOutOfRangeException ();
408 Array.Resize (ref data, value);
416 public T this [int index] {
418 if ((uint) index >= (uint) size)
419 throw new IndexOutOfRangeException ();
423 if ((uint) index >= (uint) size)
424 throw new IndexOutOfRangeException ();
425 data [index] = value;
429 #region Interface Crap
430 IEnumerator <T> IEnumerable <T>.GetEnumerator()
432 return GetEnumerator ();
435 void ICollection.CopyTo (Array array, int arrayIndex)
437 Array.Copy (data, 0, data, arrayIndex, size);
440 IEnumerator IEnumerable.GetEnumerator()
442 return GetEnumerator ();
445 int IList.Add (object item)
451 bool IList.Contains (object item)
453 return Contains ((T) item);
456 int IList.IndexOf (object item)
458 return IndexOf ((T) item);
461 void IList.Insert (int index, object item)
463 Insert (index, (T) item);
466 void IList.Remove (object item)
471 bool ICollection <T>.IsReadOnly {
472 get { return false; }
474 bool ICollection.IsSynchronized {
475 get { return false; }
478 object ICollection.SyncRoot {
481 bool IList.IsFixedSize {
482 get { return false; }
485 bool IList.IsReadOnly {
486 get { return false; }
489 object IList.this [int index] {
490 get { return this [index]; }
491 set { this [index] = (T) value; }
496 internal class ReadOnlyList<I> : IList<I>, ICollection<I>, IEnumerable<I>
500 internal ReadOnlyList (IList<I> list)
505 public void Add (I item)
507 throw new NotSupportedException ();
512 throw new NotSupportedException ();
515 public bool Contains (I item)
517 return list.Contains (item);
520 public void CopyTo (I [] array, int index)
522 list.CopyTo (array, index);
525 public IEnumerator<I> GetEnumerator ()
527 return list.GetEnumerator ();
530 public int IndexOf (I item)
532 return list.IndexOf (item);
535 public void Insert (int index, I item)
537 throw new NotSupportedException ();
540 public bool Remove (I item)
542 throw new NotSupportedException ();
545 public void RemoveAt (int index)
547 throw new NotSupportedException ();
556 public bool IsReadOnly {
562 public I this [int index] {
567 throw new NotSupportedException ();
572 public struct Enumerator <T> : IEnumerator <T>, IEnumerator, IDisposable {
573 const int NOT_STARTED = -2;
575 // this MUST be -1, because we depend on it in move next.
576 // we just decr the size, so, 0 - 1 == FINISHED
577 const int FINISHED = -1;
583 internal Enumerator (List <T> l)
590 // for some fucked up reason, MSFT added a useless dispose to this class
591 // It means that in foreach, we must still do a try/finally. Broken, very
593 public void Dispose ()
598 public bool MoveNext ()
600 if (ver != l.version)
601 throw new InvalidOperationException ();
603 if (idx == NOT_STARTED)
606 return idx != FINISHED && -- idx != FINISHED;
612 throw new InvalidOperationException ();
614 return l.data [l.size - 1 - idx];
618 void IEnumerator.Reset ()
620 if (ver != l.version)
621 throw new InvalidOperationException ();
626 object IEnumerator.Current {
627 get { return Current; }