Mark tests as not working under TARGET_JVM
[mono.git] / mcs / class / corlib / System.Collections.Generic / List.cs
1 //
2 // System.Collections.Generic.List
3 //
4 // Authors:
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)
9 //
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // Copyright (C) 2005 David Waite
12 //
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:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
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.
31 //
32
33 #if NET_2_0
34
35 using System.Collections.ObjectModel;
36 using System.Runtime.InteropServices;
37
38 namespace System.Collections.Generic {
39         [Serializable]
40         public class List <T> : IList <T>, IList, ICollection {
41                 T [] _items;
42                 int _size;
43                 int _version;
44                 
45                 static readonly T [] EmptyArray = new T [0]; 
46                 const int DefaultCapacity = 4;
47                 
48                 public List ()
49                 {
50                         _items = EmptyArray;
51                 }
52                 
53                 public List (IEnumerable <T> collection)
54                 {
55                         CheckCollection (collection);
56
57                         // initialize to needed size (if determinable)
58                         ICollection <T> c = collection as ICollection <T>;
59                         if (c == null)
60                         {
61                                 _items = EmptyArray;
62                                 AddEnumerable (collection);
63                         }
64                         else
65                         {
66                                 _items = new T [c.Count];
67                                 AddCollection (c);
68                         }
69                 }
70                 
71                 public List (int capacity)
72                 {
73                         if (capacity < 0)
74                                 throw new ArgumentOutOfRangeException ("capacity");
75                         _items = new T [capacity];
76                 }
77                 
78                 internal List (T [] data, int size)
79                 {
80                         _items = data;
81                         _size = size;
82                 }
83                 public void Add (T item)
84                 {
85                         GrowIfNeeded (1);
86                         _items [_size ++] = item;
87                         _version++;
88                 }
89                 
90                 void GrowIfNeeded (int newCount)
91                 {
92                         int minimumSize = _size + newCount;
93                         if (minimumSize > _items.Length)
94                                 Capacity = Math.Max (Math.Max (Capacity * 2, DefaultCapacity), minimumSize);
95                 }
96                 
97                 void CheckRange (int idx, int count)
98                 {
99                         if (idx < 0)
100                                 throw new ArgumentOutOfRangeException ("index");
101                         
102                         if (count < 0)
103                                 throw new ArgumentOutOfRangeException ("count");
104
105                         if ((uint) idx + (uint) count > (uint) _size)
106                                 throw new ArgumentException ("index and count exceed length of list");
107                 }
108                 
109                 void AddCollection (ICollection <T> collection)
110                 {
111                         int collectionCount = collection.Count;
112                         GrowIfNeeded (collectionCount);                  
113                         collection.CopyTo (_items, _size);
114                         _size += collectionCount;
115                 }
116                 void AddEnumerable (IEnumerable <T> enumerable)
117                 {
118                         foreach (T t in enumerable)
119                         {
120                                 Add (t);
121                         }
122                 }
123
124                 public void AddRange (IEnumerable <T> collection)
125                 {
126                         CheckCollection (collection);
127                         
128                         ICollection <T> c = collection as ICollection <T>;
129                         if (c != null)
130                                 AddCollection (c);
131                         else
132                                 AddEnumerable (collection);
133                         _version++;
134                 }
135                 
136                 public ReadOnlyCollection <T> AsReadOnly ()
137                 {
138                         return new ReadOnlyCollection <T> (this);
139                 }
140                 
141                 public int BinarySearch (T item)
142                 {
143                         return Array.BinarySearch <T> (_items, 0, _size, item);
144                 }
145                 
146                 public int BinarySearch (T item, IComparer <T> comparer)
147                 {
148                         return Array.BinarySearch <T> (_items, 0, _size, item, comparer);
149                 }
150                 
151                 public int BinarySearch (int index, int count, T item, IComparer <T> comparer)
152                 {
153                         CheckRange (index, count);
154                         return Array.BinarySearch <T> (_items, index, count, item, comparer);
155                 }
156                 
157                 public void Clear ()
158                 {
159                         Array.Clear (_items, 0, _items.Length);
160                         _size = 0;
161                         _version++;
162                 }
163                 
164                 public bool Contains (T item)
165                 {
166                         EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
167                         for (int i = 0; i < _size; i++)
168                                 if (equalityComparer.Equals (_items[i], item))
169                                         return true;
170                         return false;
171                 }
172                 
173                 public List <TOutput> ConvertAll <TOutput> (Converter <T, TOutput> converter)
174                 {
175                         if (converter == null)
176                                 throw new ArgumentNullException ("converter");
177                         List <TOutput> u = new List <TOutput> (_size);
178                         foreach (T t in this)
179                                 u.Add (converter (t));
180                         return u;
181                 }
182                 
183                 public void CopyTo (T [] array)
184                 {
185                         Array.Copy (_items, 0, array, 0, _size);
186                 }
187                 
188                 public void CopyTo (T [] array, int arrayIndex)
189                 {
190                         Array.Copy (_items, 0, array, arrayIndex, _size);
191                 }
192                 
193                 public void CopyTo (int index, T [] array, int arrayIndex, int count)
194                 {
195                         CheckRange (index, count);
196                         Array.Copy (_items, index, array, arrayIndex, count);
197                 }
198
199                 public bool Exists (Predicate <T> match)
200                 {
201                         return FindIndex (match) != -1;
202                 }
203                 
204                 public T Find (Predicate <T> match)
205                 {
206                         int i = FindIndex (match);
207                         return (i != -1) ? _items [i] : default (T);
208                 }
209                 void CheckMatch (Predicate <T> match)
210                 {
211                         if (match == null)
212                                 throw new ArgumentNullException ("match");
213                 }
214                 
215                 // Maybe we could make this faster. For example, you could
216                 // make a bit set with stackalloc for which elements to copy
217                 // then you could size the array correctly.
218                 public List <T> FindAll (Predicate <T> match)
219                 {
220                         CheckMatch (match);
221                         List <T> f = new List <T> ();
222                         
223                         foreach (T t in this)
224                                 if (match (t))
225                                         f.Add (t);
226                         
227                         return f;
228                 }
229                 
230                 public int FindIndex (Predicate <T> match)
231                 {
232                         CheckMatch (match);
233                         return GetIndex (0, _size, match);
234                 }
235                 
236                 public int FindIndex (int startIndex, Predicate <T> match)
237                 {
238                         CheckMatch (match);
239                         CheckIndex (startIndex);
240                         return GetIndex (startIndex, _size - startIndex, match);
241                 }
242                 public int FindIndex (int startIndex, int count, Predicate <T> match)
243                 {
244                         CheckMatch (match);
245                         CheckRange (startIndex, count);
246                         return GetIndex (startIndex, count, match);
247                 }
248                 int GetIndex (int startIndex, int count, Predicate <T> match)
249                 {
250                         for (int i = startIndex; i < startIndex + count; i ++)
251                                 if (match (_items [i]))
252                                         return i;
253                                 
254                         return -1;
255                 }
256                 
257                 public T FindLast (Predicate <T> match)
258                 {
259                         CheckMatch (match);
260                         int i = GetLastIndex (0, _size, match);
261                         return i == -1 ? default (T) : this [i];
262                 }
263                 
264                 public int FindLastIndex (Predicate <T> match)
265                 {
266                         CheckMatch (match);
267                         return GetLastIndex (0, _size, match);
268                 }
269                 
270                 public int FindLastIndex (int startIndex, Predicate <T> match)
271                 {
272                         CheckMatch (match);
273                         CheckIndex (startIndex);
274                         return GetLastIndex (0, startIndex + 1, match);
275                 }
276                 
277                 public int FindLastIndex (int startIndex, int count, Predicate <T> match)
278                 {
279                         CheckMatch (match);
280                         int start = startIndex - count + 1;
281                         CheckRange (start, count);
282                         return GetLastIndex (start, count, match);
283                 }
284
285                 int GetLastIndex (int startIndex, int count, Predicate <T> match)
286                 {
287                         // unlike FindLastIndex, takes regular params for search range
288                         for (int i = startIndex + count; i != startIndex;)
289                                 if (match (_items [--i]))
290                                         return i;
291                         return -1;      
292                 }
293                 
294                 public void ForEach (Action <T> action)
295                 {
296                         if (action == null)
297                                 throw new ArgumentNullException ("action");
298                         foreach (T t in this)
299                                 action (t);
300                 }
301                 
302                 public Enumerator GetEnumerator ()
303                 {
304                         return new Enumerator (this);
305                 }
306                 
307                 public List <T> GetRange (int index, int count)
308                 {
309                         CheckRange (index, count);
310                         T [] tmpArray = new T [count];
311                         Array.Copy (_items, index, tmpArray, 0, count);
312                         return new List <T> (tmpArray, count);
313                 }
314                 
315                 public int IndexOf (T item)
316                 {
317                         return Array.IndexOf<T> (_items, item, 0, _size);
318                 }
319                 
320                 public int IndexOf (T item, int index)
321                 {
322                         CheckIndex (index);
323                         return Array.IndexOf<T> (_items, item, index, _size - index);
324                 }
325                 
326                 public int IndexOf (T item, int index, int count)
327                 {
328                         if (index < 0)
329                                 throw new ArgumentOutOfRangeException ("index");
330                         
331                         if (count < 0)
332                                 throw new ArgumentOutOfRangeException ("count");
333
334                         if ((uint) index + (uint) count > (uint) _size)
335                                 throw new ArgumentOutOfRangeException ("index and count exceed length of list");
336
337                         return Array.IndexOf<T> (_items, item, index, count);
338                 }
339                 
340                 void Shift (int start, int delta)
341                 {
342                         if (delta < 0)
343                                 start -= delta;
344                         
345                         Array.Copy (_items, start, _items, start + delta, _size - start);
346                         
347                         _size += delta;
348                 }
349
350                 void CheckIndex (int index)
351                 {
352                         if (index < 0 || (uint) index > (uint) _size)
353                                 throw new ArgumentOutOfRangeException ("index");
354                 }
355                 
356                 public void Insert (int index, T item)
357                 {
358                         CheckIndex (index);                     
359                         GrowIfNeeded (1);
360                         Shift (index, 1);
361                         this [index] = item;
362                         _version++;
363                 }
364
365                 void CheckCollection (IEnumerable <T> collection)
366                 {
367                         if (collection == null)
368                                 throw new ArgumentNullException ("collection");
369                 }
370                 
371                 public void InsertRange (int index, IEnumerable <T> collection)
372                 {
373                         CheckCollection (collection);
374                         CheckIndex (index);
375                         if (collection == this) {
376                                 T[] buffer = new T[_size];
377                                 CopyTo (buffer, 0);
378                                 GrowIfNeeded (_size);
379                                 Shift (index, buffer.Length);
380                                 Array.Copy (buffer, 0, _items, index, buffer.Length);
381                         } else {
382                                 ICollection <T> c = collection as ICollection <T>;
383                                 if (c != null)
384                                         InsertCollection (index, c);
385                                 else
386                                         InsertEnumeration (index, collection);
387                         }
388                         _version++;
389                 }
390
391                 void InsertCollection (int index, ICollection <T> collection)
392                 {
393                         int collectionCount = collection.Count;
394                         GrowIfNeeded (collectionCount);
395                         
396                         Shift (index, collectionCount);
397                         collection.CopyTo (_items, index);
398                 }
399                 void InsertEnumeration (int index, IEnumerable <T> enumerable)
400                 {
401                         foreach (T t in enumerable)
402                                 Insert (index++, t);            
403                 }
404
405                 public int LastIndexOf (T item)
406                 {
407                         return Array.LastIndexOf<T> (_items, item, _size - 1, _size);
408                 }
409                 
410                 public int LastIndexOf (T item, int index)
411                 {
412                         CheckIndex (index);
413                         return Array.LastIndexOf<T> (_items, item, index, index + 1);
414                 }
415                 
416                 public int LastIndexOf (T item, int index, int count)
417                 {
418                         if (index < 0)
419                                 throw new ArgumentOutOfRangeException ("index", index, "index is negative");
420
421                         if (count < 0)
422                                 throw new ArgumentOutOfRangeException ("count", count, "count is negative");
423
424                         if (index - count + 1 < 0)
425                                 throw new ArgumentOutOfRangeException ("cound", count, "count is too large");
426
427                         return Array.LastIndexOf<T> (_items, item, index, count);
428                 }
429                 
430                 public bool Remove (T item)
431                 {
432                         int loc = IndexOf (item);
433                         if (loc != -1)
434                                 RemoveAt (loc);
435                         
436                         return loc != -1;
437                 }
438                 
439                 // FIXME: this could probably be made faster.
440                 public int RemoveAll (Predicate <T> match)
441                 {
442                         CheckMatch (match);
443
444                         int index = 0;
445                         int c = 0;
446                         while ((index = GetIndex (index, _size - index, match)) != -1) {
447                                 RemoveAt (index);
448                                 c ++;
449                         }
450                         
451                         Array.Clear (_items, _size, c);
452                         return c;
453                 }
454                 
455                 public void RemoveAt (int index)
456                 {
457                         CheckIndex (index);
458                         Shift (index, -1);
459                         Array.Clear (_items, _size, 0);
460                         _version++;
461                 }
462                 
463                 public void RemoveRange (int index, int count)
464                 {
465                         CheckRange (index, count);
466                         if (count > 0) {
467                                 Shift (index, -count);
468                                 Array.Clear (_items, _size, count);
469                                 _version++;
470                         }
471                 }
472                 
473                 public void Reverse ()
474                 {
475                         Array.Reverse (_items, 0, _size);
476                         _version++;
477                 }
478                 public void Reverse (int index, int count)
479                 {
480                         CheckRange (index, count);
481                         Array.Reverse (_items, index, count);
482                         _version++;
483                 }
484                 
485                 public void Sort ()
486                 {
487                         Array.Sort<T> (_items, 0, _size, Comparer <T>.Default);
488                         _version++;
489                 }
490                 public void Sort (IComparer <T> comparer)
491                 {
492                         Array.Sort<T> (_items, 0, _size, comparer);
493                         _version++;
494                 }
495
496                 public void Sort (Comparison <T> comparison)
497                 {
498                         Array.Sort<T> (_items, _size, comparison);
499                         _version++;
500                 }
501                 
502                 public void Sort (int index, int count, IComparer <T> comparer)
503                 {
504                         CheckRange (index, count);
505                         Array.Sort<T> (_items, index, count, comparer);
506                         _version++;
507                 }
508
509                 public T [] ToArray ()
510                 {
511                         T [] t = new T [_size];
512                         Array.Copy (_items, t, _size);
513                         
514                         return t;
515                 }
516                 
517                 public void TrimExcess ()
518                 {
519                         Capacity = _size;
520                 }
521                 
522                 public bool TrueForAll (Predicate <T> match)
523                 {
524                         CheckMatch (match);
525
526                         foreach (T t in this)
527                                 if (!match (t))
528                                         return false;
529                                 
530                         return true;
531                 }
532                 
533                 public int Capacity {
534                         get { 
535                                 return _items.Length;
536                         }
537                         set {
538                                 if ((uint) value < (uint) _size)
539                                         throw new ArgumentOutOfRangeException ();
540                                 
541                                 Array.Resize (ref _items, value);
542                         }
543                 }
544                 
545                 public int Count {
546                         get { return _size; }
547                 }
548                 
549                 public T this [int index] {
550                         get {
551                                 if ((uint) index >= (uint) _size)
552                                         throw new ArgumentOutOfRangeException ("index");
553                                 return _items [index];
554                         }
555                         set {
556                                 CheckIndex (index);
557                                 if ((uint) index == (uint) _size)
558                                         throw new ArgumentOutOfRangeException ("index");
559                                 _items [index] = value;
560                         }
561                 }
562                 
563 #region Interface implementations.
564                 IEnumerator <T> IEnumerable <T>.GetEnumerator ()
565                 {
566                         return GetEnumerator ();
567                 }
568                 
569                 void ICollection.CopyTo (Array array, int arrayIndex)
570                 {
571                         Array.Copy (_items, 0, array, arrayIndex, _size);
572                 }
573                 
574                 IEnumerator IEnumerable.GetEnumerator ()
575                 {
576                         return GetEnumerator ();
577                 }
578                 
579                 int IList.Add (object item)
580                 {
581                         try {
582                                 Add ((T) item);
583                         } catch (InvalidCastException) {
584                                 throw new ArgumentException("item");
585                         }
586                         return _size - 1;
587                 }
588                 
589                 bool IList.Contains (object item)
590                 {
591                         try {
592                                 return Contains ((T) item);
593                         } catch (InvalidCastException) {
594                                 return false;
595                         }
596                 }
597                 
598                 int IList.IndexOf (object item)
599                 {
600                         try {
601                                 return IndexOf((T) item);
602                         } catch (InvalidCastException) {
603                                 return -1;
604                         }
605                 }
606                 
607                 void IList.Insert (int index, object item)
608                 {
609                         // We need to check this first because, even if the
610                         // item is null or not the correct type, we need to
611                         // return an ArgumentOutOfRange exception if the
612                         // index is out of range
613                         CheckIndex (index);
614                         try {
615                                 Insert (index, (T) item);
616                         } catch (InvalidCastException) {
617                                 throw new ArgumentException("item");
618                         }
619                 }
620                 
621                 void IList.Remove (object item)
622                 {
623                         try {
624                                 Remove ((T) item);
625                         } catch (InvalidCastException) {
626                                 // Swallow the exception--if we
627                                 // can't cast to the correct type
628                                 // then we've already "succeeded"
629                                 // in removing the item from the
630                                 // List.
631                         }
632                 }
633                 
634                 bool ICollection <T>.IsReadOnly {
635                         get { return false; }
636                 }
637                 bool ICollection.IsSynchronized {
638                         get { return false; }
639                 }
640                 
641                 object ICollection.SyncRoot {
642                         get { return this; }
643                 }
644                 bool IList.IsFixedSize {
645                         get { return false; }
646                 }
647                 
648                 bool IList.IsReadOnly {
649                         get { return false; }
650                 }
651                 
652                 object IList.this [int index] {
653                         get { return this [index]; }
654                         set { this [index] = (T) value; }
655                 }
656 #endregion
657                                 
658                 [Serializable]
659                 public struct Enumerator : IEnumerator <T>, IDisposable {
660                         const int NOT_STARTED = -2;
661                         
662                         // this MUST be -1, because we depend on it in move next.
663                         // we just decr the size, so, 0 - 1 == FINISHED
664                         const int FINISHED = -1;
665                         
666                         List <T> l;
667                         int idx;
668                         int ver;
669                         
670                         internal Enumerator (List <T> l)
671                         {
672                                 this.l = l;
673                                 idx = NOT_STARTED;
674                                 ver = l._version;
675                         }
676                         
677                         // for some fucked up reason, MSFT added a useless dispose to this class
678                         // It means that in foreach, we must still do a try/finally. Broken, very
679                         // broken.
680                         public void Dispose ()
681                         {
682                                 idx = NOT_STARTED;
683                         }
684                         
685                         public bool MoveNext ()
686                         {
687                                 if (ver != l._version)
688                                         throw new InvalidOperationException ("Collection was modified;"
689                                                 + "enumeration operation may not execute.");
690                                 
691                                 if (idx == NOT_STARTED)
692                                         idx = l._size;
693                                 
694                                 return idx != FINISHED && -- idx != FINISHED;
695                         }
696                         
697                         public T Current {
698                                 get {
699                                         if (idx < 0)
700                                                 throw new InvalidOperationException ();
701                                         
702                                         return l._items [l._size - 1 - idx];
703                                 }
704                         }
705                         
706                         void IEnumerator.Reset ()
707                         {
708                                 if (ver != l._version)
709                                         throw new InvalidOperationException ("Collection was modified;"
710                                                 + "enumeration operation may not execute.");
711                                 
712                                 idx = NOT_STARTED;
713                         }
714                         
715                         object IEnumerator.Current {
716                                 get { return Current; }
717                         }
718                 }
719         }
720 }
721 #endif