2 // System.Collections.ArrayList
\r
5 // Vladimir Vukicevic (vladimir@pobox.com)
\r
6 // Duncan Mak (duncan@ximian.com)
\r
8 // (C) 2001 Vladimir Vukicevic
\r
9 // (C) 2002 Ximian, Inc.
\r
14 namespace System.Collections {
\r
16 [MonoTODO ("add versioning, changing the arraylist should invalidate all enumerators")]
\r
18 public class ArrayList : IList, ICollection, IEnumerable, ICloneable {
\r
20 // Keep these three fields in sync with mono-reflection.h.
\r
21 private int count = 0;
\r
22 private int capacity = defaultCapacity;
\r
23 private object[] dataArray;
\r
26 public ArrayList () {
\r
27 dataArray = new object[capacity];
\r
30 public ArrayList (ICollection c) {
\r
32 throw new ArgumentNullException();
\r
34 //Emulate MS.NET behavior. Throw RankException when passed a
\r
35 // multi-dimensional Array.
\r
36 Array arr = c as Array;
\r
37 if (null != arr && arr.Rank > 1)
\r
38 throw new RankException ();
\r
40 this.capacity = (c.Count == 0) ? defaultCapacity : c.Count;
\r
41 dataArray = new object [capacity];
\r
42 foreach (object o in c)
\r
46 public ArrayList (int capacity) {
\r
48 throw new ArgumentOutOfRangeException ("capacity", capacity, "Value must be greater than or equal to zero.");
\r
51 this.capacity = capacity;
\r
52 // else if capacity == 0 then use defaultCapacity
\r
54 dataArray = new object[this.capacity];
\r
57 private ArrayList (object[] dataArray, int count, int capacity,
\r
58 bool fixedSize, bool readOnly, bool synchronized)
\r
60 this.dataArray = new object [capacity];
\r
61 dataArray.CopyTo (this.dataArray, 0);
\r
63 this.capacity = capacity;
\r
64 this.fixedSize = fixedSize;
\r
65 this.readOnly = readOnly;
\r
66 this.synchronized = synchronized;
\r
69 public static ArrayList ReadOnly (ArrayList list)
\r
72 throw new ArgumentNullException ();
\r
73 return new ArrayList (list.ToArray (), list.Count, list.Capacity,
\r
74 list.IsFixedSize, true, list.IsSynchronized);
\r
77 public static IList ReadOnly (IList list)
\r
80 throw new ArgumentNullException ();
\r
82 ArrayList al = new ArrayList ();
\r
84 foreach (object o in list)
\r
87 return (IList) ArrayList.ReadOnly (al);
\r
90 public static ArrayList Synchronized (ArrayList list)
\r
93 throw new ArgumentNullException ();
\r
95 return new ArrayList (list.ToArray (), list.Count, list.Capacity,
\r
96 list.IsFixedSize, list.IsReadOnly, true);
\r
99 public static IList Synchronized (IList list)
\r
102 throw new ArgumentNullException ();
\r
104 ArrayList al = new ArrayList ();
\r
106 foreach (object o in list)
\r
109 return (IList) ArrayList.Synchronized (al);
\r
112 public static ArrayList FixedSize (ArrayList list)
\r
115 throw new ArgumentNullException ();
\r
117 return new ArrayList (list.ToArray (), list.Count, list.Capacity,
\r
118 true, list.IsReadOnly, list.IsSynchronized);
\r
121 public static IList FixedSize (IList list)
\r
124 throw new ArgumentNullException ();
\r
126 ArrayList al = new ArrayList ();
\r
128 foreach (object o in list)
\r
131 return (IList) ArrayList.FixedSize (al);
\r
134 public static ArrayList Repeat (object value, int count)
\r
136 ArrayList al = new ArrayList (count);
\r
137 for (int i = 0; i < count; i++) {
\r
138 al.dataArray[i] = value;
\r
146 private class ListWrapper : ArrayList
\r
150 public ListWrapper (IList list)
\r
153 throw new ArgumentNullException();
\r
156 count = ((ICollection) list).Count;
\r
161 public override int Capacity {
\r
162 get { return list.Count; }
\r
163 set { throw new NotSupportedException (); }
\r
167 public override void AddRange (ICollection collection)
\r
169 if (collection == null)
\r
170 throw new ArgumentNullException ("colllection");
\r
171 if (IsFixedSize || IsReadOnly)
\r
172 throw new NotSupportedException ();
\r
176 public override int BinarySearch (object value)
\r
178 throw new NotImplementedException ();
\r
182 public override int BinarySearch (object value, IComparer comparer)
\r
184 throw new NotImplementedException ();
\r
188 public override int BinarySearch (int index, int count, object value,
\r
189 IComparer comparer)
\r
191 throw new NotImplementedException ();
\r
194 public override void CopyTo (Array array)
\r
197 throw new ArgumentNullException("array");
\r
198 if (array.Rank > 1)
\r
199 throw new ArgumentException("array cannot be multidimensional");
\r
205 public override void CopyTo (int index, Array array,
\r
206 int arrayIndex, int count)
\r
209 throw new ArgumentNullException ();
\r
210 if (index < 0 || arrayIndex < 0 || count < 0)
\r
211 throw new ArgumentOutOfRangeException ();
\r
212 if (array.Rank > 1 || index >= Count || Count > (array.Length - arrayIndex))
\r
213 throw new ArgumentException ();
\r
214 // FIXME: handle casting error here
\r
217 public override ArrayList GetRange (int index, int count)
\r
219 if (index < 0 || count < 0)
\r
220 throw new ArgumentOutOfRangeException ();
\r
221 if (Count < (index + count))
\r
222 throw new ArgumentException ();
\r
224 ArrayList result = new ArrayList (count);
\r
226 for (int i = 0; i < count; i++)
\r
227 result.Add (list [i]);
\r
233 public override void InsertRange (int index, ICollection col)
\r
236 throw new ArgumentNullException ();
\r
237 if (index < 0 || index > Count)
\r
238 throw new ArgumentOutOfRangeException ();
\r
239 if (IsReadOnly || IsFixedSize)
\r
240 throw new NotSupportedException ();
\r
242 if (index == Count) {
\r
243 foreach (object element in col)
\r
244 list.Add (element);
\r
246 } //else if ((index + count) < Count) {
\r
247 // for (int i = index; i < (index + count); i++)
\r
248 // list [i] = col [i];
\r
251 // int added = Count - (index + count);
\r
252 // for (int i = index; i < Count; i++)
\r
253 // list [i] = col [i];
\r
254 // for (int i = 0; i < added; i++)
\r
255 // list.Add (col [Count +i]);
\r
259 public override int LastIndexOf (object value)
\r
261 return LastIndexOf (value, Count, 0);
\r
264 public override int LastIndexOf (object value, int startIndex)
\r
266 return LastIndexOf (value, startIndex, 0);
\r
269 public override int LastIndexOf (object value, int startIndex, int count)
\r
271 if (null == value){
\r
275 if (startIndex > Count || count < 0 || (startIndex + count > Count))
\r
276 throw new ArgumentOutOfRangeException ();
\r
278 int length = startIndex - count + 1;
\r
280 for (int i = startIndex; i >= length; i--)
\r
281 if (list [i] == value)
\r
286 public override void RemoveRange (int index, int count)
\r
288 if ((index < 0) || (count < 0))
\r
289 throw new ArgumentOutOfRangeException ();
\r
290 if ((index > Count) || (index + count) > Count)
\r
291 throw new ArgumentException ();
\r
292 if (IsReadOnly || IsFixedSize)
\r
293 throw new NotSupportedException ();
\r
295 for (int i = 0; i < count; i++)
\r
296 list.RemoveAt (index);
\r
299 public override void Reverse ()
\r
301 Reverse (0, Count);
\r
304 public override void Reverse (int index, int count)
\r
306 if ((index < 0) || (count < 0))
\r
307 throw new ArgumentOutOfRangeException ();
\r
308 if ((index > Count) || (index + count) > Count)
\r
309 throw new ArgumentException ();
\r
311 throw new NotSupportedException ();
\r
315 for (int i = index; i < count; i++) {
\r
317 list [i] = list [count - i];
\r
318 list [count - i] = tmp;
\r
322 public override void SetRange (int index, ICollection col)
\r
324 if (index < 0 || (index + col.Count) > Count)
\r
325 throw new ArgumentOutOfRangeException ();
\r
327 throw new ArgumentNullException ();
\r
329 throw new NotSupportedException ();
\r
331 for (int i = index; i < col.Count; i++)
\r
332 foreach (object o in col)
\r
337 public override void Sort ()
\r
342 public override void Sort (IComparer comparer)
\r
347 public override void Sort (int index, int count, IComparer comparer)
\r
351 public override object [] ToArray ()
\r
353 return (object []) ToArray (typeof (object));
\r
356 public override Array ToArray (Type type)
\r
359 Array result = Array.CreateInstance (type, count);
\r
361 for (int i = 0; i < count; i++)
\r
362 result.SetValue (list [i], i);
\r
368 public override void TrimToSize ()
\r
373 public override bool IsFixedSize {
\r
374 get { return list.IsFixedSize; }
\r
377 public override bool IsReadOnly {
\r
378 get { return list.IsReadOnly; }
\r
381 public override object this [int index] {
\r
382 get { return list [index]; }
\r
383 set { list [index] = value; }
\r
386 public override int Add (object value)
\r
388 return list.Add (value);
\r
391 public override void Clear ()
\r
396 public override bool Contains (object value)
\r
398 return list.Contains (value);
\r
401 public override int IndexOf (object value)
\r
403 return list.IndexOf (value);
\r
406 public override void Insert (int index, object value)
\r
408 list.Insert (index, value);
\r
411 public override void Remove (object value)
\r
413 list.Remove (value);
\r
416 public override void RemoveAt (int index)
\r
418 list.RemoveAt (index);
\r
422 public override int Count {
\r
423 get { return count; }
\r
426 public override bool IsSynchronized {
\r
427 get { return ((ICollection) list).IsSynchronized; }
\r
430 public override object SyncRoot {
\r
431 get { return ((ICollection) list).SyncRoot; }
\r
434 public override void CopyTo (Array array, int index)
\r
436 ((ICollection) list).CopyTo (array, index);
\r
440 public override object Clone ()
\r
442 return new ListWrapper (list);
\r
446 public override IEnumerator GetEnumerator ()
\r
448 return ((IEnumerable) list).GetEnumerator ();
\r
453 public static ArrayList Adapter (IList list)
\r
455 return new ListWrapper (list);
\r
460 private bool fixedSize = false;
\r
461 private bool readOnly = false;
\r
462 private bool synchronized = false;
\r
464 private long version = 0;
\r
465 private ArrayList source = null;
\r
467 private const int defaultCapacity = 16;
\r
469 private void copyDataArray (object[] outArray) {
\r
470 for (int i = 0; i < count; i++) {
\r
471 outArray[i] = dataArray[i];
\r
475 private void setSize (int newSize) {
\r
476 if (newSize == capacity)
\r
479 capacity = (newSize == 0) ? defaultCapacity : newSize;
\r
481 // note that this assumes that we've already sanity-checked
\r
483 object[] newDataArray = new object[newSize];
\r
484 copyDataArray (newDataArray);
\r
485 dataArray = newDataArray;
\r
488 // note that this DOES NOT update count
\r
489 private void shiftElements (int startIndex, int numshift) {
\r
490 if (numshift == 0) {
\r
494 if (count + numshift > capacity) {
\r
495 setSize (capacity * 2);
\r
496 shiftElements (startIndex, numshift);
\r
498 if (numshift > 0) {
\r
499 int numelts = count - startIndex;
\r
500 for (int i = numelts-1; i >= 0; i--) {
\r
501 dataArray[startIndex + numshift + i] = dataArray[startIndex + i];
\r
504 for (int i = startIndex; i < startIndex + numshift; i++) {
\r
505 dataArray[i] = null;
\r
508 int numelts = count - startIndex + numshift;
\r
509 for (int i = 0; i < numelts; i++) {
\r
510 dataArray [i + startIndex] = dataArray [i + startIndex - numshift];
\r
512 for (int i = count + numshift; i < count; i++) {
\r
513 dataArray[i] = null;
\r
519 public virtual int Capacity {
\r
526 throw new NotSupportedException
\r
527 ("Collection is read-only.");
\r
530 if (value < count) {
\r
531 throw new ArgumentOutOfRangeException
\r
532 ("ArrayList Capacity being set to less than Count");
\r
535 if (fixedSize && value != capacity) {
\r
536 throw new NotSupportedException
\r
537 ("Collection is fixed size.");
\r
544 private void CheckSourceVersion() {
\r
545 if (null != this.source && this.version != this.source.version) {
\r
546 throw new InvalidOperationException();
\r
550 public virtual int Count {
\r
552 CheckSourceVersion();
\r
557 public virtual bool IsFixedSize {
\r
563 public virtual bool IsReadOnly {
\r
569 public virtual bool IsSynchronized {
\r
571 return synchronized;
\r
575 public virtual object this[int index] {
\r
577 CheckSourceVersion();
\r
580 throw new ArgumentOutOfRangeException ("index < 0");
\r
583 if (index >= count) {
\r
584 throw new ArgumentOutOfRangeException ("index out of range");
\r
587 return dataArray[index];
\r
591 throw new ArgumentOutOfRangeException ("index < 0");
\r
594 if (index >= count) {
\r
595 throw new ArgumentOutOfRangeException ("index out of range");
\r
599 throw new NotSupportedException ("Collection is read-only.");
\r
602 dataArray[index] = value;
\r
608 public virtual object SyncRoot {
\r
610 throw new NotImplementedException ("System.Collections.ArrayList.SyncRoot.get");
\r
617 public virtual int Add (object value) {
\r
619 throw new NotSupportedException ("ArrayList is read-only.");
\r
621 throw new NotSupportedException ("ArrayList is fixed size.");
\r
623 if (count + 1 >= capacity)
\r
624 setSize (capacity * 2);
\r
626 dataArray[count] = value;
\r
631 public virtual void AddRange (ICollection c) {
\r
633 throw new ArgumentNullException ("c");
\r
634 if (readOnly || fixedSize)
\r
635 throw new NotSupportedException ();
\r
638 if (count + cc >= capacity)
\r
639 Capacity = cc < count? count * 2: count + cc + 1;
\r
640 c.CopyTo (dataArray, count);
\r
645 public virtual int BinarySearch (object value) {
\r
646 return BinarySearch (0, count, value, null);
\r
649 public virtual int BinarySearch (object value, IComparer comparer) {
\r
650 return BinarySearch (0, count, value, comparer);
\r
653 public virtual int BinarySearch (int index, int count,
\r
654 object value, IComparer comparer) {
\r
655 return Array.BinarySearch (dataArray, index, count, value, comparer);
\r
658 public virtual void Clear () {
\r
659 if (readOnly || fixedSize)
\r
660 throw new NotSupportedException();
\r
666 public virtual object Clone () {
\r
667 return new ArrayList (dataArray, count, capacity,
\r
668 fixedSize, readOnly, synchronized);
\r
671 public virtual bool Contains (object item) {
\r
672 for (int i = 0; i < count; i++) {
\r
673 if (Object.Equals (dataArray[i], item)) {
\r
681 public virtual void CopyTo (Array array) {
\r
683 throw new ArgumentNullException("array");
\r
684 if (array.Rank > 1)
\r
685 throw new ArgumentException("array cannot be multidimensional");
\r
687 Array.Copy (dataArray, 0, array, 0, this.count);
\r
690 public virtual void CopyTo (Array array, int arrayIndex) {
\r
692 throw new ArgumentNullException("array");
\r
693 if (arrayIndex < 0)
\r
694 throw new ArgumentOutOfRangeException("arrayIndex");
\r
695 if (array.Rank > 1)
\r
696 throw new ArgumentException("array cannot be multidimensional");
\r
697 if (this.count > array.Length - arrayIndex)
\r
698 throw new ArgumentException("this ArrayList has more items than the space available in array from arrayIndex to the end of array");
\r
700 Array.Copy (dataArray, 0, array, arrayIndex, this.count);
\r
703 public virtual void CopyTo (int index, Array array,
\r
704 int arrayIndex, int count) {
\r
706 throw new ArgumentNullException("array");
\r
707 if (arrayIndex < 0)
\r
708 throw new ArgumentOutOfRangeException("arrayIndex");
\r
710 throw new ArgumentOutOfRangeException("index");
\r
712 throw new ArgumentOutOfRangeException("count");
\r
713 if (index >= this.count)
\r
714 throw new ArgumentException("index is greater than or equal to the source ArrayList.Count");
\r
715 if (array.Rank > 1)
\r
716 throw new ArgumentException("array cannot be multidimensional");
\r
717 if (arrayIndex >= array.Length)
\r
718 throw new ArgumentException("arrayIndex is greater than or equal to array's length");
\r
719 if (this.count > array.Length - arrayIndex)
\r
720 throw new ArgumentException("this ArrayList has more items than the space available in array from arrayIndex to the end of array");
\r
722 Array.Copy (dataArray, index, array, arrayIndex, count);
\r
726 private class ArrayListEnumerator : IEnumerator, ICloneable {
\r
727 private object[] data;
\r
731 private ArrayList enumeratee;
\r
732 private long version;
\r
734 internal ArrayListEnumerator(int index, int count, object[] items, ArrayList al, long ver) {
\r
743 public object Clone ()
\r
745 return new ArrayListEnumerator (start, num, data, enumeratee, version);
\r
748 public virtual object Current {
\r
753 public virtual bool MoveNext() {
\r
754 if (enumeratee.version != version)
\r
755 throw new InvalidOperationException();
\r
756 if (++idx < start + num)
\r
760 public virtual void Reset() {
\r
765 public virtual IEnumerator GetEnumerator () {
\r
766 return new ArrayListEnumerator(0, this.Count, dataArray, this, this.version);
\r
769 private void ValidateRange(int index, int count) {
\r
771 throw new ArgumentOutOfRangeException("index", index, "Must be equal to or greater than zero");
\r
774 throw new ArgumentOutOfRangeException("count", count, "Must be equal to or greater than zero");
\r
776 if (index > this.count - 1) {
\r
777 throw new ArgumentException();
\r
779 if (index + count > this.count - 1) {
\r
780 throw new ArgumentException();
\r
784 public virtual IEnumerator GetEnumerator (int index, int count) {
\r
785 ValidateRange(index, count);
\r
786 return new ArrayListEnumerator(index, count, dataArray, this, this.version);
\r
789 public virtual ArrayList GetRange (int index, int count) {
\r
790 ValidateRange(index, count);
\r
791 ArrayList retVal = new ArrayList(count);
\r
793 for (int i = index; i < count + index; i++) {
\r
794 retVal.Add(this[i]);
\r
796 retVal.version = this.version;
\r
797 retVal.source = this;
\r
801 public virtual int IndexOf (object value) {
\r
802 return IndexOf (value, 0, count);
\r
805 public virtual int IndexOf (object value, int startIndex) {
\r
806 return IndexOf (value, startIndex, count - startIndex);
\r
809 public virtual int IndexOf (object value, int startIndex, int count) {
\r
810 if (startIndex < 0 || startIndex + count > this.count || count < 0) {
\r
811 throw new ArgumentOutOfRangeException ("IndexOf arguments out of range");
\r
813 for (int i = startIndex; i < (startIndex + count); i++) {
\r
814 if (Object.Equals (dataArray[i], value)) {
\r
822 public virtual void Insert (int index, object value) {
\r
824 throw new NotSupportedException
\r
825 ("Collection is read-only.");
\r
829 throw new NotSupportedException
\r
830 ("Collection is fixed size.");
\r
833 if (index < 0 || index >= capacity) {
\r
834 throw new ArgumentOutOfRangeException ("index < 0 or index >= capacity");
\r
837 shiftElements (index, 1);
\r
838 dataArray[index] = value;
\r
843 public virtual void InsertRange (int index, ICollection c) {
\r
846 throw new ArgumentNullException ();
\r
848 if (index < 0 || index > count)
\r
849 throw new ArgumentOutOfRangeException ();
\r
851 if (IsReadOnly || IsFixedSize)
\r
852 throw new NotSupportedException ();
\r
854 // Get a copy of the collection before the shift in case the collection
\r
855 // is this. Otherwise the enumerator will be confused.
\r
856 Array source = Array.CreateInstance(typeof(object), c.Count);
\r
857 c.CopyTo(source, 0);
\r
859 shiftElements (index, c.Count);
\r
862 foreach (object o in source)
\r
863 dataArray[index++] = o;
\r
868 public virtual int LastIndexOf (object value) {
\r
869 return LastIndexOf (value, count - 1, count);
\r
872 public virtual int LastIndexOf (object value, int startIndex) {
\r
873 if (startIndex < 0 || startIndex > count - 1) {
\r
874 throw new ArgumentOutOfRangeException("startIndex", startIndex, "");
\r
876 return LastIndexOf (value, startIndex, startIndex + 1);
\r
879 public virtual int LastIndexOf (object value, int startIndex,
\r
882 if (null == value){
\r
885 if (startIndex >= this.count)
\r
886 throw new ArgumentOutOfRangeException ("startIndex >= Count");
\r
888 throw new ArgumentOutOfRangeException ("count < 0");
\r
889 if (startIndex + 1 < count)
\r
890 throw new ArgumentOutOfRangeException ("startIndex + 1 < count");
\r
892 int EndIndex = startIndex - count + 1;
\r
893 for (int i = startIndex; i >= EndIndex; i--) {
\r
894 if (Object.Equals (dataArray[i], value)) {
\r
902 public virtual void Remove (object obj) {
\r
904 if (IsFixedSize || IsReadOnly)
\r
905 throw new NotSupportedException ();
\r
907 int objIndex = IndexOf (obj);
\r
909 if (objIndex == -1) {
\r
910 // shouldn't an exception be thrown here??
\r
911 // the MS docs don't indicate one, and testing
\r
912 // with the MS .net framework doesn't indicate one
\r
916 RemoveRange (objIndex, 1);
\r
919 public virtual void RemoveAt (int index) {
\r
920 RemoveRange (index, 1);
\r
923 public virtual void RemoveRange (int index, int count) {
\r
925 throw new NotSupportedException
\r
926 ("Collection is read-only.");
\r
930 throw new NotSupportedException
\r
931 ("Collection is fixed size.");
\r
934 if (index < 0 || index >= this.count || index + count > this.count) {
\r
935 throw new ArgumentOutOfRangeException
\r
936 ("index/count out of range");
\r
939 shiftElements (index, - count);
\r
940 this.count -= count;
\r
944 public virtual void Reverse () {
\r
945 Reverse (0, count);
\r
948 public virtual void Reverse (int index, int count) {
\r
950 throw new NotSupportedException
\r
951 ("Collection is read-only.");
\r
954 if (index < 0 || index + count > this.count) {
\r
955 throw new ArgumentOutOfRangeException
\r
956 ("index/count out of range");
\r
959 Array.Reverse (dataArray, index, count);
\r
963 public virtual void SetRange (int index, ICollection c)
\r
966 throw new ArgumentNullException ();
\r
968 throw new NotSupportedException ();
\r
969 if (index < 0 || (index + c.Count) > count)
\r
970 throw new ArgumentOutOfRangeException ();
\r
972 c.CopyTo(dataArray, index);
\r
975 public virtual void Sort () {
\r
976 Sort (0, count, null);
\r
979 public virtual void Sort (IComparer comparer) {
\r
980 Sort (0, count, comparer);
\r
983 public virtual void Sort (int index, int count, IComparer comparer) {
\r
985 throw new NotSupportedException
\r
986 ("Collection is read-only.");
\r
989 if (index < 0 || index + count > this.count) {
\r
990 throw new ArgumentOutOfRangeException
\r
991 ("index/count out of range");
\r
994 Array.Sort (dataArray, index, count, comparer);
\r
998 public virtual object[] ToArray() {
\r
999 object[] outArray = new object[count];
\r
1000 Array.Copy (dataArray, outArray, count);
\r
1004 public virtual Array ToArray (Type type) {
\r
1005 Array outArray = Array.CreateInstance (type, count);
\r
1006 Array.Copy (dataArray, outArray, count);
\r
1010 public virtual void TrimToSize () {
\r
1012 if (IsReadOnly || IsFixedSize)
\r
1013 throw new NotSupportedException ();
\r