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 Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
75 public virtual int Count {
82 public virtual bool IsSynchronized {
90 public virtual object SyncRoot {
97 public virtual bool IsFixedSize
104 public virtual bool IsReadOnly
112 public virtual IEnumerator GetEnumerator ()
118 public int GetUpperBound (int dimension)
120 return GetLowerBound (dimension) +
121 GetLength (dimension) - 1;
124 public object GetValue (int idx)
126 int[] ind = new int [1];
130 return GetValue (ind);
133 public object GetValue (int idx1, int idx2)
135 int[] ind = new int [2];
140 return GetValue (ind);
143 public object GetValue (int idx1, int idx2, int idx3)
145 int[] ind = new int [3];
151 return GetValue (ind);
154 // This function is currently unused, but just in case we need it later on ... */
155 internal int IndexToPos (int[] idxs)
158 throw new ArgumentNullException ();
160 if ((idxs.Rank != 1) || (idxs.Length != Rank))
161 throw new ArgumentException ();
163 if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
164 throw new IndexOutOfRangeException();
166 int pos = idxs [0] - GetLowerBound (0);
167 for (int i = 1; i < Rank; i++) {
168 if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
169 throw new IndexOutOfRangeException();
171 pos *= GetLength (i);
172 pos += idxs [i] - GetLowerBound (i);
178 public void SetValue (object value, int idx)
180 int[] ind = new int [1];
184 SetValue (value, ind);
187 public void SetValue (object value, int idx1, int idx2)
189 int[] ind = new int [2];
194 SetValue (value, ind);
197 public void SetValue (object value, int idx1, int idx2, int idx3)
199 int[] ind = new int [3];
205 SetValue (value, ind);
208 public static Array CreateInstance(Type elementType, int length)
210 int[] lengths = new int [1];
213 lengths [0] = length;
215 return CreateInstanceImpl (elementType, lengths, bounds);
218 public static Array CreateInstance(Type elementType, int l1, int l2)
220 int[] lengths = new int [2];
226 return CreateInstanceImpl (elementType, lengths, bounds);
229 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
231 int[] lengths = new int [3];
238 return CreateInstanceImpl (elementType, lengths, bounds);
241 public static Array CreateInstance(Type elementType, int[] lengths)
245 return CreateInstanceImpl (elementType, lengths, bounds);
248 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
251 throw new ArgumentNullException("bounds");
253 return CreateInstanceImpl (elementType, lengths, bounds);
257 public static int BinarySearch (Array array, object value)
260 throw new ArgumentNullException ();
262 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
266 public static int BinarySearch (Array array, object value, IComparer comparer)
269 throw new ArgumentNullException ();
271 return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
275 public static int BinarySearch (Array array, int index, int length, object value)
278 throw new ArgumentNullException ();
280 return BinarySearch (array, index, length, value, null);
283 public static int BinarySearch (Array array, int index,
284 int length, object value,
288 throw new ArgumentNullException ();
291 throw new RankException ();
293 if (index < array.GetLowerBound (0) || length < 0)
294 throw new ArgumentOutOfRangeException ();
296 if (index + length > array.GetUpperBound (0) + 1)
297 throw new ArgumentException ();
299 if (comparer == null && !(value is IComparable))
300 throw new ArgumentException ();
302 // FIXME: Throw an ArgumentException if comparer
303 // is null and value is not of the same type as the
304 // elements of array.
306 // FIXME: This is implementing linear search. While it should do a binary one
307 // FIXME: Should not throw exception when values are null
309 for (int i = 0; i < length; i++)
313 if (comparer == null && !(array.GetValue(index + i) is IComparable))
314 throw new ArgumentException ();
316 if (comparer == null)
317 result = (value as IComparable).CompareTo(array.GetValue(index + i));
319 result = comparer.Compare(value, array.GetValue(index + i));
327 return ~(index + length);
330 public static void Clear (Array array, int index, int length)
333 throw new ArgumentNullException ();
336 throw new RankException ();
338 if (index < array.GetLowerBound (0) || length < 0 ||
339 index + length > array.GetUpperBound (0) + 1)
340 throw new ArgumentOutOfRangeException ();
342 for (int i = 0; i < length; i++)
344 array.SetValue(null, index + i);
348 [MethodImplAttribute(MethodImplOptions.InternalCall)]
349 public virtual extern object Clone ();
351 public static void Copy (Array source, Array dest, int length)
353 if (source == null || dest == null)
354 throw new ArgumentNullException ();
356 Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);
359 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
361 if (source == null || dest == null)
362 throw new ArgumentNullException ();
365 throw new ArgumentOutOfRangeException ();
367 if (source == null || dest == null)
368 throw new ArgumentNullException ();
370 if (source_idx < source.GetLowerBound (0) || dest_idx < dest.GetLowerBound (0))
371 throw new ArgumentException ();
373 source_idx -= source.GetLowerBound (0);
374 dest_idx -= dest.GetLowerBound (0);
376 if (source_idx + length > source.Length || dest_idx + length > dest.Length)
377 throw new ArgumentException ();
379 if (source.Rank != dest.Rank)
380 throw new RankException ();
382 // FIXME: This should be implemented in C so that we can use memcpy()
383 // whereever possible.
385 for (int i = 0; i < length; i++)
387 Object srcval = source.GetValueImpl (source_idx + i);
389 bool argumentException = false;
390 bool castException = false;
393 dest.SetValueImpl (srcval, dest_idx + i);
394 } catch (ArgumentException) {
395 argumentException = true;
396 } catch (InvalidCastException) {
397 castException = true;
400 if (argumentException)
401 throw new InvalidCastException ();
404 throw new ArrayTypeMismatchException ();
408 public static int IndexOf (Array array, object value)
411 throw new ArgumentNullException ();
413 return IndexOf (array, value, 0, array.Length);
416 public static int IndexOf (Array array, object value, int index)
419 throw new ArgumentNullException ();
421 return IndexOf (array, value, index, array.Length - index);
424 public static int IndexOf (Array array, object value, int index, int length)
427 throw new ArgumentNullException ();
430 throw new RankException ();
432 if (length < 0 || index < array.GetLowerBound (0) ||
433 index+length-1 > array.GetUpperBound (0))
434 throw new ArgumentOutOfRangeException ();
436 for (int i = 0; i < length; i++)
438 if (array.GetValue(index + i).Equals(value))
442 return array.GetLowerBound (0) - 1;
445 public static int LastIndexOf (Array array, object value)
448 throw new ArgumentNullException ();
450 return LastIndexOf (array, value, array.Length-1);
453 public static int LastIndexOf (Array array, object value, int index)
456 throw new ArgumentNullException ();
458 return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
461 public static int LastIndexOf (Array array, object value, int index, int length)
464 throw new ArgumentNullException ();
467 throw new RankException ();
469 if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
470 index > array.GetUpperBound (0))
471 throw new ArgumentOutOfRangeException ();
473 for (int i = index; i >= index-length+1; i--)
475 if (array.GetValue(i).Equals(value))
479 return array.GetLowerBound (0) - 1;
482 public static void Reverse (Array array)
485 throw new ArgumentNullException ();
487 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
490 public static void Reverse (Array array, int index, int length)
493 throw new ArgumentNullException ();
496 throw new RankException ();
498 if (index < array.GetLowerBound (0) || length < 0)
499 throw new ArgumentOutOfRangeException ();
501 if (index + length > array.GetUpperBound (0) + 1)
502 throw new ArgumentException ();
504 for (int i = 0; i < length/2; i++)
508 tmp = array.GetValue (index + i);
509 array.SetValue(array.GetValue (index + length - i - 1), index + i);
510 array.SetValue(tmp, index + length - i - 1);
514 public static void Sort (Array array)
517 throw new ArgumentNullException ();
519 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
522 public static void Sort (Array keys, Array items)
525 throw new ArgumentNullException ();
527 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
530 public static void Sort (Array array, IComparer comparer)
533 throw new ArgumentNullException ();
535 Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
538 public static void Sort (Array array, int index, int length)
540 Sort (array, null, index, length, null);
543 public static void Sort (Array keys, Array items, IComparer comparer)
546 throw new ArgumentNullException ();
548 Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
551 public static void Sort (Array keys, Array items, int index, int length)
553 Sort (keys, items, index, length, null);
556 public static void Sort (Array array, int index, int length, IComparer comparer)
558 Sort (array, null, index, length, comparer);
561 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
564 int high0 = index + length - 1;
566 qsort (keys, items, index, index + length - 1, comparer);
569 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
576 throw new ArgumentNullException ();
578 if (keys.Rank > 1 || (items != null && items.Rank > 1))
579 throw new RankException ();
584 pivot = (low + high) / 2;
586 if (compare (keys.GetValue (low), keys.GetValue (pivot), comparer) > 0)
587 swap (keys, items, low, pivot);
589 if (compare (keys.GetValue (pivot), keys.GetValue (high), comparer) > 0)
590 swap (keys, items, pivot, high);
595 while (low < high && compare (keys.GetValue (low), keys.GetValue (pivot), comparer) < 0)
597 while (low < high && compare (keys.GetValue (pivot), keys.GetValue (high), comparer) < 0)
602 swap (keys, items, low, high);
608 qsort (keys, items, low0, low - 1, comparer);
609 qsort (keys, items, high + 1, high0, comparer);
612 private static void swap (Array keys, Array items, int i, int j)
616 tmp = keys.GetValue (i);
617 keys.SetValue (keys.GetValue (j), i);
618 keys.SetValue (tmp, j);
622 tmp = items.GetValue (i);
623 items.SetValue (items.GetValue (j), i);
624 items.SetValue (tmp, j);
628 private static int compare (object value1, object value2, IComparer comparer)
630 if (comparer == null)
631 return ((IComparable) value1).CompareTo(value2);
633 return comparer.Compare(value1, value2);
636 public virtual void CopyTo (Array array, int index)
639 throw new ArgumentNullException ();
641 // The order of these exception checks may look strange,
642 // but that's how the microsoft runtime does it.
644 throw new RankException ();
645 if (index + this.GetLength(0) > array.GetLength(0))
646 throw new ArgumentException ();
648 throw new RankException ();
650 throw new ArgumentOutOfRangeException ();
652 Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));