5 // Joe Shaw (joe@ximian.com)
7 // (C) 2001 Ximian, Inc. http://www.ximian.com
10 using System.Collections;
11 using System.Runtime.CompilerServices;
16 [MonoTODO("This should implement IList and IEnumerable too")]
17 public abstract class Array : ICloneable, ICollection
30 int length = this.GetLength (0);
32 for (int i = 1; i < this.Rank; i++) {
33 length *= this.GetLength (i);
44 return this.GetRank ();
48 // InternalCall Methods
50 [MethodImplAttribute(MethodImplOptions.InternalCall)]
51 public extern int GetRank ();
53 [MethodImplAttribute(MethodImplOptions.InternalCall)]
54 public extern int GetLength (int dimension);
56 [MethodImplAttribute(MethodImplOptions.InternalCall)]
57 public extern int GetLowerBound (int dimension);
59 [MethodImplAttribute(MethodImplOptions.InternalCall)]
60 public extern object GetValue (int[] idxs);
62 [MethodImplAttribute(MethodImplOptions.InternalCall)]
63 public extern void SetValue (object value, int[] idxs);
65 [MethodImplAttribute(MethodImplOptions.InternalCall)]
66 internal extern object GetValueImpl (int pos);
68 [MethodImplAttribute(MethodImplOptions.InternalCall)]
69 internal extern void SetValueImpl (object value, int pos);
71 [MethodImplAttribute(MethodImplOptions.InternalCall)]
72 internal extern static void FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
\r
74 [MethodImplAttribute(MethodImplOptions.InternalCall)]
\r
75 internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
78 public virtual int Count {
85 public virtual bool IsSynchronized {
93 public virtual object SyncRoot {
100 public virtual bool IsFixedSize
107 public virtual bool IsReadOnly
115 public virtual IEnumerator GetEnumerator ()
121 public int GetUpperBound (int dimension)
123 return GetLowerBound (dimension) +
124 GetLength (dimension) - 1;
127 public object GetValue (int idx)
129 int[] ind = new int [1];
133 return GetValue (ind);
136 public object GetValue (int idx1, int idx2)
138 int[] ind = new int [2];
143 return GetValue (ind);
146 public object GetValue (int idx1, int idx2, int idx3)
148 int[] ind = new int [3];
154 return GetValue (ind);
157 // This function is currently unused, but just in case we need it later on ... */
158 internal int IndexToPos (int[] idxs)
161 throw new ArgumentNullException ();
163 if ((idxs.Rank != 1) || (idxs.Length != Rank))
164 throw new ArgumentException ();
166 if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
167 throw new IndexOutOfRangeException();
169 int pos = idxs [0] - GetLowerBound (0);
170 for (int i = 1; i < Rank; i++) {
171 if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
172 throw new IndexOutOfRangeException();
174 pos *= GetLength (i);
175 pos += idxs [i] - GetLowerBound (i);
181 public void SetValue (object value, int idx)
183 int[] ind = new int [1];
187 SetValue (value, ind);
190 public void SetValue (object value, int idx1, int idx2)
192 int[] ind = new int [2];
197 SetValue (value, ind);
200 public void SetValue (object value, int idx1, int idx2, int idx3)
202 int[] ind = new int [3];
208 SetValue (value, ind);
211 public static Array CreateInstance(Type elementType, int length)
213 int[] lengths = new int [1];
216 lengths [0] = length;
218 return CreateInstanceImpl (elementType, lengths, bounds);
221 public static Array CreateInstance(Type elementType, int l1, int l2)
223 int[] lengths = new int [2];
229 return CreateInstanceImpl (elementType, lengths, bounds);
232 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
234 int[] lengths = new int [3];
241 return CreateInstanceImpl (elementType, lengths, bounds);
244 public static Array CreateInstance(Type elementType, int[] lengths)
248 return CreateInstanceImpl (elementType, lengths, bounds);
251 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
254 throw new ArgumentNullException("bounds");
256 return CreateInstanceImpl (elementType, lengths, bounds);
260 public static int BinarySearch (Array array, object value)
263 throw new ArgumentNullException ();
265 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
269 public static int BinarySearch (Array array, object value, IComparer comparer)
272 throw new ArgumentNullException ();
274 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
278 public static int BinarySearch (Array array, int index, int length, object value)
281 throw new ArgumentNullException ();
283 return BinarySearch (array, index, length, value, null);
286 public static int BinarySearch (Array array, int index,
287 int length, object value,
291 throw new ArgumentNullException ();
294 throw new RankException ();
296 if (index < array.GetLowerBound (0) || length < 0)
297 throw new ArgumentOutOfRangeException ();
299 if (index + length > array.GetUpperBound (0) + 1)
300 throw new ArgumentException ();
302 if (comparer == null && !(value is IComparable))
303 throw new ArgumentException ();
305 // FIXME: Throw an ArgumentException if comparer
306 // is null and value is not of the same type as the
307 // elements of array.
309 // FIXME: This is implementing linear search. While it should do a binary one
310 // FIXME: Should not throw exception when values are null
312 for (int i = 0; i < length; i++)
316 if (comparer == null && !(array.GetValue(index + i) is IComparable))
317 throw new ArgumentException ();
319 if (comparer == null)
320 result = (value as IComparable).CompareTo(array.GetValue(index + i));
322 result = comparer.Compare(value, array.GetValue(index + i));
330 return ~(index + length);
333 public static void Clear (Array array, int index, int length)
336 throw new ArgumentNullException ();
339 throw new RankException ();
341 if (index < array.GetLowerBound (0) || length < 0 ||
342 index + length > array.GetUpperBound (0) + 1)
343 throw new ArgumentOutOfRangeException ();
345 for (int i = 0; i < length; i++)
347 array.SetValue(null, index + i);
351 [MethodImplAttribute(MethodImplOptions.InternalCall)]
352 public virtual extern object Clone ();
354 public static void Copy (Array source, Array dest, int length)
356 if (source == null || dest == null)
357 throw new ArgumentNullException ();
359 Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);
362 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
364 if (source == null || dest == null)
365 throw new ArgumentNullException ();
368 throw new ArgumentOutOfRangeException ();
370 int source_pos = source_idx - source.GetLowerBound (0);
371 int dest_pos = dest_idx - dest.GetLowerBound (0);
373 if (source_idx < 0 || dest_idx < 0)
374 throw new ArgumentException ();
376 if (source_pos + length > source.Length || dest_pos + length > dest.Length)
377 throw new ArgumentException ();
379 if (source.Rank != dest.Rank)
380 throw new RankException ();
382 Type src_type = source.GetType ().GetElementType ();
383 Type dst_type = dest.GetType ().GetElementType ();
385 if (src_type.IsValueType && (src_type == dst_type)) {
386 FastCopy (source, source_pos, dest, dest_pos, length);
390 for (int i = 0; i < length; i++)
392 Object srcval = source.GetValueImpl (source_pos + i);
394 bool errorThrown = false;
397 dest.SetValueImpl (srcval, dest_pos + i);
405 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
406 (src_type.Equals (typeof (Object))))
407 throw new InvalidCastException ();
409 throw new ArrayTypeMismatchException ();
413 public static int IndexOf (Array array, object value)
416 throw new ArgumentNullException ();
418 return IndexOf (array, value, 0, array.Length);
421 public static int IndexOf (Array array, object value, int index)
424 throw new ArgumentNullException ();
426 return IndexOf (array, value, index, array.Length - index);
429 public static int IndexOf (Array array, object value, int index, int length)
432 throw new ArgumentNullException ();
435 throw new RankException ();
437 if (length < 0 || index < array.GetLowerBound (0) ||
438 index+length-1 > array.GetUpperBound (0))
439 throw new ArgumentOutOfRangeException ();
441 for (int i = 0; i < length; i++)
443 if (array.GetValue(index + i).Equals(value))
447 return array.GetLowerBound (0) - 1;
450 public static int LastIndexOf (Array array, object value)
453 throw new ArgumentNullException ();
455 return LastIndexOf (array, value, array.Length-1);
458 public static int LastIndexOf (Array array, object value, int index)
461 throw new ArgumentNullException ();
463 return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
466 public static int LastIndexOf (Array array, object value, int index, int length)
469 throw new ArgumentNullException ();
472 throw new RankException ();
474 if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
475 index > array.GetUpperBound (0))
476 throw new ArgumentOutOfRangeException ();
478 for (int i = index; i >= index-length+1; i--)
480 if (array.GetValue(i).Equals(value))
484 return array.GetLowerBound (0) - 1;
487 public static void Reverse (Array array)
490 throw new ArgumentNullException ();
492 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
495 public static void Reverse (Array array, int index, int length)
498 throw new ArgumentNullException ();
501 throw new RankException ();
503 if (index < array.GetLowerBound (0) || length < 0)
504 throw new ArgumentOutOfRangeException ();
506 if (index + length > array.GetUpperBound (0) + 1)
507 throw new ArgumentException ();
509 for (int i = 0; i < length/2; i++)
513 tmp = array.GetValue (index + i);
514 array.SetValue(array.GetValue (index + length - i - 1), index + i);
515 array.SetValue(tmp, index + length - i - 1);
519 public static void Sort (Array array)
522 throw new ArgumentNullException ();
524 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
527 public static void Sort (Array keys, Array items)
530 throw new ArgumentNullException ();
532 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
535 public static void Sort (Array array, IComparer comparer)
538 throw new ArgumentNullException ();
540 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
543 public static void Sort (Array array, int index, int length)
545 Sort (array, null, index, length, null);
548 public static void Sort (Array keys, Array items, IComparer comparer)
551 throw new ArgumentNullException ();
553 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
556 public static void Sort (Array keys, Array items, int index, int length)
558 Sort (keys, items, index, length, null);
561 public static void Sort (Array array, int index, int length, IComparer comparer)
563 Sort (array, null, index, length, comparer);
566 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
569 int high0 = index + length - 1;
571 qsort (keys, items, index, index + length - 1, comparer);
574 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
581 throw new ArgumentNullException ();
583 if (keys.Rank > 1 || (items != null && items.Rank > 1))
584 throw new RankException ();
589 pivot = (low + high) / 2;
591 if (compare (keys.GetValue (low), keys.GetValue (pivot), comparer) > 0)
592 swap (keys, items, low, pivot);
594 if (compare (keys.GetValue (pivot), keys.GetValue (high), comparer) > 0)
595 swap (keys, items, pivot, high);
600 while (low < high && compare (keys.GetValue (low), keys.GetValue (pivot), comparer) < 0)
602 while (low < high && compare (keys.GetValue (pivot), keys.GetValue (high), comparer) < 0)
607 swap (keys, items, low, high);
613 qsort (keys, items, low0, low - 1, comparer);
614 qsort (keys, items, high + 1, high0, comparer);
617 private static void swap (Array keys, Array items, int i, int j)
621 tmp = keys.GetValue (i);
622 keys.SetValue (keys.GetValue (j), i);
623 keys.SetValue (tmp, j);
627 tmp = items.GetValue (i);
628 items.SetValue (items.GetValue (j), i);
629 items.SetValue (tmp, j);
633 private static int compare (object value1, object value2, IComparer comparer)
635 if (comparer == null)
636 return ((IComparable) value1).CompareTo(value2);
638 return comparer.Compare(value1, value2);
641 public virtual void CopyTo (Array array, int index)
644 throw new ArgumentNullException ();
646 // The order of these exception checks may look strange,
647 // but that's how the microsoft runtime does it.
649 throw new RankException ();
650 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
651 throw new ArgumentException ();
653 throw new RankException ();
655 throw new ArgumentOutOfRangeException ();
657 Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));