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;
18 public abstract class Array : ICloneable, ICollection, IList, IEnumerable
31 int length = this.GetLength (0);
33 for (int i = 1; i < this.Rank; i++) {
34 length *= this.GetLength (i);
45 return this.GetRank ();
50 public object this [int index] {
52 return GetValueImpl (index);
55 SetValueImpl (value, index);
59 int IList.Add (object value) {
60 throw new NotSupportedException ();
64 Array.Clear (this, this.GetLowerBound(0), this.Length);
67 bool IList.Contains (object value) {
68 int length = this.Length;
69 for (int i = 0; i < length; i++) {
70 if (value.Equals (this.GetValueImpl (i)))
76 int IList.IndexOf (object value) {
78 throw new RankException ();
80 int length = this.Length;
81 for (int i = 0; i < length; i++) {
82 if (value.Equals (this.GetValueImpl (i)))
83 // array index may not be zero-based.
85 return i + this.GetLowerBound (0);
90 // lower bound may be MinValue
91 retVal = this.GetLowerBound (0) - 1;
97 void IList.Insert (int index, object value) {
98 throw new NotSupportedException ();
101 void IList.Remove (object value) {
102 throw new NotSupportedException ();
105 void IList.RemoveAt (int index) {
106 throw new NotSupportedException ();
109 // InternalCall Methods
111 [MethodImplAttribute(MethodImplOptions.InternalCall)]
112 public extern int GetRank ();
114 [MethodImplAttribute(MethodImplOptions.InternalCall)]
115 public extern int GetLength (int dimension);
117 [MethodImplAttribute(MethodImplOptions.InternalCall)]
118 public extern int GetLowerBound (int dimension);
120 [MethodImplAttribute(MethodImplOptions.InternalCall)]
121 public extern object GetValue (int[] idxs);
123 [MethodImplAttribute(MethodImplOptions.InternalCall)]
124 public extern void SetValue (object value, int[] idxs);
126 [MethodImplAttribute(MethodImplOptions.InternalCall)]
127 internal extern object GetValueImpl (int pos);
129 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130 internal extern void SetValueImpl (object value, int pos);
132 [MethodImplAttribute(MethodImplOptions.InternalCall)]
133 internal extern static void FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
\r
135 [MethodImplAttribute(MethodImplOptions.InternalCall)]
\r
136 internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
139 public virtual int Count {
146 public virtual bool IsSynchronized {
154 public virtual object SyncRoot {
161 public virtual bool IsFixedSize
168 public virtual bool IsReadOnly
175 public virtual IEnumerator GetEnumerator ()
177 return new SimpleEnumerator(this);
180 public int GetUpperBound (int dimension)
182 return GetLowerBound (dimension) +
183 GetLength (dimension) - 1;
186 public object GetValue (int idx)
188 int[] ind = new int [1];
192 return GetValue (ind);
195 public object GetValue (int idx1, int idx2)
197 int[] ind = new int [2];
202 return GetValue (ind);
205 public object GetValue (int idx1, int idx2, int idx3)
207 int[] ind = new int [3];
213 return GetValue (ind);
216 // This function is currently unused, but just in case we need it later on ... */
217 internal int IndexToPos (int[] idxs)
220 throw new ArgumentNullException ();
222 if ((idxs.Rank != 1) || (idxs.Length != Rank))
223 throw new ArgumentException ();
225 if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
226 throw new IndexOutOfRangeException();
228 int pos = idxs [0] - GetLowerBound (0);
229 for (int i = 1; i < Rank; i++) {
230 if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
231 throw new IndexOutOfRangeException();
233 pos *= GetLength (i);
234 pos += idxs [i] - GetLowerBound (i);
240 public void SetValue (object value, int idx)
242 int[] ind = new int [1];
246 SetValue (value, ind);
249 public void SetValue (object value, int idx1, int idx2)
251 int[] ind = new int [2];
256 SetValue (value, ind);
259 public void SetValue (object value, int idx1, int idx2, int idx3)
261 int[] ind = new int [3];
267 SetValue (value, ind);
270 public static Array CreateInstance(Type elementType, int length)
272 int[] lengths = new int [1];
275 lengths [0] = length;
277 return CreateInstanceImpl (elementType, lengths, bounds);
280 public static Array CreateInstance(Type elementType, int l1, int l2)
282 int[] lengths = new int [2];
288 return CreateInstanceImpl (elementType, lengths, bounds);
291 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
293 int[] lengths = new int [3];
300 return CreateInstanceImpl (elementType, lengths, bounds);
303 public static Array CreateInstance(Type elementType, int[] lengths)
307 return CreateInstanceImpl (elementType, lengths, bounds);
310 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
313 throw new ArgumentNullException("bounds");
315 return CreateInstanceImpl (elementType, lengths, bounds);
319 public static int BinarySearch (Array array, object value)
322 throw new ArgumentNullException ();
324 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
328 public static int BinarySearch (Array array, object value, IComparer comparer)
331 throw new ArgumentNullException ();
333 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
337 public static int BinarySearch (Array array, int index, int length, object value)
340 throw new ArgumentNullException ();
342 return BinarySearch (array, index, length, value, null);
345 public static int BinarySearch (Array array, int index,
346 int length, object value,
350 throw new ArgumentNullException ();
353 throw new RankException ();
355 if (index < array.GetLowerBound (0) || length < 0)
356 throw new ArgumentOutOfRangeException ();
358 if (index + length > array.GetUpperBound (0) + 1)
359 throw new ArgumentException ();
361 if (comparer == null && !(value is IComparable))
362 throw new ArgumentException ();
364 // FIXME: Throw an ArgumentException if comparer
365 // is null and value is not of the same type as the
366 // elements of array.
368 // FIXME: This is implementing linear search. While it should do a binary one
369 // FIXME: Should not throw exception when values are null
371 for (int i = 0; i < length; i++)
375 if (comparer == null && !(array.GetValue(index + i) is IComparable))
376 throw new ArgumentException ();
378 if (comparer == null)
379 result = (value as IComparable).CompareTo(array.GetValue(index + i));
381 result = comparer.Compare(value, array.GetValue(index + i));
389 return ~(index + length);
392 public static void Clear (Array array, int index, int length)
395 throw new ArgumentNullException ();
398 throw new RankException ();
400 if (index < array.GetLowerBound (0) || length < 0 ||
401 index + length > array.GetUpperBound (0) + 1)
402 throw new ArgumentOutOfRangeException ();
404 for (int i = 0; i < length; i++)
406 array.SetValue(null, index + i);
410 [MethodImplAttribute(MethodImplOptions.InternalCall)]
411 public virtual extern object Clone ();
413 public static void Copy (Array source, Array dest, int length)
415 if (source == null || dest == null)
416 throw new ArgumentNullException ();
418 Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);
421 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
423 if (source == null || dest == null)
424 throw new ArgumentNullException ();
427 throw new ArgumentOutOfRangeException ();
429 int source_pos = source_idx - source.GetLowerBound (0);
430 int dest_pos = dest_idx - dest.GetLowerBound (0);
432 if (source_idx < 0 || dest_idx < 0)
433 throw new ArgumentException ();
435 if (source_pos + length > source.Length || dest_pos + length > dest.Length)
436 throw new ArgumentException ();
438 if (source.Rank != dest.Rank)
439 throw new RankException ();
441 Type src_type = source.GetType ().GetElementType ();
442 Type dst_type = dest.GetType ().GetElementType ();
444 if (src_type.IsValueType && (src_type == dst_type)) {
445 FastCopy (source, source_pos, dest, dest_pos, length);
449 for (int i = 0; i < length; i++)
451 Object srcval = source.GetValueImpl (source_pos + i);
453 bool errorThrown = false;
456 dest.SetValueImpl (srcval, dest_pos + i);
464 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
465 (src_type.Equals (typeof (Object))))
466 throw new InvalidCastException ();
468 throw new ArrayTypeMismatchException ();
472 public static int IndexOf (Array array, object value)
475 throw new ArgumentNullException ();
477 return IndexOf (array, value, 0, array.Length);
480 public static int IndexOf (Array array, object value, int index)
483 throw new ArgumentNullException ();
485 return IndexOf (array, value, index, array.Length - index);
488 public static int IndexOf (Array array, object value, int index, int length)
491 throw new ArgumentNullException ();
494 throw new RankException ();
496 if (length < 0 || index < array.GetLowerBound (0) ||
497 index+length-1 > array.GetUpperBound (0))
498 throw new ArgumentOutOfRangeException ();
500 for (int i = 0; i < length; i++)
502 if (array.GetValue(index + i).Equals(value))
506 return array.GetLowerBound (0) - 1;
509 public static int LastIndexOf (Array array, object value)
512 throw new ArgumentNullException ();
514 return LastIndexOf (array, value, array.Length-1);
517 public static int LastIndexOf (Array array, object value, int index)
520 throw new ArgumentNullException ();
522 return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
525 public static int LastIndexOf (Array array, object value, int index, int length)
528 throw new ArgumentNullException ();
531 throw new RankException ();
533 if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
534 index > array.GetUpperBound (0))
535 throw new ArgumentOutOfRangeException ();
537 for (int i = index; i >= index-length+1; i--)
539 if (array.GetValue(i).Equals(value))
543 return array.GetLowerBound (0) - 1;
546 public static void Reverse (Array array)
549 throw new ArgumentNullException ();
551 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
554 public static void Reverse (Array array, int index, int length)
557 throw new ArgumentNullException ();
560 throw new RankException ();
562 if (index < array.GetLowerBound (0) || length < 0)
563 throw new ArgumentOutOfRangeException ();
565 if (index + length > array.GetUpperBound (0) + 1)
566 throw new ArgumentException ();
568 for (int i = 0; i < length/2; i++)
572 tmp = array.GetValue (index + i);
573 array.SetValue(array.GetValue (index + length - i - 1), index + i);
574 array.SetValue(tmp, index + length - i - 1);
578 public static void Sort (Array array)
581 throw new ArgumentNullException ();
583 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
586 public static void Sort (Array keys, Array items)
589 throw new ArgumentNullException ();
591 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
594 public static void Sort (Array array, IComparer comparer)
597 throw new ArgumentNullException ();
599 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
602 public static void Sort (Array array, int index, int length)
604 Sort (array, null, index, length, null);
607 public static void Sort (Array keys, Array items, IComparer comparer)
610 throw new ArgumentNullException ();
612 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
615 public static void Sort (Array keys, Array items, int index, int length)
617 Sort (keys, items, index, length, null);
620 public static void Sort (Array array, int index, int length, IComparer comparer)
622 Sort (array, null, index, length, comparer);
625 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
628 int high0 = index + length - 1;
630 qsort (keys, items, index, index + length - 1, comparer);
633 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
640 throw new ArgumentNullException ();
642 if (keys.Rank > 1 || (items != null && items.Rank > 1))
643 throw new RankException ();
648 pivot = (low + high) / 2;
650 if (compare (keys.GetValue (low), keys.GetValue (pivot), comparer) > 0)
651 swap (keys, items, low, pivot);
653 if (compare (keys.GetValue (pivot), keys.GetValue (high), comparer) > 0)
654 swap (keys, items, pivot, high);
659 while (low < high && compare (keys.GetValue (low), keys.GetValue (pivot), comparer) < 0)
661 while (low < high && compare (keys.GetValue (pivot), keys.GetValue (high), comparer) < 0)
666 swap (keys, items, low, high);
672 qsort (keys, items, low0, low - 1, comparer);
673 qsort (keys, items, high + 1, high0, comparer);
676 private static void swap (Array keys, Array items, int i, int j)
680 tmp = keys.GetValue (i);
681 keys.SetValue (keys.GetValue (j), i);
682 keys.SetValue (tmp, j);
686 tmp = items.GetValue (i);
687 items.SetValue (items.GetValue (j), i);
688 items.SetValue (tmp, j);
692 private static int compare (object value1, object value2, IComparer comparer)
694 if (comparer == null)
695 return ((IComparable) value1).CompareTo(value2);
697 return comparer.Compare(value1, value2);
700 public virtual void CopyTo (Array array, int index)
703 throw new ArgumentNullException ();
705 // The order of these exception checks may look strange,
706 // but that's how the microsoft runtime does it.
708 throw new RankException ();
709 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
710 throw new ArgumentException ();
712 throw new RankException ();
714 throw new ArgumentOutOfRangeException ();
716 Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));
719 internal class SimpleEnumerator : IEnumerator {
724 public SimpleEnumerator (Array arrayToEnumerate) {
725 this.enumeratee = arrayToEnumerate;
726 this.currentpos = -1;
727 this.length = arrayToEnumerate.Length;
730 public object Current {
732 // Exception messages based on MS implementation
733 if (currentpos < 0 ) {
734 throw new InvalidOperationException
735 ("Enumeration has not started");
737 if (currentpos >= length) {
738 throw new InvalidOperationException
739 ("Enumeration has already ended");
741 // Current should not increase the position. So no ++ over here.
742 return enumeratee.GetValueImpl(currentpos);
746 public bool MoveNext() {
747 //The docs say Current should throw an exception if last
748 //call to MoveNext returned false. This means currentpos
749 //should be set to length when returning false.
750 if (currentpos < length) {
753 if(currentpos < length)
759 public void Reset() {