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 , IStructuralComparable, IStructuralEquatable
61 * These methods are used to implement the implicit generic interfaces
62 * implemented by arrays in NET 2.0.
63 * Only make those methods generic which really need it, to avoid
64 * creating useless instantiations.
66 internal int InternalArray__ICollection_get_Count ()
71 internal bool InternalArray__ICollection_get_IsReadOnly ()
76 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
78 return new InternalEnumerator<T> (this);
81 internal void InternalArray__ICollection_Clear ()
83 throw new NotSupportedException ("Collection is read-only");
86 internal void InternalArray__ICollection_Add<T> (T item)
88 throw new NotSupportedException ("Collection is of a fixed size");
91 internal bool InternalArray__ICollection_Remove<T> (T item)
93 throw new NotSupportedException ("Collection is of a fixed size");
96 internal bool InternalArray__ICollection_Contains<T> (T item)
99 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
101 int length = this.Length;
102 for (int i = 0; i < length; i++) {
104 GetGenericValueImpl (i, out value);
113 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 T InternalArray__IReadOnlyList_get_Item<T> (int index)
145 if (unchecked ((uint) index) >= unchecked ((uint) Length))
146 throw new ArgumentOutOfRangeException ("index");
149 GetGenericValueImpl (index, out value);
153 internal int InternalArray__IReadOnlyCollection_get_Count ()
158 internal void InternalArray__Insert<T> (int index, T item)
160 throw new NotSupportedException ("Collection is of a fixed size");
163 internal void InternalArray__RemoveAt (int index)
165 throw new NotSupportedException ("Collection is of a fixed size");
168 internal int InternalArray__IndexOf<T> (T item)
171 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
173 int length = this.Length;
174 for (int i = 0; i < length; i++) {
176 GetGenericValueImpl (i, out value);
179 return i + this.GetLowerBound (0);
183 if (value.Equals (item))
184 // array index may not be zero-based.
186 return i + this.GetLowerBound (0);
190 // lower bound may be MinValue
191 return this.GetLowerBound (0) - 1;
195 internal T InternalArray__get_Item<T> (int index)
197 if (unchecked ((uint) index) >= unchecked ((uint) Length))
198 throw new ArgumentOutOfRangeException ("index");
201 GetGenericValueImpl (index, out value);
205 internal void InternalArray__set_Item<T> (int index, T item)
207 if (unchecked ((uint) index) >= unchecked ((uint) Length))
208 throw new ArgumentOutOfRangeException ("index");
210 object[] oarray = this as object [];
211 if (oarray != null) {
212 oarray [index] = (object)item;
215 SetGenericValueImpl (index, ref item);
218 // CAUTION! No bounds checking!
219 [MethodImplAttribute (MethodImplOptions.InternalCall)]
220 internal extern void GetGenericValueImpl<T> (int pos, out T value);
222 // CAUTION! No bounds checking!
223 [MethodImplAttribute (MethodImplOptions.InternalCall)]
224 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
226 internal struct InternalEnumerator<T> : IEnumerator<T>
228 const int NOT_STARTED = -2;
230 // this MUST be -1, because we depend on it in move next.
231 // we just decr the size, so, 0 - 1 == FINISHED
232 const int FINISHED = -1;
237 internal InternalEnumerator (Array array)
243 public void Dispose ()
248 public bool MoveNext ()
250 if (idx == NOT_STARTED)
253 return idx != FINISHED && -- idx != FINISHED;
258 if (idx == NOT_STARTED)
259 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
261 throw new InvalidOperationException ("Enumeration already finished");
263 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
267 void IEnumerator.Reset ()
272 object IEnumerator.Current {
281 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
283 int length = this.GetLength (0);
285 for (int i = 1; i < this.Rank; i++) {
286 length *= this.GetLength (i);
293 public long LongLength {
294 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
295 get { return Length; }
299 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
301 return this.GetRank ();
306 object IList.this [int index] {
308 if (unchecked ((uint) index) >= unchecked ((uint) Length))
309 throw new IndexOutOfRangeException ("index");
311 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
312 return GetValueImpl (index);
315 if (unchecked ((uint) index) >= unchecked ((uint) Length))
316 throw new IndexOutOfRangeException ("index");
318 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
319 SetValueImpl (value, index);
323 int IList.Add (object value)
325 throw new NotSupportedException ();
330 Array.Clear (this, this.GetLowerBound (0), this.Length);
333 bool IList.Contains (object value)
336 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
338 int length = this.Length;
339 for (int i = 0; i < length; i++) {
340 if (Object.Equals (this.GetValueImpl (i), value))
346 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
347 int IList.IndexOf (object value)
350 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
352 int length = this.Length;
353 for (int i = 0; i < length; i++) {
354 if (Object.Equals (this.GetValueImpl (i), value))
355 // array index may not be zero-based.
357 return i + this.GetLowerBound (0);
361 // lower bound may be MinValue
362 return this.GetLowerBound (0) - 1;
366 void IList.Insert (int index, object value)
368 throw new NotSupportedException ();
371 void IList.Remove (object value)
373 throw new NotSupportedException ();
376 void IList.RemoveAt (int index)
378 throw new NotSupportedException ();
381 // InternalCall Methods
382 [MethodImplAttribute (MethodImplOptions.InternalCall)]
383 extern int GetRank ();
385 [MethodImplAttribute (MethodImplOptions.InternalCall)]
386 public extern int GetLength (int dimension);
389 public long GetLongLength (int dimension)
391 return GetLength (dimension);
394 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
395 [MethodImplAttribute (MethodImplOptions.InternalCall)]
396 public extern int GetLowerBound (int dimension);
398 [MethodImplAttribute (MethodImplOptions.InternalCall)]
399 public extern object GetValue (params int[] indices);
401 [MethodImplAttribute (MethodImplOptions.InternalCall)]
402 public extern void SetValue (object value, params int[] indices);
404 // CAUTION! No bounds checking!
405 [MethodImplAttribute (MethodImplOptions.InternalCall)]
406 internal extern object GetValueImpl (int pos);
408 // CAUTION! No bounds checking!
409 [MethodImplAttribute (MethodImplOptions.InternalCall)]
410 internal extern void SetValueImpl (object value, int pos);
412 [MethodImplAttribute (MethodImplOptions.InternalCall)]
413 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
415 [MethodImplAttribute (MethodImplOptions.InternalCall)]
416 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
419 int ICollection.Count {
425 public bool IsSynchronized {
431 public object SyncRoot {
437 public bool IsFixedSize {
443 public bool IsReadOnly {
449 public IEnumerator GetEnumerator ()
451 return new SimpleEnumerator (this);
454 int IStructuralComparable.CompareTo (object other, IComparer comparer)
459 Array arr = other as Array;
461 throw new ArgumentException ("Not an array", "other");
463 int len = GetLength (0);
464 if (len != arr.GetLength (0))
465 throw new ArgumentException ("Not of the same length", "other");
468 throw new ArgumentException ("Array must be single dimensional");
471 throw new ArgumentException ("Array must be single dimensional", "other");
473 for (int i = 0; i < len; ++i) {
474 object a = GetValue (i);
475 object b = arr.GetValue (i);
476 int r = comparer.Compare (a, b);
483 bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer)
485 Array o = other as Array;
486 if (o == null || o.Length != Length)
489 if (Object.ReferenceEquals (other, this))
492 for (int i = 0; i < Length; i++) {
493 object this_item = this.GetValue (i);
494 object other_item = o.GetValue (i);
495 if (!comparer.Equals (this_item, other_item))
502 int IStructuralEquatable.GetHashCode (IEqualityComparer comparer)
504 if (comparer == null)
505 throw new ArgumentNullException ("comparer");
508 for (int i = 0; i < Length; i++)
509 hash = ((hash << 7) + hash) ^ comparer.GetHashCode (GetValueImpl (i));
513 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
514 public int GetUpperBound (int dimension)
516 return GetLowerBound (dimension) + GetLength (dimension) - 1;
519 public object GetValue (int index)
522 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
523 if (index < GetLowerBound (0) || index > GetUpperBound (0))
524 throw new IndexOutOfRangeException (Locale.GetText (
525 "Index has to be between upper and lower bound of the array."));
527 return GetValueImpl (index - GetLowerBound (0));
530 public object GetValue (int index1, int index2)
532 int[] ind = {index1, index2};
533 return GetValue (ind);
536 public object GetValue (int index1, int index2, int index3)
538 int[] ind = {index1, index2, index3};
539 return GetValue (ind);
543 public object GetValue (long index)
545 if (index < 0 || index > Int32.MaxValue)
546 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
547 "Value must be >= 0 and <= Int32.MaxValue."));
549 return GetValue ((int) index);
553 public object GetValue (long index1, long index2)
555 if (index1 < 0 || index1 > Int32.MaxValue)
556 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
557 "Value must be >= 0 and <= Int32.MaxValue."));
559 if (index2 < 0 || index2 > Int32.MaxValue)
560 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
561 "Value must be >= 0 and <= Int32.MaxValue."));
563 return GetValue ((int) index1, (int) index2);
567 public object GetValue (long index1, long index2, long index3)
569 if (index1 < 0 || index1 > Int32.MaxValue)
570 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
571 "Value must be >= 0 and <= Int32.MaxValue."));
573 if (index2 < 0 || index2 > Int32.MaxValue)
574 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
575 "Value must be >= 0 and <= Int32.MaxValue."));
577 if (index3 < 0 || index3 > Int32.MaxValue)
578 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
579 "Value must be >= 0 and <= Int32.MaxValue."));
581 return GetValue ((int) index1, (int) index2, (int) index3);
585 public void SetValue (object value, long index)
587 if (index < 0 || index > Int32.MaxValue)
588 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
589 "Value must be >= 0 and <= Int32.MaxValue."));
591 SetValue (value, (int) index);
595 public void SetValue (object value, long index1, long index2)
597 if (index1 < 0 || index1 > Int32.MaxValue)
598 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
599 "Value must be >= 0 and <= Int32.MaxValue."));
601 if (index2 < 0 || index2 > Int32.MaxValue)
602 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
603 "Value must be >= 0 and <= Int32.MaxValue."));
605 int[] ind = {(int) index1, (int) index2};
606 SetValue (value, ind);
610 public void SetValue (object value, long index1, long index2, long index3)
612 if (index1 < 0 || index1 > Int32.MaxValue)
613 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
614 "Value must be >= 0 and <= Int32.MaxValue."));
616 if (index2 < 0 || index2 > Int32.MaxValue)
617 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
618 "Value must be >= 0 and <= Int32.MaxValue."));
620 if (index3 < 0 || index3 > Int32.MaxValue)
621 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
622 "Value must be >= 0 and <= Int32.MaxValue."));
624 int[] ind = {(int) index1, (int) index2, (int) index3};
625 SetValue (value, ind);
628 public void SetValue (object value, int index)
631 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
632 if (index < GetLowerBound (0) || index > GetUpperBound (0))
633 throw new IndexOutOfRangeException (Locale.GetText (
634 "Index has to be >= lower bound and <= upper bound of the array."));
636 SetValueImpl (value, index - GetLowerBound (0));
639 public void SetValue (object value, int index1, int index2)
641 int[] ind = {index1, index2};
642 SetValue (value, ind);
645 public void SetValue (object value, int index1, int index2, int index3)
647 int[] ind = {index1, index2, index3};
648 SetValue (value, ind);
651 public static Array CreateInstance (Type elementType, int length)
653 int[] lengths = {length};
655 return CreateInstance (elementType, lengths);
658 public static Array CreateInstance (Type elementType, int length1, int length2)
660 int[] lengths = {length1, length2};
662 return CreateInstance (elementType, lengths);
665 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
667 int[] lengths = {length1, length2, length3};
669 return CreateInstance (elementType, lengths);
672 public static Array CreateInstance (Type elementType, params int[] lengths)
674 if (elementType == null)
675 throw new ArgumentNullException ("elementType");
677 throw new ArgumentNullException ("lengths");
679 if (lengths.Length > 255)
680 throw new TypeLoadException ();
684 elementType = elementType.UnderlyingSystemType;
685 if (!elementType.IsSystemType)
686 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
687 if (elementType.Equals (typeof (void)))
688 throw new NotSupportedException ("Array type can not be void");
689 if (elementType.ContainsGenericParameters)
690 throw new NotSupportedException ("Array type can not be an open generic type");
691 #if !FULL_AOT_RUNTIME
692 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
693 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
696 return CreateInstanceImpl (elementType, lengths, bounds);
699 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
701 if (elementType == null)
702 throw new ArgumentNullException ("elementType");
704 throw new ArgumentNullException ("lengths");
705 if (lowerBounds == null)
706 throw new ArgumentNullException ("lowerBounds");
708 elementType = elementType.UnderlyingSystemType;
709 if (!elementType.IsSystemType)
710 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
711 if (elementType.Equals (typeof (void)))
712 throw new NotSupportedException ("Array type can not be void");
713 if (elementType.ContainsGenericParameters)
714 throw new NotSupportedException ("Array type can not be an open generic type");
716 if (lengths.Length < 1)
717 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
719 if (lengths.Length != lowerBounds.Length)
720 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
722 for (int j = 0; j < lowerBounds.Length; j ++) {
724 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
725 "Each value has to be >= 0."));
726 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
727 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
728 "Length + bound must not exceed Int32.MaxValue."));
731 if (lengths.Length > 255)
732 throw new TypeLoadException ();
734 return CreateInstanceImpl (elementType, lengths, lowerBounds);
737 static int [] GetIntArray (long [] values)
739 int len = values.Length;
740 int [] ints = new int [len];
741 for (int i = 0; i < len; i++) {
742 long current = values [i];
743 if (current < 0 || current > (long) Int32.MaxValue)
744 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
745 "Each value has to be >= 0 and <= Int32.MaxValue."));
747 ints [i] = (int) current;
752 public static Array CreateInstance (Type elementType, params long [] lengths)
755 throw new ArgumentNullException ("lengths");
756 return CreateInstance (elementType, GetIntArray (lengths));
760 public object GetValue (params long [] indices)
763 throw new ArgumentNullException ("indices");
764 return GetValue (GetIntArray (indices));
768 public void SetValue (object value, params long [] indices)
771 throw new ArgumentNullException ("indices");
772 SetValue (value, GetIntArray (indices));
775 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
776 public static int BinarySearch (Array array, object value)
778 return BinarySearch (array, value, null);
781 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
782 public static int BinarySearch (Array array, object value, IComparer comparer)
785 throw new ArgumentNullException ("array");
788 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
790 if (array.Length == 0)
793 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
796 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
797 public static int BinarySearch (Array array, int index, int length, object value)
799 return BinarySearch (array, index, length, value, null);
802 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
803 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
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 return DoBinarySearch (array, index, length, value, comparer);
828 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
830 // cache this in case we need it
831 if (comparer == null)
832 comparer = Comparer.Default;
835 // Comment from Tum (tum@veridicus.com):
836 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
837 int iMax = index + length - 1;
840 while (iMin <= iMax) {
841 // Be careful with overflow
842 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
843 int iMid = iMin + ((iMax - iMin) / 2);
844 object elt = array.GetValueImpl (iMid);
846 iCmp = comparer.Compare (elt, value);
853 iMin = iMid + 1; // compensate for the rounding down
856 catch (Exception e) {
857 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
863 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
864 public static void Clear (Array array, int index, int length)
867 throw new ArgumentNullException ("array");
869 throw new IndexOutOfRangeException ("length < 0");
871 int low = array.GetLowerBound (0);
873 throw new IndexOutOfRangeException ("index < lower bound");
876 // re-ordered to avoid possible integer overflow
877 if (index > array.Length - length)
878 throw new IndexOutOfRangeException ("index + length > size");
880 ClearInternal (array, index, length);
883 [MethodImplAttribute (MethodImplOptions.InternalCall)]
884 static extern void ClearInternal (Array a, int index, int count);
886 [MethodImplAttribute (MethodImplOptions.InternalCall)]
887 public extern object Clone ();
889 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
890 public static void Copy (Array sourceArray, Array destinationArray, int length)
892 // need these checks here because we are going to use
893 // GetLowerBound() on source and dest.
894 if (sourceArray == null)
895 throw new ArgumentNullException ("sourceArray");
897 if (destinationArray == null)
898 throw new ArgumentNullException ("destinationArray");
900 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
901 destinationArray.GetLowerBound (0), length);
904 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
905 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
907 if (sourceArray == null)
908 throw new ArgumentNullException ("sourceArray");
910 if (destinationArray == null)
911 throw new ArgumentNullException ("destinationArray");
914 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
915 "Value has to be >= 0."));;
918 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
919 "Value has to be >= 0."));;
921 if (destinationIndex < 0)
922 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
923 "Value has to be >= 0."));;
925 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
928 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
929 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
931 // re-ordered to avoid possible integer overflow
932 if (source_pos > sourceArray.Length - length)
933 throw new ArgumentException ("length");
935 if (dest_pos > destinationArray.Length - length) {
936 string msg = "Destination array was not long enough. Check " +
937 "destIndex and length, and the array's lower bounds";
938 throw new ArgumentException (msg, string.Empty);
941 if (sourceArray.Rank != destinationArray.Rank)
942 throw new RankException (Locale.GetText ("Arrays must be of same size."));
944 Type src_type = sourceArray.GetType ().GetElementType ();
945 Type dst_type = destinationArray.GetType ().GetElementType ();
947 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
948 for (int i = 0; i < length; i++) {
949 Object srcval = sourceArray.GetValueImpl (source_pos + i);
952 destinationArray.SetValueImpl (srcval, dest_pos + i);
953 } catch (ArgumentException) {
954 throw CreateArrayTypeMismatchException ();
956 if (CanAssignArrayElement (src_type, dst_type))
959 throw CreateArrayTypeMismatchException ();
964 for (int i = length - 1; i >= 0; i--) {
965 Object srcval = sourceArray.GetValueImpl (source_pos + i);
968 destinationArray.SetValueImpl (srcval, dest_pos + i);
969 } catch (ArgumentException) {
970 throw CreateArrayTypeMismatchException ();
972 if (CanAssignArrayElement (src_type, dst_type))
975 throw CreateArrayTypeMismatchException ();
981 static Exception CreateArrayTypeMismatchException ()
983 return new ArrayTypeMismatchException ();
986 static bool CanAssignArrayElement (Type source, Type target)
988 if (source.IsValueType)
989 return source.IsAssignableFrom (target);
991 if (source.IsInterface)
992 return !target.IsValueType;
994 if (target.IsInterface)
995 return !source.IsValueType;
997 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
1000 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1001 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1002 long destinationIndex, long length)
1004 if (sourceArray == null)
1005 throw new ArgumentNullException ("sourceArray");
1007 if (destinationArray == null)
1008 throw new ArgumentNullException ("destinationArray");
1010 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1011 throw new ArgumentOutOfRangeException ("sourceIndex",
1012 Locale.GetText ("Must be in the Int32 range."));
1014 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1015 throw new ArgumentOutOfRangeException ("destinationIndex",
1016 Locale.GetText ("Must be in the Int32 range."));
1018 if (length < 0 || length > Int32.MaxValue)
1019 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1020 "Value must be >= 0 and <= Int32.MaxValue."));
1022 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1025 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1026 public static void Copy (Array sourceArray, Array destinationArray, long length)
1028 if (length < 0 || length > Int32.MaxValue)
1029 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1030 "Value must be >= 0 and <= Int32.MaxValue."));
1032 Copy (sourceArray, destinationArray, (int) length);
1035 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1036 public static int IndexOf (Array array, object value)
1039 throw new ArgumentNullException ("array");
1041 return IndexOf (array, value, 0, array.Length);
1044 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1045 public static int IndexOf (Array array, object value, int startIndex)
1048 throw new ArgumentNullException ("array");
1050 return IndexOf (array, value, startIndex, array.Length - startIndex);
1053 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1054 public static int IndexOf (Array array, object value, int startIndex, int count)
1057 throw new ArgumentNullException ("array");
1060 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1062 // re-ordered to avoid possible integer overflow
1063 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1064 throw new ArgumentOutOfRangeException ();
1066 int max = startIndex + count;
1067 for (int i = startIndex; i < max; i++) {
1068 if (Object.Equals (array.GetValueImpl (i), value))
1072 return array.GetLowerBound (0) - 1;
1075 public void Initialize()
1077 //FIXME: We would like to find a compiler that uses
1078 // this method. It looks like this method do nothing
1079 // in C# so no exception is trown by the moment.
1082 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1083 public static int LastIndexOf (Array array, object value)
1086 throw new ArgumentNullException ("array");
1088 if (array.Length == 0)
1089 return array.GetLowerBound (0) - 1;
1090 return LastIndexOf (array, value, array.Length - 1);
1093 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1094 public static int LastIndexOf (Array array, object value, int startIndex)
1097 throw new ArgumentNullException ("array");
1099 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1102 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1103 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1106 throw new ArgumentNullException ("array");
1109 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1111 int lb = array.GetLowerBound (0);
1112 // Empty arrays do not throw ArgumentOutOfRangeException
1113 if (array.Length == 0)
1116 if (count < 0 || startIndex < lb ||
1117 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1118 throw new ArgumentOutOfRangeException ();
1120 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1121 if (Object.Equals (array.GetValueImpl (i), value))
1128 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1129 public static void Reverse (Array array)
1132 throw new ArgumentNullException ("array");
1134 Reverse (array, array.GetLowerBound (0), array.Length);
1137 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1138 public static void Reverse (Array array, int index, int length)
1141 throw new ArgumentNullException ("array");
1144 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1146 if (index < array.GetLowerBound (0) || length < 0)
1147 throw new ArgumentOutOfRangeException ();
1149 // re-ordered to avoid possible integer overflow
1150 if (index > array.GetUpperBound (0) + 1 - length)
1151 throw new ArgumentException ();
1153 int end = index + length - 1;
1154 var et = array.GetType ().GetElementType ();
1155 switch (Type.GetTypeCode (et)) {
1156 case TypeCode.Boolean:
1157 while (index < end) {
1160 array.GetGenericValueImpl (index, out a);
1161 array.GetGenericValueImpl (end, out b);
1162 array.SetGenericValueImpl (index, ref b);
1163 array.SetGenericValueImpl (end, ref a);
1170 case TypeCode.SByte:
1171 while (index < end) {
1174 array.GetGenericValueImpl (index, out a);
1175 array.GetGenericValueImpl (end, out b);
1176 array.SetGenericValueImpl (index, ref b);
1177 array.SetGenericValueImpl (end, ref a);
1183 case TypeCode.Int16:
1184 case TypeCode.UInt16:
1186 while (index < end) {
1189 array.GetGenericValueImpl (index, out a);
1190 array.GetGenericValueImpl (end, out b);
1191 array.SetGenericValueImpl (index, ref b);
1192 array.SetGenericValueImpl (end, ref a);
1198 case TypeCode.Int32:
1199 case TypeCode.UInt32:
1200 case TypeCode.Single:
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.Int64:
1214 case TypeCode.UInt64:
1215 case TypeCode.Double:
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.Decimal:
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.String:
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 if (array is object[])
1255 goto case TypeCode.String;
1257 // Very slow fallback
1258 while (index < end) {
1259 object val = array.GetValueImpl (index);
1260 array.SetValueImpl (array.GetValueImpl (end), index);
1261 array.SetValueImpl (val, end);
1270 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1271 public static void Sort (Array array)
1273 Sort (array, (IComparer)null);
1276 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1277 public static void Sort (Array keys, Array items)
1279 Sort (keys, items, (IComparer)null);
1282 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1283 public static void Sort (Array array, IComparer comparer)
1286 throw new ArgumentNullException ("array");
1289 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1291 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1294 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1295 public static void Sort (Array array, int index, int length)
1297 Sort (array, index, length, (IComparer)null);
1300 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1301 public static void Sort (Array keys, Array items, IComparer comparer)
1303 if (items == null) {
1304 Sort (keys, comparer);
1309 throw new ArgumentNullException ("keys");
1311 if (keys.Rank > 1 || items.Rank > 1)
1312 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1314 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1317 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1318 public static void Sort (Array keys, Array items, int index, int length)
1320 Sort (keys, items, index, length, (IComparer)null);
1323 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1324 public static void Sort (Array array, int index, int length, IComparer comparer)
1327 throw new ArgumentNullException ("array");
1330 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1332 if (index < array.GetLowerBound (0))
1333 throw new ArgumentOutOfRangeException ("index");
1336 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1337 "Value has to be >= 0."));
1339 if (array.Length - (array.GetLowerBound (0) + index) < length)
1340 throw new ArgumentException ();
1342 SortImpl (array, null, index, length, comparer);
1345 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1346 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1348 if (items == null) {
1349 Sort (keys, index, length, comparer);
1354 throw new ArgumentNullException ("keys");
1356 if (keys.Rank > 1 || items.Rank > 1)
1357 throw new RankException ();
1359 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1360 throw new ArgumentException ();
1362 if (index < keys.GetLowerBound (0))
1363 throw new ArgumentOutOfRangeException ("index");
1366 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1367 "Value has to be >= 0."));
1369 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1370 throw new ArgumentException ();
1372 SortImpl (keys, items, index, length, comparer);
1375 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1381 int high = index + length - 1;
1383 #if !BOOTSTRAP_BASIC
1384 if (comparer == null && items is object[]) {
1385 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1386 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1387 case TypeCode.Int32:
1388 qsort (keys as Int32[], items as object[], low, high);
1390 case TypeCode.Int64:
1391 qsort (keys as Int64[], items as object[], low, high);
1394 qsort (keys as byte[], items as object[], low, high);
1397 qsort (keys as char[], items as object[], low, high);
1399 case TypeCode.DateTime:
1400 qsort (keys as DateTime[], items as object[], low, high);
1402 case TypeCode.Decimal:
1403 qsort (keys as decimal[], items as object[], low, high);
1405 case TypeCode.Double:
1406 qsort (keys as double[], items as object[], low, high);
1408 case TypeCode.Int16:
1409 qsort (keys as Int16[], items as object[], low, high);
1411 case TypeCode.SByte:
1412 qsort (keys as SByte[], items as object[], low, high);
1414 case TypeCode.Single:
1415 qsort (keys as Single[], items as object[], low, high);
1417 case TypeCode.UInt16:
1418 qsort (keys as UInt16[], items as object[], low, high);
1420 case TypeCode.UInt32:
1421 qsort (keys as UInt32[], items as object[], low, high);
1423 case TypeCode.UInt64:
1424 qsort (keys as UInt64[], items as object[], low, high);
1432 if (comparer == null)
1433 CheckComparerAvailable (keys, low, high);
1436 qsort (keys, items, low, high, comparer);
1437 } catch (Exception e) {
1438 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1447 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1452 if (comparer != null) {
1453 if (comparer.Compare (v1, v0) < 0) {
1454 swap (keys, items, lo, hi);
1461 } else if (v0 != null) {
1462 cmp = v1 as IComparable;
1464 if (v1 == null || cmp.CompareTo (v0) < 0) {
1465 swap (keys, items, lo, hi);
1477 unsafe static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1479 QSortStack* stack = stackalloc QSortStack [32];
1480 const int QSORT_THRESHOLD = 7;
1481 int high, low, mid, i, k;
1486 // initialize our stack
1487 stack[0].high = high0;
1488 stack[0].low = low0;
1493 high = stack[sp].high;
1494 low = stack[sp].low;
1496 if ((low + QSORT_THRESHOLD) > high) {
1497 // switch to insertion sort
1498 for (i = low + 1; i <= high; i++) {
1499 for (k = i; k > low; k--) {
1500 lo = keys.GetValueImpl (k - 1);
1501 hi = keys.GetValueImpl (k);
1502 if (comparer != null) {
1503 if (comparer.Compare (hi, lo) >= 0)
1510 cmp = hi as IComparable;
1511 if (cmp.CompareTo (lo) >= 0)
1516 swap (keys, items, k - 1, k);
1523 // calculate the middle element
1524 mid = low + ((high - low) / 2);
1527 key = keys.GetValueImpl (mid);
1528 hi = keys.GetValueImpl (high);
1529 lo = keys.GetValueImpl (low);
1531 // once we re-order the low, mid, and high elements to be in
1532 // ascending order, we'll use mid as our pivot.
1533 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1534 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1535 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1537 cmp = key as IComparable;
1539 // since we've already guaranteed that lo <= mid and mid <= hi,
1540 // we can skip comparing them again.
1545 // Move the walls in
1546 if (comparer != null) {
1547 // find the first element with a value >= pivot value
1548 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
1551 // find the last element with a value <= pivot value
1552 while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1554 } else if (cmp != null) {
1555 // find the first element with a value >= pivot value
1556 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
1559 // find the last element with a value <= pivot value
1560 while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1563 // This has the effect of moving the null values to the front if comparer is null
1564 while (i < k && keys.GetValueImpl (i) == null)
1567 while (k > i && keys.GetValueImpl (k) != null)
1574 swap (keys, items, i, k);
1580 // push our partitions onto the stack, largest first
1581 // (to make sure we don't run out of stack space)
1582 if ((high - k) >= (k - low)) {
1583 if ((k + 1) < high) {
1584 stack[sp].high = high;
1589 if ((k - 1) > low) {
1591 stack[sp].low = low;
1595 if ((k - 1) > low) {
1597 stack[sp].low = low;
1601 if ((k + 1) < high) {
1602 stack[sp].high = high;
1610 private static void CheckComparerAvailable (Array keys, int low, int high)
1612 // move null keys to beginning of array,
1613 // ensure that non-null keys implement IComparable
1614 for (int i = 0; i < high; i++) {
1615 object obj = keys.GetValueImpl (i);
1618 if (!(obj is IComparable)) {
1619 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1620 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1625 private static void swap (Array keys, Array items, int i, int j)
1627 object tmp = keys.GetValueImpl (i);
1628 keys.SetValueImpl (keys.GetValueImpl (j), i);
1629 keys.SetValueImpl (tmp, j);
1631 if (items != null) {
1632 tmp = items.GetValueImpl (i);
1633 items.SetValueImpl (items.GetValueImpl (j), i);
1634 items.SetValueImpl (tmp, j);
1638 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1639 public static void Sort<T> (T [] array)
1641 Sort<T> (array, (IComparer<T>)null);
1644 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1645 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1647 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1650 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1651 public static void Sort<T> (T [] array, IComparer<T> comparer)
1654 throw new ArgumentNullException ("array");
1656 SortImpl<T> (array, 0, array.Length, comparer);
1659 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1660 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1662 if (items == null) {
1663 Sort<TKey> (keys, comparer);
1668 throw new ArgumentNullException ("keys");
1670 if (keys.Length != items.Length)
1671 throw new ArgumentException ("Length of keys and items does not match.");
1673 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1676 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1677 public static void Sort<T> (T [] array, int index, int length)
1679 Sort<T> (array, index, length, (IComparer<T>)null);
1682 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1683 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1685 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1688 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1689 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1692 throw new ArgumentNullException ("array");
1695 throw new ArgumentOutOfRangeException ("index");
1698 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1699 "Value has to be >= 0."));
1701 if (index + length > array.Length)
1702 throw new ArgumentException ();
1704 SortImpl<T> (array, index, length, comparer);
1707 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1708 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1710 if (items == null) {
1711 Sort<TKey> (keys, index, length, comparer);
1716 throw new ArgumentNullException ("keys");
1719 throw new ArgumentOutOfRangeException ("index");
1722 throw new ArgumentOutOfRangeException ("length");
1724 if (items.Length - index < length || keys.Length - index < length)
1725 throw new ArgumentException ();
1727 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1730 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1732 if (keys.Length <= 1)
1736 int high = index + length - 1;
1739 // Check for value types which can be sorted without Compare () method
1741 if (comparer == null) {
1742 /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
1743 #if !FULL_AOT_RUNTIME
1744 #if !BOOTSTRAP_BASIC
1745 switch (Type.GetTypeCode (typeof (TKey))) {
1746 case TypeCode.Int32:
1747 qsort (keys as Int32[], items, low, high);
1749 case TypeCode.Int64:
1750 qsort (keys as Int64[], items, low, high);
1753 qsort (keys as byte[], items, low, high);
1756 qsort (keys as char[], items, low, high);
1758 case TypeCode.DateTime:
1759 qsort (keys as DateTime[], items, low, high);
1761 case TypeCode.Decimal:
1762 qsort (keys as decimal[], items, low, high);
1764 case TypeCode.Double:
1765 qsort (keys as double[], items, low, high);
1767 case TypeCode.Int16:
1768 qsort (keys as Int16[], items, low, high);
1770 case TypeCode.SByte:
1771 qsort (keys as SByte[], items, low, high);
1773 case TypeCode.Single:
1774 qsort (keys as Single[], items, low, high);
1776 case TypeCode.UInt16:
1777 qsort (keys as UInt16[], items, low, high);
1779 case TypeCode.UInt32:
1780 qsort (keys as UInt32[], items, low, high);
1782 case TypeCode.UInt64:
1783 qsort (keys as UInt64[], items, low, high);
1788 // Using Comparer<TKey> adds a small overload, but with value types it
1789 // helps us to not box them.
1790 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1791 typeof (TKey).IsValueType)
1792 comparer = Comparer<TKey>.Default;
1795 if (comparer == null)
1796 CheckComparerAvailable<TKey> (keys, low, high);
1799 qsort (keys, items, low, high, comparer);
1800 //} catch (Exception e) {
1801 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1805 // Specialized version for items==null
1806 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1808 if (keys.Length <= 1)
1812 int high = index + length - 1;
1815 // Check for value types which can be sorted without Compare () method
1817 if (comparer == null) {
1818 #if !BOOTSTRAP_BASIC
1819 switch (Type.GetTypeCode (typeof (TKey))) {
1820 case TypeCode.Int32:
1821 qsort (keys as Int32[], low, high);
1823 case TypeCode.Int64:
1824 qsort (keys as Int64[], low, high);
1827 qsort (keys as byte[], low, high);
1830 qsort (keys as char[], low, high);
1832 case TypeCode.DateTime:
1833 qsort (keys as DateTime[], low, high);
1835 case TypeCode.Decimal:
1836 qsort (keys as decimal[], low, high);
1838 case TypeCode.Double:
1839 qsort (keys as double[], low, high);
1841 case TypeCode.Int16:
1842 qsort (keys as Int16[], low, high);
1844 case TypeCode.SByte:
1845 qsort (keys as SByte[], low, high);
1847 case TypeCode.Single:
1848 qsort (keys as Single[], low, high);
1850 case TypeCode.UInt16:
1851 qsort (keys as UInt16[], low, high);
1853 case TypeCode.UInt32:
1854 qsort (keys as UInt32[], low, high);
1856 case TypeCode.UInt64:
1857 qsort (keys as UInt64[], low, high);
1861 // Using Comparer<TKey> adds a small overload, but with value types it
1862 // helps us to not box them.
1863 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1864 typeof (TKey).IsValueType)
1865 comparer = Comparer<TKey>.Default;
1868 if (comparer == null)
1869 CheckComparerAvailable<TKey> (keys, low, high);
1872 qsort<TKey> (keys, low, high, comparer);
1873 //} catch (Exception e) {
1874 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1878 public static void Sort<T> (T [] array, Comparison<T> comparison)
1881 throw new ArgumentNullException ("array");
1883 if (comparison == null)
1884 throw new ArgumentNullException ("comparison");
1886 SortImpl<T> (array, array.Length, comparison);
1889 // used by List<T>.Sort (Comparison <T>)
1890 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1897 int high0 = length - 1;
1898 qsort<T> (array, low0, high0, comparison);
1899 } catch (InvalidOperationException) {
1901 } catch (Exception e) {
1902 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1906 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1908 if (keys[lo] != null) {
1909 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1910 swap (keys, items, lo, hi);
1918 // Specialized version for items==null
1919 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1921 if (keys[lo] != null) {
1922 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1923 swap (keys, lo, hi);
1931 unsafe static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1933 QSortStack* stack = stackalloc QSortStack [32];
1934 const int QSORT_THRESHOLD = 7;
1935 int high, low, mid, i, k;
1939 // initialize our stack
1940 stack[0].high = high0;
1941 stack[0].low = low0;
1946 high = stack[sp].high;
1947 low = stack[sp].low;
1949 if ((low + QSORT_THRESHOLD) > high) {
1950 // switch to insertion sort
1951 for (i = low + 1; i <= high; i++) {
1952 for (k = i; k > low; k--) {
1953 // if keys[k] >= keys[k-1], break
1954 if (keys[k-1] == null)
1957 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
1960 swap (keys, items, k - 1, k);
1967 // calculate the middle element
1968 mid = low + ((high - low) / 2);
1970 // once we re-order the lo, mid, and hi elements to be in
1971 // ascending order, we'll use mid as our pivot.
1972 QSortArrange<T, U> (keys, items, low, mid);
1973 if (QSortArrange<T, U> (keys, items, mid, high))
1974 QSortArrange<T, U> (keys, items, low, mid);
1978 // since we've already guaranteed that lo <= mid and mid <= hi,
1979 // we can skip comparing them again
1985 // find the first element with a value >= pivot value
1986 while (i < k && key.CompareTo (keys[i]) > 0)
1989 // find the last element with a value <= pivot value
1990 while (k > i && key.CompareTo (keys[k]) < 0)
1993 while (i < k && keys[i] == null)
1996 while (k > i && keys[k] != null)
2003 swap (keys, items, i, k);
2009 // push our partitions onto the stack, largest first
2010 // (to make sure we don't run out of stack space)
2011 if ((high - k) >= (k - low)) {
2012 if ((k + 1) < high) {
2013 stack[sp].high = high;
2018 if ((k - 1) > low) {
2020 stack[sp].low = low;
2024 if ((k - 1) > low) {
2026 stack[sp].low = low;
2030 if ((k + 1) < high) {
2031 stack[sp].high = high;
2039 // Specialized version for items==null
2040 unsafe static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2042 QSortStack* stack = stackalloc QSortStack [32];
2043 const int QSORT_THRESHOLD = 7;
2044 int high, low, mid, i, k;
2048 // initialize our stack
2049 stack[0].high = high0;
2050 stack[0].low = low0;
2055 high = stack[sp].high;
2056 low = stack[sp].low;
2058 if ((low + QSORT_THRESHOLD) > high) {
2059 // switch to insertion sort
2060 for (i = low + 1; i <= high; i++) {
2061 for (k = i; k > low; k--) {
2062 // if keys[k] >= keys[k-1], break
2063 if (keys[k-1] == null)
2066 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2069 swap (keys, k - 1, k);
2076 // calculate the middle element
2077 mid = low + ((high - low) / 2);
2079 // once we re-order the lo, mid, and hi elements to be in
2080 // ascending order, we'll use mid as our pivot.
2081 QSortArrange<T> (keys, low, mid);
2082 if (QSortArrange<T> (keys, mid, high))
2083 QSortArrange<T> (keys, low, mid);
2087 // since we've already guaranteed that lo <= mid and mid <= hi,
2088 // we can skip comparing them again
2094 // find the first element with a value >= pivot value
2095 while (i < k && key.CompareTo (keys[i]) > 0)
2098 // find the last element with a value <= pivot value
2099 while (k >= i && key.CompareTo (keys[k]) < 0)
2102 while (i < k && keys[i] == null)
2105 while (k >= i && keys[k] != null)
2118 // push our partitions onto the stack, largest first
2119 // (to make sure we don't run out of stack space)
2120 if ((high - k) >= (k - low)) {
2121 if ((k + 1) < high) {
2122 stack[sp].high = high;
2127 if ((k - 1) > low) {
2129 stack[sp].low = low;
2133 if ((k - 1) > low) {
2135 stack[sp].low = low;
2139 if ((k + 1) < high) {
2140 stack[sp].high = high;
2148 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2150 IComparable<K> gcmp;
2153 if (comparer != null) {
2154 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2155 swap<K, V> (keys, items, lo, hi);
2158 } else if (keys[lo] != null) {
2159 if (keys[hi] == null) {
2160 swap<K, V> (keys, items, lo, hi);
2164 gcmp = keys[hi] as IComparable<K>;
2166 if (gcmp.CompareTo (keys[lo]) < 0) {
2167 swap<K, V> (keys, items, lo, hi);
2174 cmp = keys[hi] as IComparable;
2176 if (cmp.CompareTo (keys[lo]) < 0) {
2177 swap<K, V> (keys, items, lo, hi);
2188 // Specialized version for items==null
2189 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2191 IComparable<K> gcmp;
2194 if (comparer != null) {
2195 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2196 swap<K> (keys, lo, hi);
2199 } else if (keys[lo] != null) {
2200 if (keys[hi] == null) {
2201 swap<K> (keys, lo, hi);
2205 gcmp = keys[hi] as IComparable<K>;
2207 if (gcmp.CompareTo (keys[lo]) < 0) {
2208 swap<K> (keys, lo, hi);
2215 cmp = keys[hi] as IComparable;
2217 if (cmp.CompareTo (keys[lo]) < 0) {
2218 swap<K> (keys, lo, hi);
2229 unsafe static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2231 QSortStack* stack = stackalloc QSortStack [32];
2232 const int QSORT_THRESHOLD = 7;
2233 int high, low, mid, i, k;
2234 IComparable<K> gcmp;
2239 // initialize our stack
2240 stack[0].high = high0;
2241 stack[0].low = low0;
2246 high = stack[sp].high;
2247 low = stack[sp].low;
2249 if ((low + QSORT_THRESHOLD) > high) {
2250 // switch to insertion sort
2251 for (i = low + 1; i <= high; i++) {
2252 for (k = i; k > low; k--) {
2253 // if keys[k] >= keys[k-1], break
2254 if (comparer != null) {
2255 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2258 if (keys[k-1] == null)
2261 if (keys[k] != null) {
2262 gcmp = keys[k] as IComparable<K>;
2263 cmp = keys[k] as IComparable;
2265 if (gcmp.CompareTo (keys[k-1]) >= 0)
2268 if (cmp.CompareTo (keys[k-1]) >= 0)
2274 swap<K, V> (keys, items, k - 1, k);
2281 // calculate the middle element
2282 mid = low + ((high - low) / 2);
2284 // once we re-order the low, mid, and high elements to be in
2285 // ascending order, we'll use mid as our pivot.
2286 QSortArrange<K, V> (keys, items, low, mid, comparer);
2287 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2288 QSortArrange<K, V> (keys, items, low, mid, comparer);
2291 gcmp = key as IComparable<K>;
2292 cmp = key as IComparable;
2294 // since we've already guaranteed that lo <= mid and mid <= hi,
2295 // we can skip comparing them again.
2300 // Move the walls in
2301 if (comparer != null) {
2302 // find the first element with a value >= pivot value
2303 while (i < k && comparer.Compare (key, keys[i]) > 0)
2306 // find the last element with a value <= pivot value
2307 while (k > i && comparer.Compare (key, keys[k]) < 0)
2311 // find the first element with a value >= pivot value
2312 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2315 // find the last element with a value <= pivot value
2316 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2318 } else if (cmp != null) {
2319 // find the first element with a value >= pivot value
2320 while (i < k && cmp.CompareTo (keys[i]) > 0)
2323 // find the last element with a value <= pivot value
2324 while (k > i && cmp.CompareTo (keys[k]) < 0)
2327 while (i < k && keys[i] == null)
2330 while (k > i && keys[k] != null)
2338 swap<K, V> (keys, items, i, k);
2344 // push our partitions onto the stack, largest first
2345 // (to make sure we don't run out of stack space)
2346 if ((high - k) >= (k - low)) {
2347 if ((k + 1) < high) {
2348 stack[sp].high = high;
2353 if ((k - 1) > low) {
2355 stack[sp].low = low;
2359 if ((k - 1) > low) {
2361 stack[sp].low = low;
2365 if ((k + 1) < high) {
2366 stack[sp].high = high;
2374 // Specialized version for items==null
2375 unsafe static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2377 QSortStack* stack = stackalloc QSortStack [32];
2378 const int QSORT_THRESHOLD = 7;
2379 int high, low, mid, i, k;
2380 IComparable<K> gcmp;
2385 // initialize our stack
2386 stack[0].high = high0;
2387 stack[0].low = low0;
2392 high = stack[sp].high;
2393 low = stack[sp].low;
2395 if ((low + QSORT_THRESHOLD) > high) {
2396 // switch to insertion sort
2397 for (i = low + 1; i <= high; i++) {
2398 for (k = i; k > low; k--) {
2399 // if keys[k] >= keys[k-1], break
2400 if (comparer != null) {
2401 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2404 if (keys[k-1] == null)
2407 if (keys[k] != null) {
2408 gcmp = keys[k] as IComparable<K>;
2409 cmp = keys[k] as IComparable;
2411 if (gcmp.CompareTo (keys[k-1]) >= 0)
2414 if (cmp.CompareTo (keys[k-1]) >= 0)
2420 swap<K> (keys, k - 1, k);
2427 // calculate the middle element
2428 mid = low + ((high - low) / 2);
2430 // once we re-order the low, mid, and high elements to be in
2431 // ascending order, we'll use mid as our pivot.
2432 QSortArrange<K> (keys, low, mid, comparer);
2433 if (QSortArrange<K> (keys, mid, high, comparer))
2434 QSortArrange<K> (keys, low, mid, comparer);
2437 gcmp = key as IComparable<K>;
2438 cmp = key as IComparable;
2440 // since we've already guaranteed that lo <= mid and mid <= hi,
2441 // we can skip comparing them again.
2446 // Move the walls in
2447 if (comparer != null) {
2448 // find the first element with a value >= pivot value
2449 while (i < k && comparer.Compare (key, keys[i]) > 0)
2452 // find the last element with a value <= pivot value
2453 while (k > i && comparer.Compare (key, keys[k]) < 0)
2457 // find the first element with a value >= pivot value
2458 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2461 // find the last element with a value <= pivot value
2462 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2464 } else if (cmp != null) {
2465 // find the first element with a value >= pivot value
2466 while (i < k && cmp.CompareTo (keys[i]) > 0)
2469 // find the last element with a value <= pivot value
2470 while (k > i && cmp.CompareTo (keys[k]) < 0)
2473 while (i < k && keys[i] == null)
2476 while (k > i && keys[k] != null)
2484 swap<K> (keys, i, k);
2490 // push our partitions onto the stack, largest first
2491 // (to make sure we don't run out of stack space)
2492 if ((high - k) >= (k - low)) {
2493 if ((k + 1) < high) {
2494 stack[sp].high = high;
2499 if ((k - 1) > low) {
2501 stack[sp].low = low;
2505 if ((k - 1) > low) {
2507 stack[sp].low = low;
2511 if ((k + 1) < high) {
2512 stack[sp].high = high;
2520 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2522 if (array[lo] != null) {
2523 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2524 swap<T> (array, lo, hi);
2532 unsafe static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2534 QSortStack* stack = stackalloc QSortStack [32];
2535 const int QSORT_THRESHOLD = 7;
2536 int high, low, mid, i, k;
2540 // initialize our stack
2541 stack[0].high = high0;
2542 stack[0].low = low0;
2547 high = stack[sp].high;
2548 low = stack[sp].low;
2550 if ((low + QSORT_THRESHOLD) > high) {
2551 // switch to insertion sort
2552 for (i = low + 1; i <= high; i++) {
2553 for (k = i; k > low; k--) {
2554 if (compare (array[k], array[k-1]) >= 0)
2557 swap<T> (array, k - 1, k);
2564 // calculate the middle element
2565 mid = low + ((high - low) / 2);
2567 // once we re-order the lo, mid, and hi elements to be in
2568 // ascending order, we'll use mid as our pivot.
2569 QSortArrange<T> (array, low, mid, compare);
2570 if (QSortArrange<T> (array, mid, high, compare))
2571 QSortArrange<T> (array, low, mid, compare);
2575 // since we've already guaranteed that lo <= mid and mid <= hi,
2576 // we can skip comparing them again
2581 // Move the walls in
2583 // find the first element with a value >= pivot value
2584 while (i < k && compare (key, array[i]) > 0)
2587 // find the last element with a value <= pivot value
2588 while (k > i && compare (key, array[k]) < 0)
2591 while (i < k && array[i] == null)
2594 while (k > i && array[k] != null)
2601 swap<T> (array, i, k);
2607 // push our partitions onto the stack, largest first
2608 // (to make sure we don't run out of stack space)
2609 if ((high - k) >= (k - low)) {
2610 if ((k + 1) < high) {
2611 stack[sp].high = high;
2616 if ((k - 1) > low) {
2618 stack[sp].low = low;
2622 if ((k - 1) > low) {
2624 stack[sp].low = low;
2628 if ((k + 1) < high) {
2629 stack[sp].high = high;
2637 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2639 // move null keys to beginning of array,
2640 // ensure that non-null keys implement IComparable
2641 for (int i = low; i < high; i++) {
2644 if (!(key is IComparable<K>) && !(key is IComparable)) {
2645 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2646 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2652 [MethodImpl ((MethodImplOptions)256)]
2653 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2658 keys [i] = keys [j];
2661 if (items != null) {
2664 items [i] = items [j];
2669 [MethodImpl ((MethodImplOptions)256)]
2670 private static void swap<T> (T [] array, int i, int j)
2673 array [i] = array [j];
2677 public void CopyTo (Array array, int index)
2680 throw new ArgumentNullException ("array");
2682 // The order of these exception checks may look strange,
2683 // but that's how the microsoft runtime does it.
2685 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2686 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2687 throw new ArgumentException ("Destination array was not long " +
2688 "enough. Check destIndex and length, and the array's " +
2691 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2693 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2694 "Value has to be >= 0."));
2696 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2699 [ComVisible (false)]
2700 public void CopyTo (Array array, long index)
2702 if (index < 0 || index > Int32.MaxValue)
2703 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2704 "Value must be >= 0 and <= Int32.MaxValue."));
2706 CopyTo (array, (int) index);
2709 internal class SimpleEnumerator : IEnumerator, ICloneable
2715 public SimpleEnumerator (Array arrayToEnumerate)
2717 this.enumeratee = arrayToEnumerate;
2718 this.currentpos = -1;
2719 this.length = arrayToEnumerate.Length;
2722 public object Current {
2724 // Exception messages based on MS implementation
2725 if (currentpos < 0 )
2726 throw new InvalidOperationException (Locale.GetText (
2727 "Enumeration has not started."));
2728 if (currentpos >= length)
2729 throw new InvalidOperationException (Locale.GetText (
2730 "Enumeration has already ended"));
2731 // Current should not increase the position. So no ++ over here.
2732 return enumeratee.GetValueImpl (currentpos);
2736 public bool MoveNext()
2738 //The docs say Current should throw an exception if last
2739 //call to MoveNext returned false. This means currentpos
2740 //should be set to length when returning false.
2741 if (currentpos < length)
2743 if(currentpos < length)
2754 public object Clone ()
2756 return MemberwiseClone ();
2760 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2761 public static void Resize<T> (ref T [] array, int newSize)
2764 throw new ArgumentOutOfRangeException ("newSize");
2766 if (array == null) {
2767 array = new T [newSize];
2772 int length = arr.Length;
2773 if (length == newSize)
2776 T [] a = new T [newSize];
2777 int tocopy = Math.Min (newSize, length);
2780 for (int i = 0; i < tocopy; ++i)
2781 UnsafeStore (a, i, UnsafeLoad (arr, i));
2783 FastCopy (arr, 0, a, 0, tocopy);
2788 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2791 throw new ArgumentNullException ("array");
2793 throw new ArgumentNullException ("match");
2795 foreach (T t in array)
2802 public static void ForEach<T> (T [] array, Action <T> action)
2805 throw new ArgumentNullException ("array");
2807 throw new ArgumentNullException ("action");
2809 foreach (T t in array)
2813 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2816 throw new ArgumentNullException ("array");
2817 if (converter == null)
2818 throw new ArgumentNullException ("converter");
2820 TOutput [] output = new TOutput [array.Length];
2821 for (int i = 0; i < array.Length; i ++)
2822 output [i] = converter (array [i]);
2827 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2830 throw new ArgumentNullException ("array");
2833 throw new ArgumentNullException ("match");
2835 return GetLastIndex (array, 0, array.Length, match);
2838 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2841 throw new ArgumentNullException ();
2843 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2844 throw new ArgumentOutOfRangeException ("startIndex");
2847 throw new ArgumentNullException ("match");
2849 return GetLastIndex (array, 0, startIndex + 1, match);
2852 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2855 throw new ArgumentNullException ("array");
2858 throw new ArgumentNullException ("match");
2860 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2861 throw new ArgumentOutOfRangeException ("startIndex");
2864 throw new ArgumentOutOfRangeException ("count");
2866 if (startIndex - count + 1 < 0)
2867 throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
2869 return GetLastIndex (array, startIndex - count + 1, count, match);
2872 internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2874 // unlike FindLastIndex, takes regular params for search range
2875 for (int i = startIndex + count; i != startIndex;)
2876 if (match (array [--i]))
2882 public static int FindIndex<T> (T [] array, Predicate<T> match)
2885 throw new ArgumentNullException ("array");
2888 throw new ArgumentNullException ("match");
2890 return GetIndex (array, 0, array.Length, match);
2893 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2896 throw new ArgumentNullException ("array");
2898 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2899 throw new ArgumentOutOfRangeException ("startIndex");
2902 throw new ArgumentNullException ("match");
2904 return GetIndex (array, startIndex, array.Length - startIndex, match);
2907 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2910 throw new ArgumentNullException ("array");
2913 throw new ArgumentOutOfRangeException ("startIndex");
2916 throw new ArgumentOutOfRangeException ("count");
2918 if ((uint) startIndex + (uint) count > (uint) array.Length)
2919 throw new ArgumentOutOfRangeException ("index and count exceed length of list");
2921 return GetIndex (array, startIndex, count, match);
2924 internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2926 int end = startIndex + count;
2927 for (int i = startIndex; i < end; i ++)
2928 if (match (array [i]))
2934 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2935 public static int BinarySearch<T> (T [] array, T value)
2938 throw new ArgumentNullException ("array");
2940 return BinarySearch<T> (array, 0, array.Length, value, null);
2943 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2944 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2947 throw new ArgumentNullException ("array");
2949 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2952 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2953 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2955 return BinarySearch<T> (array, index, length, value, null);
2958 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2959 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2962 throw new ArgumentNullException ("array");
2964 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2965 "index is less than the lower bound of array."));
2967 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2968 "Value has to be >= 0."));
2969 // re-ordered to avoid possible integer overflow
2970 if (index > array.Length - length)
2971 throw new ArgumentException (Locale.GetText (
2972 "index and length do not specify a valid range in array."));
2973 if (comparer == null)
2974 comparer = Comparer <T>.Default;
2977 int iMax = index + length - 1;
2980 while (iMin <= iMax) {
2981 // Be careful with overflows
2982 int iMid = iMin + ((iMax - iMin) / 2);
2983 iCmp = comparer.Compare (array [iMid], value);
2991 iMin = iMid + 1; // compensate for the rounding down
2993 } catch (Exception e) {
2994 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
3000 public static int IndexOf<T> (T [] array, T value)
3003 throw new ArgumentNullException ("array");
3005 return IndexOf<T> (array, value, 0, array.Length);
3008 public static int IndexOf<T> (T [] array, T value, int startIndex)
3011 throw new ArgumentNullException ("array");
3013 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
3016 public static int IndexOf<T> (T[] array, T value, int startIndex, int count)
3019 throw new ArgumentNullException ("array");
3021 // re-ordered to avoid possible integer overflow
3022 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
3023 throw new ArgumentOutOfRangeException ();
3025 return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, startIndex + count);
3028 public static int LastIndexOf<T> (T [] array, T value)
3031 throw new ArgumentNullException ("array");
3033 if (array.Length == 0)
3035 return LastIndexOf<T> (array, value, array.Length - 1);
3038 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3041 throw new ArgumentNullException ("array");
3043 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3046 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3049 throw new ArgumentNullException ("array");
3051 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3052 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3053 throw new ArgumentOutOfRangeException ();
3055 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3056 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3057 if (equalityComparer.Equals (array [i], value))
3064 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3067 throw new ArgumentNullException ("array");
3070 throw new ArgumentNullException ("match");
3073 T [] d = new T [array.Length];
3074 foreach (T t in array)
3078 Resize <T> (ref d, pos);
3082 public static bool Exists<T> (T [] array, Predicate <T> match)
3085 throw new ArgumentNullException ("array");
3088 throw new ArgumentNullException ("match");
3090 foreach (T t in array)
3096 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3099 throw new ArgumentNullException ("array");
3101 return new ReadOnlyCollection<T> (array);
3104 public static T Find<T> (T [] array, Predicate<T> match)
3107 throw new ArgumentNullException ("array");
3110 throw new ArgumentNullException ("match");
3112 foreach (T t in array)
3119 public static T FindLast<T> (T [] array, Predicate <T> match)
3122 throw new ArgumentNullException ("array");
3125 throw new ArgumentNullException ("match");
3127 for (int i = array.Length - 1; i >= 0; i--)
3128 if (match (array [i]))
3134 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3136 // The constrained copy should guarantee that if there is an exception thrown
3137 // during the copy, the destination array remains unchanged.
3138 // This is related to System.Runtime.Reliability.CER
3139 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3141 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
3144 #region Unsafe array operations
3147 // Loads array index with no safety checks (JIT intristics)
3149 internal static T UnsafeLoad<T> (T[] array, int index) {
3150 return array [index];
3154 // Stores values at specified array index with no safety checks (JIT intristics)
3156 internal static void UnsafeStore<T> (T[] array, int index, T value) {
3157 array [index] = value;
3161 // Moved value from instance into target of different type with no checks (JIT intristics)
3163 internal static R UnsafeMov<S,R> (S instance) {
3164 return (R)(object) instance;