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 public static Array CreateInstance (Type elementType, int length)
658 int[] lengths = {length};
660 return CreateInstance (elementType, lengths);
663 public static Array CreateInstance (Type elementType, int length1, int length2)
665 int[] lengths = {length1, length2};
667 return CreateInstance (elementType, lengths);
670 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
672 int[] lengths = {length1, length2, length3};
674 return CreateInstance (elementType, lengths);
677 public static Array CreateInstance (Type elementType, params int[] lengths)
679 if (elementType == null)
680 throw new ArgumentNullException ("elementType");
682 throw new ArgumentNullException ("lengths");
684 if (lengths.Length > 255)
685 throw new TypeLoadException ();
689 elementType = elementType.UnderlyingSystemType;
690 if (!elementType.IsSystemType)
691 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
692 if (elementType.Equals (typeof (void)))
693 throw new NotSupportedException ("Array type can not be void");
694 if (elementType.ContainsGenericParameters)
695 throw new NotSupportedException ("Array type can not be an open generic type");
696 #if !FULL_AOT_RUNTIME
697 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
698 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
701 return CreateInstanceImpl (elementType, lengths, bounds);
704 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
706 if (elementType == null)
707 throw new ArgumentNullException ("elementType");
709 throw new ArgumentNullException ("lengths");
710 if (lowerBounds == null)
711 throw new ArgumentNullException ("lowerBounds");
713 elementType = elementType.UnderlyingSystemType;
714 if (!elementType.IsSystemType)
715 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
716 if (elementType.Equals (typeof (void)))
717 throw new NotSupportedException ("Array type can not be void");
718 if (elementType.ContainsGenericParameters)
719 throw new NotSupportedException ("Array type can not be an open generic type");
721 if (lengths.Length < 1)
722 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
724 if (lengths.Length != lowerBounds.Length)
725 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
727 for (int j = 0; j < lowerBounds.Length; j ++) {
729 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
730 "Each value has to be >= 0."));
731 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
732 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
733 "Length + bound must not exceed Int32.MaxValue."));
736 if (lengths.Length > 255)
737 throw new TypeLoadException ();
739 return CreateInstanceImpl (elementType, lengths, lowerBounds);
742 static int [] GetIntArray (long [] values)
744 int len = values.Length;
745 int [] ints = new int [len];
746 for (int i = 0; i < len; i++) {
747 long current = values [i];
748 if (current < 0 || current > (long) Int32.MaxValue)
749 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
750 "Each value has to be >= 0 and <= Int32.MaxValue."));
752 ints [i] = (int) current;
757 public static Array CreateInstance (Type elementType, params long [] lengths)
760 throw new ArgumentNullException ("lengths");
761 return CreateInstance (elementType, GetIntArray (lengths));
765 public object GetValue (params long [] indices)
768 throw new ArgumentNullException ("indices");
769 return GetValue (GetIntArray (indices));
773 public void SetValue (object value, params long [] indices)
776 throw new ArgumentNullException ("indices");
777 SetValue (value, GetIntArray (indices));
780 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
781 public static int BinarySearch (Array array, object value)
783 return BinarySearch (array, value, null);
786 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
787 public static int BinarySearch (Array array, object value, IComparer comparer)
790 throw new ArgumentNullException ("array");
793 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
795 if (array.Length == 0)
798 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
801 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
802 public static int BinarySearch (Array array, int index, int length, object value)
804 return BinarySearch (array, index, length, value, null);
807 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
808 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
811 throw new ArgumentNullException ("array");
814 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
816 if (index < array.GetLowerBound (0))
817 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
818 "index is less than the lower bound of array."));
820 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
821 "Value has to be >= 0."));
822 // re-ordered to avoid possible integer overflow
823 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
824 throw new ArgumentException (Locale.GetText (
825 "index and length do not specify a valid range in array."));
827 if (array.Length == 0)
830 return DoBinarySearch (array, index, length, value, comparer);
833 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
835 // cache this in case we need it
836 if (comparer == null)
837 comparer = Comparer.Default;
840 // Comment from Tum (tum@veridicus.com):
841 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
842 int iMax = index + length - 1;
845 while (iMin <= iMax) {
846 // Be careful with overflow
847 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
848 int iMid = iMin + ((iMax - iMin) / 2);
849 object elt = array.GetValueImpl (iMid);
851 iCmp = comparer.Compare (elt, value);
858 iMin = iMid + 1; // compensate for the rounding down
861 catch (Exception e) {
862 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
868 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
869 public static void Clear (Array array, int index, int length)
872 throw new ArgumentNullException ("array");
874 throw new IndexOutOfRangeException ("length < 0");
876 int low = array.GetLowerBound (0);
878 throw new IndexOutOfRangeException ("index < lower bound");
881 // re-ordered to avoid possible integer overflow
882 if (index > array.Length - length)
883 throw new IndexOutOfRangeException ("index + length > size");
885 ClearInternal (array, index, length);
888 [MethodImplAttribute (MethodImplOptions.InternalCall)]
889 static extern void ClearInternal (Array a, int index, int count);
891 [MethodImplAttribute (MethodImplOptions.InternalCall)]
892 public extern object Clone ();
894 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
895 public static void Copy (Array sourceArray, Array destinationArray, int length)
897 // need these checks here because we are going to use
898 // GetLowerBound() on source and dest.
899 if (sourceArray == null)
900 throw new ArgumentNullException ("sourceArray");
902 if (destinationArray == null)
903 throw new ArgumentNullException ("destinationArray");
905 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
906 destinationArray.GetLowerBound (0), length);
909 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
910 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
912 if (sourceArray == null)
913 throw new ArgumentNullException ("sourceArray");
915 if (destinationArray == null)
916 throw new ArgumentNullException ("destinationArray");
919 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
920 "Value has to be >= 0."));;
923 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
924 "Value has to be >= 0."));;
926 if (destinationIndex < 0)
927 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
928 "Value has to be >= 0."));;
930 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
933 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
934 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
936 // re-ordered to avoid possible integer overflow
937 if (source_pos > sourceArray.Length - length)
938 throw new ArgumentException ("length");
940 if (dest_pos > destinationArray.Length - length) {
941 string msg = "Destination array was not long enough. Check " +
942 "destIndex and length, and the array's lower bounds";
943 throw new ArgumentException (msg, string.Empty);
946 if (sourceArray.Rank != destinationArray.Rank)
947 throw new RankException (Locale.GetText ("Arrays must be of same size."));
949 Type src_type = sourceArray.GetType ().GetElementType ();
950 Type dst_type = destinationArray.GetType ().GetElementType ();
952 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
953 for (int i = 0; i < length; i++) {
954 Object srcval = sourceArray.GetValueImpl (source_pos + i);
957 destinationArray.SetValueImpl (srcval, dest_pos + i);
958 } catch (ArgumentException) {
959 throw CreateArrayTypeMismatchException ();
961 if (CanAssignArrayElement (src_type, dst_type))
964 throw CreateArrayTypeMismatchException ();
969 for (int i = length - 1; i >= 0; i--) {
970 Object srcval = sourceArray.GetValueImpl (source_pos + i);
973 destinationArray.SetValueImpl (srcval, dest_pos + i);
974 } catch (ArgumentException) {
975 throw CreateArrayTypeMismatchException ();
977 if (CanAssignArrayElement (src_type, dst_type))
980 throw CreateArrayTypeMismatchException ();
986 static Exception CreateArrayTypeMismatchException ()
988 return new ArrayTypeMismatchException ();
991 static bool CanAssignArrayElement (Type source, Type target)
993 if (source.IsValueType)
994 return source.IsAssignableFrom (target);
996 if (source.IsInterface)
997 return !target.IsValueType;
999 if (target.IsInterface)
1000 return !source.IsValueType;
1002 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
1005 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1006 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1007 long destinationIndex, long length)
1009 if (sourceArray == null)
1010 throw new ArgumentNullException ("sourceArray");
1012 if (destinationArray == null)
1013 throw new ArgumentNullException ("destinationArray");
1015 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1016 throw new ArgumentOutOfRangeException ("sourceIndex",
1017 Locale.GetText ("Must be in the Int32 range."));
1019 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1020 throw new ArgumentOutOfRangeException ("destinationIndex",
1021 Locale.GetText ("Must be in the Int32 range."));
1023 if (length < 0 || length > Int32.MaxValue)
1024 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1025 "Value must be >= 0 and <= Int32.MaxValue."));
1027 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1030 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1031 public static void Copy (Array sourceArray, Array destinationArray, long length)
1033 if (length < 0 || length > Int32.MaxValue)
1034 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1035 "Value must be >= 0 and <= Int32.MaxValue."));
1037 Copy (sourceArray, destinationArray, (int) length);
1040 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1041 public static int IndexOf (Array array, object value)
1044 throw new ArgumentNullException ("array");
1046 return IndexOf (array, value, 0, array.Length);
1049 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1050 public static int IndexOf (Array array, object value, int startIndex)
1053 throw new ArgumentNullException ("array");
1055 return IndexOf (array, value, startIndex, array.Length - startIndex);
1058 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1059 public static int IndexOf (Array array, object value, int startIndex, int count)
1062 throw new ArgumentNullException ("array");
1065 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1067 // re-ordered to avoid possible integer overflow
1068 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1069 throw new ArgumentOutOfRangeException ();
1071 int max = startIndex + count;
1072 for (int i = startIndex; i < max; i++) {
1073 if (Object.Equals (array.GetValueImpl (i), value))
1077 return array.GetLowerBound (0) - 1;
1080 public void Initialize()
1082 //FIXME: We would like to find a compiler that uses
1083 // this method. It looks like this method do nothing
1084 // in C# so no exception is trown by the moment.
1087 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1088 public static int LastIndexOf (Array array, object value)
1091 throw new ArgumentNullException ("array");
1093 if (array.Length == 0)
1094 return array.GetLowerBound (0) - 1;
1095 return LastIndexOf (array, value, array.Length - 1);
1098 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1099 public static int LastIndexOf (Array array, object value, int startIndex)
1102 throw new ArgumentNullException ("array");
1104 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1107 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1108 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1111 throw new ArgumentNullException ("array");
1114 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1116 int lb = array.GetLowerBound (0);
1117 // Empty arrays do not throw ArgumentOutOfRangeException
1118 if (array.Length == 0)
1121 if (count < 0 || startIndex < lb ||
1122 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1123 throw new ArgumentOutOfRangeException ();
1125 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1126 if (Object.Equals (array.GetValueImpl (i), value))
1133 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1134 public static void Reverse (Array array)
1137 throw new ArgumentNullException ("array");
1139 Reverse (array, array.GetLowerBound (0), array.Length);
1142 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1143 public static void Reverse (Array array, int index, int length)
1146 throw new ArgumentNullException ("array");
1149 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1151 if (index < array.GetLowerBound (0) || length < 0)
1152 throw new ArgumentOutOfRangeException ();
1154 // re-ordered to avoid possible integer overflow
1155 if (index > array.GetUpperBound (0) + 1 - length)
1156 throw new ArgumentException ();
1158 int end = index + length - 1;
1159 var et = array.GetType ().GetElementType ();
1160 switch (Type.GetTypeCode (et)) {
1161 case TypeCode.Boolean:
1162 while (index < end) {
1165 array.GetGenericValueImpl (index, out a);
1166 array.GetGenericValueImpl (end, out b);
1167 array.SetGenericValueImpl (index, ref b);
1168 array.SetGenericValueImpl (end, ref a);
1175 case TypeCode.SByte:
1176 while (index < end) {
1179 array.GetGenericValueImpl (index, out a);
1180 array.GetGenericValueImpl (end, out b);
1181 array.SetGenericValueImpl (index, ref b);
1182 array.SetGenericValueImpl (end, ref a);
1188 case TypeCode.Int16:
1189 case TypeCode.UInt16:
1191 while (index < end) {
1194 array.GetGenericValueImpl (index, out a);
1195 array.GetGenericValueImpl (end, out b);
1196 array.SetGenericValueImpl (index, ref b);
1197 array.SetGenericValueImpl (end, ref a);
1203 case TypeCode.Int32:
1204 case TypeCode.UInt32:
1205 case TypeCode.Single:
1206 while (index < end) {
1209 array.GetGenericValueImpl (index, out a);
1210 array.GetGenericValueImpl (end, out b);
1211 array.SetGenericValueImpl (index, ref b);
1212 array.SetGenericValueImpl (end, ref a);
1218 case TypeCode.Int64:
1219 case TypeCode.UInt64:
1220 case TypeCode.Double:
1221 while (index < end) {
1224 array.GetGenericValueImpl (index, out a);
1225 array.GetGenericValueImpl (end, out b);
1226 array.SetGenericValueImpl (index, ref b);
1227 array.SetGenericValueImpl (end, ref a);
1233 case TypeCode.Decimal:
1234 while (index < end) {
1237 array.GetGenericValueImpl (index, out a);
1238 array.GetGenericValueImpl (end, out b);
1239 array.SetGenericValueImpl (index, ref b);
1240 array.SetGenericValueImpl (end, ref a);
1246 case TypeCode.String:
1247 while (index < end) {
1250 array.GetGenericValueImpl (index, out a);
1251 array.GetGenericValueImpl (end, out b);
1252 array.SetGenericValueImpl (index, ref b);
1253 array.SetGenericValueImpl (end, ref a);
1259 if (array is object[])
1260 goto case TypeCode.String;
1262 // Very slow fallback
1263 while (index < end) {
1264 object val = array.GetValueImpl (index);
1265 array.SetValueImpl (array.GetValueImpl (end), index);
1266 array.SetValueImpl (val, end);
1275 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1276 public static void Sort (Array array)
1278 Sort (array, (IComparer)null);
1281 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1282 public static void Sort (Array keys, Array items)
1284 Sort (keys, items, (IComparer)null);
1287 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1288 public static void Sort (Array array, IComparer comparer)
1291 throw new ArgumentNullException ("array");
1294 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1296 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1299 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1300 public static void Sort (Array array, int index, int length)
1302 Sort (array, index, length, (IComparer)null);
1305 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1306 public static void Sort (Array keys, Array items, IComparer comparer)
1308 if (items == null) {
1309 Sort (keys, comparer);
1314 throw new ArgumentNullException ("keys");
1316 if (keys.Rank > 1 || items.Rank > 1)
1317 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1319 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1322 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1323 public static void Sort (Array keys, Array items, int index, int length)
1325 Sort (keys, items, index, length, (IComparer)null);
1328 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1329 public static void Sort (Array array, int index, int length, IComparer comparer)
1332 throw new ArgumentNullException ("array");
1335 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1337 if (index < array.GetLowerBound (0))
1338 throw new ArgumentOutOfRangeException ("index");
1341 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1342 "Value has to be >= 0."));
1344 if (array.Length - (array.GetLowerBound (0) + index) < length)
1345 throw new ArgumentException ();
1347 SortImpl (array, null, index, length, comparer);
1350 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1351 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1353 if (items == null) {
1354 Sort (keys, index, length, comparer);
1359 throw new ArgumentNullException ("keys");
1361 if (keys.Rank > 1 || items.Rank > 1)
1362 throw new RankException ();
1364 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1365 throw new ArgumentException ();
1367 if (index < keys.GetLowerBound (0))
1368 throw new ArgumentOutOfRangeException ("index");
1371 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1372 "Value has to be >= 0."));
1374 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1375 throw new ArgumentException ();
1377 SortImpl (keys, items, index, length, comparer);
1380 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1386 int high = index + length - 1;
1388 #if !BOOTSTRAP_BASIC
1389 if (comparer == null && items is object[]) {
1390 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1391 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1392 case TypeCode.Int32:
1393 qsort (keys as Int32[], items as object[], low, high);
1395 case TypeCode.Int64:
1396 qsort (keys as Int64[], items as object[], low, high);
1399 qsort (keys as byte[], items as object[], low, high);
1402 qsort (keys as char[], items as object[], low, high);
1404 case TypeCode.DateTime:
1405 qsort (keys as DateTime[], items as object[], low, high);
1407 case TypeCode.Decimal:
1408 qsort (keys as decimal[], items as object[], low, high);
1410 case TypeCode.Double:
1411 qsort (keys as double[], items as object[], low, high);
1413 case TypeCode.Int16:
1414 qsort (keys as Int16[], items as object[], low, high);
1416 case TypeCode.SByte:
1417 qsort (keys as SByte[], items as object[], low, high);
1419 case TypeCode.Single:
1420 qsort (keys as Single[], items as object[], low, high);
1422 case TypeCode.UInt16:
1423 qsort (keys as UInt16[], items as object[], low, high);
1425 case TypeCode.UInt32:
1426 qsort (keys as UInt32[], items as object[], low, high);
1428 case TypeCode.UInt64:
1429 qsort (keys as UInt64[], items as object[], low, high);
1437 if (comparer == null)
1438 CheckComparerAvailable (keys, low, high);
1441 qsort (keys, items, low, high, comparer);
1442 } catch (Exception e) {
1443 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1452 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1457 if (comparer != null) {
1458 if (comparer.Compare (v1, v0) < 0) {
1459 swap (keys, items, lo, hi);
1466 } else if (v0 != null) {
1467 cmp = v1 as IComparable;
1469 if (v1 == null || cmp.CompareTo (v0) < 0) {
1470 swap (keys, items, lo, hi);
1482 unsafe static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1484 QSortStack* stack = stackalloc QSortStack [32];
1485 const int QSORT_THRESHOLD = 7;
1486 int high, low, mid, i, k;
1491 // initialize our stack
1492 stack[0].high = high0;
1493 stack[0].low = low0;
1498 high = stack[sp].high;
1499 low = stack[sp].low;
1501 if ((low + QSORT_THRESHOLD) > high) {
1502 // switch to insertion sort
1503 for (i = low + 1; i <= high; i++) {
1504 for (k = i; k > low; k--) {
1505 lo = keys.GetValueImpl (k - 1);
1506 hi = keys.GetValueImpl (k);
1507 if (comparer != null) {
1508 if (comparer.Compare (hi, lo) >= 0)
1515 cmp = hi as IComparable;
1516 if (cmp.CompareTo (lo) >= 0)
1521 swap (keys, items, k - 1, k);
1528 // calculate the middle element
1529 mid = low + ((high - low) / 2);
1532 key = keys.GetValueImpl (mid);
1533 hi = keys.GetValueImpl (high);
1534 lo = keys.GetValueImpl (low);
1536 // once we re-order the low, mid, and high elements to be in
1537 // ascending order, we'll use mid as our pivot.
1538 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1539 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1540 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1542 cmp = key as IComparable;
1544 // since we've already guaranteed that lo <= mid and mid <= hi,
1545 // we can skip comparing them again.
1550 // Move the walls in
1551 if (comparer != null) {
1552 // find the first element with a value >= pivot value
1553 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
1556 // find the last element with a value <= pivot value
1557 while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1559 } else if (cmp != null) {
1560 // find the first element with a value >= pivot value
1561 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
1564 // find the last element with a value <= pivot value
1565 while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1568 // This has the effect of moving the null values to the front if comparer is null
1569 while (i < k && keys.GetValueImpl (i) == null)
1572 while (k > i && keys.GetValueImpl (k) != null)
1579 swap (keys, items, i, k);
1585 // push our partitions onto the stack, largest first
1586 // (to make sure we don't run out of stack space)
1587 if ((high - k) >= (k - low)) {
1588 if ((k + 1) < high) {
1589 stack[sp].high = high;
1594 if ((k - 1) > low) {
1596 stack[sp].low = low;
1600 if ((k - 1) > low) {
1602 stack[sp].low = low;
1606 if ((k + 1) < high) {
1607 stack[sp].high = high;
1615 private static void CheckComparerAvailable (Array keys, int low, int high)
1617 // move null keys to beginning of array,
1618 // ensure that non-null keys implement IComparable
1619 for (int i = 0; i < high; i++) {
1620 object obj = keys.GetValueImpl (i);
1623 if (!(obj is IComparable)) {
1624 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1625 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1630 private static void swap (Array keys, Array items, int i, int j)
1632 object tmp = keys.GetValueImpl (i);
1633 keys.SetValueImpl (keys.GetValueImpl (j), i);
1634 keys.SetValueImpl (tmp, j);
1636 if (items != null) {
1637 tmp = items.GetValueImpl (i);
1638 items.SetValueImpl (items.GetValueImpl (j), i);
1639 items.SetValueImpl (tmp, j);
1643 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1644 public static void Sort<T> (T [] array)
1646 Sort<T> (array, (IComparer<T>)null);
1649 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1650 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1652 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1655 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1656 public static void Sort<T> (T [] array, IComparer<T> comparer)
1659 throw new ArgumentNullException ("array");
1661 SortImpl<T> (array, 0, array.Length, comparer);
1664 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1665 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1667 if (items == null) {
1668 Sort<TKey> (keys, comparer);
1673 throw new ArgumentNullException ("keys");
1675 if (keys.Length != items.Length)
1676 throw new ArgumentException ("Length of keys and items does not match.");
1678 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1681 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1682 public static void Sort<T> (T [] array, int index, int length)
1684 Sort<T> (array, index, length, (IComparer<T>)null);
1687 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1688 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1690 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1693 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1694 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1697 throw new ArgumentNullException ("array");
1700 throw new ArgumentOutOfRangeException ("index");
1703 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1704 "Value has to be >= 0."));
1706 if (index + length > array.Length)
1707 throw new ArgumentException ();
1709 SortImpl<T> (array, index, length, comparer);
1712 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1713 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1715 if (items == null) {
1716 Sort<TKey> (keys, index, length, comparer);
1721 throw new ArgumentNullException ("keys");
1724 throw new ArgumentOutOfRangeException ("index");
1727 throw new ArgumentOutOfRangeException ("length");
1729 if (items.Length - index < length || keys.Length - index < length)
1730 throw new ArgumentException ();
1732 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1735 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1737 if (keys.Length <= 1)
1741 int high = index + length - 1;
1744 // Check for value types which can be sorted without Compare () method
1746 if (comparer == null) {
1747 /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
1748 #if !FULL_AOT_RUNTIME
1749 #if !BOOTSTRAP_BASIC
1750 switch (Type.GetTypeCode (typeof (TKey))) {
1751 case TypeCode.Int32:
1752 qsort (keys as Int32[], items, low, high);
1754 case TypeCode.Int64:
1755 qsort (keys as Int64[], items, low, high);
1758 qsort (keys as byte[], items, low, high);
1761 qsort (keys as char[], items, low, high);
1763 case TypeCode.DateTime:
1764 qsort (keys as DateTime[], items, low, high);
1766 case TypeCode.Decimal:
1767 qsort (keys as decimal[], items, low, high);
1769 case TypeCode.Double:
1770 qsort (keys as double[], items, low, high);
1772 case TypeCode.Int16:
1773 qsort (keys as Int16[], items, low, high);
1775 case TypeCode.SByte:
1776 qsort (keys as SByte[], items, low, high);
1778 case TypeCode.Single:
1779 qsort (keys as Single[], items, low, high);
1781 case TypeCode.UInt16:
1782 qsort (keys as UInt16[], items, low, high);
1784 case TypeCode.UInt32:
1785 qsort (keys as UInt32[], items, low, high);
1787 case TypeCode.UInt64:
1788 qsort (keys as UInt64[], items, low, high);
1793 // Using Comparer<TKey> adds a small overload, but with value types it
1794 // helps us to not box them.
1795 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1796 typeof (TKey).IsValueType)
1797 comparer = Comparer<TKey>.Default;
1800 if (comparer == null)
1801 CheckComparerAvailable<TKey> (keys, low, high);
1804 qsort (keys, items, low, high, comparer);
1805 //} catch (Exception e) {
1806 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1810 // Specialized version for items==null
1811 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1813 if (keys.Length <= 1)
1817 int high = index + length - 1;
1820 // Check for value types which can be sorted without Compare () method
1822 if (comparer == null) {
1823 #if !BOOTSTRAP_BASIC
1824 switch (Type.GetTypeCode (typeof (TKey))) {
1825 case TypeCode.Int32:
1826 qsort (keys as Int32[], low, high);
1828 case TypeCode.Int64:
1829 qsort (keys as Int64[], low, high);
1832 qsort (keys as byte[], low, high);
1835 qsort (keys as char[], low, high);
1837 case TypeCode.DateTime:
1838 qsort (keys as DateTime[], low, high);
1840 case TypeCode.Decimal:
1841 qsort (keys as decimal[], low, high);
1843 case TypeCode.Double:
1844 qsort (keys as double[], low, high);
1846 case TypeCode.Int16:
1847 qsort (keys as Int16[], low, high);
1849 case TypeCode.SByte:
1850 qsort (keys as SByte[], low, high);
1852 case TypeCode.Single:
1853 qsort (keys as Single[], low, high);
1855 case TypeCode.UInt16:
1856 qsort (keys as UInt16[], low, high);
1858 case TypeCode.UInt32:
1859 qsort (keys as UInt32[], low, high);
1861 case TypeCode.UInt64:
1862 qsort (keys as UInt64[], low, high);
1866 // Using Comparer<TKey> adds a small overload, but with value types it
1867 // helps us to not box them.
1868 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1869 typeof (TKey).IsValueType)
1870 comparer = Comparer<TKey>.Default;
1873 if (comparer == null)
1874 CheckComparerAvailable<TKey> (keys, low, high);
1877 qsort<TKey> (keys, low, high, comparer);
1878 //} catch (Exception e) {
1879 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1883 public static void Sort<T> (T [] array, Comparison<T> comparison)
1886 throw new ArgumentNullException ("array");
1888 if (comparison == null)
1889 throw new ArgumentNullException ("comparison");
1891 SortImpl<T> (array, array.Length, comparison);
1894 // used by List<T>.Sort (Comparison <T>)
1895 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1902 int high0 = length - 1;
1903 qsort<T> (array, low0, high0, comparison);
1904 } catch (InvalidOperationException) {
1906 } catch (Exception e) {
1907 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1911 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1913 if (keys[lo] != null) {
1914 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1915 swap (keys, items, lo, hi);
1923 // Specialized version for items==null
1924 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1926 if (keys[lo] != null) {
1927 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1928 swap (keys, lo, hi);
1936 unsafe static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1938 QSortStack* stack = stackalloc QSortStack [32];
1939 const int QSORT_THRESHOLD = 7;
1940 int high, low, mid, i, k;
1944 // initialize our stack
1945 stack[0].high = high0;
1946 stack[0].low = low0;
1951 high = stack[sp].high;
1952 low = stack[sp].low;
1954 if ((low + QSORT_THRESHOLD) > high) {
1955 // switch to insertion sort
1956 for (i = low + 1; i <= high; i++) {
1957 for (k = i; k > low; k--) {
1958 // if keys[k] >= keys[k-1], break
1959 if (keys[k-1] == null)
1962 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
1965 swap (keys, items, k - 1, k);
1972 // calculate the middle element
1973 mid = low + ((high - low) / 2);
1975 // once we re-order the lo, mid, and hi elements to be in
1976 // ascending order, we'll use mid as our pivot.
1977 QSortArrange<T, U> (keys, items, low, mid);
1978 if (QSortArrange<T, U> (keys, items, mid, high))
1979 QSortArrange<T, U> (keys, items, low, mid);
1983 // since we've already guaranteed that lo <= mid and mid <= hi,
1984 // we can skip comparing them again
1990 // find the first element with a value >= pivot value
1991 while (i < k && key.CompareTo (keys[i]) > 0)
1994 // find the last element with a value <= pivot value
1995 while (k > i && key.CompareTo (keys[k]) < 0)
1998 while (i < k && keys[i] == null)
2001 while (k > i && keys[k] != null)
2008 swap (keys, items, i, k);
2014 // push our partitions onto the stack, largest first
2015 // (to make sure we don't run out of stack space)
2016 if ((high - k) >= (k - low)) {
2017 if ((k + 1) < high) {
2018 stack[sp].high = high;
2023 if ((k - 1) > low) {
2025 stack[sp].low = low;
2029 if ((k - 1) > low) {
2031 stack[sp].low = low;
2035 if ((k + 1) < high) {
2036 stack[sp].high = high;
2044 // Specialized version for items==null
2045 unsafe static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2047 QSortStack* stack = stackalloc QSortStack [32];
2048 const int QSORT_THRESHOLD = 7;
2049 int high, low, mid, i, k;
2053 // initialize our stack
2054 stack[0].high = high0;
2055 stack[0].low = low0;
2060 high = stack[sp].high;
2061 low = stack[sp].low;
2063 if ((low + QSORT_THRESHOLD) > high) {
2064 // switch to insertion sort
2065 for (i = low + 1; i <= high; i++) {
2066 for (k = i; k > low; k--) {
2067 // if keys[k] >= keys[k-1], break
2068 if (keys[k-1] == null)
2071 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2074 swap (keys, k - 1, k);
2081 // calculate the middle element
2082 mid = low + ((high - low) / 2);
2084 // once we re-order the lo, mid, and hi elements to be in
2085 // ascending order, we'll use mid as our pivot.
2086 QSortArrange<T> (keys, low, mid);
2087 if (QSortArrange<T> (keys, mid, high))
2088 QSortArrange<T> (keys, low, mid);
2092 // since we've already guaranteed that lo <= mid and mid <= hi,
2093 // we can skip comparing them again
2099 // find the first element with a value >= pivot value
2100 while (i < k && key.CompareTo (keys[i]) > 0)
2103 // find the last element with a value <= pivot value
2104 while (k >= i && key.CompareTo (keys[k]) < 0)
2107 while (i < k && keys[i] == null)
2110 while (k >= i && keys[k] != null)
2123 // push our partitions onto the stack, largest first
2124 // (to make sure we don't run out of stack space)
2125 if ((high - k) >= (k - low)) {
2126 if ((k + 1) < high) {
2127 stack[sp].high = high;
2132 if ((k - 1) > low) {
2134 stack[sp].low = low;
2138 if ((k - 1) > low) {
2140 stack[sp].low = low;
2144 if ((k + 1) < high) {
2145 stack[sp].high = high;
2153 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2155 IComparable<K> gcmp;
2158 if (comparer != null) {
2159 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2160 swap<K, V> (keys, items, lo, hi);
2163 } else if (keys[lo] != null) {
2164 if (keys[hi] == null) {
2165 swap<K, V> (keys, items, lo, hi);
2169 gcmp = keys[hi] as IComparable<K>;
2171 if (gcmp.CompareTo (keys[lo]) < 0) {
2172 swap<K, V> (keys, items, lo, hi);
2179 cmp = keys[hi] as IComparable;
2181 if (cmp.CompareTo (keys[lo]) < 0) {
2182 swap<K, V> (keys, items, lo, hi);
2193 // Specialized version for items==null
2194 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2196 IComparable<K> gcmp;
2199 if (comparer != null) {
2200 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2201 swap<K> (keys, lo, hi);
2204 } else if (keys[lo] != null) {
2205 if (keys[hi] == null) {
2206 swap<K> (keys, lo, hi);
2210 gcmp = keys[hi] as IComparable<K>;
2212 if (gcmp.CompareTo (keys[lo]) < 0) {
2213 swap<K> (keys, lo, hi);
2220 cmp = keys[hi] as IComparable;
2222 if (cmp.CompareTo (keys[lo]) < 0) {
2223 swap<K> (keys, lo, hi);
2234 unsafe static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2236 QSortStack* stack = stackalloc QSortStack [32];
2237 const int QSORT_THRESHOLD = 7;
2238 int high, low, mid, i, k;
2239 IComparable<K> gcmp;
2244 // initialize our stack
2245 stack[0].high = high0;
2246 stack[0].low = low0;
2251 high = stack[sp].high;
2252 low = stack[sp].low;
2254 if ((low + QSORT_THRESHOLD) > high) {
2255 // switch to insertion sort
2256 for (i = low + 1; i <= high; i++) {
2257 for (k = i; k > low; k--) {
2258 // if keys[k] >= keys[k-1], break
2259 if (comparer != null) {
2260 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2263 if (keys[k-1] == null)
2266 if (keys[k] != null) {
2267 gcmp = keys[k] as IComparable<K>;
2268 cmp = keys[k] as IComparable;
2270 if (gcmp.CompareTo (keys[k-1]) >= 0)
2273 if (cmp.CompareTo (keys[k-1]) >= 0)
2279 swap<K, V> (keys, items, k - 1, k);
2286 // calculate the middle element
2287 mid = low + ((high - low) / 2);
2289 // once we re-order the low, mid, and high elements to be in
2290 // ascending order, we'll use mid as our pivot.
2291 QSortArrange<K, V> (keys, items, low, mid, comparer);
2292 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2293 QSortArrange<K, V> (keys, items, low, mid, comparer);
2296 gcmp = key as IComparable<K>;
2297 cmp = key as IComparable;
2299 // since we've already guaranteed that lo <= mid and mid <= hi,
2300 // we can skip comparing them again.
2305 // Move the walls in
2306 if (comparer != null) {
2307 // find the first element with a value >= pivot value
2308 while (i < k && comparer.Compare (key, keys[i]) > 0)
2311 // find the last element with a value <= pivot value
2312 while (k > i && comparer.Compare (key, keys[k]) < 0)
2316 // find the first element with a value >= pivot value
2317 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2320 // find the last element with a value <= pivot value
2321 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2323 } else if (cmp != null) {
2324 // find the first element with a value >= pivot value
2325 while (i < k && cmp.CompareTo (keys[i]) > 0)
2328 // find the last element with a value <= pivot value
2329 while (k > i && cmp.CompareTo (keys[k]) < 0)
2332 while (i < k && keys[i] == null)
2335 while (k > i && keys[k] != null)
2343 swap<K, V> (keys, items, i, k);
2349 // push our partitions onto the stack, largest first
2350 // (to make sure we don't run out of stack space)
2351 if ((high - k) >= (k - low)) {
2352 if ((k + 1) < high) {
2353 stack[sp].high = high;
2358 if ((k - 1) > low) {
2360 stack[sp].low = low;
2364 if ((k - 1) > low) {
2366 stack[sp].low = low;
2370 if ((k + 1) < high) {
2371 stack[sp].high = high;
2379 // Specialized version for items==null
2380 unsafe static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2382 QSortStack* stack = stackalloc QSortStack [32];
2383 const int QSORT_THRESHOLD = 7;
2384 int high, low, mid, i, k;
2385 IComparable<K> gcmp;
2390 // initialize our stack
2391 stack[0].high = high0;
2392 stack[0].low = low0;
2397 high = stack[sp].high;
2398 low = stack[sp].low;
2400 if ((low + QSORT_THRESHOLD) > high) {
2401 // switch to insertion sort
2402 for (i = low + 1; i <= high; i++) {
2403 for (k = i; k > low; k--) {
2404 // if keys[k] >= keys[k-1], break
2405 if (comparer != null) {
2406 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2409 if (keys[k-1] == null)
2412 if (keys[k] != null) {
2413 gcmp = keys[k] as IComparable<K>;
2414 cmp = keys[k] as IComparable;
2416 if (gcmp.CompareTo (keys[k-1]) >= 0)
2419 if (cmp.CompareTo (keys[k-1]) >= 0)
2425 swap<K> (keys, k - 1, k);
2432 // calculate the middle element
2433 mid = low + ((high - low) / 2);
2435 // once we re-order the low, mid, and high elements to be in
2436 // ascending order, we'll use mid as our pivot.
2437 QSortArrange<K> (keys, low, mid, comparer);
2438 if (QSortArrange<K> (keys, mid, high, comparer))
2439 QSortArrange<K> (keys, low, mid, comparer);
2442 gcmp = key as IComparable<K>;
2443 cmp = key as IComparable;
2445 // since we've already guaranteed that lo <= mid and mid <= hi,
2446 // we can skip comparing them again.
2451 // Move the walls in
2452 if (comparer != null) {
2453 // find the first element with a value >= pivot value
2454 while (i < k && comparer.Compare (key, keys[i]) > 0)
2457 // find the last element with a value <= pivot value
2458 while (k > i && comparer.Compare (key, keys[k]) < 0)
2462 // find the first element with a value >= pivot value
2463 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2466 // find the last element with a value <= pivot value
2467 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2469 } else if (cmp != null) {
2470 // find the first element with a value >= pivot value
2471 while (i < k && cmp.CompareTo (keys[i]) > 0)
2474 // find the last element with a value <= pivot value
2475 while (k > i && cmp.CompareTo (keys[k]) < 0)
2478 while (i < k && keys[i] == null)
2481 while (k > i && keys[k] != null)
2489 swap<K> (keys, i, k);
2495 // push our partitions onto the stack, largest first
2496 // (to make sure we don't run out of stack space)
2497 if ((high - k) >= (k - low)) {
2498 if ((k + 1) < high) {
2499 stack[sp].high = high;
2504 if ((k - 1) > low) {
2506 stack[sp].low = low;
2510 if ((k - 1) > low) {
2512 stack[sp].low = low;
2516 if ((k + 1) < high) {
2517 stack[sp].high = high;
2525 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2527 if (array[lo] != null) {
2528 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2529 swap<T> (array, lo, hi);
2537 unsafe static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2539 QSortStack* stack = stackalloc QSortStack [32];
2540 const int QSORT_THRESHOLD = 7;
2541 int high, low, mid, i, k;
2545 // initialize our stack
2546 stack[0].high = high0;
2547 stack[0].low = low0;
2552 high = stack[sp].high;
2553 low = stack[sp].low;
2555 if ((low + QSORT_THRESHOLD) > high) {
2556 // switch to insertion sort
2557 for (i = low + 1; i <= high; i++) {
2558 for (k = i; k > low; k--) {
2559 if (compare (array[k], array[k-1]) >= 0)
2562 swap<T> (array, k - 1, k);
2569 // calculate the middle element
2570 mid = low + ((high - low) / 2);
2572 // once we re-order the lo, mid, and hi elements to be in
2573 // ascending order, we'll use mid as our pivot.
2574 QSortArrange<T> (array, low, mid, compare);
2575 if (QSortArrange<T> (array, mid, high, compare))
2576 QSortArrange<T> (array, low, mid, compare);
2580 // since we've already guaranteed that lo <= mid and mid <= hi,
2581 // we can skip comparing them again
2586 // Move the walls in
2588 // find the first element with a value >= pivot value
2589 while (i < k && compare (key, array[i]) > 0)
2592 // find the last element with a value <= pivot value
2593 while (k > i && compare (key, array[k]) < 0)
2596 while (i < k && array[i] == null)
2599 while (k > i && array[k] != null)
2606 swap<T> (array, i, k);
2612 // push our partitions onto the stack, largest first
2613 // (to make sure we don't run out of stack space)
2614 if ((high - k) >= (k - low)) {
2615 if ((k + 1) < high) {
2616 stack[sp].high = high;
2621 if ((k - 1) > low) {
2623 stack[sp].low = low;
2627 if ((k - 1) > low) {
2629 stack[sp].low = low;
2633 if ((k + 1) < high) {
2634 stack[sp].high = high;
2642 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2644 // move null keys to beginning of array,
2645 // ensure that non-null keys implement IComparable
2646 for (int i = low; i < high; i++) {
2649 if (!(key is IComparable<K>) && !(key is IComparable)) {
2650 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2651 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2657 [MethodImpl ((MethodImplOptions)256)]
2658 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2663 keys [i] = keys [j];
2666 if (items != null) {
2669 items [i] = items [j];
2674 [MethodImpl ((MethodImplOptions)256)]
2675 private static void swap<T> (T [] array, int i, int j)
2678 array [i] = array [j];
2682 public void CopyTo (Array array, int index)
2685 throw new ArgumentNullException ("array");
2687 // The order of these exception checks may look strange,
2688 // but that's how the microsoft runtime does it.
2690 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2691 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2692 throw new ArgumentException ("Destination array was not long " +
2693 "enough. Check destIndex and length, and the array's " +
2696 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2698 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2699 "Value has to be >= 0."));
2701 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2704 [ComVisible (false)]
2705 public void CopyTo (Array array, long index)
2707 if (index < 0 || index > Int32.MaxValue)
2708 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2709 "Value must be >= 0 and <= Int32.MaxValue."));
2711 CopyTo (array, (int) index);
2714 internal class SimpleEnumerator : IEnumerator, ICloneable
2720 public SimpleEnumerator (Array arrayToEnumerate)
2722 this.enumeratee = arrayToEnumerate;
2723 this.currentpos = -1;
2724 this.length = arrayToEnumerate.Length;
2727 public object Current {
2729 // Exception messages based on MS implementation
2730 if (currentpos < 0 )
2731 throw new InvalidOperationException (Locale.GetText (
2732 "Enumeration has not started."));
2733 if (currentpos >= length)
2734 throw new InvalidOperationException (Locale.GetText (
2735 "Enumeration has already ended"));
2736 // Current should not increase the position. So no ++ over here.
2737 return enumeratee.GetValueImpl (currentpos);
2741 public bool MoveNext()
2743 //The docs say Current should throw an exception if last
2744 //call to MoveNext returned false. This means currentpos
2745 //should be set to length when returning false.
2746 if (currentpos < length)
2748 if(currentpos < length)
2759 public object Clone ()
2761 return MemberwiseClone ();
2765 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2766 public static void Resize<T> (ref T [] array, int newSize)
2769 throw new ArgumentOutOfRangeException ("newSize");
2771 if (array == null) {
2772 array = new T [newSize];
2777 int length = arr.Length;
2778 if (length == newSize)
2781 T [] a = new T [newSize];
2782 int tocopy = Math.Min (newSize, length);
2785 for (int i = 0; i < tocopy; ++i)
2786 UnsafeStore (a, i, UnsafeLoad (arr, i));
2788 FastCopy (arr, 0, a, 0, tocopy);
2793 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2796 throw new ArgumentNullException ("array");
2798 throw new ArgumentNullException ("match");
2800 foreach (T t in array)
2807 public static void ForEach<T> (T [] array, Action <T> action)
2810 throw new ArgumentNullException ("array");
2812 throw new ArgumentNullException ("action");
2814 foreach (T t in array)
2818 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2821 throw new ArgumentNullException ("array");
2822 if (converter == null)
2823 throw new ArgumentNullException ("converter");
2825 TOutput [] output = new TOutput [array.Length];
2826 for (int i = 0; i < array.Length; i ++)
2827 output [i] = converter (array [i]);
2832 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2835 throw new ArgumentNullException ("array");
2838 throw new ArgumentNullException ("match");
2840 return GetLastIndex (array, 0, array.Length, match);
2843 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2846 throw new ArgumentNullException ();
2848 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2849 throw new ArgumentOutOfRangeException ("startIndex");
2852 throw new ArgumentNullException ("match");
2854 return GetLastIndex (array, 0, startIndex + 1, match);
2857 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2860 throw new ArgumentNullException ("array");
2863 throw new ArgumentNullException ("match");
2865 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2866 throw new ArgumentOutOfRangeException ("startIndex");
2869 throw new ArgumentOutOfRangeException ("count");
2871 if (startIndex - count + 1 < 0)
2872 throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
2874 return GetLastIndex (array, startIndex - count + 1, count, match);
2877 internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2879 // unlike FindLastIndex, takes regular params for search range
2880 for (int i = startIndex + count; i != startIndex;)
2881 if (match (array [--i]))
2887 public static int FindIndex<T> (T [] array, Predicate<T> match)
2890 throw new ArgumentNullException ("array");
2893 throw new ArgumentNullException ("match");
2895 return GetIndex (array, 0, array.Length, match);
2898 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2901 throw new ArgumentNullException ("array");
2903 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2904 throw new ArgumentOutOfRangeException ("startIndex");
2907 throw new ArgumentNullException ("match");
2909 return GetIndex (array, startIndex, array.Length - startIndex, match);
2912 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2915 throw new ArgumentNullException ("array");
2918 throw new ArgumentOutOfRangeException ("startIndex");
2921 throw new ArgumentOutOfRangeException ("count");
2923 if ((uint) startIndex + (uint) count > (uint) array.Length)
2924 throw new ArgumentOutOfRangeException ("index and count exceed length of list");
2926 return GetIndex (array, startIndex, count, match);
2929 internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2931 int end = startIndex + count;
2932 for (int i = startIndex; i < end; i ++)
2933 if (match (array [i]))
2939 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2940 public static int BinarySearch<T> (T [] array, T value)
2943 throw new ArgumentNullException ("array");
2945 return BinarySearch<T> (array, 0, array.Length, value, null);
2948 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2949 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2952 throw new ArgumentNullException ("array");
2954 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2957 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2958 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2960 return BinarySearch<T> (array, index, length, value, null);
2963 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2964 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2967 throw new ArgumentNullException ("array");
2969 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2970 "index is less than the lower bound of array."));
2972 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2973 "Value has to be >= 0."));
2974 // re-ordered to avoid possible integer overflow
2975 if (index > array.Length - length)
2976 throw new ArgumentException (Locale.GetText (
2977 "index and length do not specify a valid range in array."));
2978 if (comparer == null)
2979 comparer = Comparer <T>.Default;
2982 int iMax = index + length - 1;
2985 while (iMin <= iMax) {
2986 // Be careful with overflows
2987 int iMid = iMin + ((iMax - iMin) / 2);
2988 iCmp = comparer.Compare (array [iMid], value);
2996 iMin = iMid + 1; // compensate for the rounding down
2998 } catch (Exception e) {
2999 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
3005 public static int IndexOf<T> (T [] array, T value)
3008 throw new ArgumentNullException ("array");
3010 return IndexOf<T> (array, value, 0, array.Length);
3013 public static int IndexOf<T> (T [] array, T value, int startIndex)
3016 throw new ArgumentNullException ("array");
3018 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
3021 public static int IndexOf<T> (T[] array, T value, int startIndex, int count)
3024 throw new ArgumentNullException ("array");
3026 // re-ordered to avoid possible integer overflow
3027 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
3028 throw new ArgumentOutOfRangeException ();
3030 return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, startIndex + count);
3033 public static int LastIndexOf<T> (T [] array, T value)
3036 throw new ArgumentNullException ("array");
3038 if (array.Length == 0)
3040 return LastIndexOf<T> (array, value, array.Length - 1);
3043 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3046 throw new ArgumentNullException ("array");
3048 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3051 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3054 throw new ArgumentNullException ("array");
3056 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3057 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3058 throw new ArgumentOutOfRangeException ();
3060 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3061 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3062 if (equalityComparer.Equals (array [i], value))
3069 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3072 throw new ArgumentNullException ("array");
3075 throw new ArgumentNullException ("match");
3078 T [] d = new T [array.Length];
3079 foreach (T t in array)
3083 Resize <T> (ref d, pos);
3087 public static bool Exists<T> (T [] array, Predicate <T> match)
3090 throw new ArgumentNullException ("array");
3093 throw new ArgumentNullException ("match");
3095 foreach (T t in array)
3101 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3104 throw new ArgumentNullException ("array");
3106 return new ReadOnlyCollection<T> (array);
3109 public static T Find<T> (T [] array, Predicate<T> match)
3112 throw new ArgumentNullException ("array");
3115 throw new ArgumentNullException ("match");
3117 foreach (T t in array)
3124 public static T FindLast<T> (T [] array, Predicate <T> match)
3127 throw new ArgumentNullException ("array");
3130 throw new ArgumentNullException ("match");
3132 for (int i = array.Length - 1; i >= 0; i--)
3133 if (match (array [i]))
3139 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3141 // The constrained copy should guarantee that if there is an exception thrown
3142 // during the copy, the destination array remains unchanged.
3143 // This is related to System.Runtime.Reliability.CER
3144 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3146 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
3149 #region Unsafe array operations
3152 // Loads array index with no safety checks (JIT intristics)
3154 internal static T UnsafeLoad<T> (T[] array, int index) {
3155 return array [index];
3159 // Stores values at specified array index with no safety checks (JIT intristics)
3161 internal static void UnsafeStore<T> (T[] array, int index, T value) {
3162 array [index] = value;
3166 // Moved value from instance into target of different type with no checks (JIT intristics)
3168 internal static R UnsafeMov<S,R> (S instance) {
3169 return (R)(object) instance;