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)
9 // Jeffrey Stedfast (fejj@novell.com)
10 // Marek Safar (marek.safar@gmail.com)
12 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004-2011 Novell, Inc (http://www.novell.com)
14 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
40 using System.Collections.Generic;
41 using System.Collections.ObjectModel;
42 using System.Runtime.ConstrainedExecution;
44 using System.Reflection.Emit;
51 // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
52 public abstract class Array : ICloneable, ICollection, IList, IEnumerable
53 #if NET_4_0 || MOONLIGHT || MOBILE
54 , IStructuralComparable, IStructuralEquatable
63 * These methods are used to implement the implicit generic interfaces
64 * implemented by arrays in NET 2.0.
65 * Only make those methods generic which really need it, to avoid
66 * creating useless instantiations.
68 internal int InternalArray__ICollection_get_Count ()
73 internal bool InternalArray__ICollection_get_IsReadOnly ()
78 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
80 return new InternalEnumerator<T> (this);
83 internal void InternalArray__ICollection_Clear ()
85 throw new NotSupportedException ("Collection is read-only");
88 internal void InternalArray__ICollection_Add<T> (T item)
90 throw new NotSupportedException ("Collection is of a fixed size");
93 internal bool InternalArray__ICollection_Remove<T> (T item)
95 throw new NotSupportedException ("Collection is of a fixed size");
98 internal bool InternalArray__ICollection_Contains<T> (T item)
101 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
103 int length = this.Length;
104 for (int i = 0; i < length; i++) {
106 GetGenericValueImpl (i, out value);
114 if (item.Equals (value))
121 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
124 throw new ArgumentNullException ("array");
126 // The order of these exception checks may look strange,
127 // but that's how the microsoft runtime does it.
129 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
130 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
131 throw new ArgumentException ("Destination array was not long " +
132 "enough. Check destIndex and length, and the array's " +
135 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
137 throw new ArgumentOutOfRangeException (
138 "index", Locale.GetText ("Value has to be >= 0."));
140 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
143 internal void InternalArray__Insert<T> (int index, T item)
145 throw new NotSupportedException ("Collection is of a fixed size");
148 internal void InternalArray__RemoveAt (int index)
150 throw new NotSupportedException ("Collection is of a fixed size");
153 internal int InternalArray__IndexOf<T> (T item)
156 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
158 int length = this.Length;
159 for (int i = 0; i < length; i++) {
161 GetGenericValueImpl (i, out value);
164 return i + this.GetLowerBound (0);
168 if (value.Equals (item))
169 // array index may not be zero-based.
171 return i + this.GetLowerBound (0);
175 // lower bound may be MinValue
176 return this.GetLowerBound (0) - 1;
180 internal T InternalArray__get_Item<T> (int index)
182 if (unchecked ((uint) index) >= unchecked ((uint) Length))
183 throw new ArgumentOutOfRangeException ("index");
186 GetGenericValueImpl (index, out value);
190 internal void InternalArray__set_Item<T> (int index, T item)
192 if (unchecked ((uint) index) >= unchecked ((uint) Length))
193 throw new ArgumentOutOfRangeException ("index");
195 object[] oarray = this as object [];
196 if (oarray != null) {
197 oarray [index] = (object)item;
200 SetGenericValueImpl (index, ref item);
203 // CAUTION! No bounds checking!
204 [MethodImplAttribute (MethodImplOptions.InternalCall)]
205 internal extern void GetGenericValueImpl<T> (int pos, out T value);
207 // CAUTION! No bounds checking!
208 [MethodImplAttribute (MethodImplOptions.InternalCall)]
209 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
211 internal struct InternalEnumerator<T> : IEnumerator<T>
213 const int NOT_STARTED = -2;
215 // this MUST be -1, because we depend on it in move next.
216 // we just decr the size, so, 0 - 1 == FINISHED
217 const int FINISHED = -1;
222 internal InternalEnumerator (Array array)
228 public void Dispose ()
233 public bool MoveNext ()
235 if (idx == NOT_STARTED)
238 return idx != FINISHED && -- idx != FINISHED;
243 if (idx == NOT_STARTED)
244 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
246 throw new InvalidOperationException ("Enumeration already finished");
248 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
252 void IEnumerator.Reset ()
257 object IEnumerator.Current {
266 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
268 int length = this.GetLength (0);
270 for (int i = 1; i < this.Rank; i++) {
271 length *= this.GetLength (i);
278 public long LongLength {
279 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
280 get { return Length; }
284 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
286 return this.GetRank ();
291 object IList.this [int index] {
293 if (unchecked ((uint) index) >= unchecked ((uint) Length))
294 throw new IndexOutOfRangeException ("index");
296 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
297 return GetValueImpl (index);
300 if (unchecked ((uint) index) >= unchecked ((uint) Length))
301 throw new IndexOutOfRangeException ("index");
303 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
304 SetValueImpl (value, index);
308 int IList.Add (object value)
310 throw new NotSupportedException ();
315 Array.Clear (this, this.GetLowerBound (0), this.Length);
318 bool IList.Contains (object value)
321 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
323 int length = this.Length;
324 for (int i = 0; i < length; i++) {
325 if (Object.Equals (this.GetValueImpl (i), value))
331 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
332 int IList.IndexOf (object value)
335 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
337 int length = this.Length;
338 for (int i = 0; i < length; i++) {
339 if (Object.Equals (this.GetValueImpl (i), value))
340 // array index may not be zero-based.
342 return i + this.GetLowerBound (0);
346 // lower bound may be MinValue
347 return this.GetLowerBound (0) - 1;
351 void IList.Insert (int index, object value)
353 throw new NotSupportedException ();
356 void IList.Remove (object value)
358 throw new NotSupportedException ();
361 void IList.RemoveAt (int index)
363 throw new NotSupportedException ();
366 // InternalCall Methods
367 [MethodImplAttribute (MethodImplOptions.InternalCall)]
368 extern int GetRank ();
370 [MethodImplAttribute (MethodImplOptions.InternalCall)]
371 public extern int GetLength (int dimension);
374 public long GetLongLength (int dimension)
376 return GetLength (dimension);
379 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
380 [MethodImplAttribute (MethodImplOptions.InternalCall)]
381 public extern int GetLowerBound (int dimension);
383 [MethodImplAttribute (MethodImplOptions.InternalCall)]
384 public extern object GetValue (params int[] indices);
386 [MethodImplAttribute (MethodImplOptions.InternalCall)]
387 public extern void SetValue (object value, params int[] indices);
389 // CAUTION! No bounds checking!
390 [MethodImplAttribute (MethodImplOptions.InternalCall)]
391 internal extern object GetValueImpl (int pos);
393 // CAUTION! No bounds checking!
394 [MethodImplAttribute (MethodImplOptions.InternalCall)]
395 internal extern void SetValueImpl (object value, int pos);
397 [MethodImplAttribute (MethodImplOptions.InternalCall)]
398 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
400 [MethodImplAttribute (MethodImplOptions.InternalCall)]
401 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
404 int ICollection.Count {
410 public bool IsSynchronized {
416 public object SyncRoot {
422 public bool IsFixedSize {
428 public bool IsReadOnly {
434 public IEnumerator GetEnumerator ()
436 return new SimpleEnumerator (this);
439 #if NET_4_0 || MOONLIGHT || MOBILE
440 int IStructuralComparable.CompareTo (object other, IComparer comparer)
445 Array arr = other as Array;
447 throw new ArgumentException ("Not an array", "other");
449 int len = GetLength (0);
450 if (len != arr.GetLength (0))
451 throw new ArgumentException ("Not of the same length", "other");
454 throw new ArgumentException ("Array must be single dimensional");
457 throw new ArgumentException ("Array must be single dimensional", "other");
459 for (int i = 0; i < len; ++i) {
460 object a = GetValue (i);
461 object b = arr.GetValue (i);
462 int r = comparer.Compare (a, b);
469 bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer)
471 Array o = other as Array;
472 if (o == null || o.Length != Length)
475 if (Object.ReferenceEquals (other, this))
478 for (int i = 0; i < Length; i++) {
479 object this_item = this.GetValue (i);
480 object other_item = o.GetValue (i);
481 if (!comparer.Equals (this_item, other_item))
488 int IStructuralEquatable.GetHashCode (IEqualityComparer comparer)
490 if (comparer == null)
491 throw new ArgumentNullException ("comparer");
494 for (int i = 0; i < Length; i++)
495 hash = ((hash << 7) + hash) ^ comparer.GetHashCode (GetValueImpl (i));
500 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
501 public int GetUpperBound (int dimension)
503 return GetLowerBound (dimension) + GetLength (dimension) - 1;
506 public object GetValue (int index)
509 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
510 if (index < GetLowerBound (0) || index > GetUpperBound (0))
511 throw new IndexOutOfRangeException (Locale.GetText (
512 "Index has to be between upper and lower bound of the array."));
514 return GetValueImpl (index - GetLowerBound (0));
517 public object GetValue (int index1, int index2)
519 int[] ind = {index1, index2};
520 return GetValue (ind);
523 public object GetValue (int index1, int index2, int index3)
525 int[] ind = {index1, index2, index3};
526 return GetValue (ind);
530 public object GetValue (long index)
532 if (index < 0 || index > Int32.MaxValue)
533 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
534 "Value must be >= 0 and <= Int32.MaxValue."));
536 return GetValue ((int) index);
540 public object GetValue (long index1, long index2)
542 if (index1 < 0 || index1 > Int32.MaxValue)
543 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
544 "Value must be >= 0 and <= Int32.MaxValue."));
546 if (index2 < 0 || index2 > Int32.MaxValue)
547 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
548 "Value must be >= 0 and <= Int32.MaxValue."));
550 return GetValue ((int) index1, (int) index2);
554 public object GetValue (long index1, long index2, long index3)
556 if (index1 < 0 || index1 > Int32.MaxValue)
557 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
558 "Value must be >= 0 and <= Int32.MaxValue."));
560 if (index2 < 0 || index2 > Int32.MaxValue)
561 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
562 "Value must be >= 0 and <= Int32.MaxValue."));
564 if (index3 < 0 || index3 > Int32.MaxValue)
565 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
566 "Value must be >= 0 and <= Int32.MaxValue."));
568 return GetValue ((int) index1, (int) index2, (int) index3);
572 public void SetValue (object value, long index)
574 if (index < 0 || index > Int32.MaxValue)
575 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
576 "Value must be >= 0 and <= Int32.MaxValue."));
578 SetValue (value, (int) index);
582 public void SetValue (object value, long index1, long index2)
584 if (index1 < 0 || index1 > Int32.MaxValue)
585 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
586 "Value must be >= 0 and <= Int32.MaxValue."));
588 if (index2 < 0 || index2 > Int32.MaxValue)
589 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
590 "Value must be >= 0 and <= Int32.MaxValue."));
592 int[] ind = {(int) index1, (int) index2};
593 SetValue (value, ind);
597 public void SetValue (object value, long index1, long index2, long index3)
599 if (index1 < 0 || index1 > Int32.MaxValue)
600 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
601 "Value must be >= 0 and <= Int32.MaxValue."));
603 if (index2 < 0 || index2 > Int32.MaxValue)
604 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
605 "Value must be >= 0 and <= Int32.MaxValue."));
607 if (index3 < 0 || index3 > Int32.MaxValue)
608 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
609 "Value must be >= 0 and <= Int32.MaxValue."));
611 int[] ind = {(int) index1, (int) index2, (int) index3};
612 SetValue (value, ind);
615 public void SetValue (object value, int index)
618 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
619 if (index < GetLowerBound (0) || index > GetUpperBound (0))
620 throw new IndexOutOfRangeException (Locale.GetText (
621 "Index has to be >= lower bound and <= upper bound of the array."));
623 SetValueImpl (value, index - GetLowerBound (0));
626 public void SetValue (object value, int index1, int index2)
628 int[] ind = {index1, index2};
629 SetValue (value, ind);
632 public void SetValue (object value, int index1, int index2, int index3)
634 int[] ind = {index1, index2, index3};
635 SetValue (value, ind);
638 public static Array CreateInstance (Type elementType, int length)
640 int[] lengths = {length};
642 return CreateInstance (elementType, lengths);
645 public static Array CreateInstance (Type elementType, int length1, int length2)
647 int[] lengths = {length1, length2};
649 return CreateInstance (elementType, lengths);
652 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
654 int[] lengths = {length1, length2, length3};
656 return CreateInstance (elementType, lengths);
659 public static Array CreateInstance (Type elementType, params int[] lengths)
661 if (elementType == null)
662 throw new ArgumentNullException ("elementType");
664 throw new ArgumentNullException ("lengths");
666 if (lengths.Length > 255)
667 throw new TypeLoadException ();
671 elementType = elementType.UnderlyingSystemType;
672 if (!elementType.IsSystemType)
673 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
674 if (elementType.Equals (typeof (void)))
675 throw new NotSupportedException ("Array type can not be void");
676 if (elementType.ContainsGenericParameters)
677 throw new NotSupportedException ("Array type can not be an open generic type");
678 #if !FULL_AOT_RUNTIME
679 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
680 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
683 return CreateInstanceImpl (elementType, lengths, bounds);
686 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
688 if (elementType == null)
689 throw new ArgumentNullException ("elementType");
691 throw new ArgumentNullException ("lengths");
692 if (lowerBounds == null)
693 throw new ArgumentNullException ("lowerBounds");
695 elementType = elementType.UnderlyingSystemType;
696 if (!elementType.IsSystemType)
697 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
698 if (elementType.Equals (typeof (void)))
699 throw new NotSupportedException ("Array type can not be void");
700 if (elementType.ContainsGenericParameters)
701 throw new NotSupportedException ("Array type can not be an open generic type");
703 if (lengths.Length < 1)
704 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
706 if (lengths.Length != lowerBounds.Length)
707 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
709 for (int j = 0; j < lowerBounds.Length; j ++) {
711 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
712 "Each value has to be >= 0."));
713 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
714 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
715 "Length + bound must not exceed Int32.MaxValue."));
718 if (lengths.Length > 255)
719 throw new TypeLoadException ();
721 return CreateInstanceImpl (elementType, lengths, lowerBounds);
724 static int [] GetIntArray (long [] values)
726 int len = values.Length;
727 int [] ints = new int [len];
728 for (int i = 0; i < len; i++) {
729 long current = values [i];
730 if (current < 0 || current > (long) Int32.MaxValue)
731 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
732 "Each value has to be >= 0 and <= Int32.MaxValue."));
734 ints [i] = (int) current;
739 public static Array CreateInstance (Type elementType, params long [] lengths)
742 throw new ArgumentNullException ("lengths");
743 return CreateInstance (elementType, GetIntArray (lengths));
747 public object GetValue (params long [] indices)
750 throw new ArgumentNullException ("indices");
751 return GetValue (GetIntArray (indices));
755 public void SetValue (object value, params long [] indices)
758 throw new ArgumentNullException ("indices");
759 SetValue (value, GetIntArray (indices));
762 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
763 public static int BinarySearch (Array array, object value)
766 throw new ArgumentNullException ("array");
772 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
774 if (array.Length == 0)
777 if (!(value is IComparable))
778 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
780 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
783 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
784 public static int BinarySearch (Array array, object value, IComparer comparer)
787 throw new ArgumentNullException ("array");
790 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
792 if (array.Length == 0)
795 if ((comparer == null) && (value != null) && !(value is IComparable))
796 throw new ArgumentException (Locale.GetText (
797 "comparer is null and value does not support IComparable."));
799 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
802 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
803 public static int BinarySearch (Array array, int index, int length, object value)
806 throw new ArgumentNullException ("array");
809 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
811 if (index < array.GetLowerBound (0))
812 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
813 "index is less than the lower bound of array."));
815 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
816 "Value has to be >= 0."));
817 // re-ordered to avoid possible integer overflow
818 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
819 throw new ArgumentException (Locale.GetText (
820 "index and length do not specify a valid range in array."));
822 if (array.Length == 0)
825 if ((value != null) && (!(value is IComparable)))
826 throw new ArgumentException (Locale.GetText (
827 "value does not support IComparable"));
829 return DoBinarySearch (array, index, length, value, null);
832 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
833 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
836 throw new ArgumentNullException ("array");
839 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
841 if (index < array.GetLowerBound (0))
842 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
843 "index is less than the lower bound of array."));
845 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
846 "Value has to be >= 0."));
847 // re-ordered to avoid possible integer overflow
848 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
849 throw new ArgumentException (Locale.GetText (
850 "index and length do not specify a valid range in array."));
852 if (array.Length == 0)
855 if ((comparer == null) && (value != null) && !(value is IComparable))
856 throw new ArgumentException (Locale.GetText (
857 "comparer is null and value does not support IComparable."));
859 return DoBinarySearch (array, index, length, value, comparer);
862 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
864 // cache this in case we need it
865 if (comparer == null)
866 comparer = Comparer.Default;
869 // Comment from Tum (tum@veridicus.com):
870 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
871 int iMax = index + length - 1;
874 while (iMin <= iMax) {
875 // Be careful with overflow
876 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
877 int iMid = iMin + ((iMax - iMin) / 2);
878 object elt = array.GetValueImpl (iMid);
880 iCmp = comparer.Compare (elt, value);
887 iMin = iMid + 1; // compensate for the rounding down
890 catch (Exception e) {
891 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
897 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
898 public static void Clear (Array array, int index, int length)
901 throw new ArgumentNullException ("array");
903 throw new IndexOutOfRangeException ("length < 0");
905 int low = array.GetLowerBound (0);
907 throw new IndexOutOfRangeException ("index < lower bound");
910 // re-ordered to avoid possible integer overflow
911 if (index > array.Length - length)
912 throw new IndexOutOfRangeException ("index + length > size");
914 ClearInternal (array, index, length);
917 [MethodImplAttribute (MethodImplOptions.InternalCall)]
918 static extern void ClearInternal (Array a, int index, int count);
920 [MethodImplAttribute (MethodImplOptions.InternalCall)]
921 public extern object Clone ();
923 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
924 public static void Copy (Array sourceArray, Array destinationArray, int length)
926 // need these checks here because we are going to use
927 // GetLowerBound() on source and dest.
928 if (sourceArray == null)
929 throw new ArgumentNullException ("sourceArray");
931 if (destinationArray == null)
932 throw new ArgumentNullException ("destinationArray");
934 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
935 destinationArray.GetLowerBound (0), length);
938 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
939 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
941 if (sourceArray == null)
942 throw new ArgumentNullException ("sourceArray");
944 if (destinationArray == null)
945 throw new ArgumentNullException ("destinationArray");
948 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
949 "Value has to be >= 0."));;
952 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
953 "Value has to be >= 0."));;
955 if (destinationIndex < 0)
956 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
957 "Value has to be >= 0."));;
959 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
962 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
963 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
965 // re-ordered to avoid possible integer overflow
966 if (source_pos > sourceArray.Length - length)
967 throw new ArgumentException ("length");
969 if (dest_pos > destinationArray.Length - length) {
970 string msg = "Destination array was not long enough. Check " +
971 "destIndex and length, and the array's lower bounds";
972 throw new ArgumentException (msg, string.Empty);
975 if (sourceArray.Rank != destinationArray.Rank)
976 throw new RankException (Locale.GetText ("Arrays must be of same size."));
978 Type src_type = sourceArray.GetType ().GetElementType ();
979 Type dst_type = destinationArray.GetType ().GetElementType ();
981 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
982 for (int i = 0; i < length; i++) {
983 Object srcval = sourceArray.GetValueImpl (source_pos + i);
986 destinationArray.SetValueImpl (srcval, dest_pos + i);
988 if (src_type.Equals (typeof (Object)))
989 throw new InvalidCastException ();
991 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
992 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
997 for (int i = length - 1; i >= 0; i--) {
998 Object srcval = sourceArray.GetValueImpl (source_pos + i);
1001 destinationArray.SetValueImpl (srcval, dest_pos + i);
1003 if (src_type.Equals (typeof (Object)))
1004 throw new InvalidCastException ();
1006 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
1007 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
1013 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1014 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1015 long destinationIndex, long length)
1017 if (sourceArray == null)
1018 throw new ArgumentNullException ("sourceArray");
1020 if (destinationArray == null)
1021 throw new ArgumentNullException ("destinationArray");
1023 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1024 throw new ArgumentOutOfRangeException ("sourceIndex",
1025 Locale.GetText ("Must be in the Int32 range."));
1027 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1028 throw new ArgumentOutOfRangeException ("destinationIndex",
1029 Locale.GetText ("Must be in the Int32 range."));
1031 if (length < 0 || length > Int32.MaxValue)
1032 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1033 "Value must be >= 0 and <= Int32.MaxValue."));
1035 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1038 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1039 public static void Copy (Array sourceArray, Array destinationArray, long length)
1041 if (length < 0 || length > Int32.MaxValue)
1042 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1043 "Value must be >= 0 and <= Int32.MaxValue."));
1045 Copy (sourceArray, destinationArray, (int) length);
1048 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1049 public static int IndexOf (Array array, object value)
1052 throw new ArgumentNullException ("array");
1054 return IndexOf (array, value, 0, array.Length);
1057 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1058 public static int IndexOf (Array array, object value, int startIndex)
1061 throw new ArgumentNullException ("array");
1063 return IndexOf (array, value, startIndex, array.Length - startIndex);
1066 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1067 public static int IndexOf (Array array, object value, int startIndex, int count)
1070 throw new ArgumentNullException ("array");
1073 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1075 // re-ordered to avoid possible integer overflow
1076 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1077 throw new ArgumentOutOfRangeException ();
1079 int max = startIndex + count;
1080 for (int i = startIndex; i < max; i++) {
1081 if (Object.Equals (array.GetValueImpl (i), value))
1085 return array.GetLowerBound (0) - 1;
1088 public void Initialize()
1090 //FIXME: We would like to find a compiler that uses
1091 // this method. It looks like this method do nothing
1092 // in C# so no exception is trown by the moment.
1095 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1096 public static int LastIndexOf (Array array, object value)
1099 throw new ArgumentNullException ("array");
1101 if (array.Length == 0)
1102 return array.GetLowerBound (0) - 1;
1103 return LastIndexOf (array, value, array.Length - 1);
1106 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1107 public static int LastIndexOf (Array array, object value, int startIndex)
1110 throw new ArgumentNullException ("array");
1112 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1115 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1116 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1119 throw new ArgumentNullException ("array");
1122 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1124 int lb = array.GetLowerBound (0);
1125 // Empty arrays do not throw ArgumentOutOfRangeException
1126 if (array.Length == 0)
1129 if (count < 0 || startIndex < lb ||
1130 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1131 throw new ArgumentOutOfRangeException ();
1133 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1134 if (Object.Equals (array.GetValueImpl (i), value))
1141 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1142 public static void Reverse (Array array)
1145 throw new ArgumentNullException ("array");
1147 Reverse (array, array.GetLowerBound (0), array.Length);
1150 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1151 public static void Reverse (Array array, int index, int length)
1154 throw new ArgumentNullException ("array");
1157 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1159 if (index < array.GetLowerBound (0) || length < 0)
1160 throw new ArgumentOutOfRangeException ();
1162 // re-ordered to avoid possible integer overflow
1163 if (index > array.GetUpperBound (0) + 1 - length)
1164 throw new ArgumentException ();
1166 int end = index + length - 1;
1167 var et = array.GetType ().GetElementType ();
1168 switch (Type.GetTypeCode (et)) {
1169 case TypeCode.Boolean:
1170 while (index < end) {
1173 array.GetGenericValueImpl (index, out a);
1174 array.GetGenericValueImpl (end, out b);
1175 array.SetGenericValueImpl (index, ref b);
1176 array.SetGenericValueImpl (end, ref a);
1183 case TypeCode.SByte:
1184 while (index < end) {
1187 array.GetGenericValueImpl (index, out a);
1188 array.GetGenericValueImpl (end, out b);
1189 array.SetGenericValueImpl (index, ref b);
1190 array.SetGenericValueImpl (end, ref a);
1196 case TypeCode.Int16:
1197 case TypeCode.UInt16:
1199 while (index < end) {
1202 array.GetGenericValueImpl (index, out a);
1203 array.GetGenericValueImpl (end, out b);
1204 array.SetGenericValueImpl (index, ref b);
1205 array.SetGenericValueImpl (end, ref a);
1211 case TypeCode.Int32:
1212 case TypeCode.UInt32:
1213 case TypeCode.Single:
1214 while (index < end) {
1217 array.GetGenericValueImpl (index, out a);
1218 array.GetGenericValueImpl (end, out b);
1219 array.SetGenericValueImpl (index, ref b);
1220 array.SetGenericValueImpl (end, ref a);
1226 case TypeCode.Int64:
1227 case TypeCode.UInt64:
1228 case TypeCode.Double:
1229 while (index < end) {
1232 array.GetGenericValueImpl (index, out a);
1233 array.GetGenericValueImpl (end, out b);
1234 array.SetGenericValueImpl (index, ref b);
1235 array.SetGenericValueImpl (end, ref a);
1241 case TypeCode.Decimal:
1242 while (index < end) {
1245 array.GetGenericValueImpl (index, out a);
1246 array.GetGenericValueImpl (end, out b);
1247 array.SetGenericValueImpl (index, ref b);
1248 array.SetGenericValueImpl (end, ref a);
1254 case TypeCode.String:
1255 case TypeCode.Object:
1256 while (index < end) {
1259 array.GetGenericValueImpl (index, out a);
1260 array.GetGenericValueImpl (end, out b);
1261 array.SetGenericValueImpl (index, ref b);
1262 array.SetGenericValueImpl (end, ref a);
1268 if (array is object[])
1269 goto case TypeCode.Object;
1271 // Very slow fallback
1272 while (index < end) {
1273 object val = array.GetValueImpl (index);
1274 array.SetValueImpl (array.GetValueImpl (end), index);
1275 array.SetValueImpl (val, end);
1284 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1285 public static void Sort (Array array)
1287 Sort (array, (IComparer)null);
1290 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1291 public static void Sort (Array keys, Array items)
1293 Sort (keys, items, (IComparer)null);
1296 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1297 public static void Sort (Array array, IComparer comparer)
1300 throw new ArgumentNullException ("array");
1303 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1305 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1308 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1309 public static void Sort (Array array, int index, int length)
1311 Sort (array, index, length, (IComparer)null);
1314 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1315 public static void Sort (Array keys, Array items, IComparer comparer)
1317 if (items == null) {
1318 Sort (keys, comparer);
1323 throw new ArgumentNullException ("keys");
1325 if (keys.Rank > 1 || items.Rank > 1)
1326 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1328 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1331 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1332 public static void Sort (Array keys, Array items, int index, int length)
1334 Sort (keys, items, index, length, (IComparer)null);
1337 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1338 public static void Sort (Array array, int index, int length, IComparer comparer)
1341 throw new ArgumentNullException ("array");
1344 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1346 if (index < array.GetLowerBound (0))
1347 throw new ArgumentOutOfRangeException ("index");
1350 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1351 "Value has to be >= 0."));
1353 if (array.Length - (array.GetLowerBound (0) + index) < length)
1354 throw new ArgumentException ();
1356 SortImpl (array, null, index, length, comparer);
1359 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1360 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1362 if (items == null) {
1363 Sort (keys, index, length, comparer);
1368 throw new ArgumentNullException ("keys");
1370 if (keys.Rank > 1 || items.Rank > 1)
1371 throw new RankException ();
1373 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1374 throw new ArgumentException ();
1376 if (index < keys.GetLowerBound (0))
1377 throw new ArgumentOutOfRangeException ("index");
1380 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1381 "Value has to be >= 0."));
1383 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1384 throw new ArgumentException ();
1386 SortImpl (keys, items, index, length, comparer);
1389 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1395 int high = index + length - 1;
1397 #if !BOOTSTRAP_BASIC
1398 if (comparer == null && items is object[]) {
1399 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1400 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1401 case TypeCode.Int32:
1402 qsort (keys as Int32[], items as object[], low, high);
1404 case TypeCode.Int64:
1405 qsort (keys as Int64[], items as object[], low, high);
1408 qsort (keys as byte[], items as object[], low, high);
1411 qsort (keys as char[], items as object[], low, high);
1413 case TypeCode.DateTime:
1414 qsort (keys as DateTime[], items as object[], low, high);
1416 case TypeCode.Decimal:
1417 qsort (keys as decimal[], items as object[], low, high);
1419 case TypeCode.Double:
1420 qsort (keys as double[], items as object[], low, high);
1422 case TypeCode.Int16:
1423 qsort (keys as Int16[], items as object[], low, high);
1425 case TypeCode.SByte:
1426 qsort (keys as SByte[], items as object[], low, high);
1428 case TypeCode.Single:
1429 qsort (keys as Single[], items as object[], low, high);
1431 case TypeCode.UInt16:
1432 qsort (keys as UInt16[], items as object[], low, high);
1434 case TypeCode.UInt32:
1435 qsort (keys as UInt32[], items as object[], low, high);
1437 case TypeCode.UInt64:
1438 qsort (keys as UInt64[], items as object[], low, high);
1446 if (comparer == null)
1447 CheckComparerAvailable (keys, low, high);
1450 qsort (keys, items, low, high, comparer);
1451 } catch (Exception e) {
1452 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1461 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1466 if (comparer != null) {
1467 if (comparer.Compare (v1, v0) < 0) {
1468 swap (keys, items, lo, hi);
1475 } else if (v0 != null) {
1476 cmp = v1 as IComparable;
1478 if (v1 == null || cmp.CompareTo (v0) < 0) {
1479 swap (keys, items, lo, hi);
1491 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1493 QSortStack[] stack = new QSortStack[32];
1494 const int QSORT_THRESHOLD = 7;
1495 int high, low, mid, i, k;
1500 // initialize our stack
1501 stack[0].high = high0;
1502 stack[0].low = low0;
1507 high = stack[sp].high;
1508 low = stack[sp].low;
1510 if ((low + QSORT_THRESHOLD) > high) {
1511 // switch to insertion sort
1512 for (i = low + 1; i <= high; i++) {
1513 for (k = i; k > low; k--) {
1514 lo = keys.GetValueImpl (k - 1);
1515 hi = keys.GetValueImpl (k);
1516 if (comparer != null) {
1517 if (comparer.Compare (hi, lo) >= 0)
1524 cmp = hi as IComparable;
1525 if (cmp.CompareTo (lo) >= 0)
1530 swap (keys, items, k - 1, k);
1537 // calculate the middle element
1538 mid = low + ((high - low) / 2);
1541 key = keys.GetValueImpl (mid);
1542 hi = keys.GetValueImpl (high);
1543 lo = keys.GetValueImpl (low);
1545 // once we re-order the low, mid, and high elements to be in
1546 // ascending order, we'll use mid as our pivot.
1547 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1548 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1549 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1551 cmp = key as IComparable;
1553 // since we've already guaranteed that lo <= mid and mid <= hi,
1554 // we can skip comparing them again.
1559 // Move the walls in
1560 if (comparer != null) {
1561 // find the first element with a value >= pivot value
1562 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
1565 // find the last element with a value <= pivot value
1566 while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1568 } else if (cmp != null) {
1569 // find the first element with a value >= pivot value
1570 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
1573 // find the last element with a value <= pivot value
1574 while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1577 // This has the effect of moving the null values to the front if comparer is null
1578 while (i < k && keys.GetValueImpl (i) == null)
1581 while (k > i && keys.GetValueImpl (k) != null)
1588 swap (keys, items, i, k);
1594 // push our partitions onto the stack, largest first
1595 // (to make sure we don't run out of stack space)
1596 if ((high - k) >= (k - low)) {
1597 if ((k + 1) < high) {
1598 stack[sp].high = high;
1603 if ((k - 1) > low) {
1605 stack[sp].low = low;
1609 if ((k - 1) > low) {
1611 stack[sp].low = low;
1615 if ((k + 1) < high) {
1616 stack[sp].high = high;
1624 private static void CheckComparerAvailable (Array keys, int low, int high)
1626 // move null keys to beginning of array,
1627 // ensure that non-null keys implement IComparable
1628 for (int i = 0; i < high; i++) {
1629 object obj = keys.GetValueImpl (i);
1632 if (!(obj is IComparable)) {
1633 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1634 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1639 private static void swap (Array keys, Array items, int i, int j)
1641 object tmp = keys.GetValueImpl (i);
1642 keys.SetValueImpl (keys.GetValueImpl (j), i);
1643 keys.SetValueImpl (tmp, j);
1645 if (items != null) {
1646 tmp = items.GetValueImpl (i);
1647 items.SetValueImpl (items.GetValueImpl (j), i);
1648 items.SetValueImpl (tmp, j);
1652 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1653 public static void Sort<T> (T [] array)
1655 Sort<T> (array, (IComparer<T>)null);
1658 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1659 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1661 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1664 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1665 public static void Sort<T> (T [] array, IComparer<T> comparer)
1668 throw new ArgumentNullException ("array");
1670 SortImpl<T> (array, 0, array.Length, comparer);
1673 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1674 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1676 if (items == null) {
1677 Sort<TKey> (keys, comparer);
1682 throw new ArgumentNullException ("keys");
1684 if (keys.Length != items.Length)
1685 throw new ArgumentException ("Length of keys and items does not match.");
1687 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1690 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1691 public static void Sort<T> (T [] array, int index, int length)
1693 Sort<T> (array, index, length, (IComparer<T>)null);
1696 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1697 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1699 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1702 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1703 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1706 throw new ArgumentNullException ("array");
1709 throw new ArgumentOutOfRangeException ("index");
1712 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1713 "Value has to be >= 0."));
1715 if (index + length > array.Length)
1716 throw new ArgumentException ();
1718 SortImpl<T> (array, index, length, comparer);
1721 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1722 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1724 if (items == null) {
1725 Sort<TKey> (keys, index, length, comparer);
1730 throw new ArgumentNullException ("keys");
1733 throw new ArgumentOutOfRangeException ("index");
1736 throw new ArgumentOutOfRangeException ("length");
1738 if (items.Length - index < length || keys.Length - index < length)
1739 throw new ArgumentException ();
1741 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1744 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1746 if (keys.Length <= 1)
1750 int high = index + length - 1;
1753 // Check for value types which can be sorted without Compare () method
1755 if (comparer == null) {
1756 /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
1757 #if FULL_AOT_RUNTIME
1758 #if !BOOTSTRAP_BASIC
1759 switch (Type.GetTypeCode (typeof (TKey))) {
1760 case TypeCode.Int32:
1761 qsort (keys as Int32[], items, low, high);
1763 case TypeCode.Int64:
1764 qsort (keys as Int64[], items, low, high);
1767 qsort (keys as byte[], items, low, high);
1770 qsort (keys as char[], items, low, high);
1772 case TypeCode.DateTime:
1773 qsort (keys as DateTime[], items, low, high);
1775 case TypeCode.Decimal:
1776 qsort (keys as decimal[], items, low, high);
1778 case TypeCode.Double:
1779 qsort (keys as double[], items, low, high);
1781 case TypeCode.Int16:
1782 qsort (keys as Int16[], items, low, high);
1784 case TypeCode.SByte:
1785 qsort (keys as SByte[], items, low, high);
1787 case TypeCode.Single:
1788 qsort (keys as Single[], items, low, high);
1790 case TypeCode.UInt16:
1791 qsort (keys as UInt16[], items, low, high);
1793 case TypeCode.UInt32:
1794 qsort (keys as UInt32[], items, low, high);
1796 case TypeCode.UInt64:
1797 qsort (keys as UInt64[], items, low, high);
1802 // Using Comparer<TKey> adds a small overload, but with value types it
1803 // helps us to not box them.
1804 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1805 typeof (TKey).IsValueType)
1806 comparer = Comparer<TKey>.Default;
1809 if (comparer == null)
1810 CheckComparerAvailable<TKey> (keys, low, high);
1813 qsort (keys, items, low, high, comparer);
1814 //} catch (Exception e) {
1815 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1819 // Specialized version for items==null
1820 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1822 if (keys.Length <= 1)
1826 int high = index + length - 1;
1829 // Check for value types which can be sorted without Compare () method
1831 if (comparer == null) {
1832 #if !BOOTSTRAP_BASIC
1833 switch (Type.GetTypeCode (typeof (TKey))) {
1834 case TypeCode.Int32:
1835 qsort (keys as Int32[], low, high);
1837 case TypeCode.Int64:
1838 qsort (keys as Int64[], low, high);
1841 qsort (keys as byte[], low, high);
1844 qsort (keys as char[], low, high);
1846 case TypeCode.DateTime:
1847 qsort (keys as DateTime[], low, high);
1849 case TypeCode.Decimal:
1850 qsort (keys as decimal[], low, high);
1852 case TypeCode.Double:
1853 qsort (keys as double[], low, high);
1855 case TypeCode.Int16:
1856 qsort (keys as Int16[], low, high);
1858 case TypeCode.SByte:
1859 qsort (keys as SByte[], low, high);
1861 case TypeCode.Single:
1862 qsort (keys as Single[], low, high);
1864 case TypeCode.UInt16:
1865 qsort (keys as UInt16[], low, high);
1867 case TypeCode.UInt32:
1868 qsort (keys as UInt32[], low, high);
1870 case TypeCode.UInt64:
1871 qsort (keys as UInt64[], low, high);
1875 // Using Comparer<TKey> adds a small overload, but with value types it
1876 // helps us to not box them.
1877 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1878 typeof (TKey).IsValueType)
1879 comparer = Comparer<TKey>.Default;
1882 if (comparer == null)
1883 CheckComparerAvailable<TKey> (keys, low, high);
1886 qsort<TKey> (keys, low, high, comparer);
1887 //} catch (Exception e) {
1888 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1892 public static void Sort<T> (T [] array, Comparison<T> comparison)
1895 throw new ArgumentNullException ("array");
1897 if (comparison == null)
1898 throw new ArgumentNullException ("comparison");
1900 SortImpl<T> (array, array.Length, comparison);
1903 // used by List<T>.Sort (Comparison <T>)
1904 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1911 int high0 = length - 1;
1912 qsort<T> (array, low0, high0, comparison);
1913 } catch (InvalidOperationException) {
1915 } catch (Exception e) {
1916 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1920 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1922 if (keys[lo] != null) {
1923 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1924 swap (keys, items, lo, hi);
1932 // Specialized version for items==null
1933 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1935 if (keys[lo] != null) {
1936 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1937 swap (keys, lo, hi);
1945 private static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1947 QSortStack[] stack = new QSortStack[32];
1948 const int QSORT_THRESHOLD = 7;
1949 int high, low, mid, i, k;
1953 // initialize our stack
1954 stack[0].high = high0;
1955 stack[0].low = low0;
1960 high = stack[sp].high;
1961 low = stack[sp].low;
1963 if ((low + QSORT_THRESHOLD) > high) {
1964 // switch to insertion sort
1965 for (i = low + 1; i <= high; i++) {
1966 for (k = i; k > low; k--) {
1967 // if keys[k] >= keys[k-1], break
1968 if (keys[k-1] == null)
1971 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
1974 swap (keys, items, k - 1, k);
1981 // calculate the middle element
1982 mid = low + ((high - low) / 2);
1984 // once we re-order the lo, mid, and hi elements to be in
1985 // ascending order, we'll use mid as our pivot.
1986 QSortArrange<T, U> (keys, items, low, mid);
1987 if (QSortArrange<T, U> (keys, items, mid, high))
1988 QSortArrange<T, U> (keys, items, low, mid);
1992 // since we've already guaranteed that lo <= mid and mid <= hi,
1993 // we can skip comparing them again
1999 // find the first element with a value >= pivot value
2000 while (i < k && key.CompareTo (keys[i]) > 0)
2003 // find the last element with a value <= pivot value
2004 while (k > i && key.CompareTo (keys[k]) < 0)
2007 while (i < k && keys[i] == null)
2010 while (k > i && keys[k] != null)
2017 swap (keys, items, i, k);
2023 // push our partitions onto the stack, largest first
2024 // (to make sure we don't run out of stack space)
2025 if ((high - k) >= (k - low)) {
2026 if ((k + 1) < high) {
2027 stack[sp].high = high;
2032 if ((k - 1) > low) {
2034 stack[sp].low = low;
2038 if ((k - 1) > low) {
2040 stack[sp].low = low;
2044 if ((k + 1) < high) {
2045 stack[sp].high = high;
2053 // Specialized version for items==null
2054 private static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2056 QSortStack[] stack = new QSortStack[32];
2057 const int QSORT_THRESHOLD = 7;
2058 int high, low, mid, i, k;
2062 // initialize our stack
2063 stack[0].high = high0;
2064 stack[0].low = low0;
2069 high = stack[sp].high;
2070 low = stack[sp].low;
2072 if ((low + QSORT_THRESHOLD) > high) {
2073 // switch to insertion sort
2074 for (i = low + 1; i <= high; i++) {
2075 for (k = i; k > low; k--) {
2076 // if keys[k] >= keys[k-1], break
2077 if (keys[k-1] == null)
2080 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2083 swap (keys, k - 1, k);
2090 // calculate the middle element
2091 mid = low + ((high - low) / 2);
2093 // once we re-order the lo, mid, and hi elements to be in
2094 // ascending order, we'll use mid as our pivot.
2095 QSortArrange<T> (keys, low, mid);
2096 if (QSortArrange<T> (keys, mid, high))
2097 QSortArrange<T> (keys, low, mid);
2101 // since we've already guaranteed that lo <= mid and mid <= hi,
2102 // we can skip comparing them again
2108 // find the first element with a value >= pivot value
2109 while (i < k && key.CompareTo (keys[i]) > 0)
2112 // find the last element with a value <= pivot value
2113 while (k >= i && key.CompareTo (keys[k]) < 0)
2116 while (i < k && keys[i] == null)
2119 while (k >= i && keys[k] != null)
2132 // push our partitions onto the stack, largest first
2133 // (to make sure we don't run out of stack space)
2134 if ((high - k) >= (k - low)) {
2135 if ((k + 1) < high) {
2136 stack[sp].high = high;
2141 if ((k - 1) > low) {
2143 stack[sp].low = low;
2147 if ((k - 1) > low) {
2149 stack[sp].low = low;
2153 if ((k + 1) < high) {
2154 stack[sp].high = high;
2162 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2164 IComparable<K> gcmp;
2167 if (comparer != null) {
2168 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2169 swap<K, V> (keys, items, lo, hi);
2172 } else if (keys[lo] != null) {
2173 if (keys[hi] == null) {
2174 swap<K, V> (keys, items, lo, hi);
2178 gcmp = keys[hi] as IComparable<K>;
2180 if (gcmp.CompareTo (keys[lo]) < 0) {
2181 swap<K, V> (keys, items, lo, hi);
2188 cmp = keys[hi] as IComparable;
2190 if (cmp.CompareTo (keys[lo]) < 0) {
2191 swap<K, V> (keys, items, lo, hi);
2202 // Specialized version for items==null
2203 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2205 IComparable<K> gcmp;
2208 if (comparer != null) {
2209 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2210 swap<K> (keys, lo, hi);
2213 } else if (keys[lo] != null) {
2214 if (keys[hi] == null) {
2215 swap<K> (keys, lo, hi);
2219 gcmp = keys[hi] as IComparable<K>;
2221 if (gcmp.CompareTo (keys[lo]) < 0) {
2222 swap<K> (keys, lo, hi);
2229 cmp = keys[hi] as IComparable;
2231 if (cmp.CompareTo (keys[lo]) < 0) {
2232 swap<K> (keys, lo, hi);
2243 private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2245 QSortStack[] stack = new QSortStack[32];
2246 const int QSORT_THRESHOLD = 7;
2247 int high, low, mid, i, k;
2248 IComparable<K> gcmp;
2253 // initialize our stack
2254 stack[0].high = high0;
2255 stack[0].low = low0;
2260 high = stack[sp].high;
2261 low = stack[sp].low;
2263 if ((low + QSORT_THRESHOLD) > high) {
2264 // switch to insertion sort
2265 for (i = low + 1; i <= high; i++) {
2266 for (k = i; k > low; k--) {
2267 // if keys[k] >= keys[k-1], break
2268 if (comparer != null) {
2269 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2272 if (keys[k-1] == null)
2275 if (keys[k] != null) {
2276 gcmp = keys[k] as IComparable<K>;
2277 cmp = keys[k] as IComparable;
2279 if (gcmp.CompareTo (keys[k-1]) >= 0)
2282 if (cmp.CompareTo (keys[k-1]) >= 0)
2288 swap<K, V> (keys, items, k - 1, k);
2295 // calculate the middle element
2296 mid = low + ((high - low) / 2);
2298 // once we re-order the low, mid, and high elements to be in
2299 // ascending order, we'll use mid as our pivot.
2300 QSortArrange<K, V> (keys, items, low, mid, comparer);
2301 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2302 QSortArrange<K, V> (keys, items, low, mid, comparer);
2305 gcmp = key as IComparable<K>;
2306 cmp = key as IComparable;
2308 // since we've already guaranteed that lo <= mid and mid <= hi,
2309 // we can skip comparing them again.
2314 // Move the walls in
2315 if (comparer != null) {
2316 // find the first element with a value >= pivot value
2317 while (i < k && comparer.Compare (key, keys[i]) > 0)
2320 // find the last element with a value <= pivot value
2321 while (k > i && comparer.Compare (key, keys[k]) < 0)
2325 // find the first element with a value >= pivot value
2326 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2329 // find the last element with a value <= pivot value
2330 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2332 } else if (cmp != null) {
2333 // find the first element with a value >= pivot value
2334 while (i < k && cmp.CompareTo (keys[i]) > 0)
2337 // find the last element with a value <= pivot value
2338 while (k > i && cmp.CompareTo (keys[k]) < 0)
2341 while (i < k && keys[i] == null)
2344 while (k > i && keys[k] != null)
2352 swap<K, V> (keys, items, i, k);
2358 // push our partitions onto the stack, largest first
2359 // (to make sure we don't run out of stack space)
2360 if ((high - k) >= (k - low)) {
2361 if ((k + 1) < high) {
2362 stack[sp].high = high;
2367 if ((k - 1) > low) {
2369 stack[sp].low = low;
2373 if ((k - 1) > low) {
2375 stack[sp].low = low;
2379 if ((k + 1) < high) {
2380 stack[sp].high = high;
2388 // Specialized version for items==null
2389 private static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2391 QSortStack[] stack = new QSortStack[32];
2392 const int QSORT_THRESHOLD = 7;
2393 int high, low, mid, i, k;
2394 IComparable<K> gcmp;
2399 // initialize our stack
2400 stack[0].high = high0;
2401 stack[0].low = low0;
2406 high = stack[sp].high;
2407 low = stack[sp].low;
2409 if ((low + QSORT_THRESHOLD) > high) {
2410 // switch to insertion sort
2411 for (i = low + 1; i <= high; i++) {
2412 for (k = i; k > low; k--) {
2413 // if keys[k] >= keys[k-1], break
2414 if (comparer != null) {
2415 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2418 if (keys[k-1] == null)
2421 if (keys[k] != null) {
2422 gcmp = keys[k] as IComparable<K>;
2423 cmp = keys[k] as IComparable;
2425 if (gcmp.CompareTo (keys[k-1]) >= 0)
2428 if (cmp.CompareTo (keys[k-1]) >= 0)
2434 swap<K> (keys, k - 1, k);
2441 // calculate the middle element
2442 mid = low + ((high - low) / 2);
2444 // once we re-order the low, mid, and high elements to be in
2445 // ascending order, we'll use mid as our pivot.
2446 QSortArrange<K> (keys, low, mid, comparer);
2447 if (QSortArrange<K> (keys, mid, high, comparer))
2448 QSortArrange<K> (keys, low, mid, comparer);
2451 gcmp = key as IComparable<K>;
2452 cmp = key as IComparable;
2454 // since we've already guaranteed that lo <= mid and mid <= hi,
2455 // we can skip comparing them again.
2460 // Move the walls in
2461 if (comparer != null) {
2462 // find the first element with a value >= pivot value
2463 while (i < k && comparer.Compare (key, keys[i]) > 0)
2466 // find the last element with a value <= pivot value
2467 while (k > i && comparer.Compare (key, keys[k]) < 0)
2471 // find the first element with a value >= pivot value
2472 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2475 // find the last element with a value <= pivot value
2476 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2478 } else if (cmp != null) {
2479 // find the first element with a value >= pivot value
2480 while (i < k && cmp.CompareTo (keys[i]) > 0)
2483 // find the last element with a value <= pivot value
2484 while (k > i && cmp.CompareTo (keys[k]) < 0)
2487 while (i < k && keys[i] == null)
2490 while (k > i && keys[k] != null)
2498 swap<K> (keys, i, k);
2504 // push our partitions onto the stack, largest first
2505 // (to make sure we don't run out of stack space)
2506 if ((high - k) >= (k - low)) {
2507 if ((k + 1) < high) {
2508 stack[sp].high = high;
2513 if ((k - 1) > low) {
2515 stack[sp].low = low;
2519 if ((k - 1) > low) {
2521 stack[sp].low = low;
2525 if ((k + 1) < high) {
2526 stack[sp].high = high;
2534 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2536 if (array[lo] != null) {
2537 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2538 swap<T> (array, lo, hi);
2546 private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2548 QSortStack[] stack = new QSortStack[32];
2549 const int QSORT_THRESHOLD = 7;
2550 int high, low, mid, i, k;
2554 // initialize our stack
2555 stack[0].high = high0;
2556 stack[0].low = low0;
2561 high = stack[sp].high;
2562 low = stack[sp].low;
2564 if ((low + QSORT_THRESHOLD) > high) {
2565 // switch to insertion sort
2566 for (i = low + 1; i <= high; i++) {
2567 for (k = i; k > low; k--) {
2568 // if keys[k] >= keys[k-1], break
2569 if (array[k-1] == null)
2572 if (array[k] != null && compare (array[k], array[k-1]) >= 0)
2575 swap<T> (array, k - 1, k);
2582 // calculate the middle element
2583 mid = low + ((high - low) / 2);
2585 // once we re-order the lo, mid, and hi elements to be in
2586 // ascending order, we'll use mid as our pivot.
2587 QSortArrange<T> (array, low, mid, compare);
2588 if (QSortArrange<T> (array, mid, high, compare))
2589 QSortArrange<T> (array, low, mid, compare);
2593 // since we've already guaranteed that lo <= mid and mid <= hi,
2594 // we can skip comparing them again
2599 // Move the walls in
2601 // find the first element with a value >= pivot value
2602 while (i < k && compare (key, array[i]) > 0)
2605 // find the last element with a value <= pivot value
2606 while (k > i && compare (key, array[k]) < 0)
2609 while (i < k && array[i] == null)
2612 while (k > i && array[k] != null)
2619 swap<T> (array, i, k);
2625 // push our partitions onto the stack, largest first
2626 // (to make sure we don't run out of stack space)
2627 if ((high - k) >= (k - low)) {
2628 if ((k + 1) < high) {
2629 stack[sp].high = high;
2634 if ((k - 1) > low) {
2636 stack[sp].low = low;
2640 if ((k - 1) > low) {
2642 stack[sp].low = low;
2646 if ((k + 1) < high) {
2647 stack[sp].high = high;
2655 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2657 // move null keys to beginning of array,
2658 // ensure that non-null keys implement IComparable
2659 for (int i = low; i < high; i++) {
2662 if (!(key is IComparable<K>) && !(key is IComparable)) {
2663 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2664 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2670 [MethodImpl ((MethodImplOptions)256)]
2671 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2676 keys [i] = keys [j];
2679 if (items != null) {
2682 items [i] = items [j];
2687 [MethodImpl ((MethodImplOptions)256)]
2688 private static void swap<T> (T [] array, int i, int j)
2691 array [i] = array [j];
2695 public void CopyTo (Array array, int index)
2698 throw new ArgumentNullException ("array");
2700 // The order of these exception checks may look strange,
2701 // but that's how the microsoft runtime does it.
2703 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2704 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2705 throw new ArgumentException ("Destination array was not long " +
2706 "enough. Check destIndex and length, and the array's " +
2709 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2711 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2712 "Value has to be >= 0."));
2714 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2717 [ComVisible (false)]
2718 public void CopyTo (Array array, long index)
2720 if (index < 0 || index > Int32.MaxValue)
2721 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2722 "Value must be >= 0 and <= Int32.MaxValue."));
2724 CopyTo (array, (int) index);
2727 internal class SimpleEnumerator : IEnumerator, ICloneable
2733 public SimpleEnumerator (Array arrayToEnumerate)
2735 this.enumeratee = arrayToEnumerate;
2736 this.currentpos = -1;
2737 this.length = arrayToEnumerate.Length;
2740 public object Current {
2742 // Exception messages based on MS implementation
2743 if (currentpos < 0 )
2744 throw new InvalidOperationException (Locale.GetText (
2745 "Enumeration has not started."));
2746 if (currentpos >= length)
2747 throw new InvalidOperationException (Locale.GetText (
2748 "Enumeration has already ended"));
2749 // Current should not increase the position. So no ++ over here.
2750 return enumeratee.GetValueImpl (currentpos);
2754 public bool MoveNext()
2756 //The docs say Current should throw an exception if last
2757 //call to MoveNext returned false. This means currentpos
2758 //should be set to length when returning false.
2759 if (currentpos < length)
2761 if(currentpos < length)
2772 public object Clone ()
2774 return MemberwiseClone ();
2778 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2779 public static void Resize<T> (ref T [] array, int newSize)
2782 throw new ArgumentOutOfRangeException ();
2784 if (array == null) {
2785 array = new T [newSize];
2789 int length = array.Length;
2790 if (length == newSize)
2793 T [] a = new T [newSize];
2795 FastCopy (array, 0, a, 0, Math.Min (newSize, length));
2799 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2802 throw new ArgumentNullException ("array");
2804 throw new ArgumentNullException ("match");
2806 foreach (T t in array)
2813 public static void ForEach<T> (T [] array, Action <T> action)
2816 throw new ArgumentNullException ("array");
2818 throw new ArgumentNullException ("action");
2820 foreach (T t in array)
2824 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2827 throw new ArgumentNullException ("array");
2828 if (converter == null)
2829 throw new ArgumentNullException ("converter");
2831 TOutput [] output = new TOutput [array.Length];
2832 for (int i = 0; i < array.Length; i ++)
2833 output [i] = converter (array [i]);
2838 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2841 throw new ArgumentNullException ("array");
2843 return FindLastIndex<T> (array, 0, array.Length, match);
2846 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2849 throw new ArgumentNullException ();
2851 return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
2854 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2857 throw new ArgumentNullException ("array");
2859 throw new ArgumentNullException ("match");
2861 if (startIndex > array.Length || startIndex + count > array.Length)
2862 throw new ArgumentOutOfRangeException ();
2864 for (int i = startIndex + count - 1; i >= startIndex; i--)
2865 if (match (array [i]))
2871 public static int FindIndex<T> (T [] array, Predicate<T> match)
2874 throw new ArgumentNullException ("array");
2876 return FindIndex<T> (array, 0, array.Length, match);
2879 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2882 throw new ArgumentNullException ("array");
2884 return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
2887 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2890 throw new ArgumentNullException ("array");
2893 throw new ArgumentNullException ("match");
2895 if (startIndex > array.Length || startIndex + count > array.Length)
2896 throw new ArgumentOutOfRangeException ();
2898 for (int i = startIndex; i < startIndex + count; i ++)
2899 if (match (array [i]))
2905 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2906 public static int BinarySearch<T> (T [] array, T value)
2909 throw new ArgumentNullException ("array");
2911 return BinarySearch<T> (array, 0, array.Length, value, null);
2914 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2915 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2918 throw new ArgumentNullException ("array");
2920 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2923 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2924 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2926 return BinarySearch<T> (array, index, length, value, null);
2929 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2930 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2933 throw new ArgumentNullException ("array");
2935 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2936 "index is less than the lower bound of array."));
2938 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2939 "Value has to be >= 0."));
2940 // re-ordered to avoid possible integer overflow
2941 if (index > array.Length - length)
2942 throw new ArgumentException (Locale.GetText (
2943 "index and length do not specify a valid range in array."));
2944 if (comparer == null)
2945 comparer = Comparer <T>.Default;
2948 int iMax = index + length - 1;
2951 while (iMin <= iMax) {
2952 // Be careful with overflows
2953 int iMid = iMin + ((iMax - iMin) / 2);
2954 iCmp = comparer.Compare (array [iMid], value);
2962 iMin = iMid + 1; // compensate for the rounding down
2964 } catch (Exception e) {
2965 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
2971 public static int IndexOf<T> (T [] array, T value)
2974 throw new ArgumentNullException ("array");
2976 return IndexOf<T> (array, value, 0, array.Length);
2979 public static int IndexOf<T> (T [] array, T value, int startIndex)
2982 throw new ArgumentNullException ("array");
2984 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
2987 public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
2990 throw new ArgumentNullException ("array");
2992 // re-ordered to avoid possible integer overflow
2993 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
2994 throw new ArgumentOutOfRangeException ();
2996 int max = startIndex + count;
2997 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
2998 for (int i = startIndex; i < max; i++) {
2999 if (equalityComparer.Equals (array [i], value))
3006 public static int LastIndexOf<T> (T [] array, T value)
3009 throw new ArgumentNullException ("array");
3011 if (array.Length == 0)
3013 return LastIndexOf<T> (array, value, array.Length - 1);
3016 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3019 throw new ArgumentNullException ("array");
3021 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3024 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3027 throw new ArgumentNullException ("array");
3029 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3030 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3031 throw new ArgumentOutOfRangeException ();
3033 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3034 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3035 if (equalityComparer.Equals (array [i], value))
3042 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3045 throw new ArgumentNullException ("array");
3048 throw new ArgumentNullException ("match");
3051 T [] d = new T [array.Length];
3052 foreach (T t in array)
3056 Resize <T> (ref d, pos);
3060 public static bool Exists<T> (T [] array, Predicate <T> match)
3063 throw new ArgumentNullException ("array");
3066 throw new ArgumentNullException ("match");
3068 foreach (T t in array)
3074 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3077 throw new ArgumentNullException ("array");
3079 return new ReadOnlyCollection<T> (array);
3082 public static T Find<T> (T [] array, Predicate<T> match)
3085 throw new ArgumentNullException ("array");
3088 throw new ArgumentNullException ("match");
3090 foreach (T t in array)
3097 public static T FindLast<T> (T [] array, Predicate <T> match)
3100 throw new ArgumentNullException ("array");
3103 throw new ArgumentNullException ("match");
3105 for (int i = array.Length - 1; i >= 0; i--)
3106 if (match (array [i]))
3112 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3114 // The constrained copy should guarantee that if there is an exception thrown
3115 // during the copy, the destination array remains unchanged.
3116 // This is related to System.Runtime.Reliability.CER
3117 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3119 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
3122 internal static T UnsafeLoad<T> (T[] array, int index) {
3123 return array [index];
3126 internal static void UnsafeStore<T> (T[] array, int index, T value) {
3127 array [index] = value;