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)
8 // David Waite (mass@akuma.org)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // Copyright (C) 2005 David Waite
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Collections
.ObjectModel
;
34 using System
.Runtime
.InteropServices
;
35 using System
.Diagnostics
;
37 namespace System
.Collections
.Generic
{
39 [DebuggerDisplay ("Count={Count}")]
40 [DebuggerTypeProxy (typeof (CollectionDebuggerView
<>))]
41 public class List
<T
> : IList
<T
>, IList
, ICollection
{
46 static readonly T
[] EmptyArray
= new T
[0];
47 const int DefaultCapacity
= 4;
54 public List (IEnumerable
<T
> collection
)
56 CheckCollection (collection
);
58 // initialize to needed size (if determinable)
59 ICollection
<T
> c
= collection
as ICollection
<T
>;
63 AddEnumerable (collection
);
67 _items
= new T
[c
.Count
];
72 public List (int capacity
)
75 throw new ArgumentOutOfRangeException ("capacity");
76 _items
= new T
[capacity
];
79 internal List (T
[] data
, int size
)
84 public void Add (T item
)
86 // If we check to see if we need to grow before trying to grow
87 // we can speed things up by 25%
88 if (_size
== _items
.Length
)
90 _items
[_size
++] = item
;
94 void GrowIfNeeded (int newCount
)
96 int minimumSize
= _size
+ newCount
;
97 if (minimumSize
> _items
.Length
)
98 Capacity
= Math
.Max (Math
.Max (Capacity
* 2, DefaultCapacity
), minimumSize
);
101 void CheckRange (int idx
, int count
)
104 throw new ArgumentOutOfRangeException ("index");
107 throw new ArgumentOutOfRangeException ("count");
109 if ((uint) idx
+ (uint) count
> (uint) _size
)
110 throw new ArgumentException ("index and count exceed length of list");
113 void AddCollection (ICollection
<T
> collection
)
115 int collectionCount
= collection
.Count
;
116 if (collectionCount
== 0)
119 GrowIfNeeded (collectionCount
);
120 collection
.CopyTo (_items
, _size
);
121 _size
+= collectionCount
;
124 void AddEnumerable (IEnumerable
<T
> enumerable
)
126 foreach (T t
in enumerable
)
132 public void AddRange (IEnumerable
<T
> collection
)
134 CheckCollection (collection
);
136 ICollection
<T
> c
= collection
as ICollection
<T
>;
140 AddEnumerable (collection
);
144 public ReadOnlyCollection
<T
> AsReadOnly ()
146 return new ReadOnlyCollection
<T
> (this);
149 public int BinarySearch (T item
)
151 return Array
.BinarySearch
<T
> (_items
, 0, _size
, item
);
154 public int BinarySearch (T item
, IComparer
<T
> comparer
)
156 return Array
.BinarySearch
<T
> (_items
, 0, _size
, item
, comparer
);
159 public int BinarySearch (int index
, int count
, T item
, IComparer
<T
> comparer
)
161 CheckRange (index
, count
);
162 return Array
.BinarySearch
<T
> (_items
, index
, count
, item
, comparer
);
167 Array
.Clear (_items
, 0, _items
.Length
);
172 public bool Contains (T item
)
174 return Array
.IndexOf
<T
>(_items
, item
, 0, _size
) != -1;
177 public List
<TOutput
> ConvertAll
<TOutput
> (Converter
<T
, TOutput
> converter
)
179 if (converter
== null)
180 throw new ArgumentNullException ("converter");
181 List
<TOutput
> u
= new List
<TOutput
> (_size
);
182 for (int i
= 0; i
< _size
; i
++)
183 u
._items
[i
] = converter(_items
[i
]);
189 public void CopyTo (T
[] array
)
191 Array
.Copy (_items
, 0, array
, 0, _size
);
194 public void CopyTo (T
[] array
, int arrayIndex
)
196 Array
.Copy (_items
, 0, array
, arrayIndex
, _size
);
199 public void CopyTo (int index
, T
[] array
, int arrayIndex
, int count
)
201 CheckRange (index
, count
);
202 Array
.Copy (_items
, index
, array
, arrayIndex
, count
);
205 public bool Exists (Predicate
<T
> match
)
208 return GetIndex(0, _size
, match
) != -1;
211 public T
Find (Predicate
<T
> match
)
214 int i
= GetIndex(0, _size
, match
);
215 return (i
!= -1) ? _items
[i
] : default (T
);
218 static void CheckMatch (Predicate
<T
> match
)
221 throw new ArgumentNullException ("match");
224 public List
<T
> FindAll (Predicate
<T
> match
)
227 if (this._size
<= 0x10000) // <= 8 * 1024 * 8 (8k in stack)
228 return this.FindAllStackBits (match
);
230 return this.FindAllList (match
);
233 private List
<T
> FindAllStackBits (Predicate
<T
> match
)
237 uint *bits
= stackalloc uint [(this._size
/ 32) + 1];
240 uint bitmask
= 0x80000000;
242 for (int i
= 0; i
< this._size
; i
++)
244 if (match (this._items
[i
]))
246 (*ptr
) = (*ptr
) | bitmask
;
250 bitmask
= bitmask
>> 1;
254 bitmask
= 0x80000000;
258 T
[] results
= new T
[found
];
259 bitmask
= 0x80000000;
262 for (int i
= 0; i
< this._size
&& j
< found
; i
++)
264 if (((*ptr
) & bitmask
) == bitmask
)
265 results
[j
++] = this._items
[i
];
267 bitmask
= bitmask
>> 1;
271 bitmask
= 0x80000000;
275 return new List
<T
> (results
, found
);
279 private List
<T
> FindAllList (Predicate
<T
> match
)
281 List
<T
> results
= new List
<T
> ();
282 for (int i
= 0; i
< this._size
; i
++)
283 if (match (this._items
[i
]))
284 results
.Add (this._items
[i
]);
289 public int FindIndex (Predicate
<T
> match
)
292 return GetIndex (0, _size
, match
);
295 public int FindIndex (int startIndex
, Predicate
<T
> match
)
298 CheckIndex (startIndex
);
299 return GetIndex (startIndex
, _size
- startIndex
, match
);
301 public int FindIndex (int startIndex
, int count
, Predicate
<T
> match
)
304 CheckRange (startIndex
, count
);
305 return GetIndex (startIndex
, count
, match
);
307 int GetIndex (int startIndex
, int count
, Predicate
<T
> match
)
309 int end
= startIndex
+ count
;
310 for (int i
= startIndex
; i
< end
; i
++)
311 if (match (_items
[i
]))
317 public T
FindLast (Predicate
<T
> match
)
320 int i
= GetLastIndex (0, _size
, match
);
321 return i
== -1 ? default (T
) : this [i
];
324 public int FindLastIndex (Predicate
<T
> match
)
327 return GetLastIndex (0, _size
, match
);
330 public int FindLastIndex (int startIndex
, Predicate
<T
> match
)
333 CheckIndex (startIndex
);
334 return GetLastIndex (0, startIndex
+ 1, match
);
337 public int FindLastIndex (int startIndex
, int count
, Predicate
<T
> match
)
340 int start
= startIndex
- count
+ 1;
341 CheckRange (start
, count
);
342 return GetLastIndex (start
, count
, match
);
345 int GetLastIndex (int startIndex
, int count
, Predicate
<T
> match
)
347 // unlike FindLastIndex, takes regular params for search range
348 for (int i
= startIndex
+ count
; i
!= startIndex
;)
349 if (match (_items
[--i
]))
354 public void ForEach (Action
<T
> action
)
357 throw new ArgumentNullException ("action");
358 for(int i
=0; i
< _size
; i
++)
362 public Enumerator
GetEnumerator ()
364 return new Enumerator (this);
367 public List
<T
> GetRange (int index
, int count
)
369 CheckRange (index
, count
);
370 T
[] tmpArray
= new T
[count
];
371 Array
.Copy (_items
, index
, tmpArray
, 0, count
);
372 return new List
<T
> (tmpArray
, count
);
375 public int IndexOf (T item
)
377 return Array
.IndexOf
<T
> (_items
, item
, 0, _size
);
380 public int IndexOf (T item
, int index
)
383 return Array
.IndexOf
<T
> (_items
, item
, index
, _size
- index
);
386 public int IndexOf (T item
, int index
, int count
)
389 throw new ArgumentOutOfRangeException ("index");
392 throw new ArgumentOutOfRangeException ("count");
394 if ((uint) index
+ (uint) count
> (uint) _size
)
395 throw new ArgumentOutOfRangeException ("index and count exceed length of list");
397 return Array
.IndexOf
<T
> (_items
, item
, index
, count
);
400 void Shift (int start
, int delta
)
406 Array
.Copy (_items
, start
, _items
, start
+ delta
, _size
- start
);
411 Array
.Clear (_items
, _size
, -delta
);
414 void CheckIndex (int index
)
416 if (index
< 0 || (uint) index
> (uint) _size
)
417 throw new ArgumentOutOfRangeException ("index");
420 public void Insert (int index
, T item
)
423 if (_size
== _items
.Length
)
426 _items
[index
] = item
;
430 void CheckCollection (IEnumerable
<T
> collection
)
432 if (collection
== null)
433 throw new ArgumentNullException ("collection");
436 public void InsertRange (int index
, IEnumerable
<T
> collection
)
438 CheckCollection (collection
);
440 if (collection
== this) {
441 T
[] buffer
= new T
[_size
];
443 GrowIfNeeded (_size
);
444 Shift (index
, buffer
.Length
);
445 Array
.Copy (buffer
, 0, _items
, index
, buffer
.Length
);
447 ICollection
<T
> c
= collection
as ICollection
<T
>;
449 InsertCollection (index
, c
);
451 InsertEnumeration (index
, collection
);
456 void InsertCollection (int index
, ICollection
<T
> collection
)
458 int collectionCount
= collection
.Count
;
459 GrowIfNeeded (collectionCount
);
461 Shift (index
, collectionCount
);
462 collection
.CopyTo (_items
, index
);
464 void InsertEnumeration (int index
, IEnumerable
<T
> enumerable
)
466 foreach (T t
in enumerable
)
470 public int LastIndexOf (T item
)
472 return Array
.LastIndexOf
<T
> (_items
, item
, _size
- 1, _size
);
475 public int LastIndexOf (T item
, int index
)
478 return Array
.LastIndexOf
<T
> (_items
, item
, index
, index
+ 1);
481 public int LastIndexOf (T item
, int index
, int count
)
484 throw new ArgumentOutOfRangeException ("index", index
, "index is negative");
487 throw new ArgumentOutOfRangeException ("count", count
, "count is negative");
489 if (index
- count
+ 1 < 0)
490 throw new ArgumentOutOfRangeException ("cound", count
, "count is too large");
492 return Array
.LastIndexOf
<T
> (_items
, item
, index
, count
);
495 public bool Remove (T item
)
497 int loc
= IndexOf (item
);
504 public int RemoveAll (Predicate
<T
> match
)
510 // Find the first item to remove
511 for (i
= 0; i
< _size
; i
++)
512 if (match(_items
[i
]))
520 // Remove any additional items
521 for (j
= i
+ 1; j
< _size
; j
++)
523 if (!match(_items
[j
]))
524 _items
[i
++] = _items
[j
];
527 Array
.Clear (_items
, i
, j
- i
);
533 public void RemoveAt (int index
)
535 if (index
< 0 || (uint)index
>= (uint)_size
)
536 throw new ArgumentOutOfRangeException("index");
538 Array
.Clear (_items
, _size
, 1);
542 public void RemoveRange (int index
, int count
)
544 CheckRange (index
, count
);
546 Shift (index
, -count
);
547 Array
.Clear (_items
, _size
, count
);
552 public void Reverse ()
554 Array
.Reverse (_items
, 0, _size
);
557 public void Reverse (int index
, int count
)
559 CheckRange (index
, count
);
560 Array
.Reverse (_items
, index
, count
);
566 Array
.Sort
<T
> (_items
, 0, _size
);
569 public void Sort (IComparer
<T
> comparer
)
571 Array
.Sort
<T
> (_items
, 0, _size
, comparer
);
575 public void Sort (Comparison
<T
> comparison
)
577 if (comparison
== null)
578 throw new ArgumentNullException ("comparison");
580 Array
.SortImpl
<T
> (_items
, _size
, comparison
);
584 public void Sort (int index
, int count
, IComparer
<T
> comparer
)
586 CheckRange (index
, count
);
587 Array
.Sort
<T
> (_items
, index
, count
, comparer
);
591 public T
[] ToArray ()
593 T
[] t
= new T
[_size
];
594 Array
.Copy (_items
, t
, _size
);
599 public void TrimExcess ()
604 public bool TrueForAll (Predicate
<T
> match
)
608 for (int i
= 0; i
< _size
; i
++)
609 if (!match(_items
[i
]))
615 public int Capacity
{
617 return _items
.Length
;
620 if ((uint) value < (uint) _size
)
621 throw new ArgumentOutOfRangeException ();
623 Array
.Resize (ref _items
, value);
628 get { return _size; }
631 public T
this [int index
] {
633 if ((uint) index
>= (uint) _size
)
634 throw new ArgumentOutOfRangeException ("index");
635 return _items
[index
];
639 if ((uint) index
== (uint) _size
)
640 throw new ArgumentOutOfRangeException ("index");
641 _items
[index
] = value;
645 #region Interface implementations.
646 IEnumerator
<T
> IEnumerable
<T
>.GetEnumerator ()
648 return GetEnumerator ();
651 void ICollection
.CopyTo (Array array
, int arrayIndex
)
653 Array
.Copy (_items
, 0, array
, arrayIndex
, _size
);
656 IEnumerator IEnumerable
.GetEnumerator ()
658 return GetEnumerator ();
661 int IList
.Add (object item
)
666 } catch (NullReferenceException
) {
667 } catch (InvalidCastException
) {
669 throw new ArgumentException ("item");
672 bool IList
.Contains (object item
)
675 return Contains ((T
) item
);
676 } catch (NullReferenceException
) {
677 } catch (InvalidCastException
) {
682 int IList
.IndexOf (object item
)
685 return IndexOf ((T
) item
);
686 } catch (NullReferenceException
) {
687 } catch (InvalidCastException
) {
692 void IList
.Insert (int index
, object item
)
694 // We need to check this first because, even if the
695 // item is null or not the correct type, we need to
696 // return an ArgumentOutOfRange exception if the
697 // index is out of range
700 Insert (index
, (T
) item
);
702 } catch (NullReferenceException
) {
703 } catch (InvalidCastException
) {
705 throw new ArgumentException ("item");
708 void IList
.Remove (object item
)
713 } catch (NullReferenceException
) {
714 } catch (InvalidCastException
) {
716 // Swallow the exception--if we can't cast to the
717 // correct type then we've already "succeeded" in
718 // removing the item from the List.
721 bool ICollection
<T
>.IsReadOnly
{
722 get { return false; }
724 bool ICollection
.IsSynchronized
{
725 get { return false; }
728 object ICollection
.SyncRoot
{
731 bool IList
.IsFixedSize
{
732 get { return false; }
735 bool IList
.IsReadOnly
{
736 get { return false; }
739 object IList
.this [int index
] {
740 get { return this [index]; }
743 this [index
] = (T
) value;
745 } catch (NullReferenceException
) {
746 // can happen when 'value' is null and T is a valuetype
747 } catch (InvalidCastException
) {
749 throw new ArgumentException ("value");
755 public struct Enumerator
: IEnumerator
<T
>, IDisposable
{
762 internal Enumerator (List
<T
> l
)
769 public void Dispose ()
777 throw new ObjectDisposedException (GetType ().FullName
);
778 if (ver
!= l
._version
)
779 throw new InvalidOperationException (
780 "Collection was modified; enumeration operation may not execute.");
783 public bool MoveNext ()
790 if (next
< l
._size
) {
791 current
= l
._items
[next
++];
800 get { return current; }
803 void IEnumerator
.Reset ()
809 object IEnumerator
.Current
{
813 throw new InvalidOperationException ();