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
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));
144 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
146 if (unchecked ((uint) index) >= unchecked ((uint) Length))
147 throw new ArgumentOutOfRangeException ("index");
150 GetGenericValueImpl (index, out value);
154 internal int InternalArray__IReadOnlyCollection_get_Count ()
160 internal void InternalArray__Insert<T> (int index, T item)
162 throw new NotSupportedException ("Collection is of a fixed size");
165 internal void InternalArray__RemoveAt (int index)
167 throw new NotSupportedException ("Collection is of a fixed size");
170 internal int InternalArray__IndexOf<T> (T item)
173 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
175 int length = this.Length;
176 for (int i = 0; i < length; i++) {
178 GetGenericValueImpl (i, out value);
181 return i + this.GetLowerBound (0);
185 if (value.Equals (item))
186 // array index may not be zero-based.
188 return i + this.GetLowerBound (0);
192 // lower bound may be MinValue
193 return this.GetLowerBound (0) - 1;
197 internal T InternalArray__get_Item<T> (int index)
199 if (unchecked ((uint) index) >= unchecked ((uint) Length))
200 throw new ArgumentOutOfRangeException ("index");
203 GetGenericValueImpl (index, out value);
207 internal void InternalArray__set_Item<T> (int index, T item)
209 if (unchecked ((uint) index) >= unchecked ((uint) Length))
210 throw new ArgumentOutOfRangeException ("index");
212 object[] oarray = this as object [];
213 if (oarray != null) {
214 oarray [index] = (object)item;
217 SetGenericValueImpl (index, ref item);
220 // CAUTION! No bounds checking!
221 [MethodImplAttribute (MethodImplOptions.InternalCall)]
222 internal extern void GetGenericValueImpl<T> (int pos, out T value);
224 // CAUTION! No bounds checking!
225 [MethodImplAttribute (MethodImplOptions.InternalCall)]
226 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
228 internal struct InternalEnumerator<T> : IEnumerator<T>
230 const int NOT_STARTED = -2;
232 // this MUST be -1, because we depend on it in move next.
233 // we just decr the size, so, 0 - 1 == FINISHED
234 const int FINISHED = -1;
239 internal InternalEnumerator (Array array)
245 public void Dispose ()
250 public bool MoveNext ()
252 if (idx == NOT_STARTED)
255 return idx != FINISHED && -- idx != FINISHED;
260 if (idx == NOT_STARTED)
261 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
263 throw new InvalidOperationException ("Enumeration already finished");
265 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
269 void IEnumerator.Reset ()
274 object IEnumerator.Current {
283 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
285 int length = this.GetLength (0);
287 for (int i = 1; i < this.Rank; i++) {
288 length *= this.GetLength (i);
295 public long LongLength {
296 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
297 get { return Length; }
301 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
303 return this.GetRank ();
308 object IList.this [int index] {
310 if (unchecked ((uint) index) >= unchecked ((uint) Length))
311 throw new IndexOutOfRangeException ("index");
313 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
314 return GetValueImpl (index);
317 if (unchecked ((uint) index) >= unchecked ((uint) Length))
318 throw new IndexOutOfRangeException ("index");
320 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
321 SetValueImpl (value, index);
325 int IList.Add (object value)
327 throw new NotSupportedException ();
332 Array.Clear (this, this.GetLowerBound (0), this.Length);
335 bool IList.Contains (object value)
338 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
340 int length = this.Length;
341 for (int i = 0; i < length; i++) {
342 if (Object.Equals (this.GetValueImpl (i), value))
348 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
349 int IList.IndexOf (object value)
352 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
354 int length = this.Length;
355 for (int i = 0; i < length; i++) {
356 if (Object.Equals (this.GetValueImpl (i), value))
357 // array index may not be zero-based.
359 return i + this.GetLowerBound (0);
363 // lower bound may be MinValue
364 return this.GetLowerBound (0) - 1;
368 void IList.Insert (int index, object value)
370 throw new NotSupportedException ();
373 void IList.Remove (object value)
375 throw new NotSupportedException ();
378 void IList.RemoveAt (int index)
380 throw new NotSupportedException ();
383 // InternalCall Methods
384 [MethodImplAttribute (MethodImplOptions.InternalCall)]
385 extern int GetRank ();
387 [MethodImplAttribute (MethodImplOptions.InternalCall)]
388 public extern int GetLength (int dimension);
391 public long GetLongLength (int dimension)
393 return GetLength (dimension);
396 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
397 [MethodImplAttribute (MethodImplOptions.InternalCall)]
398 public extern int GetLowerBound (int dimension);
400 [MethodImplAttribute (MethodImplOptions.InternalCall)]
401 public extern object GetValue (params int[] indices);
403 [MethodImplAttribute (MethodImplOptions.InternalCall)]
404 public extern void SetValue (object value, params int[] indices);
406 // CAUTION! No bounds checking!
407 [MethodImplAttribute (MethodImplOptions.InternalCall)]
408 internal extern object GetValueImpl (int pos);
410 // CAUTION! No bounds checking!
411 [MethodImplAttribute (MethodImplOptions.InternalCall)]
412 internal extern void SetValueImpl (object value, int pos);
414 [MethodImplAttribute (MethodImplOptions.InternalCall)]
415 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
417 [MethodImplAttribute (MethodImplOptions.InternalCall)]
418 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
421 int ICollection.Count {
427 public bool IsSynchronized {
433 public object SyncRoot {
439 public bool IsFixedSize {
445 public bool IsReadOnly {
451 public IEnumerator GetEnumerator ()
453 return new SimpleEnumerator (this);
456 #if NET_4_0 || MOBILE
457 int IStructuralComparable.CompareTo (object other, IComparer comparer)
462 Array arr = other as Array;
464 throw new ArgumentException ("Not an array", "other");
466 int len = GetLength (0);
467 if (len != arr.GetLength (0))
468 throw new ArgumentException ("Not of the same length", "other");
471 throw new ArgumentException ("Array must be single dimensional");
474 throw new ArgumentException ("Array must be single dimensional", "other");
476 for (int i = 0; i < len; ++i) {
477 object a = GetValue (i);
478 object b = arr.GetValue (i);
479 int r = comparer.Compare (a, b);
486 bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer)
488 Array o = other as Array;
489 if (o == null || o.Length != Length)
492 if (Object.ReferenceEquals (other, this))
495 for (int i = 0; i < Length; i++) {
496 object this_item = this.GetValue (i);
497 object other_item = o.GetValue (i);
498 if (!comparer.Equals (this_item, other_item))
505 int IStructuralEquatable.GetHashCode (IEqualityComparer comparer)
507 if (comparer == null)
508 throw new ArgumentNullException ("comparer");
511 for (int i = 0; i < Length; i++)
512 hash = ((hash << 7) + hash) ^ comparer.GetHashCode (GetValueImpl (i));
517 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
518 public int GetUpperBound (int dimension)
520 return GetLowerBound (dimension) + GetLength (dimension) - 1;
523 public object GetValue (int index)
526 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
527 if (index < GetLowerBound (0) || index > GetUpperBound (0))
528 throw new IndexOutOfRangeException (Locale.GetText (
529 "Index has to be between upper and lower bound of the array."));
531 return GetValueImpl (index - GetLowerBound (0));
534 public object GetValue (int index1, int index2)
536 int[] ind = {index1, index2};
537 return GetValue (ind);
540 public object GetValue (int index1, int index2, int index3)
542 int[] ind = {index1, index2, index3};
543 return GetValue (ind);
547 public object GetValue (long index)
549 if (index < 0 || index > Int32.MaxValue)
550 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
551 "Value must be >= 0 and <= Int32.MaxValue."));
553 return GetValue ((int) index);
557 public object GetValue (long index1, long index2)
559 if (index1 < 0 || index1 > Int32.MaxValue)
560 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
561 "Value must be >= 0 and <= Int32.MaxValue."));
563 if (index2 < 0 || index2 > Int32.MaxValue)
564 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
565 "Value must be >= 0 and <= Int32.MaxValue."));
567 return GetValue ((int) index1, (int) index2);
571 public object GetValue (long index1, long index2, long index3)
573 if (index1 < 0 || index1 > Int32.MaxValue)
574 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
575 "Value must be >= 0 and <= Int32.MaxValue."));
577 if (index2 < 0 || index2 > Int32.MaxValue)
578 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
579 "Value must be >= 0 and <= Int32.MaxValue."));
581 if (index3 < 0 || index3 > Int32.MaxValue)
582 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
583 "Value must be >= 0 and <= Int32.MaxValue."));
585 return GetValue ((int) index1, (int) index2, (int) index3);
589 public void SetValue (object value, long index)
591 if (index < 0 || index > Int32.MaxValue)
592 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
593 "Value must be >= 0 and <= Int32.MaxValue."));
595 SetValue (value, (int) index);
599 public void SetValue (object value, long index1, long index2)
601 if (index1 < 0 || index1 > Int32.MaxValue)
602 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
603 "Value must be >= 0 and <= Int32.MaxValue."));
605 if (index2 < 0 || index2 > Int32.MaxValue)
606 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
607 "Value must be >= 0 and <= Int32.MaxValue."));
609 int[] ind = {(int) index1, (int) index2};
610 SetValue (value, ind);
614 public void SetValue (object value, long index1, long index2, long index3)
616 if (index1 < 0 || index1 > Int32.MaxValue)
617 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
618 "Value must be >= 0 and <= Int32.MaxValue."));
620 if (index2 < 0 || index2 > Int32.MaxValue)
621 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
622 "Value must be >= 0 and <= Int32.MaxValue."));
624 if (index3 < 0 || index3 > Int32.MaxValue)
625 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
626 "Value must be >= 0 and <= Int32.MaxValue."));
628 int[] ind = {(int) index1, (int) index2, (int) index3};
629 SetValue (value, ind);
632 public void SetValue (object value, int index)
635 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
636 if (index < GetLowerBound (0) || index > GetUpperBound (0))
637 throw new IndexOutOfRangeException (Locale.GetText (
638 "Index has to be >= lower bound and <= upper bound of the array."));
640 SetValueImpl (value, index - GetLowerBound (0));
643 public void SetValue (object value, int index1, int index2)
645 int[] ind = {index1, index2};
646 SetValue (value, ind);
649 public void SetValue (object value, int index1, int index2, int index3)
651 int[] ind = {index1, index2, index3};
652 SetValue (value, ind);
655 public static Array CreateInstance (Type elementType, int length)
657 int[] lengths = {length};
659 return CreateInstance (elementType, lengths);
662 public static Array CreateInstance (Type elementType, int length1, int length2)
664 int[] lengths = {length1, length2};
666 return CreateInstance (elementType, lengths);
669 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
671 int[] lengths = {length1, length2, length3};
673 return CreateInstance (elementType, lengths);
676 public static Array CreateInstance (Type elementType, params int[] lengths)
678 if (elementType == null)
679 throw new ArgumentNullException ("elementType");
681 throw new ArgumentNullException ("lengths");
683 if (lengths.Length > 255)
684 throw new TypeLoadException ();
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");
695 #if !FULL_AOT_RUNTIME
696 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
697 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
700 return CreateInstanceImpl (elementType, lengths, bounds);
703 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
705 if (elementType == null)
706 throw new ArgumentNullException ("elementType");
708 throw new ArgumentNullException ("lengths");
709 if (lowerBounds == null)
710 throw new ArgumentNullException ("lowerBounds");
712 elementType = elementType.UnderlyingSystemType;
713 if (!elementType.IsSystemType)
714 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
715 if (elementType.Equals (typeof (void)))
716 throw new NotSupportedException ("Array type can not be void");
717 if (elementType.ContainsGenericParameters)
718 throw new NotSupportedException ("Array type can not be an open generic type");
720 if (lengths.Length < 1)
721 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
723 if (lengths.Length != lowerBounds.Length)
724 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
726 for (int j = 0; j < lowerBounds.Length; j ++) {
728 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
729 "Each value has to be >= 0."));
730 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
731 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
732 "Length + bound must not exceed Int32.MaxValue."));
735 if (lengths.Length > 255)
736 throw new TypeLoadException ();
738 return CreateInstanceImpl (elementType, lengths, lowerBounds);
741 static int [] GetIntArray (long [] values)
743 int len = values.Length;
744 int [] ints = new int [len];
745 for (int i = 0; i < len; i++) {
746 long current = values [i];
747 if (current < 0 || current > (long) Int32.MaxValue)
748 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
749 "Each value has to be >= 0 and <= Int32.MaxValue."));
751 ints [i] = (int) current;
756 public static Array CreateInstance (Type elementType, params long [] lengths)
759 throw new ArgumentNullException ("lengths");
760 return CreateInstance (elementType, GetIntArray (lengths));
764 public object GetValue (params long [] indices)
767 throw new ArgumentNullException ("indices");
768 return GetValue (GetIntArray (indices));
772 public void SetValue (object value, params long [] indices)
775 throw new ArgumentNullException ("indices");
776 SetValue (value, GetIntArray (indices));
779 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
780 public static int BinarySearch (Array array, object value)
783 throw new ArgumentNullException ("array");
789 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
791 if (array.Length == 0)
794 if (!(value is IComparable))
795 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
797 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
800 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
801 public static int BinarySearch (Array array, object value, IComparer comparer)
804 throw new ArgumentNullException ("array");
807 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
809 if (array.Length == 0)
812 if ((comparer == null) && (value != null) && !(value is IComparable))
813 throw new ArgumentException (Locale.GetText (
814 "comparer is null and value does not support IComparable."));
816 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
819 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
820 public static int BinarySearch (Array array, int index, int length, object value)
823 throw new ArgumentNullException ("array");
826 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
828 if (index < array.GetLowerBound (0))
829 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
830 "index is less than the lower bound of array."));
832 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
833 "Value has to be >= 0."));
834 // re-ordered to avoid possible integer overflow
835 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
836 throw new ArgumentException (Locale.GetText (
837 "index and length do not specify a valid range in array."));
839 if (array.Length == 0)
842 if ((value != null) && (!(value is IComparable)))
843 throw new ArgumentException (Locale.GetText (
844 "value does not support IComparable"));
846 return DoBinarySearch (array, index, length, value, null);
849 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
850 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
853 throw new ArgumentNullException ("array");
856 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
858 if (index < array.GetLowerBound (0))
859 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
860 "index is less than the lower bound of array."));
862 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
863 "Value has to be >= 0."));
864 // re-ordered to avoid possible integer overflow
865 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
866 throw new ArgumentException (Locale.GetText (
867 "index and length do not specify a valid range in array."));
869 if (array.Length == 0)
872 if ((comparer == null) && (value != null) && !(value is IComparable))
873 throw new ArgumentException (Locale.GetText (
874 "comparer is null and value does not support IComparable."));
876 return DoBinarySearch (array, index, length, value, comparer);
879 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
881 // cache this in case we need it
882 if (comparer == null)
883 comparer = Comparer.Default;
886 // Comment from Tum (tum@veridicus.com):
887 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
888 int iMax = index + length - 1;
891 while (iMin <= iMax) {
892 // Be careful with overflow
893 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
894 int iMid = iMin + ((iMax - iMin) / 2);
895 object elt = array.GetValueImpl (iMid);
897 iCmp = comparer.Compare (elt, value);
904 iMin = iMid + 1; // compensate for the rounding down
907 catch (Exception e) {
908 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
914 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
915 public static void Clear (Array array, int index, int length)
918 throw new ArgumentNullException ("array");
920 throw new IndexOutOfRangeException ("length < 0");
922 int low = array.GetLowerBound (0);
924 throw new IndexOutOfRangeException ("index < lower bound");
927 // re-ordered to avoid possible integer overflow
928 if (index > array.Length - length)
929 throw new IndexOutOfRangeException ("index + length > size");
931 ClearInternal (array, index, length);
934 [MethodImplAttribute (MethodImplOptions.InternalCall)]
935 static extern void ClearInternal (Array a, int index, int count);
937 [MethodImplAttribute (MethodImplOptions.InternalCall)]
938 public extern object Clone ();
940 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
941 public static void Copy (Array sourceArray, Array destinationArray, int length)
943 // need these checks here because we are going to use
944 // GetLowerBound() on source and dest.
945 if (sourceArray == null)
946 throw new ArgumentNullException ("sourceArray");
948 if (destinationArray == null)
949 throw new ArgumentNullException ("destinationArray");
951 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
952 destinationArray.GetLowerBound (0), length);
955 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
956 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
958 if (sourceArray == null)
959 throw new ArgumentNullException ("sourceArray");
961 if (destinationArray == null)
962 throw new ArgumentNullException ("destinationArray");
965 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
966 "Value has to be >= 0."));;
969 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
970 "Value has to be >= 0."));;
972 if (destinationIndex < 0)
973 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
974 "Value has to be >= 0."));;
976 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
979 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
980 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
982 // re-ordered to avoid possible integer overflow
983 if (source_pos > sourceArray.Length - length)
984 throw new ArgumentException ("length");
986 if (dest_pos > destinationArray.Length - length) {
987 string msg = "Destination array was not long enough. Check " +
988 "destIndex and length, and the array's lower bounds";
989 throw new ArgumentException (msg, string.Empty);
992 if (sourceArray.Rank != destinationArray.Rank)
993 throw new RankException (Locale.GetText ("Arrays must be of same size."));
995 Type src_type = sourceArray.GetType ().GetElementType ();
996 Type dst_type = destinationArray.GetType ().GetElementType ();
998 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
999 for (int i = 0; i < length; i++) {
1000 Object srcval = sourceArray.GetValueImpl (source_pos + i);
1003 destinationArray.SetValueImpl (srcval, dest_pos + i);
1005 if (src_type.Equals (typeof (Object)))
1006 throw new InvalidCastException ();
1008 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
1009 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
1014 for (int i = length - 1; i >= 0; i--) {
1015 Object srcval = sourceArray.GetValueImpl (source_pos + i);
1018 destinationArray.SetValueImpl (srcval, dest_pos + i);
1020 if (src_type.Equals (typeof (Object)))
1021 throw new InvalidCastException ();
1023 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
1024 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
1030 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1031 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1032 long destinationIndex, long length)
1034 if (sourceArray == null)
1035 throw new ArgumentNullException ("sourceArray");
1037 if (destinationArray == null)
1038 throw new ArgumentNullException ("destinationArray");
1040 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1041 throw new ArgumentOutOfRangeException ("sourceIndex",
1042 Locale.GetText ("Must be in the Int32 range."));
1044 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1045 throw new ArgumentOutOfRangeException ("destinationIndex",
1046 Locale.GetText ("Must be in the Int32 range."));
1048 if (length < 0 || length > Int32.MaxValue)
1049 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1050 "Value must be >= 0 and <= Int32.MaxValue."));
1052 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1055 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1056 public static void Copy (Array sourceArray, Array destinationArray, long length)
1058 if (length < 0 || length > Int32.MaxValue)
1059 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1060 "Value must be >= 0 and <= Int32.MaxValue."));
1062 Copy (sourceArray, destinationArray, (int) length);
1065 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1066 public static int IndexOf (Array array, object value)
1069 throw new ArgumentNullException ("array");
1071 return IndexOf (array, value, 0, array.Length);
1074 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1075 public static int IndexOf (Array array, object value, int startIndex)
1078 throw new ArgumentNullException ("array");
1080 return IndexOf (array, value, startIndex, array.Length - startIndex);
1083 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1084 public static int IndexOf (Array array, object value, int startIndex, int count)
1087 throw new ArgumentNullException ("array");
1090 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1092 // re-ordered to avoid possible integer overflow
1093 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1094 throw new ArgumentOutOfRangeException ();
1096 int max = startIndex + count;
1097 for (int i = startIndex; i < max; i++) {
1098 if (Object.Equals (array.GetValueImpl (i), value))
1102 return array.GetLowerBound (0) - 1;
1105 public void Initialize()
1107 //FIXME: We would like to find a compiler that uses
1108 // this method. It looks like this method do nothing
1109 // in C# so no exception is trown by the moment.
1112 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1113 public static int LastIndexOf (Array array, object value)
1116 throw new ArgumentNullException ("array");
1118 if (array.Length == 0)
1119 return array.GetLowerBound (0) - 1;
1120 return LastIndexOf (array, value, array.Length - 1);
1123 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1124 public static int LastIndexOf (Array array, object value, int startIndex)
1127 throw new ArgumentNullException ("array");
1129 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1132 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1133 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1136 throw new ArgumentNullException ("array");
1139 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1141 int lb = array.GetLowerBound (0);
1142 // Empty arrays do not throw ArgumentOutOfRangeException
1143 if (array.Length == 0)
1146 if (count < 0 || startIndex < lb ||
1147 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1148 throw new ArgumentOutOfRangeException ();
1150 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1151 if (Object.Equals (array.GetValueImpl (i), value))
1158 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1159 public static void Reverse (Array array)
1162 throw new ArgumentNullException ("array");
1164 Reverse (array, array.GetLowerBound (0), array.Length);
1167 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1168 public static void Reverse (Array array, int index, int length)
1171 throw new ArgumentNullException ("array");
1174 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1176 if (index < array.GetLowerBound (0) || length < 0)
1177 throw new ArgumentOutOfRangeException ();
1179 // re-ordered to avoid possible integer overflow
1180 if (index > array.GetUpperBound (0) + 1 - length)
1181 throw new ArgumentException ();
1183 int end = index + length - 1;
1184 var et = array.GetType ().GetElementType ();
1185 switch (Type.GetTypeCode (et)) {
1186 case TypeCode.Boolean:
1187 while (index < end) {
1190 array.GetGenericValueImpl (index, out a);
1191 array.GetGenericValueImpl (end, out b);
1192 array.SetGenericValueImpl (index, ref b);
1193 array.SetGenericValueImpl (end, ref a);
1200 case TypeCode.SByte:
1201 while (index < end) {
1204 array.GetGenericValueImpl (index, out a);
1205 array.GetGenericValueImpl (end, out b);
1206 array.SetGenericValueImpl (index, ref b);
1207 array.SetGenericValueImpl (end, ref a);
1213 case TypeCode.Int16:
1214 case TypeCode.UInt16:
1216 while (index < end) {
1219 array.GetGenericValueImpl (index, out a);
1220 array.GetGenericValueImpl (end, out b);
1221 array.SetGenericValueImpl (index, ref b);
1222 array.SetGenericValueImpl (end, ref a);
1228 case TypeCode.Int32:
1229 case TypeCode.UInt32:
1230 case TypeCode.Single:
1231 while (index < end) {
1234 array.GetGenericValueImpl (index, out a);
1235 array.GetGenericValueImpl (end, out b);
1236 array.SetGenericValueImpl (index, ref b);
1237 array.SetGenericValueImpl (end, ref a);
1243 case TypeCode.Int64:
1244 case TypeCode.UInt64:
1245 case TypeCode.Double:
1246 while (index < end) {
1249 array.GetGenericValueImpl (index, out a);
1250 array.GetGenericValueImpl (end, out b);
1251 array.SetGenericValueImpl (index, ref b);
1252 array.SetGenericValueImpl (end, ref a);
1258 case TypeCode.Decimal:
1259 while (index < end) {
1262 array.GetGenericValueImpl (index, out a);
1263 array.GetGenericValueImpl (end, out b);
1264 array.SetGenericValueImpl (index, ref b);
1265 array.SetGenericValueImpl (end, ref a);
1271 case TypeCode.String:
1272 while (index < end) {
1275 array.GetGenericValueImpl (index, out a);
1276 array.GetGenericValueImpl (end, out b);
1277 array.SetGenericValueImpl (index, ref b);
1278 array.SetGenericValueImpl (end, ref a);
1284 if (array is object[])
1285 goto case TypeCode.String;
1287 // Very slow fallback
1288 while (index < end) {
1289 object val = array.GetValueImpl (index);
1290 array.SetValueImpl (array.GetValueImpl (end), index);
1291 array.SetValueImpl (val, end);
1300 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1301 public static void Sort (Array array)
1303 Sort (array, (IComparer)null);
1306 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1307 public static void Sort (Array keys, Array items)
1309 Sort (keys, items, (IComparer)null);
1312 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1313 public static void Sort (Array array, IComparer comparer)
1316 throw new ArgumentNullException ("array");
1319 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1321 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1324 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1325 public static void Sort (Array array, int index, int length)
1327 Sort (array, index, length, (IComparer)null);
1330 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1331 public static void Sort (Array keys, Array items, IComparer comparer)
1333 if (items == null) {
1334 Sort (keys, comparer);
1339 throw new ArgumentNullException ("keys");
1341 if (keys.Rank > 1 || items.Rank > 1)
1342 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1344 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1347 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1348 public static void Sort (Array keys, Array items, int index, int length)
1350 Sort (keys, items, index, length, (IComparer)null);
1353 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1354 public static void Sort (Array array, int index, int length, IComparer comparer)
1357 throw new ArgumentNullException ("array");
1360 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1362 if (index < array.GetLowerBound (0))
1363 throw new ArgumentOutOfRangeException ("index");
1366 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1367 "Value has to be >= 0."));
1369 if (array.Length - (array.GetLowerBound (0) + index) < length)
1370 throw new ArgumentException ();
1372 SortImpl (array, null, index, length, comparer);
1375 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1376 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1378 if (items == null) {
1379 Sort (keys, index, length, comparer);
1384 throw new ArgumentNullException ("keys");
1386 if (keys.Rank > 1 || items.Rank > 1)
1387 throw new RankException ();
1389 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1390 throw new ArgumentException ();
1392 if (index < keys.GetLowerBound (0))
1393 throw new ArgumentOutOfRangeException ("index");
1396 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1397 "Value has to be >= 0."));
1399 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1400 throw new ArgumentException ();
1402 SortImpl (keys, items, index, length, comparer);
1405 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1411 int high = index + length - 1;
1413 #if !BOOTSTRAP_BASIC
1414 if (comparer == null && items is object[]) {
1415 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1416 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1417 case TypeCode.Int32:
1418 qsort (keys as Int32[], items as object[], low, high);
1420 case TypeCode.Int64:
1421 qsort (keys as Int64[], items as object[], low, high);
1424 qsort (keys as byte[], items as object[], low, high);
1427 qsort (keys as char[], items as object[], low, high);
1429 case TypeCode.DateTime:
1430 qsort (keys as DateTime[], items as object[], low, high);
1432 case TypeCode.Decimal:
1433 qsort (keys as decimal[], items as object[], low, high);
1435 case TypeCode.Double:
1436 qsort (keys as double[], items as object[], low, high);
1438 case TypeCode.Int16:
1439 qsort (keys as Int16[], items as object[], low, high);
1441 case TypeCode.SByte:
1442 qsort (keys as SByte[], items as object[], low, high);
1444 case TypeCode.Single:
1445 qsort (keys as Single[], items as object[], low, high);
1447 case TypeCode.UInt16:
1448 qsort (keys as UInt16[], items as object[], low, high);
1450 case TypeCode.UInt32:
1451 qsort (keys as UInt32[], items as object[], low, high);
1453 case TypeCode.UInt64:
1454 qsort (keys as UInt64[], items as object[], low, high);
1462 if (comparer == null)
1463 CheckComparerAvailable (keys, low, high);
1466 qsort (keys, items, low, high, comparer);
1467 } catch (Exception e) {
1468 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1477 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1482 if (comparer != null) {
1483 if (comparer.Compare (v1, v0) < 0) {
1484 swap (keys, items, lo, hi);
1491 } else if (v0 != null) {
1492 cmp = v1 as IComparable;
1494 if (v1 == null || cmp.CompareTo (v0) < 0) {
1495 swap (keys, items, lo, hi);
1507 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1509 QSortStack[] stack = new QSortStack[32];
1510 const int QSORT_THRESHOLD = 7;
1511 int high, low, mid, i, k;
1516 // initialize our stack
1517 stack[0].high = high0;
1518 stack[0].low = low0;
1523 high = stack[sp].high;
1524 low = stack[sp].low;
1526 if ((low + QSORT_THRESHOLD) > high) {
1527 // switch to insertion sort
1528 for (i = low + 1; i <= high; i++) {
1529 for (k = i; k > low; k--) {
1530 lo = keys.GetValueImpl (k - 1);
1531 hi = keys.GetValueImpl (k);
1532 if (comparer != null) {
1533 if (comparer.Compare (hi, lo) >= 0)
1540 cmp = hi as IComparable;
1541 if (cmp.CompareTo (lo) >= 0)
1546 swap (keys, items, k - 1, k);
1553 // calculate the middle element
1554 mid = low + ((high - low) / 2);
1557 key = keys.GetValueImpl (mid);
1558 hi = keys.GetValueImpl (high);
1559 lo = keys.GetValueImpl (low);
1561 // once we re-order the low, mid, and high elements to be in
1562 // ascending order, we'll use mid as our pivot.
1563 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1564 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1565 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1567 cmp = key as IComparable;
1569 // since we've already guaranteed that lo <= mid and mid <= hi,
1570 // we can skip comparing them again.
1575 // Move the walls in
1576 if (comparer != null) {
1577 // find the first element with a value >= pivot value
1578 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
1581 // find the last element with a value <= pivot value
1582 while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1584 } else if (cmp != null) {
1585 // find the first element with a value >= pivot value
1586 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
1589 // find the last element with a value <= pivot value
1590 while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1593 // This has the effect of moving the null values to the front if comparer is null
1594 while (i < k && keys.GetValueImpl (i) == null)
1597 while (k > i && keys.GetValueImpl (k) != null)
1604 swap (keys, items, i, k);
1610 // push our partitions onto the stack, largest first
1611 // (to make sure we don't run out of stack space)
1612 if ((high - k) >= (k - low)) {
1613 if ((k + 1) < high) {
1614 stack[sp].high = high;
1619 if ((k - 1) > low) {
1621 stack[sp].low = low;
1625 if ((k - 1) > low) {
1627 stack[sp].low = low;
1631 if ((k + 1) < high) {
1632 stack[sp].high = high;
1640 private static void CheckComparerAvailable (Array keys, int low, int high)
1642 // move null keys to beginning of array,
1643 // ensure that non-null keys implement IComparable
1644 for (int i = 0; i < high; i++) {
1645 object obj = keys.GetValueImpl (i);
1648 if (!(obj is IComparable)) {
1649 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1650 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1655 private static void swap (Array keys, Array items, int i, int j)
1657 object tmp = keys.GetValueImpl (i);
1658 keys.SetValueImpl (keys.GetValueImpl (j), i);
1659 keys.SetValueImpl (tmp, j);
1661 if (items != null) {
1662 tmp = items.GetValueImpl (i);
1663 items.SetValueImpl (items.GetValueImpl (j), i);
1664 items.SetValueImpl (tmp, j);
1668 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1669 public static void Sort<T> (T [] array)
1671 Sort<T> (array, (IComparer<T>)null);
1674 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1675 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1677 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1680 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1681 public static void Sort<T> (T [] array, IComparer<T> comparer)
1684 throw new ArgumentNullException ("array");
1686 SortImpl<T> (array, 0, array.Length, comparer);
1689 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1690 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1692 if (items == null) {
1693 Sort<TKey> (keys, comparer);
1698 throw new ArgumentNullException ("keys");
1700 if (keys.Length != items.Length)
1701 throw new ArgumentException ("Length of keys and items does not match.");
1703 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1706 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1707 public static void Sort<T> (T [] array, int index, int length)
1709 Sort<T> (array, index, length, (IComparer<T>)null);
1712 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1713 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1715 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1718 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1719 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1722 throw new ArgumentNullException ("array");
1725 throw new ArgumentOutOfRangeException ("index");
1728 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1729 "Value has to be >= 0."));
1731 if (index + length > array.Length)
1732 throw new ArgumentException ();
1734 SortImpl<T> (array, index, length, comparer);
1737 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1738 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1740 if (items == null) {
1741 Sort<TKey> (keys, index, length, comparer);
1746 throw new ArgumentNullException ("keys");
1749 throw new ArgumentOutOfRangeException ("index");
1752 throw new ArgumentOutOfRangeException ("length");
1754 if (items.Length - index < length || keys.Length - index < length)
1755 throw new ArgumentException ();
1757 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1760 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1762 if (keys.Length <= 1)
1766 int high = index + length - 1;
1769 // Check for value types which can be sorted without Compare () method
1771 if (comparer == null) {
1772 /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
1773 #if FULL_AOT_RUNTIME
1774 #if !BOOTSTRAP_BASIC
1775 switch (Type.GetTypeCode (typeof (TKey))) {
1776 case TypeCode.Int32:
1777 qsort (keys as Int32[], items, low, high);
1779 case TypeCode.Int64:
1780 qsort (keys as Int64[], items, low, high);
1783 qsort (keys as byte[], items, low, high);
1786 qsort (keys as char[], items, low, high);
1788 case TypeCode.DateTime:
1789 qsort (keys as DateTime[], items, low, high);
1791 case TypeCode.Decimal:
1792 qsort (keys as decimal[], items, low, high);
1794 case TypeCode.Double:
1795 qsort (keys as double[], items, low, high);
1797 case TypeCode.Int16:
1798 qsort (keys as Int16[], items, low, high);
1800 case TypeCode.SByte:
1801 qsort (keys as SByte[], items, low, high);
1803 case TypeCode.Single:
1804 qsort (keys as Single[], items, low, high);
1806 case TypeCode.UInt16:
1807 qsort (keys as UInt16[], items, low, high);
1809 case TypeCode.UInt32:
1810 qsort (keys as UInt32[], items, low, high);
1812 case TypeCode.UInt64:
1813 qsort (keys as UInt64[], items, low, high);
1818 // Using Comparer<TKey> adds a small overload, but with value types it
1819 // helps us to not box them.
1820 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1821 typeof (TKey).IsValueType)
1822 comparer = Comparer<TKey>.Default;
1825 if (comparer == null)
1826 CheckComparerAvailable<TKey> (keys, low, high);
1829 qsort (keys, items, low, high, comparer);
1830 //} catch (Exception e) {
1831 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1835 // Specialized version for items==null
1836 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1838 if (keys.Length <= 1)
1842 int high = index + length - 1;
1845 // Check for value types which can be sorted without Compare () method
1847 if (comparer == null) {
1848 #if !BOOTSTRAP_BASIC
1849 switch (Type.GetTypeCode (typeof (TKey))) {
1850 case TypeCode.Int32:
1851 qsort (keys as Int32[], low, high);
1853 case TypeCode.Int64:
1854 qsort (keys as Int64[], low, high);
1857 qsort (keys as byte[], low, high);
1860 qsort (keys as char[], low, high);
1862 case TypeCode.DateTime:
1863 qsort (keys as DateTime[], low, high);
1865 case TypeCode.Decimal:
1866 qsort (keys as decimal[], low, high);
1868 case TypeCode.Double:
1869 qsort (keys as double[], low, high);
1871 case TypeCode.Int16:
1872 qsort (keys as Int16[], low, high);
1874 case TypeCode.SByte:
1875 qsort (keys as SByte[], low, high);
1877 case TypeCode.Single:
1878 qsort (keys as Single[], low, high);
1880 case TypeCode.UInt16:
1881 qsort (keys as UInt16[], low, high);
1883 case TypeCode.UInt32:
1884 qsort (keys as UInt32[], low, high);
1886 case TypeCode.UInt64:
1887 qsort (keys as UInt64[], low, high);
1891 // Using Comparer<TKey> adds a small overload, but with value types it
1892 // helps us to not box them.
1893 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1894 typeof (TKey).IsValueType)
1895 comparer = Comparer<TKey>.Default;
1898 if (comparer == null)
1899 CheckComparerAvailable<TKey> (keys, low, high);
1902 qsort<TKey> (keys, low, high, comparer);
1903 //} catch (Exception e) {
1904 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1908 public static void Sort<T> (T [] array, Comparison<T> comparison)
1911 throw new ArgumentNullException ("array");
1913 if (comparison == null)
1914 throw new ArgumentNullException ("comparison");
1916 SortImpl<T> (array, array.Length, comparison);
1919 // used by List<T>.Sort (Comparison <T>)
1920 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1927 int high0 = length - 1;
1928 qsort<T> (array, low0, high0, comparison);
1929 } catch (InvalidOperationException) {
1931 } catch (Exception e) {
1932 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1936 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1938 if (keys[lo] != null) {
1939 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1940 swap (keys, items, lo, hi);
1948 // Specialized version for items==null
1949 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1951 if (keys[lo] != null) {
1952 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1953 swap (keys, lo, hi);
1961 private static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1963 QSortStack[] stack = new QSortStack[32];
1964 const int QSORT_THRESHOLD = 7;
1965 int high, low, mid, i, k;
1969 // initialize our stack
1970 stack[0].high = high0;
1971 stack[0].low = low0;
1976 high = stack[sp].high;
1977 low = stack[sp].low;
1979 if ((low + QSORT_THRESHOLD) > high) {
1980 // switch to insertion sort
1981 for (i = low + 1; i <= high; i++) {
1982 for (k = i; k > low; k--) {
1983 // if keys[k] >= keys[k-1], break
1984 if (keys[k-1] == null)
1987 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
1990 swap (keys, items, k - 1, k);
1997 // calculate the middle element
1998 mid = low + ((high - low) / 2);
2000 // once we re-order the lo, mid, and hi elements to be in
2001 // ascending order, we'll use mid as our pivot.
2002 QSortArrange<T, U> (keys, items, low, mid);
2003 if (QSortArrange<T, U> (keys, items, mid, high))
2004 QSortArrange<T, U> (keys, items, low, mid);
2008 // since we've already guaranteed that lo <= mid and mid <= hi,
2009 // we can skip comparing them again
2015 // find the first element with a value >= pivot value
2016 while (i < k && key.CompareTo (keys[i]) > 0)
2019 // find the last element with a value <= pivot value
2020 while (k > i && key.CompareTo (keys[k]) < 0)
2023 while (i < k && keys[i] == null)
2026 while (k > i && keys[k] != null)
2033 swap (keys, items, i, k);
2039 // push our partitions onto the stack, largest first
2040 // (to make sure we don't run out of stack space)
2041 if ((high - k) >= (k - low)) {
2042 if ((k + 1) < high) {
2043 stack[sp].high = high;
2048 if ((k - 1) > low) {
2050 stack[sp].low = low;
2054 if ((k - 1) > low) {
2056 stack[sp].low = low;
2060 if ((k + 1) < high) {
2061 stack[sp].high = high;
2069 // Specialized version for items==null
2070 private static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2072 QSortStack[] stack = new QSortStack[32];
2073 const int QSORT_THRESHOLD = 7;
2074 int high, low, mid, i, k;
2078 // initialize our stack
2079 stack[0].high = high0;
2080 stack[0].low = low0;
2085 high = stack[sp].high;
2086 low = stack[sp].low;
2088 if ((low + QSORT_THRESHOLD) > high) {
2089 // switch to insertion sort
2090 for (i = low + 1; i <= high; i++) {
2091 for (k = i; k > low; k--) {
2092 // if keys[k] >= keys[k-1], break
2093 if (keys[k-1] == null)
2096 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2099 swap (keys, k - 1, k);
2106 // calculate the middle element
2107 mid = low + ((high - low) / 2);
2109 // once we re-order the lo, mid, and hi elements to be in
2110 // ascending order, we'll use mid as our pivot.
2111 QSortArrange<T> (keys, low, mid);
2112 if (QSortArrange<T> (keys, mid, high))
2113 QSortArrange<T> (keys, low, mid);
2117 // since we've already guaranteed that lo <= mid and mid <= hi,
2118 // we can skip comparing them again
2124 // find the first element with a value >= pivot value
2125 while (i < k && key.CompareTo (keys[i]) > 0)
2128 // find the last element with a value <= pivot value
2129 while (k >= i && key.CompareTo (keys[k]) < 0)
2132 while (i < k && keys[i] == null)
2135 while (k >= i && keys[k] != null)
2148 // push our partitions onto the stack, largest first
2149 // (to make sure we don't run out of stack space)
2150 if ((high - k) >= (k - low)) {
2151 if ((k + 1) < high) {
2152 stack[sp].high = high;
2157 if ((k - 1) > low) {
2159 stack[sp].low = low;
2163 if ((k - 1) > low) {
2165 stack[sp].low = low;
2169 if ((k + 1) < high) {
2170 stack[sp].high = high;
2178 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2180 IComparable<K> gcmp;
2183 if (comparer != null) {
2184 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2185 swap<K, V> (keys, items, lo, hi);
2188 } else if (keys[lo] != null) {
2189 if (keys[hi] == null) {
2190 swap<K, V> (keys, items, lo, hi);
2194 gcmp = keys[hi] as IComparable<K>;
2196 if (gcmp.CompareTo (keys[lo]) < 0) {
2197 swap<K, V> (keys, items, lo, hi);
2204 cmp = keys[hi] as IComparable;
2206 if (cmp.CompareTo (keys[lo]) < 0) {
2207 swap<K, V> (keys, items, lo, hi);
2218 // Specialized version for items==null
2219 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2221 IComparable<K> gcmp;
2224 if (comparer != null) {
2225 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2226 swap<K> (keys, lo, hi);
2229 } else if (keys[lo] != null) {
2230 if (keys[hi] == null) {
2231 swap<K> (keys, lo, hi);
2235 gcmp = keys[hi] as IComparable<K>;
2237 if (gcmp.CompareTo (keys[lo]) < 0) {
2238 swap<K> (keys, lo, hi);
2245 cmp = keys[hi] as IComparable;
2247 if (cmp.CompareTo (keys[lo]) < 0) {
2248 swap<K> (keys, lo, hi);
2259 private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2261 QSortStack[] stack = new QSortStack[32];
2262 const int QSORT_THRESHOLD = 7;
2263 int high, low, mid, i, k;
2264 IComparable<K> gcmp;
2269 // initialize our stack
2270 stack[0].high = high0;
2271 stack[0].low = low0;
2276 high = stack[sp].high;
2277 low = stack[sp].low;
2279 if ((low + QSORT_THRESHOLD) > high) {
2280 // switch to insertion sort
2281 for (i = low + 1; i <= high; i++) {
2282 for (k = i; k > low; k--) {
2283 // if keys[k] >= keys[k-1], break
2284 if (comparer != null) {
2285 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2288 if (keys[k-1] == null)
2291 if (keys[k] != null) {
2292 gcmp = keys[k] as IComparable<K>;
2293 cmp = keys[k] as IComparable;
2295 if (gcmp.CompareTo (keys[k-1]) >= 0)
2298 if (cmp.CompareTo (keys[k-1]) >= 0)
2304 swap<K, V> (keys, items, k - 1, k);
2311 // calculate the middle element
2312 mid = low + ((high - low) / 2);
2314 // once we re-order the low, mid, and high elements to be in
2315 // ascending order, we'll use mid as our pivot.
2316 QSortArrange<K, V> (keys, items, low, mid, comparer);
2317 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2318 QSortArrange<K, V> (keys, items, low, mid, comparer);
2321 gcmp = key as IComparable<K>;
2322 cmp = key as IComparable;
2324 // since we've already guaranteed that lo <= mid and mid <= hi,
2325 // we can skip comparing them again.
2330 // Move the walls in
2331 if (comparer != null) {
2332 // find the first element with a value >= pivot value
2333 while (i < k && comparer.Compare (key, keys[i]) > 0)
2336 // find the last element with a value <= pivot value
2337 while (k > i && comparer.Compare (key, keys[k]) < 0)
2341 // find the first element with a value >= pivot value
2342 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2345 // find the last element with a value <= pivot value
2346 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2348 } else if (cmp != null) {
2349 // find the first element with a value >= pivot value
2350 while (i < k && cmp.CompareTo (keys[i]) > 0)
2353 // find the last element with a value <= pivot value
2354 while (k > i && cmp.CompareTo (keys[k]) < 0)
2357 while (i < k && keys[i] == null)
2360 while (k > i && keys[k] != null)
2368 swap<K, V> (keys, items, i, k);
2374 // push our partitions onto the stack, largest first
2375 // (to make sure we don't run out of stack space)
2376 if ((high - k) >= (k - low)) {
2377 if ((k + 1) < high) {
2378 stack[sp].high = high;
2383 if ((k - 1) > low) {
2385 stack[sp].low = low;
2389 if ((k - 1) > low) {
2391 stack[sp].low = low;
2395 if ((k + 1) < high) {
2396 stack[sp].high = high;
2404 // Specialized version for items==null
2405 private static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2407 QSortStack[] stack = new QSortStack[32];
2408 const int QSORT_THRESHOLD = 7;
2409 int high, low, mid, i, k;
2410 IComparable<K> gcmp;
2415 // initialize our stack
2416 stack[0].high = high0;
2417 stack[0].low = low0;
2422 high = stack[sp].high;
2423 low = stack[sp].low;
2425 if ((low + QSORT_THRESHOLD) > high) {
2426 // switch to insertion sort
2427 for (i = low + 1; i <= high; i++) {
2428 for (k = i; k > low; k--) {
2429 // if keys[k] >= keys[k-1], break
2430 if (comparer != null) {
2431 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2434 if (keys[k-1] == null)
2437 if (keys[k] != null) {
2438 gcmp = keys[k] as IComparable<K>;
2439 cmp = keys[k] as IComparable;
2441 if (gcmp.CompareTo (keys[k-1]) >= 0)
2444 if (cmp.CompareTo (keys[k-1]) >= 0)
2450 swap<K> (keys, k - 1, k);
2457 // calculate the middle element
2458 mid = low + ((high - low) / 2);
2460 // once we re-order the low, mid, and high elements to be in
2461 // ascending order, we'll use mid as our pivot.
2462 QSortArrange<K> (keys, low, mid, comparer);
2463 if (QSortArrange<K> (keys, mid, high, comparer))
2464 QSortArrange<K> (keys, low, mid, comparer);
2467 gcmp = key as IComparable<K>;
2468 cmp = key as IComparable;
2470 // since we've already guaranteed that lo <= mid and mid <= hi,
2471 // we can skip comparing them again.
2476 // Move the walls in
2477 if (comparer != null) {
2478 // find the first element with a value >= pivot value
2479 while (i < k && comparer.Compare (key, keys[i]) > 0)
2482 // find the last element with a value <= pivot value
2483 while (k > i && comparer.Compare (key, keys[k]) < 0)
2487 // find the first element with a value >= pivot value
2488 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2491 // find the last element with a value <= pivot value
2492 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2494 } else if (cmp != null) {
2495 // find the first element with a value >= pivot value
2496 while (i < k && cmp.CompareTo (keys[i]) > 0)
2499 // find the last element with a value <= pivot value
2500 while (k > i && cmp.CompareTo (keys[k]) < 0)
2503 while (i < k && keys[i] == null)
2506 while (k > i && keys[k] != null)
2514 swap<K> (keys, i, k);
2520 // push our partitions onto the stack, largest first
2521 // (to make sure we don't run out of stack space)
2522 if ((high - k) >= (k - low)) {
2523 if ((k + 1) < high) {
2524 stack[sp].high = high;
2529 if ((k - 1) > low) {
2531 stack[sp].low = low;
2535 if ((k - 1) > low) {
2537 stack[sp].low = low;
2541 if ((k + 1) < high) {
2542 stack[sp].high = high;
2550 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2552 if (array[lo] != null) {
2553 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2554 swap<T> (array, lo, hi);
2562 private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2564 QSortStack[] stack = new QSortStack[32];
2565 const int QSORT_THRESHOLD = 7;
2566 int high, low, mid, i, k;
2570 // initialize our stack
2571 stack[0].high = high0;
2572 stack[0].low = low0;
2577 high = stack[sp].high;
2578 low = stack[sp].low;
2580 if ((low + QSORT_THRESHOLD) > high) {
2581 // switch to insertion sort
2582 for (i = low + 1; i <= high; i++) {
2583 for (k = i; k > low; k--) {
2584 // if keys[k] >= keys[k-1], break
2585 if (array[k-1] == null)
2588 if (array[k] != null && compare (array[k], array[k-1]) >= 0)
2591 swap<T> (array, k - 1, k);
2598 // calculate the middle element
2599 mid = low + ((high - low) / 2);
2601 // once we re-order the lo, mid, and hi elements to be in
2602 // ascending order, we'll use mid as our pivot.
2603 QSortArrange<T> (array, low, mid, compare);
2604 if (QSortArrange<T> (array, mid, high, compare))
2605 QSortArrange<T> (array, low, mid, compare);
2609 // since we've already guaranteed that lo <= mid and mid <= hi,
2610 // we can skip comparing them again
2615 // Move the walls in
2617 // find the first element with a value >= pivot value
2618 while (i < k && compare (key, array[i]) > 0)
2621 // find the last element with a value <= pivot value
2622 while (k > i && compare (key, array[k]) < 0)
2625 while (i < k && array[i] == null)
2628 while (k > i && array[k] != null)
2635 swap<T> (array, i, k);
2641 // push our partitions onto the stack, largest first
2642 // (to make sure we don't run out of stack space)
2643 if ((high - k) >= (k - low)) {
2644 if ((k + 1) < high) {
2645 stack[sp].high = high;
2650 if ((k - 1) > low) {
2652 stack[sp].low = low;
2656 if ((k - 1) > low) {
2658 stack[sp].low = low;
2662 if ((k + 1) < high) {
2663 stack[sp].high = high;
2671 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2673 // move null keys to beginning of array,
2674 // ensure that non-null keys implement IComparable
2675 for (int i = low; i < high; i++) {
2678 if (!(key is IComparable<K>) && !(key is IComparable)) {
2679 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2680 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2686 [MethodImpl ((MethodImplOptions)256)]
2687 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2692 keys [i] = keys [j];
2695 if (items != null) {
2698 items [i] = items [j];
2703 [MethodImpl ((MethodImplOptions)256)]
2704 private static void swap<T> (T [] array, int i, int j)
2707 array [i] = array [j];
2711 public void CopyTo (Array array, int index)
2714 throw new ArgumentNullException ("array");
2716 // The order of these exception checks may look strange,
2717 // but that's how the microsoft runtime does it.
2719 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2720 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2721 throw new ArgumentException ("Destination array was not long " +
2722 "enough. Check destIndex and length, and the array's " +
2725 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2727 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2728 "Value has to be >= 0."));
2730 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2733 [ComVisible (false)]
2734 public void CopyTo (Array array, long index)
2736 if (index < 0 || index > Int32.MaxValue)
2737 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2738 "Value must be >= 0 and <= Int32.MaxValue."));
2740 CopyTo (array, (int) index);
2743 internal class SimpleEnumerator : IEnumerator, ICloneable
2749 public SimpleEnumerator (Array arrayToEnumerate)
2751 this.enumeratee = arrayToEnumerate;
2752 this.currentpos = -1;
2753 this.length = arrayToEnumerate.Length;
2756 public object Current {
2758 // Exception messages based on MS implementation
2759 if (currentpos < 0 )
2760 throw new InvalidOperationException (Locale.GetText (
2761 "Enumeration has not started."));
2762 if (currentpos >= length)
2763 throw new InvalidOperationException (Locale.GetText (
2764 "Enumeration has already ended"));
2765 // Current should not increase the position. So no ++ over here.
2766 return enumeratee.GetValueImpl (currentpos);
2770 public bool MoveNext()
2772 //The docs say Current should throw an exception if last
2773 //call to MoveNext returned false. This means currentpos
2774 //should be set to length when returning false.
2775 if (currentpos < length)
2777 if(currentpos < length)
2788 public object Clone ()
2790 return MemberwiseClone ();
2794 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2795 public static void Resize<T> (ref T [] array, int newSize)
2798 throw new ArgumentOutOfRangeException ("newSize");
2800 if (array == null) {
2801 array = new T [newSize];
2806 int length = arr.Length;
2807 if (length == newSize)
2810 T [] a = new T [newSize];
2812 FastCopy (arr, 0, a, 0, Math.Min (newSize, length));
2816 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2819 throw new ArgumentNullException ("array");
2821 throw new ArgumentNullException ("match");
2823 foreach (T t in array)
2830 public static void ForEach<T> (T [] array, Action <T> action)
2833 throw new ArgumentNullException ("array");
2835 throw new ArgumentNullException ("action");
2837 foreach (T t in array)
2841 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2844 throw new ArgumentNullException ("array");
2845 if (converter == null)
2846 throw new ArgumentNullException ("converter");
2848 TOutput [] output = new TOutput [array.Length];
2849 for (int i = 0; i < array.Length; i ++)
2850 output [i] = converter (array [i]);
2855 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2858 throw new ArgumentNullException ("array");
2860 return FindLastIndex<T> (array, 0, array.Length, match);
2863 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2866 throw new ArgumentNullException ();
2868 return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
2871 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2874 throw new ArgumentNullException ("array");
2876 throw new ArgumentNullException ("match");
2878 if (startIndex > array.Length || startIndex + count > array.Length)
2879 throw new ArgumentOutOfRangeException ();
2881 for (int i = startIndex + count - 1; i >= startIndex; i--)
2882 if (match (array [i]))
2888 public static int FindIndex<T> (T [] array, Predicate<T> match)
2891 throw new ArgumentNullException ("array");
2893 return FindIndex<T> (array, 0, array.Length, match);
2896 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2899 throw new ArgumentNullException ("array");
2901 return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
2904 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2907 throw new ArgumentNullException ("array");
2910 throw new ArgumentNullException ("match");
2912 if (startIndex > array.Length || startIndex + count > array.Length)
2913 throw new ArgumentOutOfRangeException ();
2915 for (int i = startIndex; i < startIndex + count; i ++)
2916 if (match (array [i]))
2922 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2923 public static int BinarySearch<T> (T [] array, T value)
2926 throw new ArgumentNullException ("array");
2928 return BinarySearch<T> (array, 0, array.Length, value, null);
2931 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2932 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2935 throw new ArgumentNullException ("array");
2937 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2940 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2941 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2943 return BinarySearch<T> (array, index, length, value, null);
2946 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2947 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2950 throw new ArgumentNullException ("array");
2952 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2953 "index is less than the lower bound of array."));
2955 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2956 "Value has to be >= 0."));
2957 // re-ordered to avoid possible integer overflow
2958 if (index > array.Length - length)
2959 throw new ArgumentException (Locale.GetText (
2960 "index and length do not specify a valid range in array."));
2961 if (comparer == null)
2962 comparer = Comparer <T>.Default;
2965 int iMax = index + length - 1;
2968 while (iMin <= iMax) {
2969 // Be careful with overflows
2970 int iMid = iMin + ((iMax - iMin) / 2);
2971 iCmp = comparer.Compare (array [iMid], value);
2979 iMin = iMid + 1; // compensate for the rounding down
2981 } catch (Exception e) {
2982 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
2988 public static int IndexOf<T> (T [] array, T value)
2991 throw new ArgumentNullException ("array");
2993 return IndexOf<T> (array, value, 0, array.Length);
2996 public static int IndexOf<T> (T [] array, T value, int startIndex)
2999 throw new ArgumentNullException ("array");
3001 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
3004 public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
3007 throw new ArgumentNullException ("array");
3009 // re-ordered to avoid possible integer overflow
3010 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
3011 throw new ArgumentOutOfRangeException ();
3013 int max = startIndex + count;
3014 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3015 for (int i = startIndex; i < max; i++) {
3016 if (equalityComparer.Equals (array [i], value))
3023 public static int LastIndexOf<T> (T [] array, T value)
3026 throw new ArgumentNullException ("array");
3028 if (array.Length == 0)
3030 return LastIndexOf<T> (array, value, array.Length - 1);
3033 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3036 throw new ArgumentNullException ("array");
3038 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3041 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3044 throw new ArgumentNullException ("array");
3046 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3047 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3048 throw new ArgumentOutOfRangeException ();
3050 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3051 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3052 if (equalityComparer.Equals (array [i], value))
3059 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3062 throw new ArgumentNullException ("array");
3065 throw new ArgumentNullException ("match");
3068 T [] d = new T [array.Length];
3069 foreach (T t in array)
3073 Resize <T> (ref d, pos);
3077 public static bool Exists<T> (T [] array, Predicate <T> match)
3080 throw new ArgumentNullException ("array");
3083 throw new ArgumentNullException ("match");
3085 foreach (T t in array)
3091 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3094 throw new ArgumentNullException ("array");
3096 return new ReadOnlyCollection<T> (array);
3099 public static T Find<T> (T [] array, Predicate<T> match)
3102 throw new ArgumentNullException ("array");
3105 throw new ArgumentNullException ("match");
3107 foreach (T t in array)
3114 public static T FindLast<T> (T [] array, Predicate <T> match)
3117 throw new ArgumentNullException ("array");
3120 throw new ArgumentNullException ("match");
3122 for (int i = array.Length - 1; i >= 0; i--)
3123 if (match (array [i]))
3129 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3131 // The constrained copy should guarantee that if there is an exception thrown
3132 // during the copy, the destination array remains unchanged.
3133 // This is related to System.Runtime.Reliability.CER
3134 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3136 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
3139 internal static T UnsafeLoad<T> (T[] array, int index) {
3140 return array [index];
3143 internal static void UnsafeStore<T> (T[] array, int index, T value) {
3144 array [index] = value;