3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>[....]</OWNER>
12 ** Purpose: Implements a generic, dynamically sized list as an
16 ===========================================================*/
17 namespace System.Collections.Generic {
21 using System.Runtime.Versioning;
22 using System.Diagnostics;
23 using System.Diagnostics.Contracts;
24 using System.Collections.ObjectModel;
25 using System.Security.Permissions;
27 // Implements a variable-size List that uses an array of objects to store the
28 // elements. A List has a capacity, which is the allocated length
29 // of the internal array. As elements are added to a List, the capacity
30 // of the List is automatically increased as required by reallocating the
33 [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))]
34 [DebuggerDisplay("Count = {Count}")]
36 public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>
38 private const int _defaultCapacity = 4;
41 [ContractPublicPropertyName("Count")]
45 private Object _syncRoot;
47 static readonly T[] _emptyArray = new T[0];
49 // Constructs a List. The list is initially empty and has a capacity
50 // of zero. Upon adding the first element to the list the capacity is
51 // increased to 16, and then increased in multiples of two as required.
56 // Constructs a List with a given initial capacity. The list is
57 // initially empty, but will have room for the given number of elements
58 // before any reallocations are required.
60 public List(int capacity) {
61 if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
62 Contract.EndContractBlock();
67 _items = new T[capacity];
70 // Constructs a List, copying the contents of the given collection. The
71 // size and capacity of the new list will both be equal to the size of the
74 public List(IEnumerable<T> collection) {
76 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
77 Contract.EndContractBlock();
79 ICollection<T> c = collection as ICollection<T>;
87 _items = new T[count];
95 // This enumerable could be empty. Let Add allocate a new array, if needed.
96 // Note it will also go to _defaultCapacity first, not 1, then 2, etc.
98 using(IEnumerator<T> en = collection.GetEnumerator()) {
99 while(en.MoveNext()) {
106 // Gets and sets the capacity of this list. The capacity is the size of
107 // the internal array used to hold items. When set, the internal
108 // array of the list is reallocated to the given capacity.
110 public int Capacity {
112 Contract.Ensures(Contract.Result<int>() >= 0);
113 return _items.Length;
117 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
119 Contract.EndContractBlock();
121 if (value != _items.Length) {
123 T[] newItems = new T[value];
125 Array.Copy(_items, 0, newItems, 0, _size);
130 _items = _emptyArray;
136 // Read-only property describing how many elements are in the List.
139 Contract.Ensures(Contract.Result<int>() >= 0);
144 bool System.Collections.IList.IsFixedSize {
145 get { return false; }
149 // Is this List read-only?
150 bool ICollection<T>.IsReadOnly {
151 get { return false; }
154 bool System.Collections.IList.IsReadOnly {
155 get { return false; }
158 // Is this List synchronized (thread-safe)?
159 bool System.Collections.ICollection.IsSynchronized {
160 get { return false; }
163 // Synchronization root for this object.
164 Object System.Collections.ICollection.SyncRoot {
166 if( _syncRoot == null) {
167 System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
172 // Sets or Gets the element at the given index.
174 public T this[int index] {
176 [System.Runtime.CompilerServices.MethodImpl (System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
179 // Following trick can reduce the range check by one
180 if ((uint) index >= (uint)_size) {
181 ThrowHelper.ThrowArgumentOutOfRangeException();
183 Contract.EndContractBlock();
185 return Array.UnsafeLoad (_items, index);
187 return _items[index];
192 if ((uint) index >= (uint)_size) {
193 ThrowHelper.ThrowArgumentOutOfRangeException();
195 Contract.EndContractBlock();
196 _items[index] = value;
201 private static bool IsCompatibleObject(object value) {
202 // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>.
203 // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
204 return ((value is T) || (value == null && default(T) == null));
207 Object System.Collections.IList.this[int index] {
212 ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value);
215 this[index] = (T)value;
217 catch (InvalidCastException) {
218 ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T));
223 // Adds the given object to the end of this list. The size of the list is
224 // increased by one. If required, the capacity of the list is doubled
225 // before adding the new element.
227 public void Add(T item) {
228 if (_size == _items.Length) EnsureCapacity(_size + 1);
229 _items[_size++] = item;
233 int System.Collections.IList.Add(Object item)
235 ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
240 catch (InvalidCastException) {
241 ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
248 // Adds the elements of the given collection to the end of this list. If
249 // required, the capacity of the list is increased to twice the previous
250 // capacity or the new size, whichever is larger.
252 public void AddRange(IEnumerable<T> collection) {
253 Contract.Ensures(Count >= Contract.OldValue(Count));
255 InsertRange(_size, collection);
258 public ReadOnlyCollection<T> AsReadOnly() {
259 Contract.Ensures(Contract.Result<ReadOnlyCollection<T>>() != null);
260 return new ReadOnlyCollection<T>(this);
263 // Searches a section of the list for a given element using a binary search
264 // algorithm. Elements of the list are compared to the search value using
265 // the given IComparer interface. If comparer is null, elements of
266 // the list are compared to the search value using the IComparable
267 // interface, which in that case must be implemented by all elements of the
268 // list and the given search value. This method assumes that the given
269 // section of the list is already sorted; if this is not the case, the
270 // result will be incorrect.
272 // The method returns the index of the given value in the list. If the
273 // list does not contain the given value, the method returns a negative
274 // integer. The bitwise complement operator (~) can be applied to a
275 // negative result to produce the index of the first element (if any) that
276 // is larger than the given search value. This is also the index at which
277 // the search value should be inserted into the list in order for the list
280 // The method uses the Array.BinarySearch method to perform the
283 public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
285 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
287 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
288 if (_size - index < count)
289 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
290 Contract.Ensures(Contract.Result<int>() <= index + count);
291 Contract.EndContractBlock();
293 return Array.BinarySearch<T>(_items, index, count, item, comparer);
296 public int BinarySearch(T item)
298 Contract.Ensures(Contract.Result<int>() <= Count);
299 return BinarySearch(0, Count, item, null);
302 public int BinarySearch(T item, IComparer<T> comparer)
304 Contract.Ensures(Contract.Result<int>() <= Count);
305 return BinarySearch(0, Count, item, comparer);
309 // Clears the contents of List.
310 public void Clear() {
313 Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
319 // Contains returns true if the specified element is in the List.
320 // It does a linear, O(n) search. Equality is determined by calling
323 public bool Contains(T item) {
324 if ((Object) item == null) {
325 for(int i=0; i<_size; i++)
326 if ((Object) _items[i] == null)
331 EqualityComparer<T> c = EqualityComparer<T>.Default;
332 for(int i=0; i<_size; i++) {
333 if (c.Equals(_items[i], item)) return true;
339 bool System.Collections.IList.Contains(Object item)
341 if(IsCompatibleObject(item)) {
342 return Contains((T) item);
347 public List<TOutput> ConvertAll<TOutput>(Converter<T,TOutput> converter) {
348 if( converter == null) {
349 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
354 Contract.EndContractBlock();
356 List<TOutput> list = new List<TOutput>(_size);
357 for( int i = 0; i< _size; i++) {
358 list._items[i] = converter(_items[i]);
364 // Copies this List into array, which must be of a
365 // compatible array type.
367 public void CopyTo(T[] array) {
371 // Copies this List into array, which must be of a
372 // compatible array type.
374 void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) {
375 if ((array != null) && (array.Rank != 1)) {
376 ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
378 Contract.EndContractBlock();
381 // Array.Copy will check for NULL.
382 Array.Copy(_items, 0, array, arrayIndex, _size);
384 catch(ArrayTypeMismatchException){
385 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
389 // Copies a section of this list to the given array at the given index.
391 // The method uses the Array.Copy method to copy the elements.
393 public void CopyTo(int index, T[] array, int arrayIndex, int count) {
394 if (_size - index < count) {
395 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
397 Contract.EndContractBlock();
399 // Delegate rest of error checking to Array.Copy.
400 Array.Copy(_items, index, array, arrayIndex, count);
403 public void CopyTo(T[] array, int arrayIndex) {
404 // Delegate rest of error checking to Array.Copy.
405 Array.Copy(_items, 0, array, arrayIndex, _size);
408 // Ensures that the capacity of this list is at least the given minimum
409 // value. If the currect capacity of the list is less than min, the
410 // capacity is increased to twice the current capacity or to min,
411 // whichever is larger.
412 private void EnsureCapacity(int min) {
413 if (_items.Length < min) {
414 int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;
415 // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
416 // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
417 if ((uint)newCapacity > Array_ReferenceSources.MaxArrayLength) newCapacity = Array_ReferenceSources.MaxArrayLength;
418 if (newCapacity < min) newCapacity = min;
419 Capacity = newCapacity;
423 public bool Exists(Predicate<T> match) {
424 return FindIndex(match) != -1;
427 public T Find(Predicate<T> match) {
429 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
431 Contract.EndContractBlock();
433 for(int i = 0 ; i < _size; i++) {
434 if(match(_items[i])) {
441 public List<T> FindAll(Predicate<T> match) {
443 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
445 Contract.EndContractBlock();
447 List<T> list = new List<T>();
448 for(int i = 0 ; i < _size; i++) {
449 if(match(_items[i])) {
456 public int FindIndex(Predicate<T> match) {
457 Contract.Ensures(Contract.Result<int>() >= -1);
458 Contract.Ensures(Contract.Result<int>() < Count);
459 return FindIndex(0, _size, match);
462 public int FindIndex(int startIndex, Predicate<T> match) {
463 Contract.Ensures(Contract.Result<int>() >= -1);
464 Contract.Ensures(Contract.Result<int>() < startIndex + Count);
465 return FindIndex(startIndex, _size - startIndex, match);
468 public int FindIndex(int startIndex, int count, Predicate<T> match) {
469 if( (uint)startIndex > (uint)_size ) {
470 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
473 if (count < 0 || startIndex > _size - count) {
474 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count);
478 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
480 Contract.Ensures(Contract.Result<int>() >= -1);
481 Contract.Ensures(Contract.Result<int>() < startIndex + count);
482 Contract.EndContractBlock();
484 int endIndex = startIndex + count;
485 for( int i = startIndex; i < endIndex; i++) {
486 if( match(_items[i])) return i;
491 public T FindLast(Predicate<T> match) {
493 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
495 Contract.EndContractBlock();
497 for(int i = _size - 1 ; i >= 0; i--) {
498 if(match(_items[i])) {
505 public int FindLastIndex(Predicate<T> match) {
506 Contract.Ensures(Contract.Result<int>() >= -1);
507 Contract.Ensures(Contract.Result<int>() < Count);
508 return FindLastIndex(_size - 1, _size, match);
511 public int FindLastIndex(int startIndex, Predicate<T> match) {
512 Contract.Ensures(Contract.Result<int>() >= -1);
513 Contract.Ensures(Contract.Result<int>() <= startIndex);
514 return FindLastIndex(startIndex, startIndex + 1, match);
517 public int FindLastIndex(int startIndex, int count, Predicate<T> match) {
519 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
521 Contract.Ensures(Contract.Result<int>() >= -1);
522 Contract.Ensures(Contract.Result<int>() <= startIndex);
523 Contract.EndContractBlock();
526 // Special case for 0 length List
527 if( startIndex != -1) {
528 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
532 // Make sure we're not out of range
533 if ( (uint)startIndex >= (uint)_size) {
534 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
538 // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
539 if (count < 0 || startIndex - count + 1 < 0) {
540 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count);
543 int endIndex = startIndex - count;
544 for( int i = startIndex; i > endIndex; i--) {
545 if( match(_items[i])) {
552 public void ForEach(Action<T> action) {
553 if( action == null) {
554 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
556 Contract.EndContractBlock();
558 int version = _version;
560 for(int i = 0 ; i < _size; i++) {
561 if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) {
567 if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
568 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
571 // Returns an enumerator for this list with the given
572 // permission for removal of elements. If modifications made to the list
573 // while an enumeration is in progress, the MoveNext and
574 // GetObject methods of the enumerator will throw an exception.
576 public Enumerator GetEnumerator() {
577 return new Enumerator(this);
581 IEnumerator<T> IEnumerable<T>.GetEnumerator() {
582 return new Enumerator(this);
585 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
586 return new Enumerator(this);
589 public List<T> GetRange(int index, int count) {
591 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
595 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
598 if (_size - index < count) {
599 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
601 Contract.Ensures(Contract.Result<List<T>>() != null);
602 Contract.EndContractBlock();
604 List<T> list = new List<T>(count);
605 Array.Copy(_items, index, list._items, 0, count);
611 // Returns the index of the first occurrence of a given value in a range of
612 // this list. The list is searched forwards from beginning to end.
613 // The elements of the list are compared to the given value using the
614 // Object.Equals method.
616 // This method uses the Array.IndexOf method to perform the
619 public int IndexOf(T item) {
620 Contract.Ensures(Contract.Result<int>() >= -1);
621 Contract.Ensures(Contract.Result<int>() < Count);
622 return Array.IndexOf(_items, item, 0, _size);
625 int System.Collections.IList.IndexOf(Object item)
627 if(IsCompatibleObject(item)) {
628 return IndexOf((T)item);
633 // Returns the index of the first occurrence of a given value in a range of
634 // this list. The list is searched forwards, starting at index
635 // index and ending at count number of elements. The
636 // elements of the list are compared to the given value using the
637 // Object.Equals method.
639 // This method uses the Array.IndexOf method to perform the
642 public int IndexOf(T item, int index) {
644 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
645 Contract.Ensures(Contract.Result<int>() >= -1);
646 Contract.Ensures(Contract.Result<int>() < Count);
647 Contract.EndContractBlock();
648 return Array.IndexOf(_items, item, index, _size - index);
651 // Returns the index of the first occurrence of a given value in a range of
652 // this list. The list is searched forwards, starting at index
653 // index and upto count number of elements. The
654 // elements of the list are compared to the given value using the
655 // Object.Equals method.
657 // This method uses the Array.IndexOf method to perform the
660 public int IndexOf(T item, int index, int count) {
662 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
664 if (count <0 || index > _size - count) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count);
665 Contract.Ensures(Contract.Result<int>() >= -1);
666 Contract.Ensures(Contract.Result<int>() < Count);
667 Contract.EndContractBlock();
669 return Array.IndexOf(_items, item, index, count);
672 // Inserts an element into this list at a given index. The size of the list
673 // is increased by one. If required, the capacity of the list is doubled
674 // before inserting the new element.
676 public void Insert(int index, T item) {
677 // Note that insertions at the end are legal.
678 if ((uint) index > (uint)_size) {
679 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_ListInsert);
681 Contract.EndContractBlock();
682 if (_size == _items.Length) EnsureCapacity(_size + 1);
684 Array.Copy(_items, index, _items, index + 1, _size - index);
686 _items[index] = item;
691 void System.Collections.IList.Insert(int index, Object item)
693 ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
696 Insert(index, (T) item);
698 catch (InvalidCastException) {
699 ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
703 // Inserts the elements of the given collection at a given index. If
704 // required, the capacity of the list is increased to twice the previous
705 // capacity or the new size, whichever is larger. Ranges may be added
706 // to the end of the list by setting index to the List's size.
708 public void InsertRange(int index, IEnumerable<T> collection) {
709 if (collection==null) {
710 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
713 if ((uint)index > (uint)_size) {
714 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
716 Contract.EndContractBlock();
718 ICollection<T> c = collection as ICollection<T>;
719 if( c != null ) { // if collection is ICollection<T>
722 EnsureCapacity(_size + count);
724 Array.Copy(_items, index, _items, index + count, _size - index);
727 // If we're inserting a List into itself, we want to be able to deal with that.
729 // Copy first part of _items to insert location
730 Array.Copy(_items, 0, _items, index, index);
731 // Copy last part of _items back to inserted location
732 Array.Copy(_items, index+count, _items, index*2, _size-index);
735 T[] itemsToInsert = new T[count];
736 c.CopyTo(itemsToInsert, 0);
737 itemsToInsert.CopyTo(_items, index);
743 using(IEnumerator<T> en = collection.GetEnumerator()) {
744 while(en.MoveNext()) {
745 Insert(index++, en.Current);
752 // Returns the index of the last occurrence of a given value in a range of
753 // this list. The list is searched backwards, starting at the end
754 // and ending at the first element in the list. The elements of the list
755 // are compared to the given value using the Object.Equals method.
757 // This method uses the Array.LastIndexOf method to perform the
760 public int LastIndexOf(T item)
762 Contract.Ensures(Contract.Result<int>() >= -1);
763 Contract.Ensures(Contract.Result<int>() < Count);
764 if (_size == 0) { // Special case for empty list
768 return LastIndexOf(item, _size - 1, _size);
772 // Returns the index of the last occurrence of a given value in a range of
773 // this list. The list is searched backwards, starting at index
774 // index and ending at the first element in the list. The
775 // elements of the list are compared to the given value using the
776 // Object.Equals method.
778 // This method uses the Array.LastIndexOf method to perform the
781 public int LastIndexOf(T item, int index)
784 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
785 Contract.Ensures(Contract.Result<int>() >= -1);
786 Contract.Ensures(((Count == 0) && (Contract.Result<int>() == -1)) || ((Count > 0) && (Contract.Result<int>() <= index)));
787 Contract.EndContractBlock();
788 return LastIndexOf(item, index, index + 1);
791 // Returns the index of the last occurrence of a given value in a range of
792 // this list. The list is searched backwards, starting at index
793 // index and upto count elements. The elements of
794 // the list are compared to the given value using the Object.Equals
797 // This method uses the Array.LastIndexOf method to perform the
800 public int LastIndexOf(T item, int index, int count) {
801 if ((Count != 0) && (index < 0)) {
802 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
805 if ((Count !=0) && (count < 0)) {
806 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
808 Contract.Ensures(Contract.Result<int>() >= -1);
809 Contract.Ensures(((Count == 0) && (Contract.Result<int>() == -1)) || ((Count > 0) && (Contract.Result<int>() <= index)));
810 Contract.EndContractBlock();
812 if (_size == 0) { // Special case for empty list
816 if (index >= _size) {
817 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_BiggerThanCollection);
820 if (count > index + 1) {
821 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_BiggerThanCollection);
824 return Array.LastIndexOf(_items, item, index, count);
827 // Removes the element at the given index. The size of the list is
830 public bool Remove(T item) {
831 int index = IndexOf(item);
840 void System.Collections.IList.Remove(Object item)
842 if(IsCompatibleObject(item)) {
847 // This method removes all items which matches the predicate.
848 // The complexity is O(n).
849 public int RemoveAll(Predicate<T> match) {
851 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
853 Contract.Ensures(Contract.Result<int>() >= 0);
854 Contract.Ensures(Contract.Result<int>() <= Contract.OldValue(Count));
855 Contract.EndContractBlock();
857 int freeIndex = 0; // the first free slot in items array
859 // Find the first item which needs to be removed.
860 while( freeIndex < _size && !match(_items[freeIndex])) freeIndex++;
861 if( freeIndex >= _size) return 0;
863 int current = freeIndex + 1;
864 while( current < _size) {
865 // Find the first item which needs to be kept.
866 while( current < _size && match(_items[current])) current++;
868 if( current < _size) {
869 // copy item to the free slot.
870 _items[freeIndex++] = _items[current++];
874 Array.Clear(_items, freeIndex, _size - freeIndex);
875 int result = _size - freeIndex;
881 // Removes the element at the given index. The size of the list is
884 public void RemoveAt(int index) {
885 if ((uint)index >= (uint)_size) {
886 ThrowHelper.ThrowArgumentOutOfRangeException();
888 Contract.EndContractBlock();
891 Array.Copy(_items, index + 1, _items, index, _size - index);
893 _items[_size] = default(T);
897 // Removes a range of elements from this list.
899 public void RemoveRange(int index, int count) {
901 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
905 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
908 if (_size - index < count)
909 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
910 Contract.EndContractBlock();
918 Array.Copy(_items, index + count, _items, index, _size - index);
920 Array.Clear(_items, _size, count);
925 // Reverses the elements in this list.
926 public void Reverse() {
930 // Reverses the elements in a range of this list. Following a call to this
931 // method, an element in the range given by index and count
932 // which was previously located at index i will now be located at
933 // index index + (index + count - i - 1).
935 // This method uses the Array.Reverse method to reverse the
938 public void Reverse(int index, int count) {
940 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
944 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
947 if (_size - index < count)
948 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
949 Contract.EndContractBlock();
950 Array.Reverse(_items, index, count);
954 // Sorts the elements in this list. Uses the default comparer and
958 Sort(0, Count, null);
961 // Sorts the elements in this list. Uses Array.Sort with the
962 // provided comparer.
963 public void Sort(IComparer<T> comparer)
965 Sort(0, Count, comparer);
968 // Sorts the elements in a section of this list. The sort compares the
969 // elements to each other using the given IComparer interface. If
970 // comparer is null, the elements are compared to each other using
971 // the IComparable interface, which in that case must be implemented by all
972 // elements of the list.
974 // This method uses the Array.Sort method to sort the elements.
976 public void Sort(int index, int count, IComparer<T> comparer) {
978 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
982 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
985 if (_size - index < count)
986 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
987 Contract.EndContractBlock();
989 Array.Sort<T>(_items, index, count, comparer);
993 public void Sort(Comparison<T> comparison) {
994 if( comparison == null) {
995 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
997 Contract.EndContractBlock();
1000 IComparer<T> comparer = new Array.FunctorComparer<T>(comparison);
1001 Array.Sort(_items, 0, _size, comparer);
1005 // ToArray returns a new Object array containing the contents of the List.
1006 // This requires copying the List, which is an O(n) operation.
1007 public T[] ToArray() {
1008 Contract.Ensures(Contract.Result<T[]>() != null);
1009 Contract.Ensures(Contract.Result<T[]>().Length == Count);
1011 T[] array = new T[_size];
1012 Array.Copy(_items, 0, array, 0, _size);
1016 // Sets the capacity of this list to the size of the list. This method can
1017 // be used to minimize a list's memory overhead once it is known that no
1018 // new elements will be added to the list. To completely clear a list and
1019 // release all memory referenced by the list, execute the following
1023 // list.TrimExcess();
1025 public void TrimExcess() {
1026 int threshold = (int)(((double)_items.Length) * 0.9);
1027 if( _size < threshold ) {
1032 public bool TrueForAll(Predicate<T> match) {
1033 if( match == null) {
1034 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
1036 Contract.EndContractBlock();
1038 for(int i = 0 ; i < _size; i++) {
1039 if( !match(_items[i])) {
1046 internal static IList<T> Synchronized(List<T> list) {
1047 return new SynchronizedList(list);
1051 internal class SynchronizedList : IList<T> {
1052 private List<T> _list;
1053 private Object _root;
1055 internal SynchronizedList(List<T> list) {
1057 _root = ((System.Collections.ICollection)list).SyncRoot;
1068 public bool IsReadOnly {
1070 return ((ICollection<T>)_list).IsReadOnly;
1074 public void Add(T item) {
1080 public void Clear() {
1086 public bool Contains(T item) {
1088 return _list.Contains(item);
1092 public void CopyTo(T[] array, int arrayIndex) {
1094 _list.CopyTo(array, arrayIndex);
1098 public bool Remove(T item) {
1100 return _list.Remove(item);
1104 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
1106 return _list.GetEnumerator();
1110 IEnumerator<T> IEnumerable<T>.GetEnumerator() {
1112 return ((IEnumerable<T>)_list).GetEnumerator();
1116 public T this[int index] {
1119 return _list[index];
1124 _list[index] = value;
1129 public int IndexOf(T item) {
1131 return _list.IndexOf(item);
1135 public void Insert(int index, T item) {
1137 _list.Insert(index, item);
1141 public void RemoveAt(int index) {
1143 _list.RemoveAt(index);
1149 public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
1151 private List<T> list;
1153 private int version;
1156 internal Enumerator(List<T> list) {
1159 version = list._version;
1160 current = default(T);
1163 public void Dispose() {
1166 public bool MoveNext() {
1168 List<T> localList = list;
1170 if (version == localList._version && ((uint)index < (uint)localList._size))
1172 current = localList._items[index];
1176 return MoveNextRare();
1179 private bool MoveNextRare()
1181 if (version != list._version) {
1182 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
1185 index = list._size + 1;
1186 current = default(T);
1196 Object System.Collections.IEnumerator.Current {
1198 if( index == 0 || index == list._size + 1) {
1199 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
1205 void System.Collections.IEnumerator.Reset() {
1206 if (version != list._version) {
1207 ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
1211 current = default(T);