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);
937 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
939 // re-ordered to avoid possible integer overflow
940 if (source_pos > sourceArray.Length - length)
941 throw new ArgumentException ("length");
943 if (dest_pos > destinationArray.Length - length) {
944 string msg = "Destination array was not long enough. Check " +
945 "destIndex and length, and the array's lower bounds";
946 throw new ArgumentException (msg, string.Empty);
949 if (sourceArray.Rank != destinationArray.Rank)
950 throw new RankException (Locale.GetText ("Arrays must be of same size."));
952 Type src_type = sourceArray.GetType ().GetElementType ();
953 Type dst_type = destinationArray.GetType ().GetElementType ();
955 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
956 for (int i = 0; i < length; i++) {
957 Object srcval = sourceArray.GetValueImpl (source_pos + i);
960 destinationArray.SetValueImpl (srcval, dest_pos + i);
961 } catch (ArgumentException) {
962 throw CreateArrayTypeMismatchException ();
964 if (CanAssignArrayElement (src_type, dst_type))
967 throw CreateArrayTypeMismatchException ();
972 for (int i = length - 1; i >= 0; i--) {
973 Object srcval = sourceArray.GetValueImpl (source_pos + i);
976 destinationArray.SetValueImpl (srcval, dest_pos + i);
977 } catch (ArgumentException) {
978 throw CreateArrayTypeMismatchException ();
980 if (CanAssignArrayElement (src_type, dst_type))
983 throw CreateArrayTypeMismatchException ();
989 static Exception CreateArrayTypeMismatchException ()
991 return new ArrayTypeMismatchException ();
994 static bool CanAssignArrayElement (Type source, Type target)
996 if (source.IsValueType)
997 return source.IsAssignableFrom (target);
999 if (source.IsInterface)
1000 return !target.IsValueType;
1002 if (target.IsInterface)
1003 return !source.IsValueType;
1005 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
1008 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1009 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1010 long destinationIndex, long length)
1012 if (sourceArray == null)
1013 throw new ArgumentNullException ("sourceArray");
1015 if (destinationArray == null)
1016 throw new ArgumentNullException ("destinationArray");
1018 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1019 throw new ArgumentOutOfRangeException ("sourceIndex",
1020 Locale.GetText ("Must be in the Int32 range."));
1022 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1023 throw new ArgumentOutOfRangeException ("destinationIndex",
1024 Locale.GetText ("Must be in the Int32 range."));
1026 if (length < 0 || length > Int32.MaxValue)
1027 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1028 "Value must be >= 0 and <= Int32.MaxValue."));
1030 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1033 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1034 public static void Copy (Array sourceArray, Array destinationArray, long length)
1036 if (length < 0 || length > Int32.MaxValue)
1037 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1038 "Value must be >= 0 and <= Int32.MaxValue."));
1040 Copy (sourceArray, destinationArray, (int) length);
1043 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1044 public static int IndexOf (Array array, object value)
1047 throw new ArgumentNullException ("array");
1049 return IndexOf (array, value, 0, array.Length);
1052 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1053 public static int IndexOf (Array array, object value, int startIndex)
1056 throw new ArgumentNullException ("array");
1058 return IndexOf (array, value, startIndex, array.Length - startIndex);
1061 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1062 public static int IndexOf (Array array, object value, int startIndex, int count)
1065 throw new ArgumentNullException ("array");
1068 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1070 // re-ordered to avoid possible integer overflow
1071 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1072 throw new ArgumentOutOfRangeException ();
1074 int max = startIndex + count;
1075 for (int i = startIndex; i < max; i++) {
1076 if (Object.Equals (array.GetValueImpl (i), value))
1080 return array.GetLowerBound (0) - 1;
1083 public void Initialize()
1085 //FIXME: We would like to find a compiler that uses
1086 // this method. It looks like this method do nothing
1087 // in C# so no exception is trown by the moment.
1090 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1091 public static int LastIndexOf (Array array, object value)
1094 throw new ArgumentNullException ("array");
1096 if (array.Length == 0)
1097 return array.GetLowerBound (0) - 1;
1098 return LastIndexOf (array, value, array.Length - 1);
1101 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1102 public static int LastIndexOf (Array array, object value, int startIndex)
1105 throw new ArgumentNullException ("array");
1107 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1110 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1111 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1114 throw new ArgumentNullException ("array");
1117 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1119 int lb = array.GetLowerBound (0);
1120 // Empty arrays do not throw ArgumentOutOfRangeException
1121 if (array.Length == 0)
1124 if (count < 0 || startIndex < lb ||
1125 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1126 throw new ArgumentOutOfRangeException ();
1128 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1129 if (Object.Equals (array.GetValueImpl (i), value))
1136 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1137 public static void Reverse (Array array)
1140 throw new ArgumentNullException ("array");
1142 Reverse (array, array.GetLowerBound (0), array.Length);
1145 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1146 public static void Reverse (Array array, int index, int length)
1149 throw new ArgumentNullException ("array");
1152 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1154 if (index < array.GetLowerBound (0) || length < 0)
1155 throw new ArgumentOutOfRangeException ();
1157 // re-ordered to avoid possible integer overflow
1158 if (index > array.GetUpperBound (0) + 1 - length)
1159 throw new ArgumentException ();
1161 int end = index + length - 1;
1162 var et = array.GetType ().GetElementType ();
1163 switch (Type.GetTypeCode (et)) {
1164 case TypeCode.Boolean:
1165 while (index < end) {
1168 array.GetGenericValueImpl (index, out a);
1169 array.GetGenericValueImpl (end, out b);
1170 array.SetGenericValueImpl (index, ref b);
1171 array.SetGenericValueImpl (end, ref a);
1178 case TypeCode.SByte:
1179 while (index < end) {
1182 array.GetGenericValueImpl (index, out a);
1183 array.GetGenericValueImpl (end, out b);
1184 array.SetGenericValueImpl (index, ref b);
1185 array.SetGenericValueImpl (end, ref a);
1191 case TypeCode.Int16:
1192 case TypeCode.UInt16:
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.Int32:
1207 case TypeCode.UInt32:
1208 case TypeCode.Single:
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.Int64:
1222 case TypeCode.UInt64:
1223 case TypeCode.Double:
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.Decimal:
1237 while (index < end) {
1240 array.GetGenericValueImpl (index, out a);
1241 array.GetGenericValueImpl (end, out b);
1242 array.SetGenericValueImpl (index, ref b);
1243 array.SetGenericValueImpl (end, ref a);
1249 case TypeCode.String:
1250 while (index < end) {
1253 array.GetGenericValueImpl (index, out a);
1254 array.GetGenericValueImpl (end, out b);
1255 array.SetGenericValueImpl (index, ref b);
1256 array.SetGenericValueImpl (end, ref a);
1262 if (array is object[])
1263 goto case TypeCode.String;
1265 // Very slow fallback
1266 while (index < end) {
1267 object val = array.GetValueImpl (index);
1268 array.SetValueImpl (array.GetValueImpl (end), index);
1269 array.SetValueImpl (val, end);
1278 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1279 public static void Sort (Array array)
1281 Sort (array, (IComparer)null);
1284 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1285 public static void Sort (Array keys, Array items)
1287 Sort (keys, items, (IComparer)null);
1290 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1291 public static void Sort (Array array, IComparer comparer)
1294 throw new ArgumentNullException ("array");
1297 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1299 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1302 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1303 public static void Sort (Array array, int index, int length)
1305 Sort (array, index, length, (IComparer)null);
1308 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1309 public static void Sort (Array keys, Array items, IComparer comparer)
1311 if (items == null) {
1312 Sort (keys, comparer);
1317 throw new ArgumentNullException ("keys");
1319 if (keys.Rank > 1 || items.Rank > 1)
1320 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1322 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1325 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1326 public static void Sort (Array keys, Array items, int index, int length)
1328 Sort (keys, items, index, length, (IComparer)null);
1331 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1332 public static void Sort (Array array, int index, int length, IComparer comparer)
1335 throw new ArgumentNullException ("array");
1338 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1340 if (index < array.GetLowerBound (0))
1341 throw new ArgumentOutOfRangeException ("index");
1344 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1345 "Value has to be >= 0."));
1347 if (array.Length - (array.GetLowerBound (0) + index) < length)
1348 throw new ArgumentException ();
1350 SortImpl (array, null, index, length, comparer);
1353 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1354 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1356 if (items == null) {
1357 Sort (keys, index, length, comparer);
1362 throw new ArgumentNullException ("keys");
1364 if (keys.Rank > 1 || items.Rank > 1)
1365 throw new RankException ();
1367 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1368 throw new ArgumentException ();
1370 if (index < keys.GetLowerBound (0))
1371 throw new ArgumentOutOfRangeException ("index");
1374 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1375 "Value has to be >= 0."));
1377 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1378 throw new ArgumentException ();
1380 SortImpl (keys, items, index, length, comparer);
1383 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1389 int high = index + length - 1;
1391 #if !BOOTSTRAP_BASIC
1392 if (comparer == null && items is object[]) {
1393 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1394 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1395 case TypeCode.Int32:
1396 qsort (keys as Int32[], items as object[], low, high);
1398 case TypeCode.Int64:
1399 qsort (keys as Int64[], items as object[], low, high);
1402 qsort (keys as byte[], items as object[], low, high);
1405 qsort (keys as char[], items as object[], low, high);
1407 case TypeCode.DateTime:
1408 qsort (keys as DateTime[], items as object[], low, high);
1410 case TypeCode.Decimal:
1411 qsort (keys as decimal[], items as object[], low, high);
1413 case TypeCode.Double:
1414 qsort (keys as double[], items as object[], low, high);
1416 case TypeCode.Int16:
1417 qsort (keys as Int16[], items as object[], low, high);
1419 case TypeCode.SByte:
1420 qsort (keys as SByte[], items as object[], low, high);
1422 case TypeCode.Single:
1423 qsort (keys as Single[], items as object[], low, high);
1425 case TypeCode.UInt16:
1426 qsort (keys as UInt16[], items as object[], low, high);
1428 case TypeCode.UInt32:
1429 qsort (keys as UInt32[], items as object[], low, high);
1431 case TypeCode.UInt64:
1432 qsort (keys as UInt64[], items as object[], low, high);
1440 if (comparer == null)
1441 CheckComparerAvailable (keys, low, high);
1444 qsort (keys, items, low, high, comparer);
1445 } catch (Exception e) {
1446 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1455 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1460 if (comparer != null) {
1461 if (comparer.Compare (v1, v0) < 0) {
1462 swap (keys, items, lo, hi);
1469 } else if (v0 != null) {
1470 cmp = v1 as IComparable;
1472 if (v1 == null || cmp.CompareTo (v0) < 0) {
1473 swap (keys, items, lo, hi);
1485 unsafe static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1487 QSortStack* stack = stackalloc QSortStack [32];
1488 const int QSORT_THRESHOLD = 7;
1489 int high, low, mid, i, k;
1494 // initialize our stack
1495 stack[0].high = high0;
1496 stack[0].low = low0;
1501 high = stack[sp].high;
1502 low = stack[sp].low;
1504 if ((low + QSORT_THRESHOLD) > high) {
1505 // switch to insertion sort
1506 for (i = low + 1; i <= high; i++) {
1507 for (k = i; k > low; k--) {
1508 lo = keys.GetValueImpl (k - 1);
1509 hi = keys.GetValueImpl (k);
1510 if (comparer != null) {
1511 if (comparer.Compare (hi, lo) >= 0)
1518 cmp = hi as IComparable;
1519 if (cmp.CompareTo (lo) >= 0)
1524 swap (keys, items, k - 1, k);
1531 // calculate the middle element
1532 mid = low + ((high - low) / 2);
1535 key = keys.GetValueImpl (mid);
1536 hi = keys.GetValueImpl (high);
1537 lo = keys.GetValueImpl (low);
1539 // once we re-order the low, mid, and high elements to be in
1540 // ascending order, we'll use mid as our pivot.
1541 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1542 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1543 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1545 cmp = key as IComparable;
1547 // since we've already guaranteed that lo <= mid and mid <= hi,
1548 // we can skip comparing them again.
1553 // Move the walls in
1554 if (comparer != null) {
1555 // find the first element with a value >= pivot value
1556 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
1559 // find the last element with a value <= pivot value
1560 while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1562 } else if (cmp != null) {
1563 // find the first element with a value >= pivot value
1564 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
1567 // find the last element with a value <= pivot value
1568 while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1571 // This has the effect of moving the null values to the front if comparer is null
1572 while (i < k && keys.GetValueImpl (i) == null)
1575 while (k > i && keys.GetValueImpl (k) != null)
1582 swap (keys, items, i, k);
1588 // push our partitions onto the stack, largest first
1589 // (to make sure we don't run out of stack space)
1590 if ((high - k) >= (k - low)) {
1591 if ((k + 1) < high) {
1592 stack[sp].high = high;
1597 if ((k - 1) > low) {
1599 stack[sp].low = low;
1603 if ((k - 1) > low) {
1605 stack[sp].low = low;
1609 if ((k + 1) < high) {
1610 stack[sp].high = high;
1618 private static void CheckComparerAvailable (Array keys, int low, int high)
1620 // move null keys to beginning of array,
1621 // ensure that non-null keys implement IComparable
1622 for (int i = 0; i < high; i++) {
1623 object obj = keys.GetValueImpl (i);
1626 if (!(obj is IComparable)) {
1627 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1628 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1633 private static void swap (Array keys, Array items, int i, int j)
1635 object tmp = keys.GetValueImpl (i);
1636 keys.SetValueImpl (keys.GetValueImpl (j), i);
1637 keys.SetValueImpl (tmp, j);
1639 if (items != null) {
1640 tmp = items.GetValueImpl (i);
1641 items.SetValueImpl (items.GetValueImpl (j), i);
1642 items.SetValueImpl (tmp, j);
1646 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1647 public static void Sort<T> (T [] array)
1649 Sort<T> (array, (IComparer<T>)null);
1652 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1653 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1655 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1658 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1659 public static void Sort<T> (T [] array, IComparer<T> comparer)
1662 throw new ArgumentNullException ("array");
1664 SortImpl<T> (array, 0, array.Length, comparer);
1667 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1668 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1670 if (items == null) {
1671 Sort<TKey> (keys, comparer);
1676 throw new ArgumentNullException ("keys");
1678 if (keys.Length != items.Length)
1679 throw new ArgumentException ("Length of keys and items does not match.");
1681 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1684 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1685 public static void Sort<T> (T [] array, int index, int length)
1687 Sort<T> (array, index, length, (IComparer<T>)null);
1690 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1691 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1693 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1696 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1697 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1700 throw new ArgumentNullException ("array");
1703 throw new ArgumentOutOfRangeException ("index");
1706 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1707 "Value has to be >= 0."));
1709 if (index + length > array.Length)
1710 throw new ArgumentException ();
1712 SortImpl<T> (array, index, length, comparer);
1715 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1716 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1718 if (items == null) {
1719 Sort<TKey> (keys, index, length, comparer);
1724 throw new ArgumentNullException ("keys");
1727 throw new ArgumentOutOfRangeException ("index");
1730 throw new ArgumentOutOfRangeException ("length");
1732 if (items.Length - index < length || keys.Length - index < length)
1733 throw new ArgumentException ();
1735 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1738 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1740 if (keys.Length <= 1)
1744 int high = index + length - 1;
1747 // Check for value types which can be sorted without Compare () method
1749 if (comparer == null) {
1750 /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
1751 #if !FULL_AOT_RUNTIME
1752 #if !BOOTSTRAP_BASIC
1753 switch (Type.GetTypeCode (typeof (TKey))) {
1754 case TypeCode.Int32:
1755 qsort (keys as Int32[], items, low, high);
1757 case TypeCode.Int64:
1758 qsort (keys as Int64[], items, low, high);
1761 qsort (keys as byte[], items, low, high);
1764 qsort (keys as char[], items, low, high);
1766 case TypeCode.DateTime:
1767 qsort (keys as DateTime[], items, low, high);
1769 case TypeCode.Decimal:
1770 qsort (keys as decimal[], items, low, high);
1772 case TypeCode.Double:
1773 qsort (keys as double[], items, low, high);
1775 case TypeCode.Int16:
1776 qsort (keys as Int16[], items, low, high);
1778 case TypeCode.SByte:
1779 qsort (keys as SByte[], items, low, high);
1781 case TypeCode.Single:
1782 qsort (keys as Single[], items, low, high);
1784 case TypeCode.UInt16:
1785 qsort (keys as UInt16[], items, low, high);
1787 case TypeCode.UInt32:
1788 qsort (keys as UInt32[], items, low, high);
1790 case TypeCode.UInt64:
1791 qsort (keys as UInt64[], items, low, high);
1796 // Using Comparer<TKey> adds a small overload, but with value types it
1797 // helps us to not box them.
1798 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1799 typeof (TKey).IsValueType)
1800 comparer = Comparer<TKey>.Default;
1803 if (comparer == null)
1804 CheckComparerAvailable<TKey> (keys, low, high);
1807 qsort (keys, items, low, high, comparer);
1808 //} catch (Exception e) {
1809 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1813 // Specialized version for items==null
1814 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1816 if (keys.Length <= 1)
1820 int high = index + length - 1;
1823 // Check for value types which can be sorted without Compare () method
1825 if (comparer == null) {
1826 #if !BOOTSTRAP_BASIC
1827 switch (Type.GetTypeCode (typeof (TKey))) {
1828 case TypeCode.Int32:
1829 qsort (keys as Int32[], low, high);
1831 case TypeCode.Int64:
1832 qsort (keys as Int64[], low, high);
1835 qsort (keys as byte[], low, high);
1838 qsort (keys as char[], low, high);
1840 case TypeCode.DateTime:
1841 qsort (keys as DateTime[], low, high);
1843 case TypeCode.Decimal:
1844 qsort (keys as decimal[], low, high);
1846 case TypeCode.Double:
1847 qsort (keys as double[], low, high);
1849 case TypeCode.Int16:
1850 qsort (keys as Int16[], low, high);
1852 case TypeCode.SByte:
1853 qsort (keys as SByte[], low, high);
1855 case TypeCode.Single:
1856 qsort (keys as Single[], low, high);
1858 case TypeCode.UInt16:
1859 qsort (keys as UInt16[], low, high);
1861 case TypeCode.UInt32:
1862 qsort (keys as UInt32[], low, high);
1864 case TypeCode.UInt64:
1865 qsort (keys as UInt64[], low, high);
1869 // Using Comparer<TKey> adds a small overload, but with value types it
1870 // helps us to not box them.
1871 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1872 typeof (TKey).IsValueType)
1873 comparer = Comparer<TKey>.Default;
1876 if (comparer == null)
1877 CheckComparerAvailable<TKey> (keys, low, high);
1880 qsort<TKey> (keys, low, high, comparer);
1881 //} catch (Exception e) {
1882 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1886 public static void Sort<T> (T [] array, Comparison<T> comparison)
1889 throw new ArgumentNullException ("array");
1891 if (comparison == null)
1892 throw new ArgumentNullException ("comparison");
1894 SortImpl<T> (array, array.Length, comparison);
1897 // used by List<T>.Sort (Comparison <T>)
1898 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1905 int high0 = length - 1;
1906 qsort<T> (array, low0, high0, comparison);
1907 } catch (InvalidOperationException) {
1909 } catch (Exception e) {
1910 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1914 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1916 if (keys[lo] != null) {
1917 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1918 swap (keys, items, lo, hi);
1926 // Specialized version for items==null
1927 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1929 if (keys[lo] != null) {
1930 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1931 swap (keys, lo, hi);
1939 unsafe static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1941 QSortStack* stack = stackalloc QSortStack [32];
1942 const int QSORT_THRESHOLD = 7;
1943 int high, low, mid, i, k;
1947 // initialize our stack
1948 stack[0].high = high0;
1949 stack[0].low = low0;
1954 high = stack[sp].high;
1955 low = stack[sp].low;
1957 if ((low + QSORT_THRESHOLD) > high) {
1958 // switch to insertion sort
1959 for (i = low + 1; i <= high; i++) {
1960 for (k = i; k > low; k--) {
1961 // if keys[k] >= keys[k-1], break
1962 if (keys[k-1] == null)
1965 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
1968 swap (keys, items, k - 1, k);
1975 // calculate the middle element
1976 mid = low + ((high - low) / 2);
1978 // once we re-order the lo, mid, and hi elements to be in
1979 // ascending order, we'll use mid as our pivot.
1980 QSortArrange<T, U> (keys, items, low, mid);
1981 if (QSortArrange<T, U> (keys, items, mid, high))
1982 QSortArrange<T, U> (keys, items, low, mid);
1986 // since we've already guaranteed that lo <= mid and mid <= hi,
1987 // we can skip comparing them again
1993 // find the first element with a value >= pivot value
1994 while (i < k && key.CompareTo (keys[i]) > 0)
1997 // find the last element with a value <= pivot value
1998 while (k > i && key.CompareTo (keys[k]) < 0)
2001 while (i < k && keys[i] == null)
2004 while (k > i && keys[k] != null)
2011 swap (keys, items, i, k);
2017 // push our partitions onto the stack, largest first
2018 // (to make sure we don't run out of stack space)
2019 if ((high - k) >= (k - low)) {
2020 if ((k + 1) < high) {
2021 stack[sp].high = high;
2026 if ((k - 1) > low) {
2028 stack[sp].low = low;
2032 if ((k - 1) > low) {
2034 stack[sp].low = low;
2038 if ((k + 1) < high) {
2039 stack[sp].high = high;
2047 // Specialized version for items==null
2048 unsafe static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2050 QSortStack* stack = stackalloc QSortStack [32];
2051 const int QSORT_THRESHOLD = 7;
2052 int high, low, mid, i, k;
2056 // initialize our stack
2057 stack[0].high = high0;
2058 stack[0].low = low0;
2063 high = stack[sp].high;
2064 low = stack[sp].low;
2066 if ((low + QSORT_THRESHOLD) > high) {
2067 // switch to insertion sort
2068 for (i = low + 1; i <= high; i++) {
2069 for (k = i; k > low; k--) {
2070 // if keys[k] >= keys[k-1], break
2071 if (keys[k-1] == null)
2074 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2077 swap (keys, k - 1, k);
2084 // calculate the middle element
2085 mid = low + ((high - low) / 2);
2087 // once we re-order the lo, mid, and hi elements to be in
2088 // ascending order, we'll use mid as our pivot.
2089 QSortArrange<T> (keys, low, mid);
2090 if (QSortArrange<T> (keys, mid, high))
2091 QSortArrange<T> (keys, low, mid);
2095 // since we've already guaranteed that lo <= mid and mid <= hi,
2096 // we can skip comparing them again
2102 // find the first element with a value >= pivot value
2103 while (i < k && key.CompareTo (keys[i]) > 0)
2106 // find the last element with a value <= pivot value
2107 while (k >= i && key.CompareTo (keys[k]) < 0)
2110 while (i < k && keys[i] == null)
2113 while (k >= i && keys[k] != null)
2126 // push our partitions onto the stack, largest first
2127 // (to make sure we don't run out of stack space)
2128 if ((high - k) >= (k - low)) {
2129 if ((k + 1) < high) {
2130 stack[sp].high = high;
2135 if ((k - 1) > low) {
2137 stack[sp].low = low;
2141 if ((k - 1) > low) {
2143 stack[sp].low = low;
2147 if ((k + 1) < high) {
2148 stack[sp].high = high;
2156 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2158 IComparable<K> gcmp;
2161 if (comparer != null) {
2162 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2163 swap<K, V> (keys, items, lo, hi);
2166 } else if (keys[lo] != null) {
2167 if (keys[hi] == null) {
2168 swap<K, V> (keys, items, lo, hi);
2172 gcmp = keys[hi] as IComparable<K>;
2174 if (gcmp.CompareTo (keys[lo]) < 0) {
2175 swap<K, V> (keys, items, lo, hi);
2182 cmp = keys[hi] as IComparable;
2184 if (cmp.CompareTo (keys[lo]) < 0) {
2185 swap<K, V> (keys, items, lo, hi);
2196 // Specialized version for items==null
2197 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2199 IComparable<K> gcmp;
2202 if (comparer != null) {
2203 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2204 swap<K> (keys, lo, hi);
2207 } else if (keys[lo] != null) {
2208 if (keys[hi] == null) {
2209 swap<K> (keys, lo, hi);
2213 gcmp = keys[hi] as IComparable<K>;
2215 if (gcmp.CompareTo (keys[lo]) < 0) {
2216 swap<K> (keys, lo, hi);
2223 cmp = keys[hi] as IComparable;
2225 if (cmp.CompareTo (keys[lo]) < 0) {
2226 swap<K> (keys, lo, hi);
2237 unsafe static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2239 QSortStack* stack = stackalloc QSortStack [32];
2240 const int QSORT_THRESHOLD = 7;
2241 int high, low, mid, i, k;
2242 IComparable<K> gcmp;
2247 // initialize our stack
2248 stack[0].high = high0;
2249 stack[0].low = low0;
2254 high = stack[sp].high;
2255 low = stack[sp].low;
2257 if ((low + QSORT_THRESHOLD) > high) {
2258 // switch to insertion sort
2259 for (i = low + 1; i <= high; i++) {
2260 for (k = i; k > low; k--) {
2261 // if keys[k] >= keys[k-1], break
2262 if (comparer != null) {
2263 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2266 if (keys[k-1] == null)
2269 if (keys[k] != null) {
2270 gcmp = keys[k] as IComparable<K>;
2271 cmp = keys[k] as IComparable;
2273 if (gcmp.CompareTo (keys[k-1]) >= 0)
2276 if (cmp.CompareTo (keys[k-1]) >= 0)
2282 swap<K, V> (keys, items, k - 1, k);
2289 // calculate the middle element
2290 mid = low + ((high - low) / 2);
2292 // once we re-order the low, mid, and high elements to be in
2293 // ascending order, we'll use mid as our pivot.
2294 QSortArrange<K, V> (keys, items, low, mid, comparer);
2295 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2296 QSortArrange<K, V> (keys, items, low, mid, comparer);
2299 gcmp = key as IComparable<K>;
2300 cmp = key as IComparable;
2302 // since we've already guaranteed that lo <= mid and mid <= hi,
2303 // we can skip comparing them again.
2308 // Move the walls in
2309 if (comparer != null) {
2310 // find the first element with a value >= pivot value
2311 while (i < k && comparer.Compare (key, keys[i]) > 0)
2314 // find the last element with a value <= pivot value
2315 while (k > i && comparer.Compare (key, keys[k]) < 0)
2319 // find the first element with a value >= pivot value
2320 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2323 // find the last element with a value <= pivot value
2324 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2326 } else if (cmp != null) {
2327 // find the first element with a value >= pivot value
2328 while (i < k && cmp.CompareTo (keys[i]) > 0)
2331 // find the last element with a value <= pivot value
2332 while (k > i && cmp.CompareTo (keys[k]) < 0)
2335 while (i < k && keys[i] == null)
2338 while (k > i && keys[k] != null)
2346 swap<K, V> (keys, items, i, k);
2352 // push our partitions onto the stack, largest first
2353 // (to make sure we don't run out of stack space)
2354 if ((high - k) >= (k - low)) {
2355 if ((k + 1) < high) {
2356 stack[sp].high = high;
2361 if ((k - 1) > low) {
2363 stack[sp].low = low;
2367 if ((k - 1) > low) {
2369 stack[sp].low = low;
2373 if ((k + 1) < high) {
2374 stack[sp].high = high;
2382 // Specialized version for items==null
2383 unsafe static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2385 QSortStack* stack = stackalloc QSortStack [32];
2386 const int QSORT_THRESHOLD = 7;
2387 int high, low, mid, i, k;
2388 IComparable<K> gcmp;
2393 // initialize our stack
2394 stack[0].high = high0;
2395 stack[0].low = low0;
2400 high = stack[sp].high;
2401 low = stack[sp].low;
2403 if ((low + QSORT_THRESHOLD) > high) {
2404 // switch to insertion sort
2405 for (i = low + 1; i <= high; i++) {
2406 for (k = i; k > low; k--) {
2407 // if keys[k] >= keys[k-1], break
2408 if (comparer != null) {
2409 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2412 if (keys[k-1] == null)
2415 if (keys[k] != null) {
2416 gcmp = keys[k] as IComparable<K>;
2417 cmp = keys[k] as IComparable;
2419 if (gcmp.CompareTo (keys[k-1]) >= 0)
2422 if (cmp.CompareTo (keys[k-1]) >= 0)
2428 swap<K> (keys, k - 1, k);
2435 // calculate the middle element
2436 mid = low + ((high - low) / 2);
2438 // once we re-order the low, mid, and high elements to be in
2439 // ascending order, we'll use mid as our pivot.
2440 QSortArrange<K> (keys, low, mid, comparer);
2441 if (QSortArrange<K> (keys, mid, high, comparer))
2442 QSortArrange<K> (keys, low, mid, comparer);
2445 gcmp = key as IComparable<K>;
2446 cmp = key as IComparable;
2448 // since we've already guaranteed that lo <= mid and mid <= hi,
2449 // we can skip comparing them again.
2454 // Move the walls in
2455 if (comparer != null) {
2456 // find the first element with a value >= pivot value
2457 while (i < k && comparer.Compare (key, keys[i]) > 0)
2460 // find the last element with a value <= pivot value
2461 while (k > i && comparer.Compare (key, keys[k]) < 0)
2465 // find the first element with a value >= pivot value
2466 while (i < k && gcmp.CompareTo (keys[i]) > 0)
2469 // find the last element with a value <= pivot value
2470 while (k > i && gcmp.CompareTo (keys[k]) < 0)
2472 } else if (cmp != null) {
2473 // find the first element with a value >= pivot value
2474 while (i < k && cmp.CompareTo (keys[i]) > 0)
2477 // find the last element with a value <= pivot value
2478 while (k > i && cmp.CompareTo (keys[k]) < 0)
2481 while (i < k && keys[i] == null)
2484 while (k > i && keys[k] != null)
2492 swap<K> (keys, i, k);
2498 // push our partitions onto the stack, largest first
2499 // (to make sure we don't run out of stack space)
2500 if ((high - k) >= (k - low)) {
2501 if ((k + 1) < high) {
2502 stack[sp].high = high;
2507 if ((k - 1) > low) {
2509 stack[sp].low = low;
2513 if ((k - 1) > low) {
2515 stack[sp].low = low;
2519 if ((k + 1) < high) {
2520 stack[sp].high = high;
2528 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2530 if (array[lo] != null) {
2531 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2532 swap<T> (array, lo, hi);
2540 unsafe static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2542 QSortStack* stack = stackalloc QSortStack [32];
2543 const int QSORT_THRESHOLD = 7;
2544 int high, low, mid, i, k;
2548 // initialize our stack
2549 stack[0].high = high0;
2550 stack[0].low = low0;
2555 high = stack[sp].high;
2556 low = stack[sp].low;
2558 if ((low + QSORT_THRESHOLD) > high) {
2559 // switch to insertion sort
2560 for (i = low + 1; i <= high; i++) {
2561 for (k = i; k > low; k--) {
2562 if (compare (array[k], array[k-1]) >= 0)
2565 swap<T> (array, k - 1, k);
2572 // calculate the middle element
2573 mid = low + ((high - low) / 2);
2575 // once we re-order the lo, mid, and hi elements to be in
2576 // ascending order, we'll use mid as our pivot.
2577 QSortArrange<T> (array, low, mid, compare);
2578 if (QSortArrange<T> (array, mid, high, compare))
2579 QSortArrange<T> (array, low, mid, compare);
2583 // since we've already guaranteed that lo <= mid and mid <= hi,
2584 // we can skip comparing them again
2589 // Move the walls in
2591 // find the first element with a value >= pivot value
2592 while (i < k && compare (key, array[i]) > 0)
2595 // find the last element with a value <= pivot value
2596 while (k > i && compare (key, array[k]) < 0)
2599 while (i < k && array[i] == null)
2602 while (k > i && array[k] != null)
2609 swap<T> (array, i, k);
2615 // push our partitions onto the stack, largest first
2616 // (to make sure we don't run out of stack space)
2617 if ((high - k) >= (k - low)) {
2618 if ((k + 1) < high) {
2619 stack[sp].high = high;
2624 if ((k - 1) > low) {
2626 stack[sp].low = low;
2630 if ((k - 1) > low) {
2632 stack[sp].low = low;
2636 if ((k + 1) < high) {
2637 stack[sp].high = high;
2645 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2647 // move null keys to beginning of array,
2648 // ensure that non-null keys implement IComparable
2649 for (int i = low; i < high; i++) {
2652 if (!(key is IComparable<K>) && !(key is IComparable)) {
2653 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2654 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2660 [MethodImpl ((MethodImplOptions)256)]
2661 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2666 keys [i] = keys [j];
2669 if (items != null) {
2672 items [i] = items [j];
2677 [MethodImpl ((MethodImplOptions)256)]
2678 private static void swap<T> (T [] array, int i, int j)
2681 array [i] = array [j];
2685 public void CopyTo (Array array, int index)
2688 throw new ArgumentNullException ("array");
2690 // The order of these exception checks may look strange,
2691 // but that's how the microsoft runtime does it.
2693 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2694 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2695 throw new ArgumentException ("Destination array was not long " +
2696 "enough. Check destIndex and length, and the array's " +
2699 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2701 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2702 "Value has to be >= 0."));
2704 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2707 [ComVisible (false)]
2708 public void CopyTo (Array array, long index)
2710 if (index < 0 || index > Int32.MaxValue)
2711 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2712 "Value must be >= 0 and <= Int32.MaxValue."));
2714 CopyTo (array, (int) index);
2717 internal class SimpleEnumerator : IEnumerator, ICloneable
2723 public SimpleEnumerator (Array arrayToEnumerate)
2725 this.enumeratee = arrayToEnumerate;
2726 this.currentpos = -1;
2727 this.length = arrayToEnumerate.Length;
2730 public object Current {
2732 // Exception messages based on MS implementation
2733 if (currentpos < 0 )
2734 throw new InvalidOperationException (Locale.GetText (
2735 "Enumeration has not started."));
2736 if (currentpos >= length)
2737 throw new InvalidOperationException (Locale.GetText (
2738 "Enumeration has already ended"));
2739 // Current should not increase the position. So no ++ over here.
2740 return enumeratee.GetValueImpl (currentpos);
2744 public bool MoveNext()
2746 //The docs say Current should throw an exception if last
2747 //call to MoveNext returned false. This means currentpos
2748 //should be set to length when returning false.
2749 if (currentpos < length)
2751 if(currentpos < length)
2762 public object Clone ()
2764 return MemberwiseClone ();
2768 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2769 public static void Resize<T> (ref T [] array, int newSize)
2772 throw new ArgumentOutOfRangeException ("newSize");
2774 if (array == null) {
2775 array = new T [newSize];
2780 int length = arr.Length;
2781 if (length == newSize)
2784 T [] a = new T [newSize];
2785 int tocopy = Math.Min (newSize, length);
2788 for (int i = 0; i < tocopy; ++i)
2789 UnsafeStore (a, i, UnsafeLoad (arr, i));
2791 FastCopy (arr, 0, a, 0, tocopy);
2796 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2799 throw new ArgumentNullException ("array");
2801 throw new ArgumentNullException ("match");
2803 foreach (T t in array)
2810 public static void ForEach<T> (T [] array, Action <T> action)
2813 throw new ArgumentNullException ("array");
2815 throw new ArgumentNullException ("action");
2817 foreach (T t in array)
2821 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2824 throw new ArgumentNullException ("array");
2825 if (converter == null)
2826 throw new ArgumentNullException ("converter");
2828 TOutput [] output = new TOutput [array.Length];
2829 for (int i = 0; i < array.Length; i ++)
2830 output [i] = converter (array [i]);
2835 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2838 throw new ArgumentNullException ("array");
2841 throw new ArgumentNullException ("match");
2843 return GetLastIndex (array, 0, array.Length, match);
2846 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2849 throw new ArgumentNullException ();
2851 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2852 throw new ArgumentOutOfRangeException ("startIndex");
2855 throw new ArgumentNullException ("match");
2857 return GetLastIndex (array, 0, startIndex + 1, match);
2860 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2863 throw new ArgumentNullException ("array");
2866 throw new ArgumentNullException ("match");
2868 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2869 throw new ArgumentOutOfRangeException ("startIndex");
2872 throw new ArgumentOutOfRangeException ("count");
2874 if (startIndex - count + 1 < 0)
2875 throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
2877 return GetLastIndex (array, startIndex - count + 1, count, match);
2880 internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2882 // unlike FindLastIndex, takes regular params for search range
2883 for (int i = startIndex + count; i != startIndex;)
2884 if (match (array [--i]))
2890 public static int FindIndex<T> (T [] array, Predicate<T> match)
2893 throw new ArgumentNullException ("array");
2896 throw new ArgumentNullException ("match");
2898 return GetIndex (array, 0, array.Length, match);
2901 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2904 throw new ArgumentNullException ("array");
2906 if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
2907 throw new ArgumentOutOfRangeException ("startIndex");
2910 throw new ArgumentNullException ("match");
2912 return GetIndex (array, startIndex, array.Length - startIndex, match);
2915 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2918 throw new ArgumentNullException ("array");
2921 throw new ArgumentOutOfRangeException ("startIndex");
2924 throw new ArgumentOutOfRangeException ("count");
2926 if ((uint) startIndex + (uint) count > (uint) array.Length)
2927 throw new ArgumentOutOfRangeException ("index and count exceed length of list");
2929 return GetIndex (array, startIndex, count, match);
2932 internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
2934 int end = startIndex + count;
2935 for (int i = startIndex; i < end; i ++)
2936 if (match (array [i]))
2942 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2943 public static int BinarySearch<T> (T [] array, T value)
2946 throw new ArgumentNullException ("array");
2948 return BinarySearch<T> (array, 0, array.Length, value, null);
2951 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2952 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2955 throw new ArgumentNullException ("array");
2957 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2960 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2961 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2963 return BinarySearch<T> (array, index, length, value, null);
2966 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2967 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2970 throw new ArgumentNullException ("array");
2972 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2973 "index is less than the lower bound of array."));
2975 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2976 "Value has to be >= 0."));
2977 // re-ordered to avoid possible integer overflow
2978 if (index > array.Length - length)
2979 throw new ArgumentException (Locale.GetText (
2980 "index and length do not specify a valid range in array."));
2981 if (comparer == null)
2982 comparer = Comparer <T>.Default;
2985 int iMax = index + length - 1;
2988 while (iMin <= iMax) {
2989 // Be careful with overflows
2990 int iMid = iMin + ((iMax - iMin) / 2);
2991 iCmp = comparer.Compare (array [iMid], value);
2999 iMin = iMid + 1; // compensate for the rounding down
3001 } catch (Exception e) {
3002 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
3008 public static int IndexOf<T> (T [] array, T value)
3011 throw new ArgumentNullException ("array");
3013 return IndexOf<T> (array, value, 0, array.Length);
3016 public static int IndexOf<T> (T [] array, T value, int startIndex)
3019 throw new ArgumentNullException ("array");
3021 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
3024 public static int IndexOf<T> (T[] array, T value, int startIndex, int count)
3027 throw new ArgumentNullException ("array");
3029 // re-ordered to avoid possible integer overflow
3030 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
3031 throw new ArgumentOutOfRangeException ();
3033 return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, startIndex + count);
3036 public static int LastIndexOf<T> (T [] array, T value)
3039 throw new ArgumentNullException ("array");
3041 if (array.Length == 0)
3043 return LastIndexOf<T> (array, value, array.Length - 1);
3046 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3049 throw new ArgumentNullException ("array");
3051 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3054 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3057 throw new ArgumentNullException ("array");
3059 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3060 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3061 throw new ArgumentOutOfRangeException ();
3063 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3064 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3065 if (equalityComparer.Equals (array [i], value))
3072 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3075 throw new ArgumentNullException ("array");
3078 throw new ArgumentNullException ("match");
3081 T [] d = new T [array.Length];
3082 foreach (T t in array)
3086 Resize <T> (ref d, pos);
3090 public static bool Exists<T> (T [] array, Predicate <T> match)
3093 throw new ArgumentNullException ("array");
3096 throw new ArgumentNullException ("match");
3098 foreach (T t in array)
3104 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3107 throw new ArgumentNullException ("array");
3109 return new ReadOnlyCollection<T> (array);
3112 public static T Find<T> (T [] array, Predicate<T> match)
3115 throw new ArgumentNullException ("array");
3118 throw new ArgumentNullException ("match");
3120 foreach (T t in array)
3127 public static T FindLast<T> (T [] array, Predicate <T> match)
3130 throw new ArgumentNullException ("array");
3133 throw new ArgumentNullException ("match");
3135 for (int i = array.Length - 1; i >= 0; i--)
3136 if (match (array [i]))
3142 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3144 // The constrained copy should guarantee that if there is an exception thrown
3145 // during the copy, the destination array remains unchanged.
3146 // This is related to System.Runtime.Reliability.CER
3147 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3149 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
3152 #region Unsafe array operations
3155 // Loads array index with no safety checks (JIT intristics)
3157 internal static T UnsafeLoad<T> (T[] array, int index) {
3158 return array [index];
3162 // Stores values at specified array index with no safety checks (JIT intristics)
3164 internal static void UnsafeStore<T> (T[] array, int index, T value) {
3165 array [index] = value;
3169 // Moved value from instance into target of different type with no checks (JIT intristics)
3171 internal static R UnsafeMov<S,R> (S instance) {
3172 return (R)(object) instance;
3177 internal sealed class FunctorComparer<T> : IComparer<T> {
3178 Comparison<T> comparison;
3180 public FunctorComparer(Comparison<T> comparison) {
3181 this.comparison = comparison;
3184 public int Compare(T x, T y) {
3185 return comparison(x, y);