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 public object 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) {
69 int length = this.Length;
70 for (int i = 0; i < length; i++) {
71 if (value.Equals (this.GetValueImpl (i)))
77 int IList.IndexOf (object value) {
79 throw new RankException ();
81 int length = this.Length;
82 for (int i = 0; i < length; i++) {
83 if (value.Equals (this.GetValueImpl (i)))
84 // array index may not be zero-based.
86 return i + this.GetLowerBound (0);
91 // lower bound may be MinValue
92 retVal = this.GetLowerBound (0) - 1;
98 void IList.Insert (int index, object value) {
99 throw new NotSupportedException ();
102 void IList.Remove (object value) {
103 throw new NotSupportedException ();
106 void IList.RemoveAt (int index) {
107 throw new NotSupportedException ();
110 // InternalCall Methods
112 [MethodImplAttribute(MethodImplOptions.InternalCall)]
113 private extern int GetRank ();
115 [MethodImplAttribute(MethodImplOptions.InternalCall)]
116 public extern int GetLength (int dimension);
118 [MethodImplAttribute(MethodImplOptions.InternalCall)]
119 public extern int GetLowerBound (int dimension);
121 [MethodImplAttribute(MethodImplOptions.InternalCall)]
122 public extern object GetValue (int[] idxs);
124 [MethodImplAttribute(MethodImplOptions.InternalCall)]
125 public extern void SetValue (object value, int[] idxs);
127 [MethodImplAttribute(MethodImplOptions.InternalCall)]
128 internal extern object GetValueImpl (int pos);
130 [MethodImplAttribute(MethodImplOptions.InternalCall)]
131 internal extern void SetValueImpl (object value, int pos);
133 [MethodImplAttribute(MethodImplOptions.InternalCall)]
134 internal extern static void FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
\r
136 [MethodImplAttribute(MethodImplOptions.InternalCall)]
\r
137 internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
140 public virtual int Count {
147 public virtual bool IsSynchronized {
155 public virtual object SyncRoot {
162 public virtual bool IsFixedSize
169 public virtual bool IsReadOnly
176 public virtual IEnumerator GetEnumerator ()
178 return new SimpleEnumerator(this);
181 public int GetUpperBound (int dimension)
183 return GetLowerBound (dimension) +
184 GetLength (dimension) - 1;
187 public object GetValue (int idx)
189 int[] ind = new int [1];
193 return GetValue (ind);
196 public object GetValue (int idx1, int idx2)
198 int[] ind = new int [2];
203 return GetValue (ind);
206 public object GetValue (int idx1, int idx2, int idx3)
208 int[] ind = new int [3];
214 return GetValue (ind);
217 // This function is currently unused, but just in case we need it later on ... */
218 internal int IndexToPos (int[] idxs)
221 throw new ArgumentNullException ();
223 if ((idxs.Rank != 1) || (idxs.Length != Rank))
224 throw new ArgumentException ();
226 if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
227 throw new IndexOutOfRangeException();
229 int pos = idxs [0] - GetLowerBound (0);
230 for (int i = 1; i < Rank; i++) {
231 if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
232 throw new IndexOutOfRangeException();
234 pos *= GetLength (i);
235 pos += idxs [i] - GetLowerBound (i);
241 public void SetValue (object value, int idx)
243 int[] ind = new int [1];
247 SetValue (value, ind);
250 public void SetValue (object value, int idx1, int idx2)
252 int[] ind = new int [2];
257 SetValue (value, ind);
260 public void SetValue (object value, int idx1, int idx2, int idx3)
262 int[] ind = new int [3];
268 SetValue (value, ind);
271 public static Array CreateInstance(Type elementType, int length)
273 int[] lengths = new int [1];
276 lengths [0] = length;
278 return CreateInstanceImpl (elementType, lengths, bounds);
281 public static Array CreateInstance(Type elementType, int l1, int l2)
283 int[] lengths = new int [2];
289 return CreateInstanceImpl (elementType, lengths, bounds);
292 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
294 int[] lengths = new int [3];
301 return CreateInstanceImpl (elementType, lengths, bounds);
304 public static Array CreateInstance(Type elementType, int[] lengths)
308 return CreateInstanceImpl (elementType, lengths, bounds);
311 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
314 throw new ArgumentNullException("bounds");
316 return CreateInstanceImpl (elementType, lengths, bounds);
320 public static int BinarySearch (Array array, object value)
322 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
326 public static int BinarySearch (Array array, object value, IComparer comparer)
328 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
332 public static int BinarySearch (Array array, int index, int length, object value)
334 return BinarySearch (array, index, length, value, null);
337 public static int BinarySearch (Array array, int index,
338 int length, object value,
342 throw new ArgumentNullException ("array");
345 throw new RankException ();
347 if (index < array.GetLowerBound (0) || length < 0)
348 throw new ArgumentOutOfRangeException ("index");
350 if (index + length > array.GetUpperBound (0) + 1)
351 throw new ArgumentException ("length");
353 // cache this in case we need it
354 IComparable valueCompare = value as IComparable;
357 int iMax = index + length;
361 // there's a subtle balance here between
362 // 1) the while condition
363 // 2) the rounding down of the '/ 2'
364 // 3) the asymetrical recursion
365 // 4) the fact that iMax starts beyond the end of the array
368 int iMid = (iMin + iMax) / 2;
369 object elt = array.GetValue (iMid);
371 // this order is from MSDN
372 if (comparer != null)
373 iCmp = comparer.Compare (value, elt);
376 IComparable eltCompare = elt as IComparable;
377 if (eltCompare != null)
378 iCmp = -eltCompare.CompareTo (value);
380 iCmp = valueCompare.CompareTo (elt);
388 iMin = iMid + 1; // compensate for the rounding down
391 catch (InvalidCastException e)
393 throw new ArgumentException ("array", e);
402 public static void Clear (Array array, int index, int length)
405 throw new ArgumentNullException ();
408 throw new RankException ();
410 if (index < array.GetLowerBound (0) || length < 0 ||
411 index + length > array.GetUpperBound (0) + 1)
412 throw new ArgumentOutOfRangeException ();
414 for (int i = 0; i < length; i++)
416 array.SetValue(null, index + i);
420 [MethodImplAttribute(MethodImplOptions.InternalCall)]
421 public virtual extern object Clone ();
423 public static void Copy (Array source, Array dest, int length)
425 Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);
428 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
431 throw new ArgumentNullException ("null");
434 throw new ArgumentNullException ("dest");
437 throw new ArgumentOutOfRangeException ("length");
440 throw new ArgumentException ("source_idx");
443 throw new ArgumentException ("dest_idx");
445 int source_pos = source_idx - source.GetLowerBound (0);
446 int dest_pos = dest_idx - dest.GetLowerBound (0);
449 if (source_pos + length > source.Length || dest_pos + length > dest.Length)
450 throw new ArgumentException ("length");
452 if (source.Rank != dest.Rank)
453 throw new RankException ();
455 Type src_type = source.GetType ().GetElementType ();
456 Type dst_type = dest.GetType ().GetElementType ();
458 if (src_type == dst_type) {
459 FastCopy (source, source_pos, dest, dest_pos, length);
463 if (!Object.ReferenceEquals (source, dest) || source_pos > dest_pos)
465 for (int i = 0; i < length; i++)
467 Object srcval = source.GetValueImpl (source_pos + i);
470 dest.SetValueImpl (srcval, dest_pos + i);
472 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
473 (src_type.Equals (typeof (Object))))
474 throw new InvalidCastException ();
476 throw new ArrayTypeMismatchException (
477 String.Format ("(Types: source={0}; target={1})", src_type.FullName, dst_type.FullName));
483 for (int i = length - 1; i >= 0; i--)
485 Object srcval = source.GetValueImpl (source_pos + i);
488 dest.SetValueImpl (srcval, dest_pos + i);
490 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
491 (src_type.Equals (typeof (Object))))
492 throw new InvalidCastException ();
494 throw new ArrayTypeMismatchException (
495 String.Format ("(Types: source={0}; target={1})", src_type.FullName, dst_type.FullName));
501 public static int IndexOf (Array array, object value)
504 throw new ArgumentNullException ();
506 return IndexOf (array, value, 0, array.Length);
509 public static int IndexOf (Array array, object value, int index)
512 throw new ArgumentNullException ();
514 return IndexOf (array, value, index, array.Length - index);
517 public static int IndexOf (Array array, object value, int index, int length)
520 throw new ArgumentNullException ();
523 throw new RankException ();
525 if (length < 0 || index < array.GetLowerBound (0) ||
526 index+length-1 > array.GetUpperBound (0))
527 throw new ArgumentOutOfRangeException ();
529 for (int i = 0; i < length; i++)
531 if (array.GetValue(index + i).Equals(value))
535 return array.GetLowerBound (0) - 1;
538 public static int LastIndexOf (Array array, object value)
541 throw new ArgumentNullException ();
543 return LastIndexOf (array, value, array.Length-1);
546 public static int LastIndexOf (Array array, object value, int index)
549 throw new ArgumentNullException ();
551 return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
554 public static int LastIndexOf (Array array, object value, int index, int length)
557 throw new ArgumentNullException ();
560 throw new RankException ();
562 if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
563 index > array.GetUpperBound (0))
564 throw new ArgumentOutOfRangeException ();
566 for (int i = index; i >= index-length+1; i--)
568 if (array.GetValue(i).Equals(value))
572 return array.GetLowerBound (0) - 1;
575 public static void Reverse (Array array)
578 throw new ArgumentNullException ();
580 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
583 public static void Reverse (Array array, int index, int length)
586 throw new ArgumentNullException ();
589 throw new RankException ();
591 if (index < array.GetLowerBound (0) || length < 0)
592 throw new ArgumentOutOfRangeException ();
594 if (index + length > array.GetUpperBound (0) + 1)
595 throw new ArgumentException ();
597 for (int i = 0; i < length/2; i++)
601 tmp = array.GetValue (index + i);
602 array.SetValue(array.GetValue (index + length - i - 1), index + i);
603 array.SetValue(tmp, index + length - i - 1);
607 public static void Sort (Array array)
610 throw new ArgumentNullException ();
612 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
615 public static void Sort (Array keys, Array items)
618 throw new ArgumentNullException ();
620 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
623 public static void Sort (Array array, IComparer comparer)
626 throw new ArgumentNullException ();
628 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
631 public static void Sort (Array array, int index, int length)
633 Sort (array, null, index, length, null);
636 public static void Sort (Array keys, Array items, IComparer comparer)
639 throw new ArgumentNullException ();
641 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
644 public static void Sort (Array keys, Array items, int index, int length)
646 Sort (keys, items, index, length, null);
649 public static void Sort (Array array, int index, int length, IComparer comparer)
651 Sort (array, null, index, length, comparer);
654 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
657 int high0 = index + length - 1;
659 qsort (keys, items, index, index + length - 1, comparer);
662 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
669 throw new ArgumentNullException ();
671 if (keys.Rank > 1 || (items != null && items.Rank > 1))
672 throw new RankException ();
677 pivot = (low + high) / 2;
679 if (compare (keys.GetValue (low), keys.GetValue (pivot), comparer) > 0)
680 swap (keys, items, low, pivot);
682 if (compare (keys.GetValue (pivot), keys.GetValue (high), comparer) > 0)
683 swap (keys, items, pivot, high);
688 while (low < high && compare (keys.GetValue (low), keys.GetValue (pivot), comparer) < 0)
690 while (low < high && compare (keys.GetValue (pivot), keys.GetValue (high), comparer) < 0)
695 swap (keys, items, low, high);
701 qsort (keys, items, low0, low - 1, comparer);
702 qsort (keys, items, high + 1, high0, comparer);
705 private static void swap (Array keys, Array items, int i, int j)
709 tmp = keys.GetValue (i);
710 keys.SetValue (keys.GetValue (j), i);
711 keys.SetValue (tmp, j);
715 tmp = items.GetValue (i);
716 items.SetValue (items.GetValue (j), i);
717 items.SetValue (tmp, j);
721 private static int compare (object value1, object value2, IComparer comparer)
723 if (comparer == null)
724 return ((IComparable) value1).CompareTo(value2);
726 return comparer.Compare(value1, value2);
729 public virtual void CopyTo (Array array, int index)
732 throw new ArgumentNullException ();
734 // The order of these exception checks may look strange,
735 // but that's how the microsoft runtime does it.
737 throw new RankException ();
738 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
739 throw new ArgumentException ();
741 throw new RankException ();
743 throw new ArgumentOutOfRangeException ();
745 Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));
748 internal class SimpleEnumerator : IEnumerator {
753 public SimpleEnumerator (Array arrayToEnumerate) {
754 this.enumeratee = arrayToEnumerate;
755 this.currentpos = -1;
756 this.length = arrayToEnumerate.Length;
759 public object Current {
761 // Exception messages based on MS implementation
762 if (currentpos < 0 ) {
763 throw new InvalidOperationException
764 ("Enumeration has not started");
766 if (currentpos >= length) {
767 throw new InvalidOperationException
768 ("Enumeration has already ended");
770 // Current should not increase the position. So no ++ over here.
771 return enumeratee.GetValueImpl(currentpos);
775 public bool MoveNext() {
776 //The docs say Current should throw an exception if last
777 //call to MoveNext returned false. This means currentpos
778 //should be set to length when returning false.
779 if (currentpos < length) {
782 if(currentpos < length)
788 public void Reset() {