5 // Joe Shaw (joe@ximian.com)
6 // Martin Baulig (martin@gnome.org)
7 // Dietmar Maurer (dietmar@ximian.com)
8 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
11 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
37 using System.Collections.Generic;
38 using System.Collections.ObjectModel;
39 using System.Runtime.ConstrainedExecution;
45 // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
46 public abstract class Array : ICloneable, ICollection, IList, IEnumerable
48 , IStructuralComparable, IStructuralEquatable
57 * These methods are used to implement the implicit generic interfaces
58 * implemented by arrays in NET 2.0.
59 * Only make those methods generic which really need it, to avoid
60 * creating useless instantiations.
62 internal int InternalArray__ICollection_get_Count ()
67 internal bool InternalArray__ICollection_get_IsReadOnly ()
72 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
74 return new InternalEnumerator<T> (this);
77 internal void InternalArray__ICollection_Clear ()
79 throw new NotSupportedException ("Collection is read-only");
82 internal void InternalArray__ICollection_Add<T> (T item)
84 throw new NotSupportedException ("Collection is read-only");
87 internal bool InternalArray__ICollection_Remove<T> (T item)
89 throw new NotSupportedException ("Collection is read-only");
92 internal bool InternalArray__ICollection_Contains<T> (T item)
95 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
97 int length = this.Length;
98 for (int i = 0; i < length; i++) {
100 GetGenericValueImpl (i, out value);
108 if (item.Equals (value))
115 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
118 throw new ArgumentNullException ("array");
120 // The order of these exception checks may look strange,
121 // but that's how the microsoft runtime does it.
123 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
124 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
125 throw new ArgumentException ("Destination array was not long " +
126 "enough. Check destIndex and length, and the array's " +
129 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
131 throw new ArgumentOutOfRangeException (
132 "index", Locale.GetText ("Value has to be >= 0."));
134 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
137 internal void InternalArray__Insert<T> (int index, T item)
139 throw new NotSupportedException ("Collection is read-only");
142 internal void InternalArray__RemoveAt (int index)
144 throw new NotSupportedException ("Collection is read-only");
147 internal int InternalArray__IndexOf<T> (T item)
150 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
152 int length = this.Length;
153 for (int i = 0; i < length; i++) {
155 GetGenericValueImpl (i, out value);
158 return i + this.GetLowerBound (0);
161 return this.GetLowerBound (0) - 1;
165 if (value.Equals (item))
166 // array index may not be zero-based.
168 return i + this.GetLowerBound (0);
172 // lower bound may be MinValue
173 return this.GetLowerBound (0) - 1;
177 internal T InternalArray__get_Item<T> (int index)
179 if (unchecked ((uint) index) >= unchecked ((uint) Length))
180 throw new ArgumentOutOfRangeException ("index");
183 GetGenericValueImpl (index, out value);
187 internal void InternalArray__set_Item<T> (int index, T item)
189 if (unchecked ((uint) index) >= unchecked ((uint) Length))
190 throw new ArgumentOutOfRangeException ("index");
192 object[] oarray = this as object [];
193 if (oarray != null) {
194 oarray [index] = (object)item;
197 SetGenericValueImpl (index, ref item);
200 // CAUTION! No bounds checking!
201 [MethodImplAttribute (MethodImplOptions.InternalCall)]
202 internal extern void GetGenericValueImpl<T> (int pos, out T value);
204 // CAUTION! No bounds checking!
205 [MethodImplAttribute (MethodImplOptions.InternalCall)]
206 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
208 internal struct InternalEnumerator<T> : IEnumerator<T>
210 const int NOT_STARTED = -2;
212 // this MUST be -1, because we depend on it in move next.
213 // we just decr the size, so, 0 - 1 == FINISHED
214 const int FINISHED = -1;
219 internal InternalEnumerator (Array array)
225 public void Dispose ()
230 public bool MoveNext ()
232 if (idx == NOT_STARTED)
235 return idx != FINISHED && -- idx != FINISHED;
240 if (idx == NOT_STARTED)
241 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
243 throw new InvalidOperationException ("Enumeration already finished");
245 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
249 void IEnumerator.Reset ()
254 object IEnumerator.Current {
263 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
265 int length = this.GetLength (0);
267 for (int i = 1; i < this.Rank; i++) {
268 length *= this.GetLength (i);
275 public long LongLength {
276 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
277 get { return Length; }
281 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
283 return this.GetRank ();
288 object IList.this [int index] {
290 if (unchecked ((uint) index) >= unchecked ((uint) Length))
291 throw new IndexOutOfRangeException ("index");
293 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
294 return GetValueImpl (index);
297 if (unchecked ((uint) index) >= unchecked ((uint) Length))
298 throw new IndexOutOfRangeException ("index");
300 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
301 SetValueImpl (value, index);
305 int IList.Add (object value)
307 throw new NotSupportedException ();
312 Array.Clear (this, this.GetLowerBound (0), this.Length);
315 bool IList.Contains (object value)
318 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
320 int length = this.Length;
321 for (int i = 0; i < length; i++) {
322 if (Object.Equals (this.GetValueImpl (i), value))
328 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
329 int IList.IndexOf (object value)
332 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
334 int length = this.Length;
335 for (int i = 0; i < length; i++) {
336 if (Object.Equals (this.GetValueImpl (i), value))
337 // array index may not be zero-based.
339 return i + this.GetLowerBound (0);
343 // lower bound may be MinValue
344 return this.GetLowerBound (0) - 1;
348 void IList.Insert (int index, object value)
350 throw new NotSupportedException ();
353 void IList.Remove (object value)
355 throw new NotSupportedException ();
358 void IList.RemoveAt (int index)
360 throw new NotSupportedException ();
363 // InternalCall Methods
364 [MethodImplAttribute (MethodImplOptions.InternalCall)]
365 extern int GetRank ();
367 [MethodImplAttribute (MethodImplOptions.InternalCall)]
368 public extern int GetLength (int dimension);
371 public long GetLongLength (int dimension)
373 return GetLength (dimension);
376 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
377 [MethodImplAttribute (MethodImplOptions.InternalCall)]
378 public extern int GetLowerBound (int dimension);
380 [MethodImplAttribute (MethodImplOptions.InternalCall)]
381 public extern object GetValue (params int[] indices);
383 [MethodImplAttribute (MethodImplOptions.InternalCall)]
384 public extern void SetValue (object value, params int[] indices);
386 // CAUTION! No bounds checking!
387 [MethodImplAttribute (MethodImplOptions.InternalCall)]
388 internal extern object GetValueImpl (int pos);
390 // CAUTION! No bounds checking!
391 [MethodImplAttribute (MethodImplOptions.InternalCall)]
392 internal extern void SetValueImpl (object value, int pos);
394 [MethodImplAttribute (MethodImplOptions.InternalCall)]
395 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
397 [MethodImplAttribute (MethodImplOptions.InternalCall)]
398 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
401 int ICollection.Count {
407 public bool IsSynchronized {
413 public object SyncRoot {
419 public bool IsFixedSize {
425 public bool IsReadOnly {
431 public IEnumerator GetEnumerator ()
433 return new SimpleEnumerator (this);
437 int IStructuralComparable.CompareTo (object other, IComparer comparer)
442 Array arr = other as Array;
444 throw new ArgumentException ("Not an array", "other");
446 int len = GetLength (0);
447 if (len != arr.GetLength (0))
448 throw new ArgumentException ("Not of the same length", "other");
451 throw new ArgumentException ("Array must be single dimensional");
454 throw new ArgumentException ("Array must be single dimensional", "other");
456 for (int i = 0; i < len; ++i) {
457 object a = GetValue (i);
458 object b = arr.GetValue (i);
459 int r = comparer.Compare (a, b);
466 bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer)
468 Array o = other as Array;
469 if (o == null || o.Length != Length)
472 if (Object.ReferenceEquals (other, this))
475 for (int i = 0; i < Length; i++) {
476 object this_item = this.GetValue (i);
477 object other_item = o.GetValue (i);
478 if (!comparer.Equals (this_item, other_item))
485 int IStructuralEquatable.GetHashCode (IEqualityComparer comparer)
487 if (comparer == null)
488 throw new ArgumentNullException ("comparer");
491 for (int i = 0; i < Length; i++)
492 hash = ((hash << 7) + hash) ^ GetValue (i).GetHashCode ();
497 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
498 public int GetUpperBound (int dimension)
500 return GetLowerBound (dimension) + GetLength (dimension) - 1;
503 public object GetValue (int index)
506 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
507 if (index < GetLowerBound (0) || index > GetUpperBound (0))
508 throw new IndexOutOfRangeException (Locale.GetText (
509 "Index has to be between upper and lower bound of the array."));
511 return GetValueImpl (index - GetLowerBound (0));
514 public object GetValue (int index1, int index2)
516 int[] ind = {index1, index2};
517 return GetValue (ind);
520 public object GetValue (int index1, int index2, int index3)
522 int[] ind = {index1, index2, index3};
523 return GetValue (ind);
527 public object GetValue (long index)
529 if (index < 0 || index > Int32.MaxValue)
530 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
531 "Value must be >= 0 and <= Int32.MaxValue."));
533 return GetValue ((int) index);
537 public object GetValue (long index1, long index2)
539 if (index1 < 0 || index1 > Int32.MaxValue)
540 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
541 "Value must be >= 0 and <= Int32.MaxValue."));
543 if (index2 < 0 || index2 > Int32.MaxValue)
544 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
545 "Value must be >= 0 and <= Int32.MaxValue."));
547 return GetValue ((int) index1, (int) index2);
551 public object GetValue (long index1, long index2, long index3)
553 if (index1 < 0 || index1 > Int32.MaxValue)
554 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
555 "Value must be >= 0 and <= Int32.MaxValue."));
557 if (index2 < 0 || index2 > Int32.MaxValue)
558 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
559 "Value must be >= 0 and <= Int32.MaxValue."));
561 if (index3 < 0 || index3 > Int32.MaxValue)
562 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
563 "Value must be >= 0 and <= Int32.MaxValue."));
565 return GetValue ((int) index1, (int) index2, (int) index3);
569 public void SetValue (object value, long index)
571 if (index < 0 || index > Int32.MaxValue)
572 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
573 "Value must be >= 0 and <= Int32.MaxValue."));
575 SetValue (value, (int) index);
579 public void SetValue (object value, long index1, long index2)
581 if (index1 < 0 || index1 > Int32.MaxValue)
582 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
583 "Value must be >= 0 and <= Int32.MaxValue."));
585 if (index2 < 0 || index2 > Int32.MaxValue)
586 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
587 "Value must be >= 0 and <= Int32.MaxValue."));
589 int[] ind = {(int) index1, (int) index2};
590 SetValue (value, ind);
594 public void SetValue (object value, long index1, long index2, long index3)
596 if (index1 < 0 || index1 > Int32.MaxValue)
597 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
598 "Value must be >= 0 and <= Int32.MaxValue."));
600 if (index2 < 0 || index2 > Int32.MaxValue)
601 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
602 "Value must be >= 0 and <= Int32.MaxValue."));
604 if (index3 < 0 || index3 > Int32.MaxValue)
605 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
606 "Value must be >= 0 and <= Int32.MaxValue."));
608 int[] ind = {(int) index1, (int) index2, (int) index3};
609 SetValue (value, ind);
612 public void SetValue (object value, int index)
615 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
616 if (index < GetLowerBound (0) || index > GetUpperBound (0))
617 throw new IndexOutOfRangeException (Locale.GetText (
618 "Index has to be >= lower bound and <= upper bound of the array."));
620 SetValueImpl (value, index - GetLowerBound (0));
623 public void SetValue (object value, int index1, int index2)
625 int[] ind = {index1, index2};
626 SetValue (value, ind);
629 public void SetValue (object value, int index1, int index2, int index3)
631 int[] ind = {index1, index2, index3};
632 SetValue (value, ind);
635 public static Array CreateInstance (Type elementType, int length)
637 int[] lengths = {length};
639 return CreateInstance (elementType, lengths);
642 public static Array CreateInstance (Type elementType, int length1, int length2)
644 int[] lengths = {length1, length2};
646 return CreateInstance (elementType, lengths);
649 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
651 int[] lengths = {length1, length2, length3};
653 return CreateInstance (elementType, lengths);
656 public static Array CreateInstance (Type elementType, params int[] lengths)
658 if (elementType == null)
659 throw new ArgumentNullException ("elementType");
661 throw new ArgumentNullException ("lengths");
663 if (lengths.Length > 255)
664 throw new TypeLoadException ();
668 elementType = elementType.UnderlyingSystemType;
669 if (!elementType.IsSystemType)
670 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
671 if (elementType.Equals (typeof (void)))
672 throw new NotSupportedException ("Array type can not be void");
673 if (elementType.ContainsGenericParameters)
674 throw new NotSupportedException ("Array type can not be an open generic type");
676 return CreateInstanceImpl (elementType, lengths, bounds);
679 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
681 if (elementType == null)
682 throw new ArgumentNullException ("elementType");
684 throw new ArgumentNullException ("lengths");
685 if (lowerBounds == null)
686 throw new ArgumentNullException ("lowerBounds");
688 elementType = elementType.UnderlyingSystemType;
689 if (!elementType.IsSystemType)
690 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
691 if (elementType.Equals (typeof (void)))
692 throw new NotSupportedException ("Array type can not be void");
693 if (elementType.ContainsGenericParameters)
694 throw new NotSupportedException ("Array type can not be an open generic type");
696 if (lengths.Length < 1)
697 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
699 if (lengths.Length != lowerBounds.Length)
700 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
702 for (int j = 0; j < lowerBounds.Length; j ++) {
704 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
705 "Each value has to be >= 0."));
706 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
707 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
708 "Length + bound must not exceed Int32.MaxValue."));
711 if (lengths.Length > 255)
712 throw new TypeLoadException ();
714 return CreateInstanceImpl (elementType, lengths, lowerBounds);
717 static int [] GetIntArray (long [] values)
719 int len = values.Length;
720 int [] ints = new int [len];
721 for (int i = 0; i < len; i++) {
722 long current = values [i];
723 if (current < 0 || current > (long) Int32.MaxValue)
724 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
725 "Each value has to be >= 0 and <= Int32.MaxValue."));
727 ints [i] = (int) current;
732 public static Array CreateInstance (Type elementType, params long [] lengths)
735 throw new ArgumentNullException ("lengths");
736 return CreateInstance (elementType, GetIntArray (lengths));
740 public object GetValue (params long [] indices)
743 throw new ArgumentNullException ("indices");
744 return GetValue (GetIntArray (indices));
748 public void SetValue (object value, params long [] indices)
751 throw new ArgumentNullException ("indices");
752 SetValue (value, GetIntArray (indices));
755 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
756 public static int BinarySearch (Array array, object value)
759 throw new ArgumentNullException ("array");
765 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
767 if (array.Length == 0)
770 if (!(value is IComparable))
771 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
773 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
776 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
777 public static int BinarySearch (Array array, object value, IComparer comparer)
780 throw new ArgumentNullException ("array");
783 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
785 if (array.Length == 0)
788 if ((comparer == null) && (value != null) && !(value is IComparable))
789 throw new ArgumentException (Locale.GetText (
790 "comparer is null and value does not support IComparable."));
792 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
795 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
796 public static int BinarySearch (Array array, int index, int length, object value)
799 throw new ArgumentNullException ("array");
802 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
804 if (index < array.GetLowerBound (0))
805 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
806 "index is less than the lower bound of array."));
808 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
809 "Value has to be >= 0."));
810 // re-ordered to avoid possible integer overflow
811 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
812 throw new ArgumentException (Locale.GetText (
813 "index and length do not specify a valid range in array."));
815 if (array.Length == 0)
818 if ((value != null) && (!(value is IComparable)))
819 throw new ArgumentException (Locale.GetText (
820 "value does not support IComparable"));
822 return DoBinarySearch (array, index, length, value, null);
825 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
826 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
829 throw new ArgumentNullException ("array");
832 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
834 if (index < array.GetLowerBound (0))
835 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
836 "index is less than the lower bound of array."));
838 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
839 "Value has to be >= 0."));
840 // re-ordered to avoid possible integer overflow
841 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
842 throw new ArgumentException (Locale.GetText (
843 "index and length do not specify a valid range in array."));
845 if (array.Length == 0)
848 if ((comparer == null) && (value != null) && !(value is IComparable))
849 throw new ArgumentException (Locale.GetText (
850 "comparer is null and value does not support IComparable."));
852 return DoBinarySearch (array, index, length, value, comparer);
855 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
857 // cache this in case we need it
858 if (comparer == null)
859 comparer = Comparer.Default;
862 // Comment from Tum (tum@veridicus.com):
863 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
864 int iMax = index + length - 1;
867 while (iMin <= iMax) {
868 // Be careful with overflow
869 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
870 int iMid = iMin + ((iMax - iMin) / 2);
871 object elt = array.GetValueImpl (iMid);
873 iCmp = comparer.Compare (elt, value);
880 iMin = iMid + 1; // compensate for the rounding down
883 catch (Exception e) {
884 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
890 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
891 public static void Clear (Array array, int index, int length)
894 throw new ArgumentNullException ("array");
896 throw new IndexOutOfRangeException ("length < 0");
898 int low = array.GetLowerBound (0);
900 throw new IndexOutOfRangeException ("index < lower bound");
903 // re-ordered to avoid possible integer overflow
904 if (index > array.Length - length)
905 throw new IndexOutOfRangeException ("index + length > size");
907 ClearInternal (array, index, length);
910 [MethodImplAttribute (MethodImplOptions.InternalCall)]
911 static extern void ClearInternal (Array a, int index, int count);
913 [MethodImplAttribute (MethodImplOptions.InternalCall)]
914 public extern object Clone ();
916 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
917 public static void Copy (Array sourceArray, Array destinationArray, int length)
919 // need these checks here because we are going to use
920 // GetLowerBound() on source and dest.
921 if (sourceArray == null)
922 throw new ArgumentNullException ("sourceArray");
924 if (destinationArray == null)
925 throw new ArgumentNullException ("destinationArray");
927 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
928 destinationArray.GetLowerBound (0), length);
931 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
932 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
934 if (sourceArray == null)
935 throw new ArgumentNullException ("sourceArray");
937 if (destinationArray == null)
938 throw new ArgumentNullException ("destinationArray");
941 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
942 "Value has to be >= 0."));;
945 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
946 "Value has to be >= 0."));;
948 if (destinationIndex < 0)
949 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
950 "Value has to be >= 0."));;
952 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
955 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
956 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
958 // re-ordered to avoid possible integer overflow
959 if (source_pos > sourceArray.Length - length)
960 throw new ArgumentException ("length");
962 if (dest_pos > destinationArray.Length - length) {
963 string msg = "Destination array was not long enough. Check " +
964 "destIndex and length, and the array's lower bounds";
965 throw new ArgumentException (msg, string.Empty);
968 if (sourceArray.Rank != destinationArray.Rank)
969 throw new RankException (Locale.GetText ("Arrays must be of same size."));
971 Type src_type = sourceArray.GetType ().GetElementType ();
972 Type dst_type = destinationArray.GetType ().GetElementType ();
974 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
975 for (int i = 0; i < length; i++) {
976 Object srcval = sourceArray.GetValueImpl (source_pos + i);
979 destinationArray.SetValueImpl (srcval, dest_pos + i);
981 if (src_type.Equals (typeof (Object)))
982 throw new InvalidCastException ();
984 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
985 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
990 for (int i = length - 1; i >= 0; i--) {
991 Object srcval = sourceArray.GetValueImpl (source_pos + i);
994 destinationArray.SetValueImpl (srcval, dest_pos + i);
996 if (src_type.Equals (typeof (Object)))
997 throw new InvalidCastException ();
999 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
1000 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
1006 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1007 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1008 long destinationIndex, long length)
1010 if (sourceArray == null)
1011 throw new ArgumentNullException ("sourceArray");
1013 if (destinationArray == null)
1014 throw new ArgumentNullException ("destinationArray");
1016 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1017 throw new ArgumentOutOfRangeException ("sourceIndex",
1018 Locale.GetText ("Must be in the Int32 range."));
1020 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1021 throw new ArgumentOutOfRangeException ("destinationIndex",
1022 Locale.GetText ("Must be in the Int32 range."));
1024 if (length < 0 || length > Int32.MaxValue)
1025 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1026 "Value must be >= 0 and <= Int32.MaxValue."));
1028 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1031 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1032 public static void Copy (Array sourceArray, Array destinationArray, long length)
1034 if (length < 0 || length > Int32.MaxValue)
1035 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1036 "Value must be >= 0 and <= Int32.MaxValue."));
1038 Copy (sourceArray, destinationArray, (int) length);
1041 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1042 public static int IndexOf (Array array, object value)
1045 throw new ArgumentNullException ("array");
1047 return IndexOf (array, value, 0, array.Length);
1050 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1051 public static int IndexOf (Array array, object value, int startIndex)
1054 throw new ArgumentNullException ("array");
1056 return IndexOf (array, value, startIndex, array.Length - startIndex);
1059 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1060 public static int IndexOf (Array array, object value, int startIndex, int count)
1063 throw new ArgumentNullException ("array");
1066 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1068 // re-ordered to avoid possible integer overflow
1069 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1070 throw new ArgumentOutOfRangeException ();
1072 int max = startIndex + count;
1073 for (int i = startIndex; i < max; i++) {
1074 if (Object.Equals (array.GetValueImpl (i), value))
1078 return array.GetLowerBound (0) - 1;
1081 public void Initialize()
1083 //FIXME: We would like to find a compiler that uses
1084 // this method. It looks like this method do nothing
1085 // in C# so no exception is trown by the moment.
1088 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1089 public static int LastIndexOf (Array array, object value)
1092 throw new ArgumentNullException ("array");
1094 if (array.Length == 0)
1095 return array.GetLowerBound (0) - 1;
1096 return LastIndexOf (array, value, array.Length - 1);
1099 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1100 public static int LastIndexOf (Array array, object value, int startIndex)
1103 throw new ArgumentNullException ("array");
1105 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1108 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1109 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1112 throw new ArgumentNullException ("array");
1115 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1117 int lb = array.GetLowerBound (0);
1118 // Empty arrays do not throw ArgumentOutOfRangeException
1119 if (array.Length == 0)
1122 if (count < 0 || startIndex < lb ||
1123 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1124 throw new ArgumentOutOfRangeException ();
1126 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1127 if (Object.Equals (array.GetValueImpl (i), value))
1134 /* delegate used to swap array elements */
1135 delegate void Swapper (int i, int j);
1137 static Swapper get_swapper (Array array)
1140 return new Swapper (array.int_swapper);
1141 if (array is double[])
1142 return new Swapper (array.double_swapper);
1143 if (array is object[]) {
1144 return new Swapper (array.obj_swapper);
1146 return new Swapper (array.slow_swapper);
1149 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1150 public static void Reverse (Array array)
1153 throw new ArgumentNullException ("array");
1155 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
1158 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1159 public static void Reverse (Array array, int index, int length)
1162 throw new ArgumentNullException ("array");
1165 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1167 if (index < array.GetLowerBound (0) || length < 0)
1168 throw new ArgumentOutOfRangeException ();
1170 // re-ordered to avoid possible integer overflow
1171 if (index > array.GetUpperBound (0) + 1 - length)
1172 throw new ArgumentException ();
1174 int end = index + length - 1;
1175 object[] oarray = array as object[];
1176 if (oarray != null) {
1177 while (index < end) {
1178 object tmp = oarray [index];
1179 oarray [index] = oarray [end];
1186 int[] iarray = array as int[];
1187 if (iarray != null) {
1188 while (index < end) {
1189 int tmp = iarray [index];
1190 iarray [index] = iarray [end];
1197 double[] darray = array as double[];
1198 if (darray != null) {
1199 while (index < end) {
1200 double tmp = darray [index];
1201 darray [index] = darray [end];
1209 Swapper swapper = get_swapper (array);
1210 while (index < end) {
1211 swapper (index, end);
1217 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1218 public static void Sort (Array array)
1220 Sort (array, (IComparer)null);
1223 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1224 public static void Sort (Array keys, Array items)
1226 Sort (keys, items, (IComparer)null);
1229 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1230 public static void Sort (Array array, IComparer comparer)
1233 throw new ArgumentNullException ("array");
1236 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1238 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1241 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1242 public static void Sort (Array array, int index, int length)
1244 Sort (array, index, length, (IComparer)null);
1247 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1248 public static void Sort (Array keys, Array items, IComparer comparer)
1250 if (items == null) {
1251 Sort (keys, comparer);
1256 throw new ArgumentNullException ("keys");
1258 if (keys.Rank > 1 || items.Rank > 1)
1259 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1261 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1264 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1265 public static void Sort (Array keys, Array items, int index, int length)
1267 Sort (keys, items, index, length, (IComparer)null);
1270 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1271 public static void Sort (Array array, int index, int length, IComparer comparer)
1274 throw new ArgumentNullException ("array");
1277 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1279 if (index < array.GetLowerBound (0))
1280 throw new ArgumentOutOfRangeException ("index");
1283 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1284 "Value has to be >= 0."));
1286 if (array.Length - (array.GetLowerBound (0) + index) < length)
1287 throw new ArgumentException ();
1289 SortImpl (array, null, index, length, comparer);
1292 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1293 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1295 if (items == null) {
1296 Sort (keys, index, length, comparer);
1301 throw new ArgumentNullException ("keys");
1303 if (keys.Rank > 1 || items.Rank > 1)
1304 throw new RankException ();
1306 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1307 throw new ArgumentException ();
1309 if (index < keys.GetLowerBound (0))
1310 throw new ArgumentOutOfRangeException ("index");
1313 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1314 "Value has to be >= 0."));
1316 if (keys.Length != items.Length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1317 throw new ArgumentException ();
1319 SortImpl (keys, items, index, length, comparer);
1322 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1328 int high = index + length - 1;
1330 #if !BOOTSTRAP_BASIC
1331 if (comparer == null) {
1332 if (keys is int[]) {
1333 qsort (keys as int[], items as object[], low, high);
1336 if (keys is long[]) {
1337 qsort (keys as long[], items as object[], low, high);
1340 if (keys is char[]) {
1341 qsort (keys as char[], items as object[], low, high);
1344 if (keys is double[]) {
1345 qsort (keys as double[], items as object[], low, high);
1348 if (keys is uint[]) {
1349 qsort (keys as uint[], items as object[], low, high);
1352 if (keys is ulong[]) {
1353 qsort (keys as ulong[], items as object[], low, high);
1356 if (keys is byte[]) {
1357 qsort (keys as byte[], items as object[], low, high);
1360 if (keys is ushort[]) {
1361 qsort (keys as ushort[], items as object[], low, high);
1367 low = MoveNullKeysToFront (keys, items, low, high, comparer == null);
1372 qsort (keys, items, low, high, comparer);
1373 } catch (Exception e) {
1374 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1378 /* note, these are instance methods */
1379 void int_swapper (int i, int j) {
1380 int[] array = this as int[];
1381 int val = array [i];
1382 array [i] = array [j];
1386 void obj_swapper (int i, int j) {
1387 object[] array = this as object[];
1388 object val = array [i];
1389 array [i] = array [j];
1393 void slow_swapper (int i, int j) {
1394 object val = GetValueImpl (i);
1395 SetValueImpl (GetValue (j), i);
1396 SetValueImpl (val, j);
1399 void double_swapper (int i, int j) {
1400 double[] array = this as double[];
1401 double val = array [i];
1402 array [i] = array [j];
1406 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1411 // Be careful with overflows
1412 int mid = low + ((high - low) / 2);
1413 object keyPivot = keys.GetValueImpl (mid);
1414 IComparable cmpPivot = keyPivot as IComparable;
1417 // Move the walls in
1418 if (comparer != null) {
1419 while (low < high0 && comparer.Compare (keyPivot, keys.GetValueImpl (low)) > 0)
1421 while (high > low0 && comparer.Compare (keyPivot, keys.GetValueImpl (high)) < 0)
1424 while (low < high0 && cmpPivot.CompareTo (keys.GetValueImpl (low)) > 0)
1426 while (high > low0 && cmpPivot.CompareTo (keys.GetValueImpl (high)) < 0)
1431 swap (keys, items, low, high);
1439 qsort (keys, items, low0, high, comparer);
1441 qsort (keys, items, low, high0, comparer);
1444 private static int MoveNullKeysToFront (Array keys, Array items, int low, int high, bool ensureComparable)
1446 // find first nun-null key
1447 while (low < high && keys.GetValueImpl (low) == null)
1450 // move null keys to beginning of array,
1451 // ensure that non-null keys implement IComparable
1452 for (int i = low + 1; i <= high; i++) {
1453 object obj = keys.GetValueImpl (i);
1455 swap (keys, items, low, i);
1458 if (ensureComparable && !(obj is IComparable)) {
1459 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1460 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1467 private static void swap (Array keys, Array items, int i, int j)
1469 object tmp = keys.GetValueImpl (i);
1470 keys.SetValueImpl (keys.GetValueImpl (j), i);
1471 keys.SetValueImpl (tmp, j);
1473 if (items != null) {
1474 tmp = items.GetValueImpl (i);
1475 items.SetValueImpl (items.GetValueImpl (j), i);
1476 items.SetValueImpl (tmp, j);
1480 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1481 public static void Sort<T> (T [] array)
1483 Sort<T> (array, (IComparer<T>)null);
1486 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1487 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1489 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1492 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1493 public static void Sort<T> (T [] array, IComparer<T> comparer)
1496 throw new ArgumentNullException ("array");
1498 SortImpl<T, T> (array, null, 0, array.Length, comparer);
1501 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1502 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1504 if (items == null) {
1505 Sort<TKey> (keys, comparer);
1510 throw new ArgumentNullException ("keys");
1512 if (keys.Length != items.Length)
1513 throw new ArgumentException ("Length of keys and items does not match.");
1515 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1518 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1519 public static void Sort<T> (T [] array, int index, int length)
1521 Sort<T> (array, index, length, (IComparer<T>)null);
1524 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1525 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1527 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1530 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1531 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1534 throw new ArgumentNullException ("array");
1537 throw new ArgumentOutOfRangeException ("index");
1540 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1541 "Value has to be >= 0."));
1543 if (index + length > array.Length)
1544 throw new ArgumentException ();
1546 SortImpl<T, T> (array, null, index, length, comparer);
1549 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1550 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1552 if (items == null) {
1553 Sort<TKey> (keys, index, length, comparer);
1558 throw new ArgumentNullException ("keys");
1561 throw new ArgumentOutOfRangeException ("index");
1564 throw new ArgumentOutOfRangeException ("length");
1566 if (keys.Length != items.Length || keys.Length - index < length)
1567 throw new ArgumentException ();
1569 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1572 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1574 if (keys.Length <= 1)
1578 int high = index + length - 1;
1581 // Check for value types which can be sorted without Compare () method
1583 if (comparer == null) {
1584 #if !BOOTSTRAP_BASIC
1585 switch (Type.GetTypeCode (typeof (TKey))) {
1586 case TypeCode.Int32:
1587 qsort (keys as Int32[], items, low, high);
1589 case TypeCode.Int64:
1590 qsort (keys as Int64[], items, low, high);
1593 qsort (keys as byte[], items, low, high);
1596 qsort (keys as char[], items, low, high);
1598 case TypeCode.DateTime:
1599 qsort (keys as DateTime[], items, low, high);
1601 case TypeCode.Decimal:
1602 qsort (keys as decimal[], items, low, high);
1604 case TypeCode.Double:
1605 qsort (keys as double[], items, low, high);
1607 case TypeCode.Int16:
1608 qsort (keys as Int16[], items, low, high);
1610 case TypeCode.SByte:
1611 qsort (keys as SByte[], items, low, high);
1613 case TypeCode.Single:
1614 qsort (keys as Single[], items, low, high);
1616 case TypeCode.UInt16:
1617 qsort (keys as UInt16[], items, low, high);
1619 case TypeCode.UInt32:
1620 qsort (keys as UInt32[], items, low, high);
1622 case TypeCode.UInt64:
1623 qsort (keys as UInt64[], items, low, high);
1627 // Using Comparer<TKey> adds a small overload, but with value types it
1628 // helps us to not box them.
1629 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1630 typeof (TKey).IsValueType)
1631 comparer = Comparer<TKey>.Default;
1634 low = MoveNullKeysToFront<TKey, TValue> (keys, items, low, high, comparer == null);
1640 qsort (keys, items, low, high, comparer);
1641 } catch (Exception e) {
1642 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1646 public static void Sort<T> (T [] array, Comparison<T> comparison)
1649 throw new ArgumentNullException ("array");
1651 if (comparison == null)
1652 throw new ArgumentNullException ("comparison");
1654 SortImpl<T> (array, array.Length, comparison);
1657 // used by List<T>.Sort (Comparison <T>)
1658 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1665 int high0 = length - 1;
1666 qsort<T> (array, low0, high0, comparison);
1667 } catch (InvalidOperationException) {
1669 } catch (Exception e) {
1670 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1674 private static void qsort<T, U> (T[] array, U[] items, int low0, int high0) where T : IComparable<T>
1679 // Be careful with overflows
1680 int mid = low + ((high - low) / 2);
1681 var keyPivot = array [mid];
1684 // Move the walls in
1685 while (low < high0 && keyPivot.CompareTo (array [low]) > 0)
1687 while (high > low0 && keyPivot.CompareTo (array [high]) < 0)
1691 swap (array, items, low, high);
1699 qsort (array, items, low0, high);
1701 qsort (array, items, low, high0);
1704 private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
1709 // Be careful with overflows
1710 int mid = low + ((high - low) / 2);
1711 K keyPivot = keys [mid];
1712 IComparable<K> genCmpPivot = keyPivot as IComparable<K>;
1713 IComparable cmpPivot = keyPivot as IComparable;
1716 // Move the walls in
1717 if (comparer != null) {
1718 while (low < high0 && comparer.Compare (keyPivot, keys [low]) > 0)
1720 while (high > low0 && comparer.Compare (keyPivot, keys [high]) < 0)
1723 if (genCmpPivot != null) {
1724 while (low < high0 && genCmpPivot.CompareTo (keys [low]) > 0)
1726 while (high > low0 && genCmpPivot.CompareTo (keys [high]) < 0)
1729 while (low < high0 && cmpPivot.CompareTo (keys [low]) > 0)
1731 while (high > low0 && cmpPivot.CompareTo (keys [high]) < 0)
1737 swap<K, V> (keys, items, low, high);
1745 qsort<K, V> (keys, items, low0, high, comparer);
1747 qsort<K, V> (keys, items, low, high0, comparer);
1750 private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> comparison)
1755 // Be careful with overflows
1756 int mid = low + ((high - low) / 2);
1757 T keyPivot = array [mid];
1760 // Move the walls in
1761 while (low < high0 && comparison (array [low], keyPivot) < 0)
1763 while (high > low0 && comparison (keyPivot, array [high]) < 0)
1767 swap<T> (array, low, high);
1775 qsort<T> (array, low0, high, comparison);
1777 qsort<T> (array, low, high0, comparison);
1780 private static int MoveNullKeysToFront<K, V> (K [] keys, V [] items, int low, int high, bool ensureComparable)
1782 // find first nun-null key
1783 while (low < high && keys [low] == null)
1786 // move null keys to beginning of array,
1787 // ensure that non-null keys implement IComparable
1788 for (int i = low + 1; i <= high; i++) {
1791 swap<K, V> (keys, items, low, i);
1794 if (ensureComparable && !(key is IComparable<K>) && !(key is IComparable)) {
1795 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
1796 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
1803 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
1808 keys [i] = keys [j];
1811 if (items != null) {
1814 items [i] = items [j];
1819 private static void swap<T> (T [] array, int i, int j)
1822 array [i] = array [j];
1826 public void CopyTo (Array array, int index)
1829 throw new ArgumentNullException ("array");
1831 // The order of these exception checks may look strange,
1832 // but that's how the microsoft runtime does it.
1834 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1835 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
1836 throw new ArgumentException ("Destination array was not long " +
1837 "enough. Check destIndex and length, and the array's " +
1840 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1842 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1843 "Value has to be >= 0."));
1845 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
1848 [ComVisible (false)]
1849 public void CopyTo (Array array, long index)
1851 if (index < 0 || index > Int32.MaxValue)
1852 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1853 "Value must be >= 0 and <= Int32.MaxValue."));
1855 CopyTo (array, (int) index);
1858 internal class SimpleEnumerator : IEnumerator, ICloneable
1864 public SimpleEnumerator (Array arrayToEnumerate)
1866 this.enumeratee = arrayToEnumerate;
1867 this.currentpos = -1;
1868 this.length = arrayToEnumerate.Length;
1871 public object Current {
1873 // Exception messages based on MS implementation
1874 if (currentpos < 0 )
1875 throw new InvalidOperationException (Locale.GetText (
1876 "Enumeration has not started."));
1877 if (currentpos >= length)
1878 throw new InvalidOperationException (Locale.GetText (
1879 "Enumeration has already ended"));
1880 // Current should not increase the position. So no ++ over here.
1881 return enumeratee.GetValueImpl (currentpos);
1885 public bool MoveNext()
1887 //The docs say Current should throw an exception if last
1888 //call to MoveNext returned false. This means currentpos
1889 //should be set to length when returning false.
1890 if (currentpos < length)
1892 if(currentpos < length)
1903 public object Clone ()
1905 return MemberwiseClone ();
1909 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1910 public static void Resize<T> (ref T [] array, int newSize)
1912 Resize<T> (ref array, array == null ? 0 : array.Length, newSize);
1915 internal static void Resize<T> (ref T[] array, int length, int newSize)
1918 throw new ArgumentOutOfRangeException ();
1920 if (array == null) {
1921 array = new T [newSize];
1925 if (array.Length == newSize)
1928 T [] a = new T [newSize];
1929 Array.Copy (array, a, Math.Min (newSize, length));
1933 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
1936 throw new ArgumentNullException ("array");
1938 throw new ArgumentNullException ("match");
1940 foreach (T t in array)
1947 public static void ForEach<T> (T [] array, Action <T> action)
1950 throw new ArgumentNullException ("array");
1952 throw new ArgumentNullException ("action");
1954 foreach (T t in array)
1958 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
1961 throw new ArgumentNullException ("array");
1962 if (converter == null)
1963 throw new ArgumentNullException ("converter");
1965 TOutput [] output = new TOutput [array.Length];
1966 for (int i = 0; i < array.Length; i ++)
1967 output [i] = converter (array [i]);
1972 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
1975 throw new ArgumentNullException ("array");
1977 return FindLastIndex<T> (array, 0, array.Length, match);
1980 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
1983 throw new ArgumentNullException ();
1985 return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
1988 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
1991 throw new ArgumentNullException ("array");
1993 throw new ArgumentNullException ("match");
1995 if (startIndex > array.Length || startIndex + count > array.Length)
1996 throw new ArgumentOutOfRangeException ();
1998 for (int i = startIndex + count - 1; i >= startIndex; i--)
1999 if (match (array [i]))
2005 public static int FindIndex<T> (T [] array, Predicate<T> match)
2008 throw new ArgumentNullException ("array");
2010 return FindIndex<T> (array, 0, array.Length, match);
2013 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2016 throw new ArgumentNullException ("array");
2018 return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
2021 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2024 throw new ArgumentNullException ("array");
2027 throw new ArgumentNullException ("match");
2029 if (startIndex > array.Length || startIndex + count > array.Length)
2030 throw new ArgumentOutOfRangeException ();
2032 for (int i = startIndex; i < startIndex + count; i ++)
2033 if (match (array [i]))
2039 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2040 public static int BinarySearch<T> (T [] array, T value)
2043 throw new ArgumentNullException ("array");
2045 return BinarySearch<T> (array, 0, array.Length, value, null);
2048 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2049 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2052 throw new ArgumentNullException ("array");
2054 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2057 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2058 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2060 return BinarySearch<T> (array, index, length, value, null);
2063 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2064 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2067 throw new ArgumentNullException ("array");
2069 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2070 "index is less than the lower bound of array."));
2072 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2073 "Value has to be >= 0."));
2074 // re-ordered to avoid possible integer overflow
2075 if (index > array.Length - length)
2076 throw new ArgumentException (Locale.GetText (
2077 "index and length do not specify a valid range in array."));
2078 if (comparer == null)
2079 comparer = Comparer <T>.Default;
2082 int iMax = index + length - 1;
2085 while (iMin <= iMax) {
2086 // Be careful with overflows
2087 int iMid = iMin + ((iMax - iMin) / 2);
2088 iCmp = comparer.Compare (value, array [iMid]);
2095 iMin = iMid + 1; // compensate for the rounding down
2097 } catch (Exception e) {
2098 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
2104 public static int IndexOf<T> (T [] array, T value)
2107 throw new ArgumentNullException ("array");
2109 return IndexOf<T> (array, value, 0, array.Length);
2112 public static int IndexOf<T> (T [] array, T value, int startIndex)
2115 throw new ArgumentNullException ("array");
2117 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
2120 public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
2123 throw new ArgumentNullException ("array");
2125 // re-ordered to avoid possible integer overflow
2126 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
2127 throw new ArgumentOutOfRangeException ();
2129 int max = startIndex + count;
2130 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
2131 for (int i = startIndex; i < max; i++) {
2132 if (equalityComparer.Equals (array [i], value))
2139 public static int LastIndexOf<T> (T [] array, T value)
2142 throw new ArgumentNullException ("array");
2144 if (array.Length == 0)
2146 return LastIndexOf<T> (array, value, array.Length - 1);
2149 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
2152 throw new ArgumentNullException ("array");
2154 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
2157 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
2160 throw new ArgumentNullException ("array");
2162 if (count < 0 || startIndex < array.GetLowerBound (0) ||
2163 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
2164 throw new ArgumentOutOfRangeException ();
2166 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
2167 for (int i = startIndex; i >= startIndex - count + 1; i--) {
2168 if (equalityComparer.Equals (array [i], value))
2175 public static T [] FindAll<T> (T [] array, Predicate <T> match)
2178 throw new ArgumentNullException ("array");
2181 throw new ArgumentNullException ("match");
2184 T [] d = new T [array.Length];
2185 foreach (T t in array)
2189 Resize <T> (ref d, pos);
2193 public static bool Exists<T> (T [] array, Predicate <T> match)
2196 throw new ArgumentNullException ("array");
2199 throw new ArgumentNullException ("match");
2201 foreach (T t in array)
2207 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
2210 throw new ArgumentNullException ("array");
2211 return new ReadOnlyCollection<T> (new ArrayReadOnlyList<T> (array));
2214 public static T Find<T> (T [] array, Predicate<T> match)
2217 throw new ArgumentNullException ("array");
2220 throw new ArgumentNullException ("match");
2222 foreach (T t in array)
2229 public static T FindLast<T> (T [] array, Predicate <T> match)
2232 throw new ArgumentNullException ("array");
2235 throw new ArgumentNullException ("match");
2237 for (int i = array.Length - 1; i >= 0; i--)
2238 if (match (array [i]))
2244 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
2246 // The constrained copy should guarantee that if there is an exception thrown
2247 // during the copy, the destination array remains unchanged.
2248 // This is related to System.Runtime.Reliability.CER
2249 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
2251 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
2254 class ArrayReadOnlyList<T> : IList<T>
2258 public ArrayReadOnlyList (T [] array)
2263 public T this [int index] {
2265 if (unchecked ((uint) index) >= unchecked ((uint) array.Length))
2266 throw new ArgumentOutOfRangeException ("index");
2267 return array [index];
2269 set { throw ReadOnlyError (); }
2273 get { return array.Length; }
2276 public bool IsReadOnly {
2277 get { return true; }
2280 public void Add (T item)
2282 throw ReadOnlyError ();
2285 public void Clear ()
2287 throw ReadOnlyError ();
2290 public bool Contains (T item)
2292 return Array.IndexOf<T> (array, item) >= 0;
2295 public void CopyTo (T [] array, int index)
2297 this.array.CopyTo (array, index);
2300 IEnumerator IEnumerable.GetEnumerator ()
2302 return GetEnumerator ();
2305 public IEnumerator<T> GetEnumerator ()
2307 for (int i = 0; i < array.Length; i++)
2308 yield return array [i];
2311 public int IndexOf (T item)
2313 return Array.IndexOf<T> (array, item);
2316 public void Insert (int index, T item)
2318 throw ReadOnlyError ();
2321 public bool Remove (T item)
2323 throw ReadOnlyError ();
2326 public void RemoveAt (int index)
2328 throw ReadOnlyError ();
2331 static Exception ReadOnlyError ()
2333 return new NotSupportedException ("This collection is read-only.");