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 internal static Array UnsafeCreateInstance (Type elementType, int length)
653 return CreateInstance (elementType, length);
656 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
658 return CreateInstance(elementType, lengths, lowerBounds);
661 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
663 return CreateInstance (elementType, length1, length2);
666 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
668 return CreateInstance(elementType, lengths);
671 public static Array CreateInstance (Type elementType, int length)
673 int[] lengths = {length};
675 return CreateInstance (elementType, lengths);
678 public static Array CreateInstance (Type elementType, int length1, int length2)
680 int[] lengths = {length1, length2};
682 return CreateInstance (elementType, lengths);
685 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
687 int[] lengths = {length1, length2, length3};
689 return CreateInstance (elementType, lengths);
692 public static Array CreateInstance (Type elementType, params int[] lengths)
694 if (elementType == null)
695 throw new ArgumentNullException ("elementType");
697 throw new ArgumentNullException ("lengths");
699 if (lengths.Length > 255)
700 throw new TypeLoadException ();
704 elementType = elementType.UnderlyingSystemType as RuntimeType;
705 if (elementType == null)
706 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
707 if (elementType.Equals (typeof (void)))
708 throw new NotSupportedException ("Array type can not be void");
709 if (elementType.ContainsGenericParameters)
710 throw new NotSupportedException ("Array type can not be an open generic type");
711 #if !FULL_AOT_RUNTIME
712 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
713 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
716 return CreateInstanceImpl (elementType, lengths, bounds);
719 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
721 if (elementType == null)
722 throw new ArgumentNullException ("elementType");
724 throw new ArgumentNullException ("lengths");
725 if (lowerBounds == null)
726 throw new ArgumentNullException ("lowerBounds");
728 elementType = elementType.UnderlyingSystemType as RuntimeType;
729 if (elementType == null)
730 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
731 if (elementType.Equals (typeof (void)))
732 throw new NotSupportedException ("Array type can not be void");
733 if (elementType.ContainsGenericParameters)
734 throw new NotSupportedException ("Array type can not be an open generic type");
736 if (lengths.Length < 1)
737 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
739 if (lengths.Length != lowerBounds.Length)
740 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
742 for (int j = 0; j < lowerBounds.Length; j ++) {
744 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
745 "Each value has to be >= 0."));
746 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
747 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
748 "Length + bound must not exceed Int32.MaxValue."));
751 if (lengths.Length > 255)
752 throw new TypeLoadException ();
754 return CreateInstanceImpl (elementType, lengths, lowerBounds);
757 static int [] GetIntArray (long [] values)
759 int len = values.Length;
760 int [] ints = new int [len];
761 for (int i = 0; i < len; i++) {
762 long current = values [i];
763 if (current < 0 || current > (long) Int32.MaxValue)
764 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
765 "Each value has to be >= 0 and <= Int32.MaxValue."));
767 ints [i] = (int) current;
772 public static Array CreateInstance (Type elementType, params long [] lengths)
775 throw new ArgumentNullException ("lengths");
776 return CreateInstance (elementType, GetIntArray (lengths));
780 public object GetValue (params long [] indices)
783 throw new ArgumentNullException ("indices");
784 return GetValue (GetIntArray (indices));
788 public void SetValue (object value, params long [] indices)
791 throw new ArgumentNullException ("indices");
792 SetValue (value, GetIntArray (indices));
795 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
796 public static int BinarySearch (Array array, object value)
798 return BinarySearch (array, value, null);
801 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
802 public static int BinarySearch (Array array, object value, IComparer comparer)
805 throw new ArgumentNullException ("array");
808 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
810 if (array.Length == 0)
813 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
816 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
817 public static int BinarySearch (Array array, int index, int length, object value)
819 return BinarySearch (array, index, length, value, null);
822 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
823 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
826 throw new ArgumentNullException ("array");
829 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
831 if (index < array.GetLowerBound (0))
832 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
833 "index is less than the lower bound of array."));
835 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
836 "Value has to be >= 0."));
837 // re-ordered to avoid possible integer overflow
838 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
839 throw new ArgumentException (Locale.GetText (
840 "index and length do not specify a valid range in array."));
842 if (array.Length == 0)
845 return DoBinarySearch (array, index, length, value, comparer);
848 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
850 // cache this in case we need it
851 if (comparer == null)
852 comparer = Comparer.Default;
855 // Comment from Tum (tum@veridicus.com):
856 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
857 int iMax = index + length - 1;
860 while (iMin <= iMax) {
861 // Be careful with overflow
862 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
863 int iMid = iMin + ((iMax - iMin) / 2);
864 object elt = array.GetValueImpl (iMid);
866 iCmp = comparer.Compare (elt, value);
873 iMin = iMid + 1; // compensate for the rounding down
876 catch (Exception e) {
877 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
883 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
884 public static void Clear (Array array, int index, int length)
887 throw new ArgumentNullException ("array");
889 throw new IndexOutOfRangeException ("length < 0");
891 int low = array.GetLowerBound (0);
893 throw new IndexOutOfRangeException ("index < lower bound");
896 // re-ordered to avoid possible integer overflow
897 if (index > array.Length - length)
898 throw new IndexOutOfRangeException ("index + length > size");
900 ClearInternal (array, index, length);
903 [MethodImplAttribute (MethodImplOptions.InternalCall)]
904 static extern void ClearInternal (Array a, int index, int count);
906 [MethodImplAttribute (MethodImplOptions.InternalCall)]
907 public extern object Clone ();
909 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
910 public static void Copy (Array sourceArray, Array destinationArray, int length)
912 // need these checks here because we are going to use
913 // GetLowerBound() on source and dest.
914 if (sourceArray == null)
915 throw new ArgumentNullException ("sourceArray");
917 if (destinationArray == null)
918 throw new ArgumentNullException ("destinationArray");
920 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
921 destinationArray.GetLowerBound (0), length);
924 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
925 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
927 if (sourceArray == null)
928 throw new ArgumentNullException ("sourceArray");
930 if (destinationArray == null)
931 throw new ArgumentNullException ("destinationArray");
934 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
935 "Value has to be >= 0."));;
938 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
939 "Value has to be >= 0."));;
941 if (destinationIndex < 0)
942 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
943 "Value has to be >= 0."));;
945 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
948 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
949 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
952 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
954 // re-ordered to avoid possible integer overflow
955 if (source_pos > sourceArray.Length - length)
956 throw new ArgumentException ("length");
958 if (dest_pos > destinationArray.Length - length) {
959 string msg = "Destination array was not long enough. Check " +
960 "destIndex and length, and the array's lower bounds";
961 throw new ArgumentException (msg, string.Empty);
964 if (sourceArray.Rank != destinationArray.Rank)
965 throw new RankException (Locale.GetText ("Arrays must be of same size."));
967 Type src_type = sourceArray.GetType ().GetElementType ();
968 Type dst_type = destinationArray.GetType ().GetElementType ();
970 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
971 for (int i = 0; i < length; i++) {
972 Object srcval = sourceArray.GetValueImpl (source_pos + i);
975 destinationArray.SetValueImpl (srcval, dest_pos + i);
976 } catch (ArgumentException) {
977 throw CreateArrayTypeMismatchException ();
979 if (CanAssignArrayElement (src_type, dst_type))
982 throw CreateArrayTypeMismatchException ();
987 for (int i = length - 1; i >= 0; i--) {
988 Object srcval = sourceArray.GetValueImpl (source_pos + i);
991 destinationArray.SetValueImpl (srcval, dest_pos + i);
992 } catch (ArgumentException) {
993 throw CreateArrayTypeMismatchException ();
995 if (CanAssignArrayElement (src_type, dst_type))
998 throw CreateArrayTypeMismatchException ();
1004 static Exception CreateArrayTypeMismatchException ()
1006 return new ArrayTypeMismatchException ();
1009 static bool CanAssignArrayElement (Type source, Type target)
1011 if (source.IsValueType)
1012 return source.IsAssignableFrom (target);
1014 if (source.IsInterface)
1015 return !target.IsValueType;
1017 if (target.IsInterface)
1018 return !source.IsValueType;
1020 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
1023 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1024 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1025 long destinationIndex, long length)
1027 if (sourceArray == null)
1028 throw new ArgumentNullException ("sourceArray");
1030 if (destinationArray == null)
1031 throw new ArgumentNullException ("destinationArray");
1033 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1034 throw new ArgumentOutOfRangeException ("sourceIndex",
1035 Locale.GetText ("Must be in the Int32 range."));
1037 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1038 throw new ArgumentOutOfRangeException ("destinationIndex",
1039 Locale.GetText ("Must be in the Int32 range."));
1041 if (length < 0 || length > Int32.MaxValue)
1042 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1043 "Value must be >= 0 and <= Int32.MaxValue."));
1045 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1048 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1049 public static void Copy (Array sourceArray, Array destinationArray, long length)
1051 if (length < 0 || length > Int32.MaxValue)
1052 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1053 "Value must be >= 0 and <= Int32.MaxValue."));
1055 Copy (sourceArray, destinationArray, (int) length);
1058 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1059 public static int IndexOf (Array array, object value)
1062 throw new ArgumentNullException ("array");
1064 return IndexOf (array, value, 0, array.Length);
1067 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1068 public static int IndexOf (Array array, object value, int startIndex)
1071 throw new ArgumentNullException ("array");
1073 return IndexOf (array, value, startIndex, array.Length - startIndex);
1076 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1077 public static int IndexOf (Array array, object value, int startIndex, int count)
1080 throw new ArgumentNullException ("array");
1083 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1085 // re-ordered to avoid possible integer overflow
1086 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1087 throw new ArgumentOutOfRangeException ();
1089 int max = startIndex + count;
1090 for (int i = startIndex; i < max; i++) {
1091 if (Object.Equals (array.GetValueImpl (i), value))
1095 return array.GetLowerBound (0) - 1;
1098 public void Initialize()
1100 //FIXME: We would like to find a compiler that uses
1101 // this method. It looks like this method do nothing
1102 // in C# so no exception is trown by the moment.
1105 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1106 public static int LastIndexOf (Array array, object value)
1109 throw new ArgumentNullException ("array");
1111 if (array.Length == 0)
1112 return array.GetLowerBound (0) - 1;
1113 return LastIndexOf (array, value, array.Length - 1);
1116 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1117 public static int LastIndexOf (Array array, object value, int startIndex)
1120 throw new ArgumentNullException ("array");
1122 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1125 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1126 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1129 throw new ArgumentNullException ("array");
1132 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1134 int lb = array.GetLowerBound (0);
1135 // Empty arrays do not throw ArgumentOutOfRangeException
1136 if (array.Length == 0)
1139 if (count < 0 || startIndex < lb ||
1140 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1141 throw new ArgumentOutOfRangeException ();
1143 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1144 if (Object.Equals (array.GetValueImpl (i), value))
1151 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1152 public static void Reverse (Array array)
1155 throw new ArgumentNullException ("array");
1157 Reverse (array, array.GetLowerBound (0), array.Length);
1160 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1161 public static void Reverse (Array array, int index, int length)
1164 throw new ArgumentNullException ("array");
1167 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1169 if (index < array.GetLowerBound (0) || length < 0)
1170 throw new ArgumentOutOfRangeException ();
1172 // re-ordered to avoid possible integer overflow
1173 if (index > array.GetUpperBound (0) + 1 - length)
1174 throw new ArgumentException ();
1176 int end = index + length - 1;
1177 var et = array.GetType ().GetElementType ();
1178 switch (Type.GetTypeCode (et)) {
1179 case TypeCode.Boolean:
1180 while (index < end) {
1183 array.GetGenericValueImpl (index, out a);
1184 array.GetGenericValueImpl (end, out b);
1185 array.SetGenericValueImpl (index, ref b);
1186 array.SetGenericValueImpl (end, ref a);
1193 case TypeCode.SByte:
1194 while (index < end) {
1197 array.GetGenericValueImpl (index, out a);
1198 array.GetGenericValueImpl (end, out b);
1199 array.SetGenericValueImpl (index, ref b);
1200 array.SetGenericValueImpl (end, ref a);
1206 case TypeCode.Int16:
1207 case TypeCode.UInt16:
1209 while (index < end) {
1212 array.GetGenericValueImpl (index, out a);
1213 array.GetGenericValueImpl (end, out b);
1214 array.SetGenericValueImpl (index, ref b);
1215 array.SetGenericValueImpl (end, ref a);
1221 case TypeCode.Int32:
1222 case TypeCode.UInt32:
1223 case TypeCode.Single:
1224 while (index < end) {
1227 array.GetGenericValueImpl (index, out a);
1228 array.GetGenericValueImpl (end, out b);
1229 array.SetGenericValueImpl (index, ref b);
1230 array.SetGenericValueImpl (end, ref a);
1236 case TypeCode.Int64:
1237 case TypeCode.UInt64:
1238 case TypeCode.Double:
1239 while (index < end) {
1242 array.GetGenericValueImpl (index, out a);
1243 array.GetGenericValueImpl (end, out b);
1244 array.SetGenericValueImpl (index, ref b);
1245 array.SetGenericValueImpl (end, ref a);
1251 case TypeCode.Decimal:
1252 while (index < end) {
1255 array.GetGenericValueImpl (index, out a);
1256 array.GetGenericValueImpl (end, out b);
1257 array.SetGenericValueImpl (index, ref b);
1258 array.SetGenericValueImpl (end, ref a);
1264 case TypeCode.String:
1265 while (index < end) {
1268 array.GetGenericValueImpl (index, out a);
1269 array.GetGenericValueImpl (end, out b);
1270 array.SetGenericValueImpl (index, ref b);
1271 array.SetGenericValueImpl (end, ref a);
1277 if (array is object[])
1278 goto case TypeCode.String;
1280 // Very slow fallback
1281 while (index < end) {
1282 object val = array.GetValueImpl (index);
1283 array.SetValueImpl (array.GetValueImpl (end), index);
1284 array.SetValueImpl (val, end);
1293 public static void Reverse<T>(T[] array)
1296 throw new ArgumentNullException (nameof (array));
1298 Reverse (array, 0, array.Length);
1301 public static void Reverse<T>(T[] array, int index, int length)
1304 throw new ArgumentNullException (nameof (array));
1305 if (index < 0 || length < 0)
1306 throw new ArgumentOutOfRangeException ((index < 0 ? nameof (index) : nameof (length)));
1307 if (array.Length - index < length)
1308 throw new ArgumentException ();
1311 int j = index + length - 1;
1314 array [i] = array [j];
1321 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1322 public static void Sort (Array array)
1324 Sort (array, (IComparer)null);
1327 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1328 public static void Sort (Array keys, Array items)
1330 Sort (keys, items, (IComparer)null);
1333 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1334 public static void Sort (Array array, IComparer comparer)
1337 throw new ArgumentNullException ("array");
1340 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1342 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1345 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1346 public static void Sort (Array array, int index, int length)
1348 Sort (array, index, length, (IComparer)null);
1351 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1352 public static void Sort (Array keys, Array items, IComparer comparer)
1354 if (items == null) {
1355 Sort (keys, comparer);
1360 throw new ArgumentNullException ("keys");
1362 if (keys.Rank > 1 || items.Rank > 1)
1363 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1365 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1368 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1369 public static void Sort (Array keys, Array items, int index, int length)
1371 Sort (keys, items, index, length, (IComparer)null);
1374 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1375 public static void Sort (Array array, int index, int length, IComparer comparer)
1378 throw new ArgumentNullException ("array");
1381 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1383 if (index < array.GetLowerBound (0))
1384 throw new ArgumentOutOfRangeException ("index");
1387 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1388 "Value has to be >= 0."));
1390 if (array.Length - (array.GetLowerBound (0) + index) < length)
1391 throw new ArgumentException ();
1393 SortImpl (array, null, index, length, comparer);
1396 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1397 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1399 if (items == null) {
1400 Sort (keys, index, length, comparer);
1405 throw new ArgumentNullException ("keys");
1407 if (keys.Rank > 1 || items.Rank > 1)
1408 throw new RankException ();
1410 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1411 throw new ArgumentException ();
1413 if (index < keys.GetLowerBound (0))
1414 throw new ArgumentOutOfRangeException ("index");
1417 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1418 "Value has to be >= 0."));
1420 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1421 throw new ArgumentException ();
1423 SortImpl (keys, items, index, length, comparer);
1426 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1432 int high = index + length - 1;
1434 #if !BOOTSTRAP_BASIC
1435 if (comparer == null && items is object[]) {
1436 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1437 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1438 case TypeCode.Int32:
1439 qsort (keys as Int32[], items as object[], low, high);
1441 case TypeCode.Int64:
1442 qsort (keys as Int64[], items as object[], low, high);
1445 qsort (keys as byte[], items as object[], low, high);
1448 qsort (keys as char[], items as object[], low, high);
1450 case TypeCode.DateTime:
1451 qsort (keys as DateTime[], items as object[], low, high);
1453 case TypeCode.Decimal:
1454 qsort (keys as decimal[], items as object[], low, high);
1456 case TypeCode.Double:
1457 qsort (keys as double[], items as object[], low, high);
1459 case TypeCode.Int16:
1460 qsort (keys as Int16[], items as object[], low, high);
1462 case TypeCode.SByte:
1463 qsort (keys as SByte[], items as object[], low, high);
1465 case TypeCode.Single:
1466 qsort (keys as Single[], items as object[], low, high);
1468 case TypeCode.UInt16:
1469 qsort (keys as UInt16[], items as object[], low, high);
1471 case TypeCode.UInt32:
1472 qsort (keys as UInt32[], items as object[], low, high);
1474 case TypeCode.UInt64:
1475 qsort (keys as UInt64[], items as object[], low, high);
1483 if (comparer == null)
1484 CheckComparerAvailable (keys, low, high);
1487 qsort (keys, items, low, high, comparer);
1488 } catch (Exception e) {
1489 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1498 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1503 if (comparer != null) {
1504 if (comparer.Compare (v1, v0) < 0) {
1505 swap (keys, items, lo, hi);
1512 } else if (v0 != null) {
1513 cmp = v1 as IComparable;
1515 if (v1 == null || cmp.CompareTo (v0) < 0) {
1516 swap (keys, items, lo, hi);
1528 unsafe static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1530 QSortStack* stack = stackalloc QSortStack [32];
1531 const int QSORT_THRESHOLD = 7;
1532 int high, low, mid, i, k;
1537 // initialize our stack
1538 stack[0].high = high0;
1539 stack[0].low = low0;
1544 high = stack[sp].high;
1545 low = stack[sp].low;
1547 if ((low + QSORT_THRESHOLD) > high) {
1548 // switch to insertion sort
1549 for (i = low + 1; i <= high; i++) {
1550 for (k = i; k > low; k--) {
1551 lo = keys.GetValueImpl (k - 1);
1552 hi = keys.GetValueImpl (k);
1553 if (comparer != null) {
1554 if (comparer.Compare (hi, lo) >= 0)
1561 cmp = hi as IComparable;
1562 if (cmp.CompareTo (lo) >= 0)
1567 swap (keys, items, k - 1, k);
1574 // calculate the middle element
1575 mid = low + ((high - low) / 2);
1578 key = keys.GetValueImpl (mid);
1579 hi = keys.GetValueImpl (high);
1580 lo = keys.GetValueImpl (low);
1582 // once we re-order the low, mid, and high elements to be in
1583 // ascending order, we'll use mid as our pivot.
1584 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1585 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1586 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1588 cmp = key as IComparable;
1590 // since we've already guaranteed that lo <= mid and mid <= hi,
1591 // we can skip comparing them again.
1596 // Move the walls in
1597 if (comparer != null) {
1598 // find the first element with a value >= pivot value
1599 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
1602 // find the last element with a value <= pivot value
1603 while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1605 } else if (cmp != null) {
1606 // find the first element with a value >= pivot value
1607 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
1610 // find the last element with a value <= pivot value
1611 while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1614 // This has the effect of moving the null values to the front if comparer is null
1615 while (i < k && keys.GetValueImpl (i) == null)
1618 while (k > i && keys.GetValueImpl (k) != null)
1625 swap (keys, items, i, k);
1631 // push our partitions onto the stack, largest first
1632 // (to make sure we don't run out of stack space)
1633 if ((high - k) >= (k - low)) {
1634 if ((k + 1) < high) {
1635 stack[sp].high = high;
1640 if ((k - 1) > low) {
1642 stack[sp].low = low;
1646 if ((k - 1) > low) {
1648 stack[sp].low = low;
1652 if ((k + 1) < high) {
1653 stack[sp].high = high;
1661 private static void CheckComparerAvailable (Array keys, int low, int high)
1663 // move null keys to beginning of array,
1664 // ensure that non-null keys implement IComparable
1665 for (int i = 0; i < high; i++) {
1666 object obj = keys.GetValueImpl (i);
1669 if (!(obj is IComparable)) {
1670 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1671 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1676 private static void swap (Array keys, Array items, int i, int j)
1678 object tmp = keys.GetValueImpl (i);
1679 keys.SetValueImpl (keys.GetValueImpl (j), i);
1680 keys.SetValueImpl (tmp, j);
1682 if (items != null) {
1683 tmp = items.GetValueImpl (i);
1684 items.SetValueImpl (items.GetValueImpl (j), i);
1685 items.SetValueImpl (tmp, j);
1689 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1690 public static void Sort<T> (T [] array)
1692 Sort<T> (array, (IComparer<T>)null);
1695 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1696 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1698 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1701 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1702 public static void Sort<T> (T [] array, IComparer<T> comparer)
1705 throw new ArgumentNullException ("array");
1707 SortImpl<T> (array, 0, array.Length, comparer);
1710 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1711 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1713 if (items == null) {
1714 Sort<TKey> (keys, comparer);
1719 throw new ArgumentNullException ("keys");
1721 if (keys.Length > items.Length)
1722 throw new ArgumentException ("Length of keys is larger than length of items.");
1724 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1727 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1728 public static void Sort<T> (T [] array, int index, int length)
1730 Sort<T> (array, index, length, (IComparer<T>)null);
1733 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1734 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1736 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1739 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1740 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1743 throw new ArgumentNullException ("array");
1746 throw new ArgumentOutOfRangeException ("index");
1749 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1750 "Value has to be >= 0."));
1752 if (index + length > array.Length)
1753 throw new ArgumentException ();
1755 SortImpl<T> (array, index, length, comparer);
1758 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1759 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1761 if (items == null) {
1762 Sort<TKey> (keys, index, length, comparer);
1767 throw new ArgumentNullException ("keys");
1770 throw new ArgumentOutOfRangeException ("index");
1773 throw new ArgumentOutOfRangeException ("length");
1775 if (items.Length - index < length || keys.Length - index < length)
1776 throw new ArgumentException ();
1778 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1781 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1783 if (keys.Length <= 1)
1787 int high = index + length - 1;
1790 // Check for value types which can be sorted without Compare () method
1792 if (comparer == null) {
1793 /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
1794 #if !FULL_AOT_RUNTIME
1795 #if !BOOTSTRAP_BASIC
1796 switch (Type.GetTypeCode (typeof (TKey))) {
1797 case TypeCode.Int32:
1798 qsort (keys as Int32[], items, low, high);
1800 case TypeCode.Int64:
1801 qsort (keys as Int64[], items, low, high);
1804 qsort (keys as byte[], items, low, high);
1807 qsort (keys as char[], items, low, high);
1809 case TypeCode.DateTime:
1810 qsort (keys as DateTime[], items, low, high);
1812 case TypeCode.Decimal:
1813 qsort (keys as decimal[], items, low, high);
1815 case TypeCode.Double:
1816 qsort (keys as double[], items, low, high);
1818 case TypeCode.Int16:
1819 qsort (keys as Int16[], items, low, high);
1821 case TypeCode.SByte:
1822 qsort (keys as SByte[], items, low, high);
1824 case TypeCode.Single:
1825 qsort (keys as Single[], items, low, high);
1827 case TypeCode.UInt16:
1828 qsort (keys as UInt16[], items, low, high);
1830 case TypeCode.UInt32:
1831 qsort (keys as UInt32[], items, low, high);
1833 case TypeCode.UInt64:
1834 qsort (keys as UInt64[], items, low, high);
1839 // Using Comparer<TKey> adds a small overload, but with value types it
1840 // helps us to not box them.
1841 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1842 typeof (TKey).IsValueType)
1843 comparer = Comparer<TKey>.Default;
1846 if (comparer == null)
1847 CheckComparerAvailable<TKey> (keys, low, high);
1850 qsort (keys, items, low, high, comparer);
1851 //} catch (Exception e) {
1852 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1856 // Specialized version for items==null
1857 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1859 if (keys.Length <= 1)
1863 int high = index + length - 1;
1866 // Check for value types which can be sorted without Compare () method
1868 if (comparer == null) {
1869 #if !BOOTSTRAP_BASIC
1870 switch (Type.GetTypeCode (typeof (TKey))) {
1871 case TypeCode.Int32:
1872 qsort (keys as Int32[], low, high);
1874 case TypeCode.Int64:
1875 qsort (keys as Int64[], low, high);
1878 qsort (keys as byte[], low, high);
1881 qsort (keys as char[], low, high);
1883 case TypeCode.DateTime:
1884 qsort (keys as DateTime[], low, high);
1886 case TypeCode.Decimal:
1887 qsort (keys as decimal[], low, high);
1889 case TypeCode.Double:
1890 qsort (keys as double[], low, high);
1892 case TypeCode.Int16:
1893 qsort (keys as Int16[], low, high);
1895 case TypeCode.SByte:
1896 qsort (keys as SByte[], low, high);
1898 case TypeCode.Single:
1899 qsort (keys as Single[], low, high);
1901 case TypeCode.UInt16:
1902 qsort (keys as UInt16[], low, high);
1904 case TypeCode.UInt32:
1905 qsort (keys as UInt32[], low, high);
1907 case TypeCode.UInt64:
1908 qsort (keys as UInt64[], low, high);
1912 // Using Comparer<TKey> adds a small overload, but with value types it
1913 // helps us to not box them.
1914 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1915 typeof (TKey).IsValueType)
1916 comparer = Comparer<TKey>.Default;
1919 if (comparer == null)
1920 CheckComparerAvailable<TKey> (keys, low, high);
1923 qsort<TKey> (keys, low, high, comparer);
1924 //} catch (Exception e) {
1925 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1929 public static void Sort<T> (T [] array, Comparison<T> comparison)
1932 throw new ArgumentNullException ("array");
1934 if (comparison == null)
1935 throw new ArgumentNullException ("comparison");
1937 SortImpl<T> (array, array.Length, comparison);
1940 // used by List<T>.Sort (Comparison <T>)
1941 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1948 int high0 = length - 1;
1949 qsort<T> (array, low0, high0, comparison);
1950 } catch (InvalidOperationException) {
1952 } catch (Exception e) {
1953 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1957 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1959 if (keys[lo] != null) {
1960 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1961 swap (keys, items, lo, hi);
1969 // Specialized version for items==null
1970 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1972 if (keys[lo] != null) {
1973 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1974 swap (keys, lo, hi);
1982 unsafe static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1984 QSortStack* stack = stackalloc QSortStack [32];
1985 const int QSORT_THRESHOLD = 7;
1986 int high, low, mid, i, k;
1990 // initialize our stack
1991 stack[0].high = high0;
1992 stack[0].low = low0;
1997 high = stack[sp].high;
1998 low = stack[sp].low;
2000 if ((low + QSORT_THRESHOLD) > high) {
2001 // switch to insertion sort
2002 for (i = low + 1; i <= high; i++) {
2003 for (k = i; k > low; k--) {
2004 // if keys[k] >= keys[k-1], break
2005 if (keys[k-1] == null)
2008 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2011 swap (keys, items, k - 1, k);
2018 // calculate the middle element
2019 mid = low + ((high - low) / 2);
2021 // once we re-order the lo, mid, and hi elements to be in
2022 // ascending order, we'll use mid as our pivot.
2023 QSortArrange<T, U> (keys, items, low, mid);
2024 if (QSortArrange<T, U> (keys, items, mid, high))
2025 QSortArrange<T, U> (keys, items, low, mid);
2029 // since we've already guaranteed that lo <= mid and mid <= hi,
2030 // we can skip comparing them again
2036 // find the first element with a value >= pivot value
2037 while (i < k && key.CompareTo (keys[i]) > 0)
2040 // find the last element with a value <= pivot value
2041 while (k > i && key.CompareTo (keys[k]) < 0)
2044 while (i < k && keys[i] == null)
2047 while (k > i && keys[k] != null)
2054 swap (keys, items, i, k);
2060 // push our partitions onto the stack, largest first
2061 // (to make sure we don't run out of stack space)
2062 if ((high - k) >= (k - low)) {
2063 if ((k + 1) < high) {
2064 stack[sp].high = high;
2069 if ((k - 1) > low) {
2071 stack[sp].low = low;
2075 if ((k - 1) > low) {
2077 stack[sp].low = low;
2081 if ((k + 1) < high) {
2082 stack[sp].high = high;
2090 // Specialized version for items==null
2091 unsafe static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2093 QSortStack* stack = stackalloc QSortStack [32];
2094 const int QSORT_THRESHOLD = 7;
2095 int high, low, mid, i, k;
2099 // initialize our stack
2100 stack[0].high = high0;
2101 stack[0].low = low0;
2106 high = stack[sp].high;
2107 low = stack[sp].low;
2109 if ((low + QSORT_THRESHOLD) > high) {
2110 // switch to insertion sort
2111 for (i = low + 1; i <= high; i++) {
2112 for (k = i; k > low; k--) {
2113 // if keys[k] >= keys[k-1], break
2114 if (keys[k-1] == null)
2117 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2120 swap (keys, k - 1, k);
2127 // calculate the middle element
2128 mid = low + ((high - low) / 2);
2130 // once we re-order the lo, mid, and hi elements to be in
2131 // ascending order, we'll use mid as our pivot.
2132 QSortArrange<T> (keys, low, mid);
2133 if (QSortArrange<T> (keys, mid, high))
2134 QSortArrange<T> (keys, low, mid);
2138 // since we've already guaranteed that lo <= mid and mid <= hi,
2139 // we can skip comparing them again
2145 // find the first element with a value >= pivot value
2146 while (i < k && key.CompareTo (keys[i]) > 0)
2149 // find the last element with a value <= pivot value
2150 while (k >= i && key.CompareTo (keys[k]) < 0)
2153 while (i < k && keys[i] == null)
2156 while (k >= i && keys[k] != null)
2169 // push our partitions onto the stack, largest first
2170 // (to make sure we don't run out of stack space)
2171 if ((high - k) >= (k - low)) {
2172 if ((k + 1) < high) {
2173 stack[sp].high = high;
2178 if ((k - 1) > low) {
2180 stack[sp].low = low;
2184 if ((k - 1) > low) {
2186 stack[sp].low = low;
2190 if ((k + 1) < high) {
2191 stack[sp].high = high;
2199 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2201 IComparable<K> gcmp;
2204 if (comparer != null) {
2205 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2206 swap<K, V> (keys, items, lo, hi);
2209 } else if (keys[lo] != null) {
2210 if (keys[hi] == null) {
2211 swap<K, V> (keys, items, lo, hi);
2215 gcmp = keys[hi] as IComparable<K>;
2217 if (gcmp.CompareTo (keys[lo]) < 0) {
2218 swap<K, V> (keys, items, lo, hi);
2225 cmp = keys[hi] as IComparable;
2227 if (cmp.CompareTo (keys[lo]) < 0) {
2228 swap<K, V> (keys, items, lo, hi);
2239 // Specialized version for items==null
2240 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2242 IComparable<K> gcmp;
2245 if (comparer != null) {
2246 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2247 swap<K> (keys, lo, hi);
2250 } else if (keys[lo] != null) {
2251 if (keys[hi] == null) {
2252 swap<K> (keys, lo, hi);
2256 gcmp = keys[hi] as IComparable<K>;
2258 if (gcmp.CompareTo (keys[lo]) < 0) {
2259 swap<K> (keys, lo, hi);
2266 cmp = keys[hi] as IComparable;
2268 if (cmp.CompareTo (keys[lo]) < 0) {
2269 swap<K> (keys, lo, hi);
2280 unsafe static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2282 QSortStack* stack = stackalloc QSortStack [32];
2283 const int QSORT_THRESHOLD = 7;
2284 int high, low, mid, i, k;
2285 IComparable<K> gcmp;
2290 // initialize our stack
2291 stack[0].high = high0;
2292 stack[0].low = low0;
2297 high = stack[sp].high;
2298 low = stack[sp].low;
2300 if ((low + QSORT_THRESHOLD) > high) {
2301 // switch to insertion sort
2302 for (i = low + 1; i <= high; i++) {
2303 for (k = i; k > low; k--) {
2304 // if keys[k] >= keys[k-1], break
2305 if (comparer != null) {
2306 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2309 if (keys[k-1] == null)
2312 if (keys[k] != null) {
2313 gcmp = keys[k] as IComparable<K>;
2314 cmp = keys[k] as IComparable;
2316 if (gcmp.CompareTo (keys[k-1]) >= 0)
2319 if (cmp.CompareTo (keys[k-1]) >= 0)
2325 swap<K, V> (keys, items, k - 1, k);
2332 // calculate the middle element
2333 mid = low + ((high - low) / 2);
2335 // once we re-order the low, mid, and high elements to be in
2336 // ascending order, we'll use mid as our pivot.
2337 QSortArrange<K, V> (keys, items, low, mid, comparer);
2338 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2339 QSortArrange<K, V> (keys, items, low, mid, comparer);
2342 gcmp = key as IComparable<K>;
2343 cmp = key as IComparable;
2345 // since we've already guaranteed that lo <= mid and mid <= hi,
2346 // we can skip comparing them again.
2351 // Move the walls in
2352 if (comparer != null) {
2353 // find the first element with a value >= pivot value
2354 while (i < k && comparer.Compare (key, keys[i]) > 0)
2357 // find the last element with a value <= pivot value
2358 while (k > i && comparer.Compare (key, keys[k]) < 0)
2362 // find the first element with a value >= pivot value
2363 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2366 // find the last element with a value <= pivot value
2367 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2369 } else if (cmp != null) {
2370 // find the first element with a value >= pivot value
2371 while (i < k && cmp.CompareTo (keys[i]) > 0)
2374 // find the last element with a value <= pivot value
2375 while (k > i && cmp.CompareTo (keys[k]) < 0)
2378 while (i < k && keys[i] == null)
2381 while (k > i && keys[k] != null)
2389 swap<K, V> (keys, items, i, k);
2395 // push our partitions onto the stack, largest first
2396 // (to make sure we don't run out of stack space)
2397 if ((high - k) >= (k - low)) {
2398 if ((k + 1) < high) {
2399 stack[sp].high = high;
2404 if ((k - 1) > low) {
2406 stack[sp].low = low;
2410 if ((k - 1) > low) {
2412 stack[sp].low = low;
2416 if ((k + 1) < high) {
2417 stack[sp].high = high;
2425 // Specialized version for items==null
2426 unsafe static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2428 QSortStack* stack = stackalloc QSortStack [32];
2429 const int QSORT_THRESHOLD = 7;
2430 int high, low, mid, i, k;
2431 IComparable<K> gcmp;
2436 // initialize our stack
2437 stack[0].high = high0;
2438 stack[0].low = low0;
2443 high = stack[sp].high;
2444 low = stack[sp].low;
2446 if ((low + QSORT_THRESHOLD) > high) {
2447 // switch to insertion sort
2448 for (i = low + 1; i <= high; i++) {
2449 for (k = i; k > low; k--) {
2450 // if keys[k] >= keys[k-1], break
2451 if (comparer != null) {
2452 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2455 if (keys[k-1] == null)
2458 if (keys[k] != null) {
2459 gcmp = keys[k] as IComparable<K>;
2460 cmp = keys[k] as IComparable;
2462 if (gcmp.CompareTo (keys[k-1]) >= 0)
2465 if (cmp.CompareTo (keys[k-1]) >= 0)
2471 swap<K> (keys, k - 1, k);
2478 // calculate the middle element
2479 mid = low + ((high - low) / 2);
2481 // once we re-order the low, mid, and high elements to be in
2482 // ascending order, we'll use mid as our pivot.
2483 QSortArrange<K> (keys, low, mid, comparer);
2484 if (QSortArrange<K> (keys, mid, high, comparer))
2485 QSortArrange<K> (keys, low, mid, comparer);
2488 gcmp = key as IComparable<K>;
2489 cmp = key as IComparable;
2491 // since we've already guaranteed that lo <= mid and mid <= hi,
2492 // we can skip comparing them again.
2497 // Move the walls in
2498 if (comparer != null) {
2499 // find the first element with a value >= pivot value
2500 while (i < k && comparer.Compare (key, keys[i]) > 0)
2503 // find the last element with a value <= pivot value
2504 while (k > i && comparer.Compare (key, keys[k]) < 0)
2508 // find the first element with a value >= pivot value
2509 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2512 // find the last element with a value <= pivot value
2513 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2515 } else if (cmp != null) {
2516 // find the first element with a value >= pivot value
2517 while (i < k && cmp.CompareTo (keys[i]) > 0)
2520 // find the last element with a value <= pivot value
2521 while (k > i && cmp.CompareTo (keys[k]) < 0)
2524 while (i < k && keys[i] == null)
2527 while (k > i && keys[k] != null)
2535 swap<K> (keys, i, k);
2541 // push our partitions onto the stack, largest first
2542 // (to make sure we don't run out of stack space)
2543 if ((high - k) >= (k - low)) {
2544 if ((k + 1) < high) {
2545 stack[sp].high = high;
2550 if ((k - 1) > low) {
2552 stack[sp].low = low;
2556 if ((k - 1) > low) {
2558 stack[sp].low = low;
2562 if ((k + 1) < high) {
2563 stack[sp].high = high;
2571 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2573 if (array[lo] != null) {
2574 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2575 swap<T> (array, lo, hi);
2583 unsafe static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2585 QSortStack* stack = stackalloc QSortStack [32];
2586 const int QSORT_THRESHOLD = 7;
2587 int high, low, mid, i, k;
2591 // initialize our stack
2592 stack[0].high = high0;
2593 stack[0].low = low0;
2598 high = stack[sp].high;
2599 low = stack[sp].low;
2601 if ((low + QSORT_THRESHOLD) > high) {
2602 // switch to insertion sort
2603 for (i = low + 1; i <= high; i++) {
2604 for (k = i; k > low; k--) {
2605 if (compare (array[k], array[k-1]) >= 0)
2608 swap<T> (array, k - 1, k);
2615 // calculate the middle element
2616 mid = low + ((high - low) / 2);
2618 // once we re-order the lo, mid, and hi elements to be in
2619 // ascending order, we'll use mid as our pivot.
2620 QSortArrange<T> (array, low, mid, compare);
2621 if (QSortArrange<T> (array, mid, high, compare))
2622 QSortArrange<T> (array, low, mid, compare);
2626 // since we've already guaranteed that lo <= mid and mid <= hi,
2627 // we can skip comparing them again
2632 // Move the walls in
2634 // find the first element with a value >= pivot value
2635 while (i < k && compare (key, array[i]) > 0)
2638 // find the last element with a value <= pivot value
2639 while (k > i && compare (key, array[k]) < 0)
2642 while (i < k && array[i] == null)
2645 while (k > i && array[k] != null)
2652 swap<T> (array, i, k);
2658 // push our partitions onto the stack, largest first
2659 // (to make sure we don't run out of stack space)
2660 if ((high - k) >= (k - low)) {
2661 if ((k + 1) < high) {
2662 stack[sp].high = high;
2667 if ((k - 1) > low) {
2669 stack[sp].low = low;
2673 if ((k - 1) > low) {
2675 stack[sp].low = low;
2679 if ((k + 1) < high) {
2680 stack[sp].high = high;
2688 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2690 // move null keys to beginning of array,
2691 // ensure that non-null keys implement IComparable
2692 for (int i = low; i < high; i++) {
2695 if (!(key is IComparable<K>) && !(key is IComparable)) {
2696 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2697 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2703 [MethodImpl ((MethodImplOptions)256)]
2704 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2709 keys [i] = keys [j];
2712 if (items != null) {
2715 items [i] = items [j];
2720 [MethodImpl ((MethodImplOptions)256)]
2721 private static void swap<T> (T [] array, int i, int j)
2724 array [i] = array [j];
2728 public void CopyTo (Array array, int index)
2731 throw new ArgumentNullException ("array");
2733 // The order of these exception checks may look strange,
2734 // but that's how the microsoft runtime does it.
2736 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2737 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2738 throw new ArgumentException ("Destination array was not long " +
2739 "enough. Check destIndex and length, and the array's " +
2742 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2744 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2745 "Value has to be >= 0."));
2747 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2750 [ComVisible (false)]
2751 public void CopyTo (Array array, long index)
2753 if (index < 0 || index > Int32.MaxValue)
2754 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2755 "Value must be >= 0 and <= Int32.MaxValue."));
2757 CopyTo (array, (int) index);
2760 internal class SimpleEnumerator : IEnumerator, ICloneable
2766 public SimpleEnumerator (Array arrayToEnumerate)
2768 this.enumeratee = arrayToEnumerate;
2769 this.currentpos = -1;
2770 this.length = arrayToEnumerate.Length;
2773 public object Current {
2775 // Exception messages based on MS implementation
2776 if (currentpos < 0 )
2777 throw new InvalidOperationException (Locale.GetText (
2778 "Enumeration has not started."));
2779 if (currentpos >= length)
2780 throw new InvalidOperationException (Locale.GetText (
2781 "Enumeration has already ended"));
2782 // Current should not increase the position. So no ++ over here.
2783 return enumeratee.GetValueImpl (currentpos);
2787 public bool MoveNext()
2789 //The docs say Current should throw an exception if last
2790 //call to MoveNext returned false. This means currentpos
2791 //should be set to length when returning false.
2792 if (currentpos < length)
2794 if(currentpos < length)
2805 public object Clone ()
2807 return MemberwiseClone ();
2811 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2812 public static void Resize<T> (ref T [] array, int newSize)
2815 throw new ArgumentOutOfRangeException ("newSize");
2817 if (array == null) {
2818 array = new T [newSize];
2823 int length = arr.Length;
2824 if (length == newSize)
2827 T [] a = new T [newSize];
2828 int tocopy = Math.Min (newSize, length);
2831 for (int i = 0; i < tocopy; ++i)
2832 UnsafeStore (a, i, UnsafeLoad (arr, i));
2834 FastCopy (arr, 0, a, 0, tocopy);
2839 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2842 throw new ArgumentNullException ("array");
2844 throw new ArgumentNullException ("match");
2846 foreach (T t in array)
2853 public static void ForEach<T> (T [] array, Action <T> action)
2856 throw new ArgumentNullException ("array");
2858 throw new ArgumentNullException ("action");
2860 foreach (T t in array)
2864 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2867 throw new ArgumentNullException ("array");
2868 if (converter == null)
2869 throw new ArgumentNullException ("converter");
2871 TOutput [] output = new TOutput [array.Length];
2872 for (int i = 0; i < array.Length; i ++)
2873 output [i] = converter (array [i]);
2878 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2881 throw new ArgumentNullException ("array");
2884 throw new ArgumentNullException ("match");
2886 return GetLastIndex (array, 0, array.Length, match);
2889 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2892 throw new ArgumentNullException ();
2894 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2895 throw new ArgumentOutOfRangeException ("startIndex");
2898 throw new ArgumentNullException ("match");
2900 return GetLastIndex (array, 0, startIndex + 1, match);
2903 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2906 throw new ArgumentNullException ("array");
2909 throw new ArgumentNullException ("match");
2911 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2912 throw new ArgumentOutOfRangeException ("startIndex");
2915 throw new ArgumentOutOfRangeException ("count");
2917 if (startIndex - count + 1 < 0)
2918 throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
2920 return GetLastIndex (array, startIndex - count + 1, count, match);
2923 internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2925 // unlike FindLastIndex, takes regular params for search range
2926 for (int i = startIndex + count; i != startIndex;)
2927 if (match (array [--i]))
2933 public static int FindIndex<T> (T [] array, Predicate<T> match)
2936 throw new ArgumentNullException ("array");
2939 throw new ArgumentNullException ("match");
2941 return GetIndex (array, 0, array.Length, match);
2944 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2947 throw new ArgumentNullException ("array");
2949 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2950 throw new ArgumentOutOfRangeException ("startIndex");
2953 throw new ArgumentNullException ("match");
2955 return GetIndex (array, startIndex, array.Length - startIndex, match);
2958 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2961 throw new ArgumentNullException ("array");
2964 throw new ArgumentOutOfRangeException ("startIndex");
2967 throw new ArgumentOutOfRangeException ("count");
2969 if ((uint) startIndex + (uint) count > (uint) array.Length)
2970 throw new ArgumentOutOfRangeException ("index and count exceed length of list");
2972 return GetIndex (array, startIndex, count, match);
2975 internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2977 int end = startIndex + count;
2978 for (int i = startIndex; i < end; i ++)
2979 if (match (array [i]))
2985 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2986 public static int BinarySearch<T> (T [] array, T value)
2989 throw new ArgumentNullException ("array");
2991 return BinarySearch<T> (array, 0, array.Length, value, null);
2994 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2995 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2998 throw new ArgumentNullException ("array");
3000 return BinarySearch<T> (array, 0, array.Length, value, comparer);
3003 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
3004 public static int BinarySearch<T> (T [] array, int index, int length, T value)
3006 return BinarySearch<T> (array, index, length, value, null);
3009 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
3010 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
3013 throw new ArgumentNullException ("array");
3015 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
3016 "index is less than the lower bound of array."));
3018 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
3019 "Value has to be >= 0."));
3020 // re-ordered to avoid possible integer overflow
3021 if (index > array.Length - length)
3022 throw new ArgumentException (Locale.GetText (
3023 "index and length do not specify a valid range in array."));
3024 if (comparer == null)
3025 comparer = Comparer <T>.Default;
3028 int iMax = index + length - 1;
3031 while (iMin <= iMax) {
3032 // Be careful with overflows
3033 int iMid = iMin + ((iMax - iMin) / 2);
3034 iCmp = comparer.Compare (array [iMid], value);
3042 iMin = iMid + 1; // compensate for the rounding down
3044 } catch (Exception e) {
3045 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
3051 public static int IndexOf<T> (T [] array, T value)
3054 throw new ArgumentNullException ("array");
3056 return IndexOf<T> (array, value, 0, array.Length);
3059 public static int IndexOf<T> (T [] array, T value, int startIndex)
3062 throw new ArgumentNullException ("array");
3064 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
3067 public static int IndexOf<T> (T[] array, T value, int startIndex, int count)
3070 throw new ArgumentNullException ("array");
3072 // re-ordered to avoid possible integer overflow
3073 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
3074 throw new ArgumentOutOfRangeException ();
3076 return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, count);
3079 public static int LastIndexOf<T> (T [] array, T value)
3082 throw new ArgumentNullException ("array");
3084 if (array.Length == 0)
3086 return LastIndexOf<T> (array, value, array.Length - 1);
3089 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3092 throw new ArgumentNullException ("array");
3094 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3097 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3100 throw new ArgumentNullException ("array");
3102 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3103 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3104 throw new ArgumentOutOfRangeException ();
3106 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3107 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3108 if (equalityComparer.Equals (array [i], value))
3115 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3118 throw new ArgumentNullException ("array");
3121 throw new ArgumentNullException ("match");
3124 T [] d = new T [array.Length];
3125 foreach (T t in array)
3129 Resize <T> (ref d, pos);
3133 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
3134 public static T[] Empty<T>()
3136 return EmptyArray<T>.Value;
3139 public static bool Exists<T> (T [] array, Predicate <T> match)
3142 throw new ArgumentNullException ("array");
3145 throw new ArgumentNullException ("match");
3147 foreach (T t in array)
3153 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3156 throw new ArgumentNullException ("array");
3158 return new ReadOnlyCollection<T> (array);
3161 public static void Fill<T> (T[] array, T value)
3164 throw new ArgumentNullException (nameof (array));
3166 for (int i = 0; i < array.Length; i++)
3170 public static void Fill<T> (T[] array, T value, int startIndex, int count)
3173 throw new ArgumentNullException (nameof (array));
3175 if (startIndex < 0 || startIndex > array.Length)
3176 throw new ArgumentOutOfRangeException (nameof (startIndex));
3178 if (count < 0 || startIndex > array.Length - count)
3179 throw new ArgumentOutOfRangeException (nameof (count));
3181 for (int i = startIndex; i < startIndex + count; i++)
3185 public static T Find<T> (T [] array, Predicate<T> match)
3188 throw new ArgumentNullException ("array");
3191 throw new ArgumentNullException ("match");
3193 foreach (T t in array)
3200 public static T FindLast<T> (T [] array, Predicate <T> match)
3203 throw new ArgumentNullException ("array");
3206 throw new ArgumentNullException ("match");
3208 for (int i = array.Length - 1; i >= 0; i--)
3209 if (match (array [i]))
3215 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3217 // The constrained copy should guarantee that if there is an exception thrown
3218 // during the copy, the destination array remains unchanged.
3219 // This is related to System.Runtime.Reliability.CER
3220 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3222 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
3225 #region Unsafe array operations
3228 // Loads array index with no safety checks (JIT intristics)
3230 internal static T UnsafeLoad<T> (T[] array, int index) {
3231 return array [index];
3235 // Stores values at specified array index with no safety checks (JIT intristics)
3237 internal static void UnsafeStore<T> (T[] array, int index, T value) {
3238 array [index] = value;
3242 // Moved value from instance into target of different type with no checks (JIT intristics)
3246 // S and R must either:
3247 // both be blitable valuetypes
3248 // both be reference types (IOW, an unsafe cast)
3249 // S and R cannot be float or double
3250 // S and R must either:
3253 // S and R must either:
3255 // both be a scalar of size <= 4
3257 internal static R UnsafeMov<S,R> (S instance) {
3258 return (R)(object) instance;
3263 internal sealed class FunctorComparer<T> : IComparer<T> {
3264 Comparison<T> comparison;
3266 public FunctorComparer(Comparison<T> comparison) {
3267 this.comparison = comparison;
3270 public int Compare(T x, T y) {
3271 return comparison(x, y);