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 (
469 String.Format ("(Types: source={0}; target={1})", src_type.FullName, dst_type.FullName));
473 public static int IndexOf (Array array, object value)
476 throw new ArgumentNullException ();
478 return IndexOf (array, value, 0, array.Length);
481 public static int IndexOf (Array array, object value, int index)
484 throw new ArgumentNullException ();
486 return IndexOf (array, value, index, array.Length - index);
489 public static int IndexOf (Array array, object value, int index, int length)
492 throw new ArgumentNullException ();
495 throw new RankException ();
497 if (length < 0 || index < array.GetLowerBound (0) ||
498 index+length-1 > array.GetUpperBound (0))
499 throw new ArgumentOutOfRangeException ();
501 for (int i = 0; i < length; i++)
503 if (array.GetValue(index + i).Equals(value))
507 return array.GetLowerBound (0) - 1;
510 public static int LastIndexOf (Array array, object value)
513 throw new ArgumentNullException ();
515 return LastIndexOf (array, value, array.Length-1);
518 public static int LastIndexOf (Array array, object value, int index)
521 throw new ArgumentNullException ();
523 return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
526 public static int LastIndexOf (Array array, object value, int index, int length)
529 throw new ArgumentNullException ();
532 throw new RankException ();
534 if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
535 index > array.GetUpperBound (0))
536 throw new ArgumentOutOfRangeException ();
538 for (int i = index; i >= index-length+1; i--)
540 if (array.GetValue(i).Equals(value))
544 return array.GetLowerBound (0) - 1;
547 public static void Reverse (Array array)
550 throw new ArgumentNullException ();
552 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
555 public static void Reverse (Array array, int index, int length)
558 throw new ArgumentNullException ();
561 throw new RankException ();
563 if (index < array.GetLowerBound (0) || length < 0)
564 throw new ArgumentOutOfRangeException ();
566 if (index + length > array.GetUpperBound (0) + 1)
567 throw new ArgumentException ();
569 for (int i = 0; i < length/2; i++)
573 tmp = array.GetValue (index + i);
574 array.SetValue(array.GetValue (index + length - i - 1), index + i);
575 array.SetValue(tmp, index + length - i - 1);
579 public static void Sort (Array array)
582 throw new ArgumentNullException ();
584 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
587 public static void Sort (Array keys, Array items)
590 throw new ArgumentNullException ();
592 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
595 public static void Sort (Array array, IComparer comparer)
598 throw new ArgumentNullException ();
600 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
603 public static void Sort (Array array, int index, int length)
605 Sort (array, null, index, length, null);
608 public static void Sort (Array keys, Array items, IComparer comparer)
611 throw new ArgumentNullException ();
613 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
616 public static void Sort (Array keys, Array items, int index, int length)
618 Sort (keys, items, index, length, null);
621 public static void Sort (Array array, int index, int length, IComparer comparer)
623 Sort (array, null, index, length, comparer);
626 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
629 int high0 = index + length - 1;
631 qsort (keys, items, index, index + length - 1, comparer);
634 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
641 throw new ArgumentNullException ();
643 if (keys.Rank > 1 || (items != null && items.Rank > 1))
644 throw new RankException ();
649 pivot = (low + high) / 2;
651 if (compare (keys.GetValue (low), keys.GetValue (pivot), comparer) > 0)
652 swap (keys, items, low, pivot);
654 if (compare (keys.GetValue (pivot), keys.GetValue (high), comparer) > 0)
655 swap (keys, items, pivot, high);
660 while (low < high && compare (keys.GetValue (low), keys.GetValue (pivot), comparer) < 0)
662 while (low < high && compare (keys.GetValue (pivot), keys.GetValue (high), comparer) < 0)
667 swap (keys, items, low, high);
673 qsort (keys, items, low0, low - 1, comparer);
674 qsort (keys, items, high + 1, high0, comparer);
677 private static void swap (Array keys, Array items, int i, int j)
681 tmp = keys.GetValue (i);
682 keys.SetValue (keys.GetValue (j), i);
683 keys.SetValue (tmp, j);
687 tmp = items.GetValue (i);
688 items.SetValue (items.GetValue (j), i);
689 items.SetValue (tmp, j);
693 private static int compare (object value1, object value2, IComparer comparer)
695 if (comparer == null)
696 return ((IComparable) value1).CompareTo(value2);
698 return comparer.Compare(value1, value2);
701 public virtual void CopyTo (Array array, int index)
704 throw new ArgumentNullException ();
706 // The order of these exception checks may look strange,
707 // but that's how the microsoft runtime does it.
709 throw new RankException ();
710 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
711 throw new ArgumentException ();
713 throw new RankException ();
715 throw new ArgumentOutOfRangeException ();
717 Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));
720 internal class SimpleEnumerator : IEnumerator {
725 public SimpleEnumerator (Array arrayToEnumerate) {
726 this.enumeratee = arrayToEnumerate;
727 this.currentpos = -1;
728 this.length = arrayToEnumerate.Length;
731 public object Current {
733 // Exception messages based on MS implementation
734 if (currentpos < 0 ) {
735 throw new InvalidOperationException
736 ("Enumeration has not started");
738 if (currentpos >= length) {
739 throw new InvalidOperationException
740 ("Enumeration has already ended");
742 // Current should not increase the position. So no ++ over here.
743 return enumeratee.GetValueImpl(currentpos);
747 public bool MoveNext() {
748 //The docs say Current should throw an exception if last
749 //call to MoveNext returned false. This means currentpos
750 //should be set to length when returning false.
751 if (currentpos < length) {
754 if(currentpos < length)
760 public void Reset() {