5 // Joe Shaw (joe@ximian.com)
6 // Martin Baulig (martin@gnome.org)
7 // Dietmar Maurer (dietmar@ximian.com)
9 // (C) 2001 Ximian, Inc. http://www.ximian.com
12 using System.Collections;
13 using System.Runtime.CompilerServices;
19 public abstract class Array : ICloneable, ICollection, IList, IEnumerable
32 int length = this.GetLength (0);
34 for (int i = 1; i < this.Rank; i++) {
35 length *= this.GetLength (i);
46 return this.GetRank ();
51 object IList.this [int index] {
53 return GetValueImpl (index);
56 SetValueImpl (value, index);
60 int IList.Add (object value) {
61 throw new NotSupportedException ();
65 Array.Clear (this, this.GetLowerBound(0), this.Length);
68 bool IList.Contains (object value) {
70 throw new RankException ("Only single dimension arrays are supported.");
72 int length = this.Length;
73 for (int i = 0; i < length; i++) {
74 if (value.Equals (this.GetValueImpl (i)))
80 int IList.IndexOf (object value) {
82 throw new RankException ();
84 int length = this.Length;
85 for (int i = 0; i < length; i++) {
86 if (value.Equals (this.GetValueImpl (i)))
87 // array index may not be zero-based.
89 return i + this.GetLowerBound (0);
94 // lower bound may be MinValue
95 retVal = this.GetLowerBound (0) - 1;
101 void IList.Insert (int index, object value) {
102 throw new NotSupportedException ();
105 void IList.Remove (object value) {
106 throw new NotSupportedException ();
109 void IList.RemoveAt (int index) {
110 throw new NotSupportedException ();
113 // InternalCall Methods
115 [MethodImplAttribute(MethodImplOptions.InternalCall)]
116 private extern int GetRank ();
118 [MethodImplAttribute(MethodImplOptions.InternalCall)]
119 public extern int GetLength (int dimension);
121 [MethodImplAttribute(MethodImplOptions.InternalCall)]
122 public extern int GetLowerBound (int dimension);
124 [MethodImplAttribute(MethodImplOptions.InternalCall)]
125 public extern object GetValue (int[] idxs);
127 [MethodImplAttribute(MethodImplOptions.InternalCall)]
128 public extern void SetValue (object value, int[] idxs);
130 [MethodImplAttribute(MethodImplOptions.InternalCall)]
131 internal extern object GetValueImpl (int pos);
133 [MethodImplAttribute(MethodImplOptions.InternalCall)]
134 internal extern void SetValueImpl (object value, int pos);
136 [MethodImplAttribute(MethodImplOptions.InternalCall)]
137 internal extern static void FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
\r
139 [MethodImplAttribute(MethodImplOptions.InternalCall)]
\r
140 internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
143 int ICollection.Count {
150 public virtual bool IsSynchronized {
158 public virtual object SyncRoot {
165 public virtual bool IsFixedSize
172 public virtual bool IsReadOnly
179 public virtual IEnumerator GetEnumerator ()
181 return new SimpleEnumerator(this);
184 public int GetUpperBound (int dimension)
186 return GetLowerBound (dimension) +
187 GetLength (dimension) - 1;
190 public object GetValue (int idx)
192 int[] ind = new int [1];
196 return GetValue (ind);
199 public object GetValue (int idx1, int idx2)
201 int[] ind = new int [2];
206 return GetValue (ind);
209 public object GetValue (int idx1, int idx2, int idx3)
211 int[] ind = new int [3];
217 return GetValue (ind);
220 // This function is currently unused, but just in case we need it later on ... */
221 internal int IndexToPos (int[] idxs)
224 throw new ArgumentNullException ();
226 if ((idxs.Rank != 1) || (idxs.Length != Rank))
227 throw new ArgumentException ();
229 if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
230 throw new IndexOutOfRangeException();
232 int pos = idxs [0] - GetLowerBound (0);
233 for (int i = 1; i < Rank; i++) {
234 if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
235 throw new IndexOutOfRangeException();
237 pos *= GetLength (i);
238 pos += idxs [i] - GetLowerBound (i);
244 public void SetValue (object value, int idx)
246 int[] ind = new int [1];
250 SetValue (value, ind);
253 public void SetValue (object value, int idx1, int idx2)
255 int[] ind = new int [2];
260 SetValue (value, ind);
263 public void SetValue (object value, int idx1, int idx2, int idx3)
265 int[] ind = new int [3];
271 SetValue (value, ind);
274 public static Array CreateInstance(Type elementType, int length)
276 int[] lengths = new int [1];
279 lengths [0] = length;
281 return CreateInstanceImpl (elementType, lengths, bounds);
284 public static Array CreateInstance(Type elementType, int l1, int l2)
286 int[] lengths = new int [2];
292 return CreateInstanceImpl (elementType, lengths, bounds);
295 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
297 int[] lengths = new int [3];
304 return CreateInstanceImpl (elementType, lengths, bounds);
307 public static Array CreateInstance(Type elementType, int[] lengths)
311 return CreateInstanceImpl (elementType, lengths, bounds);
314 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
317 throw new ArgumentNullException("bounds");
319 return CreateInstanceImpl (elementType, lengths, bounds);
323 public static int BinarySearch (Array array, object value)
326 throw new ArgumentNullException("array");
329 throw new RankException();
331 if (!(value is IComparable))
332 throw new ArgumentException("value does not support IComparable");
334 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
338 public static int BinarySearch (Array array, object value, IComparer comparer)
341 throw new ArgumentNullException("array");
344 throw new RankException();
346 if ((comparer == null) && !(value is IComparable))
347 throw new ArgumentException("comparer is null and value does not support IComparable");
349 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
353 public static int BinarySearch (Array array, int index, int length, object value)
356 throw new ArgumentNullException("array");
359 throw new RankException();
361 if (index < array.GetLowerBound (0))
362 throw new ArgumentOutOfRangeException("index is less than the lower bound of array.");
364 throw new ArgumentOutOfRangeException("length is less than zero.");
366 if (index + length > array.GetLowerBound (0) + array.GetLength (0))
367 throw new ArgumentException("index and length do not specify a valid range in array.");
368 if (!(value is IComparable))
369 throw new ArgumentException("value does not support IComparable");
371 return BinarySearch (array, index, length, value, null);
374 public static int BinarySearch (Array array, int index,
375 int length, object value,
379 throw new ArgumentNullException ("array");
382 throw new RankException ();
384 if (index < array.GetLowerBound (0))
385 throw new ArgumentOutOfRangeException("index is less than the lower bound of array.");
387 throw new ArgumentOutOfRangeException("length is less than zero.");
389 if (index + length > array.GetLowerBound (0) + array.GetLength (0))
390 throw new ArgumentException("index and length do not specify a valid range in array.");
392 if ((comparer == null) && !(value is IComparable))
393 throw new ArgumentException("comparer is null and value does not support IComparable");
395 // cache this in case we need it
396 IComparable valueCompare = value as IComparable;
399 int iMax = index + length;
403 // there's a subtle balance here between
404 // 1) the while condition
405 // 2) the rounding down of the '/ 2'
406 // 3) the asymetrical recursion
407 // 4) the fact that iMax starts beyond the end of the array
410 int iMid = (iMin + iMax) / 2;
411 object elt = array.GetValueImpl (iMid);
413 // this order is from MSDN
414 if (comparer != null)
415 iCmp = comparer.Compare (value, elt);
418 IComparable eltCompare = elt as IComparable;
419 if (eltCompare != null)
420 iCmp = -eltCompare.CompareTo (value);
422 iCmp = valueCompare.CompareTo (elt);
430 iMin = iMid + 1; // compensate for the rounding down
433 catch (InvalidCastException e)
435 throw new ArgumentException ("array", e);
444 public static void Clear (Array array, int index, int length)
447 throw new ArgumentNullException ();
450 throw new RankException ();
452 if (index < array.GetLowerBound (0) || length < 0 ||
453 index + length > array.GetUpperBound (0) + 1)
454 throw new ArgumentOutOfRangeException ();
456 for (int i = 0; i < length; i++)
458 array.SetValueImpl(null, index + i);
462 [MethodImplAttribute(MethodImplOptions.InternalCall)]
463 public virtual extern object Clone ();
465 public static void Copy (Array source, Array dest, int length)
467 // need these checks here because we are going to use
468 // GetLowerBound() on source and dest.
470 throw new ArgumentNullException ("null");
473 throw new ArgumentNullException ("dest");
475 Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);
478 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
481 throw new ArgumentNullException ("null");
484 throw new ArgumentNullException ("dest");
487 throw new ArgumentOutOfRangeException ("length");
490 throw new ArgumentException ("source_idx");
493 throw new ArgumentException ("dest_idx");
495 int source_pos = source_idx - source.GetLowerBound (0);
496 int dest_pos = dest_idx - dest.GetLowerBound (0);
499 if (source_pos + length > source.Length || dest_pos + length > dest.Length)
500 throw new ArgumentException ("length");
502 if (source.Rank != dest.Rank)
503 throw new RankException ();
505 Type src_type = source.GetType ().GetElementType ();
506 Type dst_type = dest.GetType ().GetElementType ();
508 if (src_type == dst_type) {
509 FastCopy (source, source_pos, dest, dest_pos, length);
513 if (!Object.ReferenceEquals (source, dest) || source_pos > dest_pos)
515 for (int i = 0; i < length; i++)
517 Object srcval = source.GetValueImpl (source_pos + i);
520 dest.SetValueImpl (srcval, dest_pos + i);
522 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
523 (src_type.Equals (typeof (Object))))
524 throw new InvalidCastException ();
526 throw new ArrayTypeMismatchException (
527 String.Format ("(Types: source={0}; target={1})", src_type.FullName, dst_type.FullName));
533 for (int i = length - 1; i >= 0; i--)
535 Object srcval = source.GetValueImpl (source_pos + i);
538 dest.SetValueImpl (srcval, dest_pos + i);
540 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
541 (src_type.Equals (typeof (Object))))
542 throw new InvalidCastException ();
544 throw new ArrayTypeMismatchException (
545 String.Format ("(Types: source={0}; target={1})", src_type.FullName, dst_type.FullName));
551 public static int IndexOf (Array array, object value)
554 throw new ArgumentNullException ();
556 return IndexOf (array, value, 0, array.Length);
559 public static int IndexOf (Array array, object value, int index)
562 throw new ArgumentNullException ();
564 return IndexOf (array, value, index, array.Length - index);
567 public static int IndexOf (Array array, object value, int index, int length)
570 throw new ArgumentNullException ();
573 throw new RankException ();
575 if (length < 0 || index < array.GetLowerBound (0) ||
576 index+length-1 > array.GetUpperBound (0))
577 throw new ArgumentOutOfRangeException ();
579 for (int i = 0; i < length; i++)
581 if (array.GetValueImpl(index + i).Equals(value))
585 return array.GetLowerBound (0) - 1;
588 public static int LastIndexOf (Array array, object value)
591 throw new ArgumentNullException ();
593 return LastIndexOf (array, value, array.Length-1);
596 public static int LastIndexOf (Array array, object value, int index)
599 throw new ArgumentNullException ();
601 return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
604 public static int LastIndexOf (Array array, object value, int index, int length)
607 throw new ArgumentNullException ();
610 throw new RankException ();
612 if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
613 index > array.GetUpperBound (0))
614 throw new ArgumentOutOfRangeException ();
616 for (int i = index; i >= index-length+1; i--)
618 if (array.GetValueImpl(i).Equals(value))
622 return array.GetLowerBound (0) - 1;
625 public static void Reverse (Array array)
628 throw new ArgumentNullException ();
630 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
633 public static void Reverse (Array array, int index, int length)
636 throw new ArgumentNullException ();
639 throw new RankException ();
641 if (index < array.GetLowerBound (0) || length < 0)
642 throw new ArgumentOutOfRangeException ();
644 if (index + length > array.GetUpperBound (0) + 1)
645 throw new ArgumentException ();
647 for (int i = 0; i < length/2; i++)
651 tmp = array.GetValueImpl (index + i);
652 array.SetValueImpl(array.GetValueImpl (index + length - i - 1), index + i);
653 array.SetValueImpl(tmp, index + length - i - 1);
657 public static void Sort (Array array)
660 throw new ArgumentNullException ();
662 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
665 public static void Sort (Array keys, Array items)
668 throw new ArgumentNullException ();
670 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
673 public static void Sort (Array array, IComparer comparer)
676 throw new ArgumentNullException ();
678 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
681 public static void Sort (Array array, int index, int length)
683 Sort (array, null, index, length, null);
686 public static void Sort (Array keys, Array items, IComparer comparer)
689 throw new ArgumentNullException ();
691 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
694 public static void Sort (Array keys, Array items, int index, int length)
696 Sort (keys, items, index, length, null);
699 public static void Sort (Array array, int index, int length, IComparer comparer)
701 Sort (array, null, index, length, comparer);
704 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
707 int high0 = index + length - 1;
709 qsort (keys, items, index, index + length - 1, comparer);
712 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
715 throw new ArgumentNullException ();
717 if (keys.Rank > 1 || (items != null && items.Rank > 1))
718 throw new RankException ();
726 object objPivot = keys.GetValueImpl ((low + high) / 2);
731 while (low < high0 && compare (keys.GetValueImpl (low), objPivot, comparer) < 0)
733 while (high > low0 && compare (objPivot, keys.GetValueImpl (high), comparer) < 0)
738 swap (keys, items, low, high);
745 qsort (keys, items, low0, high, comparer);
747 qsort (keys, items, low, high0, comparer);
750 private static void swap (Array keys, Array items, int i, int j)
754 tmp = keys.GetValueImpl (i);
755 keys.SetValueImpl (keys.GetValue (j), i);
756 keys.SetValueImpl (tmp, j);
760 tmp = items.GetValueImpl (i);
761 items.SetValueImpl (items.GetValueImpl (j), i);
762 items.SetValueImpl (tmp, j);
766 private static int compare (object value1, object value2, IComparer comparer)
768 if (comparer == null)
769 return ((IComparable) value1).CompareTo(value2);
771 return comparer.Compare(value1, value2);
774 public virtual void CopyTo (Array array, int index)
777 throw new ArgumentNullException ();
779 // The order of these exception checks may look strange,
780 // but that's how the microsoft runtime does it.
782 throw new RankException ();
783 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
784 throw new ArgumentException ();
786 throw new RankException ();
788 throw new ArgumentOutOfRangeException ();
790 Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));
793 internal class SimpleEnumerator : IEnumerator {
798 public SimpleEnumerator (Array arrayToEnumerate) {
799 this.enumeratee = arrayToEnumerate;
800 this.currentpos = -1;
801 this.length = arrayToEnumerate.Length;
804 public object Current {
806 // Exception messages based on MS implementation
807 if (currentpos < 0 ) {
808 throw new InvalidOperationException
809 ("Enumeration has not started");
811 if (currentpos >= length) {
812 throw new InvalidOperationException
813 ("Enumeration has already ended");
815 // Current should not increase the position. So no ++ over here.
816 return enumeratee.GetValueImpl(currentpos);
820 public bool MoveNext() {
821 //The docs say Current should throw an exception if last
822 //call to MoveNext returned false. This means currentpos
823 //should be set to length when returning false.
824 if (currentpos < length) {
827 if(currentpos < length)
833 public void Reset() {