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;
43 using System.Reflection.Emit;
49 // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
50 public abstract class Array : ICloneable, ICollection, IList, IEnumerable
51 #if NET_4_0 || MOONLIGHT || MOBILE
52 , 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);
112 if (item.Equals (value))
119 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
122 throw new ArgumentNullException ("array");
124 // The order of these exception checks may look strange,
125 // but that's how the microsoft runtime does it.
127 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
128 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
129 throw new ArgumentException ("Destination array was not long " +
130 "enough. Check destIndex and length, and the array's " +
133 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
135 throw new ArgumentOutOfRangeException (
136 "index", Locale.GetText ("Value has to be >= 0."));
138 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
141 internal void InternalArray__Insert<T> (int index, T item)
143 throw new NotSupportedException ("Collection is of a fixed size");
146 internal void InternalArray__RemoveAt (int index)
148 throw new NotSupportedException ("Collection is of a fixed size");
151 internal int InternalArray__IndexOf<T> (T item)
154 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
156 int length = this.Length;
157 for (int i = 0; i < length; i++) {
159 GetGenericValueImpl (i, out value);
162 return i + this.GetLowerBound (0);
166 if (value.Equals (item))
167 // array index may not be zero-based.
169 return i + this.GetLowerBound (0);
173 // lower bound may be MinValue
174 return this.GetLowerBound (0) - 1;
178 internal T InternalArray__get_Item<T> (int index)
180 if (unchecked ((uint) index) >= unchecked ((uint) Length))
181 throw new ArgumentOutOfRangeException ("index");
184 GetGenericValueImpl (index, out value);
188 internal void InternalArray__set_Item<T> (int index, T item)
190 if (unchecked ((uint) index) >= unchecked ((uint) Length))
191 throw new ArgumentOutOfRangeException ("index");
193 object[] oarray = this as object [];
194 if (oarray != null) {
195 oarray [index] = (object)item;
198 SetGenericValueImpl (index, ref item);
201 // CAUTION! No bounds checking!
202 [MethodImplAttribute (MethodImplOptions.InternalCall)]
203 internal extern void GetGenericValueImpl<T> (int pos, out T value);
205 // CAUTION! No bounds checking!
206 [MethodImplAttribute (MethodImplOptions.InternalCall)]
207 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
209 internal struct InternalEnumerator<T> : IEnumerator<T>
211 const int NOT_STARTED = -2;
213 // this MUST be -1, because we depend on it in move next.
214 // we just decr the size, so, 0 - 1 == FINISHED
215 const int FINISHED = -1;
220 internal InternalEnumerator (Array array)
226 public void Dispose ()
231 public bool MoveNext ()
233 if (idx == NOT_STARTED)
236 return idx != FINISHED && -- idx != FINISHED;
241 if (idx == NOT_STARTED)
242 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
244 throw new InvalidOperationException ("Enumeration already finished");
246 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
250 void IEnumerator.Reset ()
255 object IEnumerator.Current {
264 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
266 int length = this.GetLength (0);
268 for (int i = 1; i < this.Rank; i++) {
269 length *= this.GetLength (i);
276 public long LongLength {
277 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
278 get { return Length; }
282 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
284 return this.GetRank ();
289 object IList.this [int index] {
291 if (unchecked ((uint) index) >= unchecked ((uint) Length))
292 throw new IndexOutOfRangeException ("index");
294 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
295 return GetValueImpl (index);
298 if (unchecked ((uint) index) >= unchecked ((uint) Length))
299 throw new IndexOutOfRangeException ("index");
301 throw new ArgumentException (Locale.GetText ("Only single dimension arrays are supported."));
302 SetValueImpl (value, index);
306 int IList.Add (object value)
308 throw new NotSupportedException ();
313 Array.Clear (this, this.GetLowerBound (0), this.Length);
316 bool IList.Contains (object value)
319 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
321 int length = this.Length;
322 for (int i = 0; i < length; i++) {
323 if (Object.Equals (this.GetValueImpl (i), value))
329 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
330 int IList.IndexOf (object value)
333 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
335 int length = this.Length;
336 for (int i = 0; i < length; i++) {
337 if (Object.Equals (this.GetValueImpl (i), value))
338 // array index may not be zero-based.
340 return i + this.GetLowerBound (0);
344 // lower bound may be MinValue
345 return this.GetLowerBound (0) - 1;
349 void IList.Insert (int index, object value)
351 throw new NotSupportedException ();
354 void IList.Remove (object value)
356 throw new NotSupportedException ();
359 void IList.RemoveAt (int index)
361 throw new NotSupportedException ();
364 // InternalCall Methods
365 [MethodImplAttribute (MethodImplOptions.InternalCall)]
366 extern int GetRank ();
368 [MethodImplAttribute (MethodImplOptions.InternalCall)]
369 public extern int GetLength (int dimension);
372 public long GetLongLength (int dimension)
374 return GetLength (dimension);
377 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
378 [MethodImplAttribute (MethodImplOptions.InternalCall)]
379 public extern int GetLowerBound (int dimension);
381 [MethodImplAttribute (MethodImplOptions.InternalCall)]
382 public extern object GetValue (params int[] indices);
384 [MethodImplAttribute (MethodImplOptions.InternalCall)]
385 public extern void SetValue (object value, params int[] indices);
387 // CAUTION! No bounds checking!
388 [MethodImplAttribute (MethodImplOptions.InternalCall)]
389 internal extern object GetValueImpl (int pos);
391 // CAUTION! No bounds checking!
392 [MethodImplAttribute (MethodImplOptions.InternalCall)]
393 internal extern void SetValueImpl (object value, int pos);
395 [MethodImplAttribute (MethodImplOptions.InternalCall)]
396 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
398 [MethodImplAttribute (MethodImplOptions.InternalCall)]
399 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
402 int ICollection.Count {
408 public bool IsSynchronized {
414 public object SyncRoot {
420 public bool IsFixedSize {
426 public bool IsReadOnly {
432 public IEnumerator GetEnumerator ()
434 return new SimpleEnumerator (this);
437 #if NET_4_0 || MOONLIGHT || MOBILE
438 int IStructuralComparable.CompareTo (object other, IComparer comparer)
443 Array arr = other as Array;
445 throw new ArgumentException ("Not an array", "other");
447 int len = GetLength (0);
448 if (len != arr.GetLength (0))
449 throw new ArgumentException ("Not of the same length", "other");
452 throw new ArgumentException ("Array must be single dimensional");
455 throw new ArgumentException ("Array must be single dimensional", "other");
457 for (int i = 0; i < len; ++i) {
458 object a = GetValue (i);
459 object b = arr.GetValue (i);
460 int r = comparer.Compare (a, b);
467 bool IStructuralEquatable.Equals (object other, IEqualityComparer comparer)
469 Array o = other as Array;
470 if (o == null || o.Length != Length)
473 if (Object.ReferenceEquals (other, this))
476 for (int i = 0; i < Length; i++) {
477 object this_item = this.GetValue (i);
478 object other_item = o.GetValue (i);
479 if (!comparer.Equals (this_item, other_item))
486 int IStructuralEquatable.GetHashCode (IEqualityComparer comparer)
488 if (comparer == null)
489 throw new ArgumentNullException ("comparer");
492 for (int i = 0; i < Length; i++)
493 hash = ((hash << 7) + hash) ^ GetValue (i).GetHashCode ();
498 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
499 public int GetUpperBound (int dimension)
501 return GetLowerBound (dimension) + GetLength (dimension) - 1;
504 public object GetValue (int index)
507 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
508 if (index < GetLowerBound (0) || index > GetUpperBound (0))
509 throw new IndexOutOfRangeException (Locale.GetText (
510 "Index has to be between upper and lower bound of the array."));
512 return GetValueImpl (index - GetLowerBound (0));
515 public object GetValue (int index1, int index2)
517 int[] ind = {index1, index2};
518 return GetValue (ind);
521 public object GetValue (int index1, int index2, int index3)
523 int[] ind = {index1, index2, index3};
524 return GetValue (ind);
528 public object GetValue (long index)
530 if (index < 0 || index > Int32.MaxValue)
531 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
532 "Value must be >= 0 and <= Int32.MaxValue."));
534 return GetValue ((int) index);
538 public object GetValue (long index1, long index2)
540 if (index1 < 0 || index1 > Int32.MaxValue)
541 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
542 "Value must be >= 0 and <= Int32.MaxValue."));
544 if (index2 < 0 || index2 > Int32.MaxValue)
545 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
546 "Value must be >= 0 and <= Int32.MaxValue."));
548 return GetValue ((int) index1, (int) index2);
552 public object GetValue (long index1, long index2, long index3)
554 if (index1 < 0 || index1 > Int32.MaxValue)
555 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
556 "Value must be >= 0 and <= Int32.MaxValue."));
558 if (index2 < 0 || index2 > Int32.MaxValue)
559 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
560 "Value must be >= 0 and <= Int32.MaxValue."));
562 if (index3 < 0 || index3 > Int32.MaxValue)
563 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
564 "Value must be >= 0 and <= Int32.MaxValue."));
566 return GetValue ((int) index1, (int) index2, (int) index3);
570 public void SetValue (object value, long index)
572 if (index < 0 || index > Int32.MaxValue)
573 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
574 "Value must be >= 0 and <= Int32.MaxValue."));
576 SetValue (value, (int) index);
580 public void SetValue (object value, long index1, long index2)
582 if (index1 < 0 || index1 > Int32.MaxValue)
583 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
584 "Value must be >= 0 and <= Int32.MaxValue."));
586 if (index2 < 0 || index2 > Int32.MaxValue)
587 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
588 "Value must be >= 0 and <= Int32.MaxValue."));
590 int[] ind = {(int) index1, (int) index2};
591 SetValue (value, ind);
595 public void SetValue (object value, long index1, long index2, long index3)
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 if (index3 < 0 || index3 > Int32.MaxValue)
606 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
607 "Value must be >= 0 and <= Int32.MaxValue."));
609 int[] ind = {(int) index1, (int) index2, (int) index3};
610 SetValue (value, ind);
613 public void SetValue (object value, int index)
616 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
617 if (index < GetLowerBound (0) || index > GetUpperBound (0))
618 throw new IndexOutOfRangeException (Locale.GetText (
619 "Index has to be >= lower bound and <= upper bound of the array."));
621 SetValueImpl (value, index - GetLowerBound (0));
624 public void SetValue (object value, int index1, int index2)
626 int[] ind = {index1, index2};
627 SetValue (value, ind);
630 public void SetValue (object value, int index1, int index2, int index3)
632 int[] ind = {index1, index2, index3};
633 SetValue (value, ind);
636 public static Array CreateInstance (Type elementType, int length)
638 int[] lengths = {length};
640 return CreateInstance (elementType, lengths);
643 public static Array CreateInstance (Type elementType, int length1, int length2)
645 int[] lengths = {length1, length2};
647 return CreateInstance (elementType, lengths);
650 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
652 int[] lengths = {length1, length2, length3};
654 return CreateInstance (elementType, lengths);
657 public static Array CreateInstance (Type elementType, params int[] lengths)
659 if (elementType == null)
660 throw new ArgumentNullException ("elementType");
662 throw new ArgumentNullException ("lengths");
664 if (lengths.Length > 255)
665 throw new TypeLoadException ();
669 elementType = elementType.UnderlyingSystemType;
670 if (!elementType.IsSystemType)
671 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
672 if (elementType.Equals (typeof (void)))
673 throw new NotSupportedException ("Array type can not be void");
674 if (elementType.ContainsGenericParameters)
675 throw new NotSupportedException ("Array type can not be an open generic type");
676 if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
677 throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
679 return CreateInstanceImpl (elementType, lengths, bounds);
682 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
684 if (elementType == null)
685 throw new ArgumentNullException ("elementType");
687 throw new ArgumentNullException ("lengths");
688 if (lowerBounds == null)
689 throw new ArgumentNullException ("lowerBounds");
691 elementType = elementType.UnderlyingSystemType;
692 if (!elementType.IsSystemType)
693 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
694 if (elementType.Equals (typeof (void)))
695 throw new NotSupportedException ("Array type can not be void");
696 if (elementType.ContainsGenericParameters)
697 throw new NotSupportedException ("Array type can not be an open generic type");
699 if (lengths.Length < 1)
700 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
702 if (lengths.Length != lowerBounds.Length)
703 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
705 for (int j = 0; j < lowerBounds.Length; j ++) {
707 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
708 "Each value has to be >= 0."));
709 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
710 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
711 "Length + bound must not exceed Int32.MaxValue."));
714 if (lengths.Length > 255)
715 throw new TypeLoadException ();
717 return CreateInstanceImpl (elementType, lengths, lowerBounds);
720 static int [] GetIntArray (long [] values)
722 int len = values.Length;
723 int [] ints = new int [len];
724 for (int i = 0; i < len; i++) {
725 long current = values [i];
726 if (current < 0 || current > (long) Int32.MaxValue)
727 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
728 "Each value has to be >= 0 and <= Int32.MaxValue."));
730 ints [i] = (int) current;
735 public static Array CreateInstance (Type elementType, params long [] lengths)
738 throw new ArgumentNullException ("lengths");
739 return CreateInstance (elementType, GetIntArray (lengths));
743 public object GetValue (params long [] indices)
746 throw new ArgumentNullException ("indices");
747 return GetValue (GetIntArray (indices));
751 public void SetValue (object value, params long [] indices)
754 throw new ArgumentNullException ("indices");
755 SetValue (value, GetIntArray (indices));
758 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
759 public static int BinarySearch (Array array, object value)
762 throw new ArgumentNullException ("array");
768 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
770 if (array.Length == 0)
773 if (!(value is IComparable))
774 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
776 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
779 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
780 public static int BinarySearch (Array array, object value, IComparer comparer)
783 throw new ArgumentNullException ("array");
786 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
788 if (array.Length == 0)
791 if ((comparer == null) && (value != null) && !(value is IComparable))
792 throw new ArgumentException (Locale.GetText (
793 "comparer is null and value does not support IComparable."));
795 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
798 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
799 public static int BinarySearch (Array array, int index, int length, object value)
802 throw new ArgumentNullException ("array");
805 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
807 if (index < array.GetLowerBound (0))
808 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
809 "index is less than the lower bound of array."));
811 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
812 "Value has to be >= 0."));
813 // re-ordered to avoid possible integer overflow
814 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
815 throw new ArgumentException (Locale.GetText (
816 "index and length do not specify a valid range in array."));
818 if (array.Length == 0)
821 if ((value != null) && (!(value is IComparable)))
822 throw new ArgumentException (Locale.GetText (
823 "value does not support IComparable"));
825 return DoBinarySearch (array, index, length, value, null);
828 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
829 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
832 throw new ArgumentNullException ("array");
835 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
837 if (index < array.GetLowerBound (0))
838 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
839 "index is less than the lower bound of array."));
841 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
842 "Value has to be >= 0."));
843 // re-ordered to avoid possible integer overflow
844 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
845 throw new ArgumentException (Locale.GetText (
846 "index and length do not specify a valid range in array."));
848 if (array.Length == 0)
851 if ((comparer == null) && (value != null) && !(value is IComparable))
852 throw new ArgumentException (Locale.GetText (
853 "comparer is null and value does not support IComparable."));
855 return DoBinarySearch (array, index, length, value, comparer);
858 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
860 // cache this in case we need it
861 if (comparer == null)
862 comparer = Comparer.Default;
865 // Comment from Tum (tum@veridicus.com):
866 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
867 int iMax = index + length - 1;
870 while (iMin <= iMax) {
871 // Be careful with overflow
872 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
873 int iMid = iMin + ((iMax - iMin) / 2);
874 object elt = array.GetValueImpl (iMid);
876 iCmp = comparer.Compare (elt, value);
883 iMin = iMid + 1; // compensate for the rounding down
886 catch (Exception e) {
887 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
893 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
894 public static void Clear (Array array, int index, int length)
897 throw new ArgumentNullException ("array");
899 throw new IndexOutOfRangeException ("length < 0");
901 int low = array.GetLowerBound (0);
903 throw new IndexOutOfRangeException ("index < lower bound");
906 // re-ordered to avoid possible integer overflow
907 if (index > array.Length - length)
908 throw new IndexOutOfRangeException ("index + length > size");
910 ClearInternal (array, index, length);
913 [MethodImplAttribute (MethodImplOptions.InternalCall)]
914 static extern void ClearInternal (Array a, int index, int count);
916 [MethodImplAttribute (MethodImplOptions.InternalCall)]
917 public extern object Clone ();
919 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
920 public static void Copy (Array sourceArray, Array destinationArray, int length)
922 // need these checks here because we are going to use
923 // GetLowerBound() on source and dest.
924 if (sourceArray == null)
925 throw new ArgumentNullException ("sourceArray");
927 if (destinationArray == null)
928 throw new ArgumentNullException ("destinationArray");
930 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
931 destinationArray.GetLowerBound (0), length);
934 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
935 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
937 if (sourceArray == null)
938 throw new ArgumentNullException ("sourceArray");
940 if (destinationArray == null)
941 throw new ArgumentNullException ("destinationArray");
944 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
945 "Value has to be >= 0."));;
948 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
949 "Value has to be >= 0."));;
951 if (destinationIndex < 0)
952 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
953 "Value has to be >= 0."));;
955 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
958 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
959 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
961 // re-ordered to avoid possible integer overflow
962 if (source_pos > sourceArray.Length - length)
963 throw new ArgumentException ("length");
965 if (dest_pos > destinationArray.Length - length) {
966 string msg = "Destination array was not long enough. Check " +
967 "destIndex and length, and the array's lower bounds";
968 throw new ArgumentException (msg, string.Empty);
971 if (sourceArray.Rank != destinationArray.Rank)
972 throw new RankException (Locale.GetText ("Arrays must be of same size."));
974 Type src_type = sourceArray.GetType ().GetElementType ();
975 Type dst_type = destinationArray.GetType ().GetElementType ();
977 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
978 for (int i = 0; i < length; i++) {
979 Object srcval = sourceArray.GetValueImpl (source_pos + i);
982 destinationArray.SetValueImpl (srcval, dest_pos + i);
984 if (src_type.Equals (typeof (Object)))
985 throw new InvalidCastException ();
987 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
988 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
993 for (int i = length - 1; i >= 0; i--) {
994 Object srcval = sourceArray.GetValueImpl (source_pos + i);
997 destinationArray.SetValueImpl (srcval, dest_pos + i);
999 if (src_type.Equals (typeof (Object)))
1000 throw new InvalidCastException ();
1002 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
1003 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
1009 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1010 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
1011 long destinationIndex, long length)
1013 if (sourceArray == null)
1014 throw new ArgumentNullException ("sourceArray");
1016 if (destinationArray == null)
1017 throw new ArgumentNullException ("destinationArray");
1019 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
1020 throw new ArgumentOutOfRangeException ("sourceIndex",
1021 Locale.GetText ("Must be in the Int32 range."));
1023 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
1024 throw new ArgumentOutOfRangeException ("destinationIndex",
1025 Locale.GetText ("Must be in the Int32 range."));
1027 if (length < 0 || length > Int32.MaxValue)
1028 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1029 "Value must be >= 0 and <= Int32.MaxValue."));
1031 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
1034 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1035 public static void Copy (Array sourceArray, Array destinationArray, long length)
1037 if (length < 0 || length > Int32.MaxValue)
1038 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1039 "Value must be >= 0 and <= Int32.MaxValue."));
1041 Copy (sourceArray, destinationArray, (int) length);
1044 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1045 public static int IndexOf (Array array, object value)
1048 throw new ArgumentNullException ("array");
1050 return IndexOf (array, value, 0, array.Length);
1053 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1054 public static int IndexOf (Array array, object value, int startIndex)
1057 throw new ArgumentNullException ("array");
1059 return IndexOf (array, value, startIndex, array.Length - startIndex);
1062 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1063 public static int IndexOf (Array array, object value, int startIndex, int count)
1066 throw new ArgumentNullException ("array");
1069 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1071 // re-ordered to avoid possible integer overflow
1072 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
1073 throw new ArgumentOutOfRangeException ();
1075 int max = startIndex + count;
1076 for (int i = startIndex; i < max; i++) {
1077 if (Object.Equals (array.GetValueImpl (i), value))
1081 return array.GetLowerBound (0) - 1;
1084 public void Initialize()
1086 //FIXME: We would like to find a compiler that uses
1087 // this method. It looks like this method do nothing
1088 // in C# so no exception is trown by the moment.
1091 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1092 public static int LastIndexOf (Array array, object value)
1095 throw new ArgumentNullException ("array");
1097 if (array.Length == 0)
1098 return array.GetLowerBound (0) - 1;
1099 return LastIndexOf (array, value, array.Length - 1);
1102 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1103 public static int LastIndexOf (Array array, object value, int startIndex)
1106 throw new ArgumentNullException ("array");
1108 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1111 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1112 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1115 throw new ArgumentNullException ("array");
1118 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1120 int lb = array.GetLowerBound (0);
1121 // Empty arrays do not throw ArgumentOutOfRangeException
1122 if (array.Length == 0)
1125 if (count < 0 || startIndex < lb ||
1126 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1127 throw new ArgumentOutOfRangeException ();
1129 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1130 if (Object.Equals (array.GetValueImpl (i), value))
1137 /* delegate used to swap array elements */
1138 delegate void Swapper (int i, int j);
1140 static Swapper get_swapper (Array array)
1143 return new Swapper (array.int_swapper);
1144 if (array is double[])
1145 return new Swapper (array.double_swapper);
1146 if (array is object[]) {
1147 return new Swapper (array.obj_swapper);
1149 return new Swapper (array.slow_swapper);
1152 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1153 public static void Reverse (Array array)
1156 throw new ArgumentNullException ("array");
1158 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
1161 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1162 public static void Reverse (Array array, int index, int length)
1165 throw new ArgumentNullException ("array");
1168 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1170 if (index < array.GetLowerBound (0) || length < 0)
1171 throw new ArgumentOutOfRangeException ();
1173 // re-ordered to avoid possible integer overflow
1174 if (index > array.GetUpperBound (0) + 1 - length)
1175 throw new ArgumentException ();
1177 int end = index + length - 1;
1178 object[] oarray = array as object[];
1179 if (oarray != null) {
1180 while (index < end) {
1181 object tmp = oarray [index];
1182 oarray [index] = oarray [end];
1189 int[] iarray = array as int[];
1190 if (iarray != null) {
1191 while (index < end) {
1192 int tmp = iarray [index];
1193 iarray [index] = iarray [end];
1200 double[] darray = array as double[];
1201 if (darray != null) {
1202 while (index < end) {
1203 double tmp = darray [index];
1204 darray [index] = darray [end];
1212 Swapper swapper = get_swapper (array);
1213 while (index < end) {
1214 swapper (index, end);
1220 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1221 public static void Sort (Array array)
1223 Sort (array, (IComparer)null);
1226 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1227 public static void Sort (Array keys, Array items)
1229 Sort (keys, items, (IComparer)null);
1232 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1233 public static void Sort (Array array, IComparer comparer)
1236 throw new ArgumentNullException ("array");
1239 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1241 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1244 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1245 public static void Sort (Array array, int index, int length)
1247 Sort (array, index, length, (IComparer)null);
1250 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1251 public static void Sort (Array keys, Array items, IComparer comparer)
1253 if (items == null) {
1254 Sort (keys, comparer);
1259 throw new ArgumentNullException ("keys");
1261 if (keys.Rank > 1 || items.Rank > 1)
1262 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1264 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1267 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1268 public static void Sort (Array keys, Array items, int index, int length)
1270 Sort (keys, items, index, length, (IComparer)null);
1273 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1274 public static void Sort (Array array, int index, int length, IComparer comparer)
1277 throw new ArgumentNullException ("array");
1280 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1282 if (index < array.GetLowerBound (0))
1283 throw new ArgumentOutOfRangeException ("index");
1286 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1287 "Value has to be >= 0."));
1289 if (array.Length - (array.GetLowerBound (0) + index) < length)
1290 throw new ArgumentException ();
1292 SortImpl (array, null, index, length, comparer);
1295 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1296 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1298 if (items == null) {
1299 Sort (keys, index, length, comparer);
1304 throw new ArgumentNullException ("keys");
1306 if (keys.Rank > 1 || items.Rank > 1)
1307 throw new RankException ();
1309 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1310 throw new ArgumentException ();
1312 if (index < keys.GetLowerBound (0))
1313 throw new ArgumentOutOfRangeException ("index");
1316 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1317 "Value has to be >= 0."));
1319 if (items.Length - (index + items.GetLowerBound (0)) < length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1320 throw new ArgumentException ();
1322 SortImpl (keys, items, index, length, comparer);
1325 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1331 int high = index + length - 1;
1333 #if !BOOTSTRAP_BASIC
1334 if (comparer == null && items is object[]) {
1335 /* Its better to compare typecodes as casts treat long/ulong/long based enums the same */
1336 switch (Type.GetTypeCode (keys.GetType ().GetElementType ())) {
1337 case TypeCode.Int32:
1338 qsort (keys as Int32[], items as object[], low, high);
1340 case TypeCode.Int64:
1341 qsort (keys as Int64[], items as object[], low, high);
1344 qsort (keys as byte[], items as object[], low, high);
1347 qsort (keys as char[], items as object[], low, high);
1349 case TypeCode.DateTime:
1350 qsort (keys as DateTime[], items as object[], low, high);
1352 case TypeCode.Decimal:
1353 qsort (keys as decimal[], items as object[], low, high);
1355 case TypeCode.Double:
1356 qsort (keys as double[], items as object[], low, high);
1358 case TypeCode.Int16:
1359 qsort (keys as Int16[], items as object[], low, high);
1361 case TypeCode.SByte:
1362 qsort (keys as SByte[], items as object[], low, high);
1364 case TypeCode.Single:
1365 qsort (keys as Single[], items as object[], low, high);
1367 case TypeCode.UInt16:
1368 qsort (keys as UInt16[], items as object[], low, high);
1370 case TypeCode.UInt32:
1371 qsort (keys as UInt32[], items as object[], low, high);
1373 case TypeCode.UInt64:
1374 qsort (keys as UInt64[], items as object[], low, high);
1382 if (comparer == null)
1383 CheckComparerAvailable (keys, low, high);
1386 qsort (keys, items, low, high, comparer);
1387 } catch (Exception e) {
1388 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1392 /* note, these are instance methods */
1393 void int_swapper (int i, int j) {
1394 int[] array = this as int[];
1395 int val = array [i];
1396 array [i] = array [j];
1400 void obj_swapper (int i, int j) {
1401 object[] array = this as object[];
1402 object val = array [i];
1403 array [i] = array [j];
1407 void slow_swapper (int i, int j) {
1408 object val = GetValueImpl (i);
1409 SetValueImpl (GetValue (j), i);
1410 SetValueImpl (val, j);
1413 void double_swapper (int i, int j) {
1414 double[] array = this as double[];
1415 double val = array [i];
1416 array [i] = array [j];
1425 static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
1430 if (comparer != null) {
1431 if (comparer.Compare (v1, v0) < 0) {
1432 swap (keys, items, lo, hi);
1439 } else if (v0 != null) {
1440 cmp = v1 as IComparable;
1442 if (v1 == null || cmp.CompareTo (v0) < 0) {
1443 swap (keys, items, lo, hi);
1455 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1457 QSortStack[] stack = new QSortStack[32];
1458 const int QSORT_THRESHOLD = 7;
1459 int high, low, mid, i, k;
1464 // initialize our stack
1465 stack[0].high = high0;
1466 stack[0].low = low0;
1471 high = stack[sp].high;
1472 low = stack[sp].low;
1474 if ((low + QSORT_THRESHOLD) > high) {
1475 // switch to insertion sort
1476 for (i = low + 1; i <= high; i++) {
1477 for (k = i; k > low; k--) {
1478 lo = keys.GetValueImpl (k - 1);
1479 hi = keys.GetValueImpl (k);
1480 if (comparer != null) {
1481 if (comparer.Compare (hi, lo) >= 0)
1488 cmp = hi as IComparable;
1489 if (cmp.CompareTo (lo) >= 0)
1494 swap (keys, items, k - 1, k);
1501 // calculate the middle element
1502 mid = low + ((high - low) / 2);
1505 key = keys.GetValueImpl (mid);
1506 hi = keys.GetValueImpl (high);
1507 lo = keys.GetValueImpl (low);
1509 // once we re-order the low, mid, and high elements to be in
1510 // ascending order, we'll use mid as our pivot.
1511 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1512 if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
1513 QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
1515 cmp = key as IComparable;
1517 // since we've already guaranteed that lo <= mid and mid <= hi,
1518 // we can skip comparing them again.
1523 // Move the walls in
1524 if (comparer != null) {
1525 while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) >= 0)
1528 while (k >= i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
1530 } else if (cmp != null) {
1531 while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) >= 0)
1534 while (k >= i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
1537 // This has the effect of moving the null values to the front if comparer is null
1538 while (i < k && keys.GetValueImpl (i) == null)
1541 while (k >= i && keys.GetValueImpl (k) != null)
1548 swap (keys, items, i, k);
1550 // make sure we keep track of our pivot element
1561 // swap the pivot with the last element in the first partition
1562 swap (keys, items, mid, k);
1565 // push our partitions onto the stack, largest first
1566 // (to make sure we don't run out of stack space)
1567 if ((high - k) >= (k - low)) {
1568 if ((k + 1) < high) {
1569 stack[sp].high = high;
1570 stack[sp].low = k + 1;
1574 if ((k - 1) > low) {
1575 stack[sp].high = k - 1;
1576 stack[sp].low = low;
1580 if ((k - 1) > low) {
1581 stack[sp].high = k - 1;
1582 stack[sp].low = low;
1586 if ((k + 1) < high) {
1587 stack[sp].high = high;
1588 stack[sp].low = k + 1;
1595 private static void CheckComparerAvailable (Array keys, int low, int high)
1597 // move null keys to beginning of array,
1598 // ensure that non-null keys implement IComparable
1599 for (int i = 0; i < high; i++) {
1600 object obj = keys.GetValueImpl (i);
1603 if (!(obj is IComparable)) {
1604 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1605 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1610 private static void swap (Array keys, Array items, int i, int j)
1612 object tmp = keys.GetValueImpl (i);
1613 keys.SetValueImpl (keys.GetValueImpl (j), i);
1614 keys.SetValueImpl (tmp, j);
1616 if (items != null) {
1617 tmp = items.GetValueImpl (i);
1618 items.SetValueImpl (items.GetValueImpl (j), i);
1619 items.SetValueImpl (tmp, j);
1623 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1624 public static void Sort<T> (T [] array)
1626 Sort<T> (array, (IComparer<T>)null);
1629 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1630 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1632 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1635 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1636 public static void Sort<T> (T [] array, IComparer<T> comparer)
1639 throw new ArgumentNullException ("array");
1641 SortImpl<T> (array, 0, array.Length, comparer);
1644 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1645 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1647 if (items == null) {
1648 Sort<TKey> (keys, comparer);
1653 throw new ArgumentNullException ("keys");
1655 if (keys.Length != items.Length)
1656 throw new ArgumentException ("Length of keys and items does not match.");
1658 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1661 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1662 public static void Sort<T> (T [] array, int index, int length)
1664 Sort<T> (array, index, length, (IComparer<T>)null);
1667 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1668 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1670 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1673 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1674 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1677 throw new ArgumentNullException ("array");
1680 throw new ArgumentOutOfRangeException ("index");
1683 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1684 "Value has to be >= 0."));
1686 if (index + length > array.Length)
1687 throw new ArgumentException ();
1689 SortImpl<T, T> (array, null, index, length, comparer);
1692 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1693 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1695 if (items == null) {
1696 Sort<TKey> (keys, index, length, comparer);
1701 throw new ArgumentNullException ("keys");
1704 throw new ArgumentOutOfRangeException ("index");
1707 throw new ArgumentOutOfRangeException ("length");
1709 if (items.Length - index < length || keys.Length - index < length)
1710 throw new ArgumentException ();
1712 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1715 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1717 if (keys.Length <= 1)
1721 int high = index + length - 1;
1724 // Check for value types which can be sorted without Compare () method
1726 if (comparer == null) {
1727 #if !BOOTSTRAP_BASIC
1728 switch (Type.GetTypeCode (typeof (TKey))) {
1729 case TypeCode.Int32:
1730 qsort (keys as Int32[], items, low, high);
1732 case TypeCode.Int64:
1733 qsort (keys as Int64[], items, low, high);
1736 qsort (keys as byte[], items, low, high);
1739 qsort (keys as char[], items, low, high);
1741 case TypeCode.DateTime:
1742 qsort (keys as DateTime[], items, low, high);
1744 case TypeCode.Decimal:
1745 qsort (keys as decimal[], items, low, high);
1747 case TypeCode.Double:
1748 qsort (keys as double[], items, low, high);
1750 case TypeCode.Int16:
1751 qsort (keys as Int16[], items, low, high);
1753 case TypeCode.SByte:
1754 qsort (keys as SByte[], items, low, high);
1756 case TypeCode.Single:
1757 qsort (keys as Single[], items, low, high);
1759 case TypeCode.UInt16:
1760 qsort (keys as UInt16[], items, low, high);
1762 case TypeCode.UInt32:
1763 qsort (keys as UInt32[], items, low, high);
1765 case TypeCode.UInt64:
1766 qsort (keys as UInt64[], items, low, high);
1770 // Using Comparer<TKey> adds a small overload, but with value types it
1771 // helps us to not box them.
1772 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1773 typeof (TKey).IsValueType)
1774 comparer = Comparer<TKey>.Default;
1777 if (comparer == null)
1778 CheckComparerAvailable<TKey> (keys, low, high);
1781 qsort (keys, items, low, high, comparer);
1782 //} catch (Exception e) {
1783 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1787 // Specialized version for items==null
1788 private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
1790 if (keys.Length <= 1)
1794 int high = index + length - 1;
1797 // Check for value types which can be sorted without Compare () method
1799 if (comparer == null) {
1800 #if !BOOTSTRAP_BASIC
1801 switch (Type.GetTypeCode (typeof (TKey))) {
1802 case TypeCode.Int32:
1803 qsort (keys as Int32[], low, high);
1805 case TypeCode.Int64:
1806 qsort (keys as Int64[], low, high);
1809 qsort (keys as byte[], low, high);
1812 qsort (keys as char[], low, high);
1814 case TypeCode.DateTime:
1815 qsort (keys as DateTime[], low, high);
1817 case TypeCode.Decimal:
1818 qsort (keys as decimal[], low, high);
1820 case TypeCode.Double:
1821 qsort (keys as double[], low, high);
1823 case TypeCode.Int16:
1824 qsort (keys as Int16[], low, high);
1826 case TypeCode.SByte:
1827 qsort (keys as SByte[], low, high);
1829 case TypeCode.Single:
1830 qsort (keys as Single[], low, high);
1832 case TypeCode.UInt16:
1833 qsort (keys as UInt16[], low, high);
1835 case TypeCode.UInt32:
1836 qsort (keys as UInt32[], low, high);
1838 case TypeCode.UInt64:
1839 qsort (keys as UInt64[], low, high);
1843 // Using Comparer<TKey> adds a small overload, but with value types it
1844 // helps us to not box them.
1845 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1846 typeof (TKey).IsValueType)
1847 comparer = Comparer<TKey>.Default;
1850 if (comparer == null)
1851 CheckComparerAvailable<TKey> (keys, low, high);
1854 qsort<TKey> (keys, low, high, comparer);
1855 //} catch (Exception e) {
1856 //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1860 public static void Sort<T> (T [] array, Comparison<T> comparison)
1863 throw new ArgumentNullException ("array");
1865 if (comparison == null)
1866 throw new ArgumentNullException ("comparison");
1868 SortImpl<T> (array, array.Length, comparison);
1871 // used by List<T>.Sort (Comparison <T>)
1872 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1879 int high0 = length - 1;
1880 qsort<T> (array, low0, high0, comparison);
1881 } catch (InvalidOperationException) {
1883 } catch (Exception e) {
1884 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1888 static bool QSortArrange<T, U> (T [] keys, U [] items, int lo, int hi) where T : IComparable<T>
1890 if (keys[lo] != null) {
1891 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1892 swap (keys, items, lo, hi);
1900 // Specialized version for items==null
1901 static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
1903 if (keys[lo] != null) {
1904 if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
1905 swap (keys, lo, hi);
1913 private static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
1915 QSortStack[] stack = new QSortStack[32];
1916 const int QSORT_THRESHOLD = 7;
1917 int high, low, mid, i, k;
1921 // initialize our stack
1922 stack[0].high = high0;
1923 stack[0].low = low0;
1928 high = stack[sp].high;
1929 low = stack[sp].low;
1931 if ((low + QSORT_THRESHOLD) > high) {
1932 // switch to insertion sort
1933 for (i = low + 1; i <= high; i++) {
1934 for (k = i; k > low; k--) {
1935 // if keys[k] >= keys[k-1], break
1936 if (keys[k-1] == null)
1939 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
1942 swap (keys, items, k - 1, k);
1949 // calculate the middle element
1950 mid = low + ((high - low) / 2);
1952 // once we re-order the lo, mid, and hi elements to be in
1953 // ascending order, we'll use mid as our pivot.
1954 QSortArrange<T, U> (keys, items, low, mid);
1955 if (QSortArrange<T, U> (keys, items, mid, high))
1956 QSortArrange<T, U> (keys, items, low, mid);
1960 // since we've already guaranteed that lo <= mid and mid <= hi,
1961 // we can skip comparing them again
1967 // find the first element with a value > pivot value
1968 while (i < k && key.CompareTo (keys[i]) >= 0)
1971 // find the last element with a value <= pivot value
1972 while (k >= i && key.CompareTo (keys[k]) < 0)
1975 while (i < k && keys[i] == null)
1978 while (k >= i && keys[k] != null)
1985 swap (keys, items, i, k);
1987 // make sure we keep track of our pivot element
1998 // swap the pivot with the last element in the first partition
1999 swap (keys, items, mid, k);
2002 // push our partitions onto the stack, largest first
2003 // (to make sure we don't run out of stack space)
2004 if ((high - k) >= (k - low)) {
2005 if ((k + 1) < high) {
2006 stack[sp].high = high;
2007 stack[sp].low = k + 1;
2011 if ((k - 1) > low) {
2012 stack[sp].high = k - 1;
2013 stack[sp].low = low;
2017 if ((k - 1) > low) {
2018 stack[sp].high = k - 1;
2019 stack[sp].low = low;
2023 if ((k + 1) < high) {
2024 stack[sp].high = high;
2025 stack[sp].low = k + 1;
2032 // Specialized version for items==null
2033 private static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
2035 QSortStack[] stack = new QSortStack[32];
2036 const int QSORT_THRESHOLD = 7;
2037 int high, low, mid, i, k;
2041 // initialize our stack
2042 stack[0].high = high0;
2043 stack[0].low = low0;
2048 high = stack[sp].high;
2049 low = stack[sp].low;
2051 if ((low + QSORT_THRESHOLD) > high) {
2052 // switch to insertion sort
2053 for (i = low + 1; i <= high; i++) {
2054 for (k = i; k > low; k--) {
2055 // if keys[k] >= keys[k-1], break
2056 if (keys[k-1] == null)
2059 if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
2062 swap (keys, k - 1, k);
2069 // calculate the middle element
2070 mid = low + ((high - low) / 2);
2072 // once we re-order the lo, mid, and hi elements to be in
2073 // ascending order, we'll use mid as our pivot.
2074 QSortArrange<T> (keys, low, mid);
2075 if (QSortArrange<T> (keys, mid, high))
2076 QSortArrange<T> (keys, low, mid);
2080 // since we've already guaranteed that lo <= mid and mid <= hi,
2081 // we can skip comparing them again
2087 // find the first element with a value > pivot value
2088 while (i < k && key.CompareTo (keys[i]) >= 0)
2091 // find the last element with a value <= pivot value
2092 while (k >= i && key.CompareTo (keys[k]) < 0)
2095 while (i < k && keys[i] == null)
2098 while (k >= i && keys[k] != null)
2107 // make sure we keep track of our pivot element
2118 // swap the pivot with the last element in the first partition
2119 swap (keys, mid, k);
2122 // push our partitions onto the stack, largest first
2123 // (to make sure we don't run out of stack space)
2124 if ((high - k) >= (k - low)) {
2125 if ((k + 1) < high) {
2126 stack[sp].high = high;
2127 stack[sp].low = k + 1;
2131 if ((k - 1) > low) {
2132 stack[sp].high = k - 1;
2133 stack[sp].low = low;
2137 if ((k - 1) > low) {
2138 stack[sp].high = k - 1;
2139 stack[sp].low = low;
2143 if ((k + 1) < high) {
2144 stack[sp].high = high;
2145 stack[sp].low = k + 1;
2152 static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
2154 IComparable<K> gcmp;
2157 if (comparer != null) {
2158 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2159 swap<K, V> (keys, items, lo, hi);
2162 } else if (keys[lo] != null) {
2163 if (keys[hi] == null) {
2164 swap<K, V> (keys, items, lo, hi);
2168 gcmp = keys[hi] as IComparable<K>;
2170 if (gcmp.CompareTo (keys[lo]) < 0) {
2171 swap<K, V> (keys, items, lo, hi);
2178 cmp = keys[hi] as IComparable;
2180 if (cmp.CompareTo (keys[lo]) < 0) {
2181 swap<K, V> (keys, items, lo, hi);
2192 // Specialized version for items==null
2193 static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
2195 IComparable<K> gcmp;
2198 if (comparer != null) {
2199 if (comparer.Compare (keys[hi], keys[lo]) < 0) {
2200 swap<K> (keys, lo, hi);
2203 } else if (keys[lo] != null) {
2204 if (keys[hi] == null) {
2205 swap<K> (keys, lo, hi);
2209 gcmp = keys[hi] as IComparable<K>;
2211 if (gcmp.CompareTo (keys[lo]) < 0) {
2212 swap<K> (keys, lo, hi);
2219 cmp = keys[hi] as IComparable;
2221 if (cmp.CompareTo (keys[lo]) < 0) {
2222 swap<K> (keys, lo, hi);
2233 private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
2235 QSortStack[] stack = new QSortStack[32];
2236 const int QSORT_THRESHOLD = 7;
2237 int high, low, mid, i, k;
2238 IComparable<K> gcmp;
2243 // initialize our stack
2244 stack[0].high = high0;
2245 stack[0].low = low0;
2250 high = stack[sp].high;
2251 low = stack[sp].low;
2253 if ((low + QSORT_THRESHOLD) > high) {
2254 // switch to insertion sort
2255 for (i = low + 1; i <= high; i++) {
2256 for (k = i; k > low; k--) {
2257 // if keys[k] >= keys[k-1], break
2258 if (comparer != null) {
2259 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2262 if (keys[k-1] == null)
2265 if (keys[k] != null) {
2266 gcmp = keys[k] as IComparable<K>;
2267 cmp = keys[k] as IComparable;
2269 if (gcmp.CompareTo (keys[k-1]) >= 0)
2272 if (cmp.CompareTo (keys[k-1]) >= 0)
2278 swap<K, V> (keys, items, k - 1, k);
2285 // calculate the middle element
2286 mid = low + ((high - low) / 2);
2288 // once we re-order the low, mid, and high elements to be in
2289 // ascending order, we'll use mid as our pivot.
2290 QSortArrange<K, V> (keys, items, low, mid, comparer);
2291 if (QSortArrange<K, V> (keys, items, mid, high, comparer))
2292 QSortArrange<K, V> (keys, items, low, mid, comparer);
2295 gcmp = key as IComparable<K>;
2296 cmp = key as IComparable;
2298 // since we've already guaranteed that lo <= mid and mid <= hi,
2299 // we can skip comparing them again.
2304 // Move the walls in
2305 if (comparer != null) {
2306 while (i < k && comparer.Compare (key, keys[i]) >= 0)
2309 while (k >= i && comparer.Compare (key, keys[k]) < 0)
2313 while (i < k && gcmp.CompareTo (keys[i]) >= 0)
2316 while (k >= i && gcmp.CompareTo (keys[k]) < 0)
2318 } else if (cmp != null) {
2319 while (i < k && cmp.CompareTo (keys[i]) >= 0)
2322 while (k >= i && cmp.CompareTo (keys[k]) < 0)
2325 while (i < k && keys[i] == null)
2328 while (k >= i && keys[k] != null)
2336 swap<K, V> (keys, items, i, k);
2338 // make sure we keep track of our pivot element
2349 // swap the pivot with the last element in the first partition
2350 swap<K, V> (keys, items, mid, k);
2353 // push our partitions onto the stack, largest first
2354 // (to make sure we don't run out of stack space)
2355 if ((high - k) >= (k - low)) {
2356 if ((k + 1) < high) {
2357 stack[sp].high = high;
2358 stack[sp].low = k + 1;
2362 if ((k - 1) > low) {
2363 stack[sp].high = k - 1;
2364 stack[sp].low = low;
2368 if ((k - 1) > low) {
2369 stack[sp].high = k - 1;
2370 stack[sp].low = low;
2374 if ((k + 1) < high) {
2375 stack[sp].high = high;
2376 stack[sp].low = k + 1;
2383 // Specialized version for items==null
2384 private static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
2386 QSortStack[] stack = new QSortStack[32];
2387 const int QSORT_THRESHOLD = 7;
2388 int high, low, mid, i, k;
2389 IComparable<K> gcmp;
2394 // initialize our stack
2395 stack[0].high = high0;
2396 stack[0].low = low0;
2401 high = stack[sp].high;
2402 low = stack[sp].low;
2404 if ((low + QSORT_THRESHOLD) > high) {
2405 // switch to insertion sort
2406 for (i = low + 1; i <= high; i++) {
2407 for (k = i; k > low; k--) {
2408 // if keys[k] >= keys[k-1], break
2409 if (comparer != null) {
2410 if (comparer.Compare (keys[k], keys[k-1]) >= 0)
2413 if (keys[k-1] == null)
2416 if (keys[k] != null) {
2417 gcmp = keys[k] as IComparable<K>;
2418 cmp = keys[k] as IComparable;
2420 if (gcmp.CompareTo (keys[k-1]) >= 0)
2423 if (cmp.CompareTo (keys[k-1]) >= 0)
2429 swap<K> (keys, k - 1, k);
2436 // calculate the middle element
2437 mid = low + ((high - low) / 2);
2439 // once we re-order the low, mid, and high elements to be in
2440 // ascending order, we'll use mid as our pivot.
2441 QSortArrange<K> (keys, low, mid, comparer);
2442 if (QSortArrange<K> (keys, mid, high, comparer))
2443 QSortArrange<K> (keys, low, mid, comparer);
2446 gcmp = key as IComparable<K>;
2447 cmp = key as IComparable;
2449 // since we've already guaranteed that lo <= mid and mid <= hi,
2450 // we can skip comparing them again.
2455 // Move the walls in
2456 if (comparer != null) {
2457 while (i < k && comparer.Compare (key, keys[i]) >= 0)
2460 while (k >= i && comparer.Compare (key, keys[k]) < 0)
2464 while (i < k && gcmp.CompareTo (keys[i]) >= 0)
2467 while (k >= i && gcmp.CompareTo (keys[k]) < 0)
2469 } else if (cmp != null) {
2470 while (i < k && cmp.CompareTo (keys[i]) >= 0)
2473 while (k >= i && cmp.CompareTo (keys[k]) < 0)
2476 while (i < k && keys[i] == null)
2479 while (k >= i && keys[k] != null)
2487 swap<K> (keys, i, k);
2489 // make sure we keep track of our pivot element
2500 // swap the pivot with the last element in the first partition
2501 swap<K> (keys, mid, k);
2504 // push our partitions onto the stack, largest first
2505 // (to make sure we don't run out of stack space)
2506 if ((high - k) >= (k - low)) {
2507 if ((k + 1) < high) {
2508 stack[sp].high = high;
2509 stack[sp].low = k + 1;
2513 if ((k - 1) > low) {
2514 stack[sp].high = k - 1;
2515 stack[sp].low = low;
2519 if ((k - 1) > low) {
2520 stack[sp].high = k - 1;
2521 stack[sp].low = low;
2525 if ((k + 1) < high) {
2526 stack[sp].high = high;
2527 stack[sp].low = k + 1;
2534 static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
2536 if (array[lo] != null) {
2537 if (array[hi] == null || compare (array[hi], array[lo]) < 0) {
2538 swap<T> (array, lo, hi);
2546 private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
2548 QSortStack[] stack = new QSortStack[32];
2549 const int QSORT_THRESHOLD = 7;
2550 int high, low, mid, i, k;
2554 // initialize our stack
2555 stack[0].high = high0;
2556 stack[0].low = low0;
2561 high = stack[sp].high;
2562 low = stack[sp].low;
2564 if ((low + QSORT_THRESHOLD) > high) {
2565 // switch to insertion sort
2566 for (i = low + 1; i <= high; i++) {
2567 for (k = i; k > low; k--) {
2568 // if keys[k] >= keys[k-1], break
2569 if (array[k-1] == null)
2572 if (array[k] != null && compare (array[k], array[k-1]) >= 0)
2575 swap<T> (array, k - 1, k);
2582 // calculate the middle element
2583 mid = low + ((high - low) / 2);
2585 // once we re-order the lo, mid, and hi elements to be in
2586 // ascending order, we'll use mid as our pivot.
2587 QSortArrange<T> (array, low, mid, compare);
2588 if (QSortArrange<T> (array, mid, high, compare))
2589 QSortArrange<T> (array, low, mid, compare);
2593 // since we've already guaranteed that lo <= mid and mid <= hi,
2594 // we can skip comparing them again
2599 // Move the walls in
2601 // find the first element with a value > pivot value
2602 while (i < k && compare (key, array[i]) >= 0)
2605 // find the last element with a value <= pivot value
2606 while (k >= i && compare (key, array[k]) < 0)
2609 while (i < k && array[i] == null)
2612 while (k >= i && array[k] != null)
2619 swap<T> (array, i, k);
2621 // make sure we keep track of our pivot element
2632 // swap the pivot with the last element in the first partition
2633 swap<T> (array, mid, k);
2636 // push our partitions onto the stack, largest first
2637 // (to make sure we don't run out of stack space)
2638 if ((high - k) >= (k - low)) {
2639 if ((k + 1) < high) {
2640 stack[sp].high = high;
2641 stack[sp].low = k + 1;
2645 if ((k - 1) > low) {
2646 stack[sp].high = k - 1;
2647 stack[sp].low = low;
2651 if ((k - 1) > low) {
2652 stack[sp].high = k - 1;
2653 stack[sp].low = low;
2657 if ((k + 1) < high) {
2658 stack[sp].high = high;
2659 stack[sp].low = k + 1;
2666 private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
2668 // move null keys to beginning of array,
2669 // ensure that non-null keys implement IComparable
2670 for (int i = low; i < high; i++) {
2673 if (!(key is IComparable<K>) && !(key is IComparable)) {
2674 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
2675 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
2681 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
2686 keys [i] = keys [j];
2689 if (items != null) {
2692 items [i] = items [j];
2697 private static void swap<T> (T [] array, int i, int j)
2700 array [i] = array [j];
2704 public void CopyTo (Array array, int index)
2707 throw new ArgumentNullException ("array");
2709 // The order of these exception checks may look strange,
2710 // but that's how the microsoft runtime does it.
2712 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2713 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
2714 throw new ArgumentException ("Destination array was not long " +
2715 "enough. Check destIndex and length, and the array's " +
2718 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
2720 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2721 "Value has to be >= 0."));
2723 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
2726 [ComVisible (false)]
2727 public void CopyTo (Array array, long index)
2729 if (index < 0 || index > Int32.MaxValue)
2730 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2731 "Value must be >= 0 and <= Int32.MaxValue."));
2733 CopyTo (array, (int) index);
2736 internal class SimpleEnumerator : IEnumerator, ICloneable
2742 public SimpleEnumerator (Array arrayToEnumerate)
2744 this.enumeratee = arrayToEnumerate;
2745 this.currentpos = -1;
2746 this.length = arrayToEnumerate.Length;
2749 public object Current {
2751 // Exception messages based on MS implementation
2752 if (currentpos < 0 )
2753 throw new InvalidOperationException (Locale.GetText (
2754 "Enumeration has not started."));
2755 if (currentpos >= length)
2756 throw new InvalidOperationException (Locale.GetText (
2757 "Enumeration has already ended"));
2758 // Current should not increase the position. So no ++ over here.
2759 return enumeratee.GetValueImpl (currentpos);
2763 public bool MoveNext()
2765 //The docs say Current should throw an exception if last
2766 //call to MoveNext returned false. This means currentpos
2767 //should be set to length when returning false.
2768 if (currentpos < length)
2770 if(currentpos < length)
2781 public object Clone ()
2783 return MemberwiseClone ();
2787 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2788 public static void Resize<T> (ref T [] array, int newSize)
2791 throw new ArgumentOutOfRangeException ();
2793 if (array == null) {
2794 array = new T [newSize];
2798 int length = array.Length;
2799 if (length == newSize)
2802 T [] a = new T [newSize];
2804 FastCopy (array, 0, a, 0, Math.Min (newSize, length));
2808 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
2811 throw new ArgumentNullException ("array");
2813 throw new ArgumentNullException ("match");
2815 foreach (T t in array)
2822 public static void ForEach<T> (T [] array, Action <T> action)
2825 throw new ArgumentNullException ("array");
2827 throw new ArgumentNullException ("action");
2829 foreach (T t in array)
2833 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
2836 throw new ArgumentNullException ("array");
2837 if (converter == null)
2838 throw new ArgumentNullException ("converter");
2840 TOutput [] output = new TOutput [array.Length];
2841 for (int i = 0; i < array.Length; i ++)
2842 output [i] = converter (array [i]);
2847 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
2850 throw new ArgumentNullException ("array");
2852 return FindLastIndex<T> (array, 0, array.Length, match);
2855 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
2858 throw new ArgumentNullException ();
2860 return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
2863 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2866 throw new ArgumentNullException ("array");
2868 throw new ArgumentNullException ("match");
2870 if (startIndex > array.Length || startIndex + count > array.Length)
2871 throw new ArgumentOutOfRangeException ();
2873 for (int i = startIndex + count - 1; i >= startIndex; i--)
2874 if (match (array [i]))
2880 public static int FindIndex<T> (T [] array, Predicate<T> match)
2883 throw new ArgumentNullException ("array");
2885 return FindIndex<T> (array, 0, array.Length, match);
2888 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
2891 throw new ArgumentNullException ("array");
2893 return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
2896 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
2899 throw new ArgumentNullException ("array");
2902 throw new ArgumentNullException ("match");
2904 if (startIndex > array.Length || startIndex + count > array.Length)
2905 throw new ArgumentOutOfRangeException ();
2907 for (int i = startIndex; i < startIndex + count; i ++)
2908 if (match (array [i]))
2914 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2915 public static int BinarySearch<T> (T [] array, T value)
2918 throw new ArgumentNullException ("array");
2920 return BinarySearch<T> (array, 0, array.Length, value, null);
2923 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2924 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
2927 throw new ArgumentNullException ("array");
2929 return BinarySearch<T> (array, 0, array.Length, value, comparer);
2932 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2933 public static int BinarySearch<T> (T [] array, int index, int length, T value)
2935 return BinarySearch<T> (array, index, length, value, null);
2938 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2939 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2942 throw new ArgumentNullException ("array");
2944 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2945 "index is less than the lower bound of array."));
2947 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2948 "Value has to be >= 0."));
2949 // re-ordered to avoid possible integer overflow
2950 if (index > array.Length - length)
2951 throw new ArgumentException (Locale.GetText (
2952 "index and length do not specify a valid range in array."));
2953 if (comparer == null)
2954 comparer = Comparer <T>.Default;
2957 int iMax = index + length - 1;
2960 while (iMin <= iMax) {
2961 // Be careful with overflows
2962 int iMid = iMin + ((iMax - iMin) / 2);
2963 iCmp = comparer.Compare (array [iMid], value);
2971 iMin = iMid + 1; // compensate for the rounding down
2973 } catch (Exception e) {
2974 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
2980 public static int IndexOf<T> (T [] array, T value)
2983 throw new ArgumentNullException ("array");
2985 return IndexOf<T> (array, value, 0, array.Length);
2988 public static int IndexOf<T> (T [] array, T value, int startIndex)
2991 throw new ArgumentNullException ("array");
2993 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
2996 public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
2999 throw new ArgumentNullException ("array");
3001 // re-ordered to avoid possible integer overflow
3002 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
3003 throw new ArgumentOutOfRangeException ();
3005 int max = startIndex + count;
3006 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3007 for (int i = startIndex; i < max; i++) {
3008 if (equalityComparer.Equals (array [i], value))
3015 public static int LastIndexOf<T> (T [] array, T value)
3018 throw new ArgumentNullException ("array");
3020 if (array.Length == 0)
3022 return LastIndexOf<T> (array, value, array.Length - 1);
3025 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
3028 throw new ArgumentNullException ("array");
3030 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
3033 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
3036 throw new ArgumentNullException ("array");
3038 if (count < 0 || startIndex < array.GetLowerBound (0) ||
3039 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
3040 throw new ArgumentOutOfRangeException ();
3042 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
3043 for (int i = startIndex; i >= startIndex - count + 1; i--) {
3044 if (equalityComparer.Equals (array [i], value))
3051 public static T [] FindAll<T> (T [] array, Predicate <T> match)
3054 throw new ArgumentNullException ("array");
3057 throw new ArgumentNullException ("match");
3060 T [] d = new T [array.Length];
3061 foreach (T t in array)
3065 Resize <T> (ref d, pos);
3069 public static bool Exists<T> (T [] array, Predicate <T> match)
3072 throw new ArgumentNullException ("array");
3075 throw new ArgumentNullException ("match");
3077 foreach (T t in array)
3083 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
3086 throw new ArgumentNullException ("array");
3088 return new ReadOnlyCollection<T> (array);
3091 public static T Find<T> (T [] array, Predicate<T> match)
3094 throw new ArgumentNullException ("array");
3097 throw new ArgumentNullException ("match");
3099 foreach (T t in array)
3106 public static T FindLast<T> (T [] array, Predicate <T> match)
3109 throw new ArgumentNullException ("array");
3112 throw new ArgumentNullException ("match");
3114 for (int i = array.Length - 1; i >= 0; i--)
3115 if (match (array [i]))
3121 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
3123 // The constrained copy should guarantee that if there is an exception thrown
3124 // during the copy, the destination array remains unchanged.
3125 // This is related to System.Runtime.Reliability.CER
3126 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
3128 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);