using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.ConstrainedExecution;
+#if !FULL_AOT_RUNTIME
using System.Reflection.Emit;
+#endif
namespace System
{
[ComVisible (true)]
// FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
public abstract class Array : ICloneable, ICollection, IList, IEnumerable
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
, IStructuralComparable, IStructuralEquatable
#endif
{
T value;
GetGenericValueImpl (i, out value);
if (item == null){
- if (value == null)
+ if (value == null) {
return true;
+ }
continue;
}
-
- if (item.Equals (value))
+
+ if (item.Equals (value)) {
return true;
+ }
}
return false;
Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
}
+#if NET_4_5
+ internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
+ {
+ if (unchecked ((uint) index) >= unchecked ((uint) Length))
+ throw new ArgumentOutOfRangeException ("index");
+
+ T value;
+ GetGenericValueImpl (index, out value);
+ return value;
+ }
+
+ internal int InternalArray__IReadOnlyCollection_get_Count ()
+ {
+ return Length;
+ }
+#endif
+
internal void InternalArray__Insert<T> (int index, T item)
{
throw new NotSupportedException ("Collection is of a fixed size");
return new SimpleEnumerator (this);
}
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
int IStructuralComparable.CompareTo (object other, IComparer comparer)
{
if (other == null)
int hash = 0;
for (int i = 0; i < Length; i++)
- hash = ((hash << 7) + hash) ^ GetValue (i).GetHashCode ();
+ hash = ((hash << 7) + hash) ^ comparer.GetHashCode (GetValueImpl (i));
return hash;
}
#endif
throw new NotSupportedException ("Array type can not be void");
if (elementType.ContainsGenericParameters)
throw new NotSupportedException ("Array type can not be an open generic type");
+#if !FULL_AOT_RUNTIME
if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
+#endif
return CreateInstanceImpl (elementType, lengths, bounds);
}
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
public static int BinarySearch (Array array, object value)
{
- if (array == null)
- throw new ArgumentNullException ("array");
-
- if (value == null)
- return -1;
-
- if (array.Rank > 1)
- throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
-
- if (array.Length == 0)
- return -1;
-
- if (!(value is IComparable))
- throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
-
- return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
+ return BinarySearch (array, value, null);
}
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
if (array.Length == 0)
return -1;
- if ((comparer == null) && (value != null) && !(value is IComparable))
- throw new ArgumentException (Locale.GetText (
- "comparer is null and value does not support IComparable."));
-
return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
}
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
public static int BinarySearch (Array array, int index, int length, object value)
{
- if (array == null)
- throw new ArgumentNullException ("array");
-
- if (array.Rank > 1)
- throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
-
- if (index < array.GetLowerBound (0))
- throw new ArgumentOutOfRangeException ("index", Locale.GetText (
- "index is less than the lower bound of array."));
- if (length < 0)
- throw new ArgumentOutOfRangeException ("length", Locale.GetText (
- "Value has to be >= 0."));
- // re-ordered to avoid possible integer overflow
- if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
- throw new ArgumentException (Locale.GetText (
- "index and length do not specify a valid range in array."));
-
- if (array.Length == 0)
- return -1;
-
- if ((value != null) && (!(value is IComparable)))
- throw new ArgumentException (Locale.GetText (
- "value does not support IComparable"));
-
- return DoBinarySearch (array, index, length, value, null);
+ return BinarySearch (array, index, length, value, null);
}
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
if (array.Length == 0)
return -1;
- if ((comparer == null) && (value != null) && !(value is IComparable))
- throw new ArgumentException (Locale.GetText (
- "comparer is null and value does not support IComparable."));
-
return DoBinarySearch (array, index, length, value, comparer);
}
try {
destinationArray.SetValueImpl (srcval, dest_pos + i);
+ } catch (ArgumentException) {
+ throw CreateArrayTypeMismatchException ();
} catch {
- if (src_type.Equals (typeof (Object)))
- throw new InvalidCastException ();
- else
- throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
- "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
+ if (CanAssignArrayElement (src_type, dst_type))
+ throw;
+
+ throw CreateArrayTypeMismatchException ();
}
}
}
try {
destinationArray.SetValueImpl (srcval, dest_pos + i);
+ } catch (ArgumentException) {
+ throw CreateArrayTypeMismatchException ();
} catch {
- if (src_type.Equals (typeof (Object)))
- throw new InvalidCastException ();
- else
- throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
- "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
+ if (CanAssignArrayElement (src_type, dst_type))
+ throw;
+
+ throw CreateArrayTypeMismatchException ();
}
}
}
}
+ static Exception CreateArrayTypeMismatchException ()
+ {
+ return new ArrayTypeMismatchException ();
+ }
+
+ static bool CanAssignArrayElement (Type source, Type target)
+ {
+ if (source.IsValueType)
+ return source.IsAssignableFrom (target);
+
+ if (source.IsInterface)
+ return !target.IsValueType;
+
+ if (target.IsInterface)
+ return !source.IsValueType;
+
+ return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
+ }
+
[ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
long destinationIndex, long length)
return lb - 1;
}
- /* delegate used to swap array elements */
- delegate void Swapper (int i, int j);
-
- static Swapper get_swapper (Array array)
- {
- if (array is int[])
- return new Swapper (array.int_swapper);
- if (array is double[])
- return new Swapper (array.double_swapper);
- if (array is object[]) {
- return new Swapper (array.obj_swapper);
- }
- return new Swapper (array.slow_swapper);
- }
-
[ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
public static void Reverse (Array array)
{
if (array == null)
throw new ArgumentNullException ("array");
- Reverse (array, array.GetLowerBound (0), array.GetLength (0));
+ Reverse (array, array.GetLowerBound (0), array.Length);
}
[ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
throw new ArgumentException ();
int end = index + length - 1;
- object[] oarray = array as object[];
- if (oarray != null) {
+ var et = array.GetType ().GetElementType ();
+ switch (Type.GetTypeCode (et)) {
+ case TypeCode.Boolean:
while (index < end) {
- object tmp = oarray [index];
- oarray [index] = oarray [end];
- oarray [end] = tmp;
+ bool a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
++index;
--end;
}
return;
- }
- int[] iarray = array as int[];
- if (iarray != null) {
+
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ while (index < end) {
+ byte a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
+ ++index;
+ --end;
+ }
+ return;
+
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Char:
while (index < end) {
- int tmp = iarray [index];
- iarray [index] = iarray [end];
- iarray [end] = tmp;
+ short a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
++index;
--end;
}
return;
- }
- double[] darray = array as double[];
- if (darray != null) {
+
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ case TypeCode.Single:
while (index < end) {
- double tmp = darray [index];
- darray [index] = darray [end];
- darray [end] = tmp;
+ int a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
++index;
--end;
}
return;
- }
- // fallback
- Swapper swapper = get_swapper (array);
- while (index < end) {
- swapper (index, end);
- ++index;
- --end;
+
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ case TypeCode.Double:
+ while (index < end) {
+ long a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
+ ++index;
+ --end;
+ }
+ return;
+
+ case TypeCode.Decimal:
+ while (index < end) {
+ decimal a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
+ ++index;
+ --end;
+ }
+ return;
+
+ case TypeCode.String:
+ while (index < end) {
+ object a, b;
+
+ array.GetGenericValueImpl (index, out a);
+ array.GetGenericValueImpl (end, out b);
+ array.SetGenericValueImpl (index, ref b);
+ array.SetGenericValueImpl (end, ref a);
+ ++index;
+ --end;
+ }
+ return;
+ default:
+ if (array is object[])
+ goto case TypeCode.String;
+
+ // Very slow fallback
+ while (index < end) {
+ object val = array.GetValueImpl (index);
+ array.SetValueImpl (array.GetValueImpl (end), index);
+ array.SetValueImpl (val, end);
+ ++index;
+ --end;
+ }
+
+ return;
}
}
throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
}
}
-
- /* note, these are instance methods */
- void int_swapper (int i, int j) {
- int[] array = this as int[];
- int val = array [i];
- array [i] = array [j];
- array [j] = val;
- }
-
- void obj_swapper (int i, int j) {
- object[] array = this as object[];
- object val = array [i];
- array [i] = array [j];
- array [j] = val;
- }
-
- void slow_swapper (int i, int j) {
- object val = GetValueImpl (i);
- SetValueImpl (GetValue (j), i);
- SetValueImpl (val, j);
- }
-
- void double_swapper (int i, int j) {
- double[] array = this as double[];
- double val = array [i];
- array [i] = array [j];
- array [j] = val;
+
+ struct QSortStack {
+ public int high;
+ public int low;
}
static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
return false;
}
- private static void qsort (Array keys, Array items, int low, int high, IComparer comparer)
+ private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
{
- //const int QSORT_THRESHOLD = 7;
+ QSortStack[] stack = new QSortStack[32];
+ const int QSORT_THRESHOLD = 7;
+ int high, low, mid, i, k;
object key, hi, lo;
IComparable cmp;
- int mid, i, k;
-
- // TODO: implement InsertionSort when QSORT_THRESHOLD reached
-
- // calculate the middle element
- mid = low + ((high - low) / 2);
-
- // get the 3 keys
- key = keys.GetValueImpl (mid);
- hi = keys.GetValueImpl (high);
- lo = keys.GetValueImpl (low);
-
- // once we re-order the low, mid, and high elements to be in
- // ascending order, we'll use mid as our pivot.
- QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
- if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
- QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
+ int sp = 1;
- cmp = key as IComparable;
-
- // since we've already guaranteed that lo <= mid and mid <= hi,
- // we can skip comparing them again.
- k = high - 1;
- i = low + 1;
+ // initialize our stack
+ stack[0].high = high0;
+ stack[0].low = low0;
do {
- // Move the walls in
- if (comparer != null) {
- while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) >= 0)
- i++;
-
- while (k >= i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
- k--;
- } else if (cmp != null) {
- while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) >= 0)
- i++;
-
- while (k >= i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
- k--;
- } else {
- // This has the effect of moving the null values to the front if comparer is null
- while (i < k && keys.GetValueImpl (i) == null)
- i++;
+ // pop the stack
+ sp--;
+ high = stack[sp].high;
+ low = stack[sp].low;
+
+ if ((low + QSORT_THRESHOLD) > high) {
+ // switch to insertion sort
+ for (i = low + 1; i <= high; i++) {
+ for (k = i; k > low; k--) {
+ lo = keys.GetValueImpl (k - 1);
+ hi = keys.GetValueImpl (k);
+ if (comparer != null) {
+ if (comparer.Compare (hi, lo) >= 0)
+ break;
+ } else {
+ if (lo == null)
+ break;
+
+ if (hi != null) {
+ cmp = hi as IComparable;
+ if (cmp.CompareTo (lo) >= 0)
+ break;
+ }
+ }
+
+ swap (keys, items, k - 1, k);
+ }
+ }
- while (k >= i && keys.GetValueImpl (k) != null)
- k--;
+ continue;
}
- if (k <= i)
- break;
+ // calculate the middle element
+ mid = low + ((high - low) / 2);
- swap (keys, items, i, k);
+ // get the 3 keys
+ key = keys.GetValueImpl (mid);
+ hi = keys.GetValueImpl (high);
+ lo = keys.GetValueImpl (low);
- // make sure we keep track of our pivot element
- if (mid == i)
- mid = k;
- else if (mid == k)
- mid = i;
+ // once we re-order the low, mid, and high elements to be in
+ // ascending order, we'll use mid as our pivot.
+ QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
+ if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
+ QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
- i++;
- k--;
- } while (true);
-
- if (k != mid) {
- // swap the pivot with the last element in the first partition
- swap (keys, items, mid, k);
- }
-
- // recursively sort each partition
- if ((k + 1) < high)
- qsort (keys, items, k + 1, high, comparer);
- if ((k - 1) > low)
- qsort (keys, items, low, k - 1, comparer);
+ cmp = key as IComparable;
+
+ // since we've already guaranteed that lo <= mid and mid <= hi,
+ // we can skip comparing them again.
+ k = high - 1;
+ i = low + 1;
+
+ do {
+ // Move the walls in
+ if (comparer != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
+ k--;
+ } else if (cmp != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
+ k--;
+ } else {
+ // This has the effect of moving the null values to the front if comparer is null
+ while (i < k && keys.GetValueImpl (i) == null)
+ i++;
+
+ while (k > i && keys.GetValueImpl (k) != null)
+ k--;
+ }
+
+ if (k <= i)
+ break;
+
+ swap (keys, items, i, k);
+
+ i++;
+ k--;
+ } while (true);
+
+ // push our partitions onto the stack, largest first
+ // (to make sure we don't run out of stack space)
+ if ((high - k) >= (k - low)) {
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+ } else {
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+ }
+ } while (sp > 0);
}
private static void CheckComparerAvailable (Array keys, int low, int high)
if (array == null)
throw new ArgumentNullException ("array");
- SortImpl<T, T> (array, null, 0, array.Length, comparer);
+ SortImpl<T> (array, 0, array.Length, comparer);
}
[ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
if (index + length > array.Length)
throw new ArgumentException ();
- SortImpl<T, T> (array, null, index, length, comparer);
+ SortImpl<T> (array, index, length, comparer);
}
[ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
// Check for value types which can be sorted without Compare () method
//
if (comparer == null) {
-#if !BOOTSTRAP_BASIC
+ /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
+#if FULL_AOT_RUNTIME
+#if !BOOTSTRAP_BASIC
switch (Type.GetTypeCode (typeof (TKey))) {
case TypeCode.Int32:
qsort (keys as Int32[], items, low, high);
qsort (keys as UInt64[], items, low, high);
return;
}
+#endif
#endif
// Using Comparer<TKey> adds a small overload, but with value types it
// helps us to not box them.
//throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
//}
}
+
+ // Specialized version for items==null
+ private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
+ {
+ if (keys.Length <= 1)
+ return;
+
+ int low = index;
+ int high = index + length - 1;
+
+ //
+ // Check for value types which can be sorted without Compare () method
+ //
+ if (comparer == null) {
+#if !BOOTSTRAP_BASIC
+ switch (Type.GetTypeCode (typeof (TKey))) {
+ case TypeCode.Int32:
+ qsort (keys as Int32[], low, high);
+ return;
+ case TypeCode.Int64:
+ qsort (keys as Int64[], low, high);
+ return;
+ case TypeCode.Byte:
+ qsort (keys as byte[], low, high);
+ return;
+ case TypeCode.Char:
+ qsort (keys as char[], low, high);
+ return;
+ case TypeCode.DateTime:
+ qsort (keys as DateTime[], low, high);
+ return;
+ case TypeCode.Decimal:
+ qsort (keys as decimal[], low, high);
+ return;
+ case TypeCode.Double:
+ qsort (keys as double[], low, high);
+ return;
+ case TypeCode.Int16:
+ qsort (keys as Int16[], low, high);
+ return;
+ case TypeCode.SByte:
+ qsort (keys as SByte[], low, high);
+ return;
+ case TypeCode.Single:
+ qsort (keys as Single[], low, high);
+ return;
+ case TypeCode.UInt16:
+ qsort (keys as UInt16[], low, high);
+ return;
+ case TypeCode.UInt32:
+ qsort (keys as UInt32[], low, high);
+ return;
+ case TypeCode.UInt64:
+ qsort (keys as UInt64[], low, high);
+ return;
+ }
+#endif
+ // Using Comparer<TKey> adds a small overload, but with value types it
+ // helps us to not box them.
+ if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
+ typeof (TKey).IsValueType)
+ comparer = Comparer<TKey>.Default;
+ }
+
+ if (comparer == null)
+ CheckComparerAvailable<TKey> (keys, low, high);
+
+ //try {
+ qsort<TKey> (keys, low, high, comparer);
+ //} catch (Exception e) {
+ //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
+ //}
+ }
public static void Sort<T> (T [] array, Comparison<T> comparison)
{
return false;
}
+
+ // Specialized version for items==null
+ static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
+ {
+ if (keys[lo] != null) {
+ if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
+ swap (keys, lo, hi);
+ return true;
+ }
+ }
+
+ return false;
+ }
- private static void qsort<T, U> (T[] keys, U[] items, int low, int high) where T : IComparable<T>
+ private static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
{
+ QSortStack[] stack = new QSortStack[32];
const int QSORT_THRESHOLD = 7;
- int mid, i, k;
+ int high, low, mid, i, k;
+ int sp = 1;
T key;
- if ((low + QSORT_THRESHOLD) > high) {
- // switch to insertion sort
- for (i = low + 1; i <= high; i++) {
- for (k = i; k > low; k--) {
- // if keys[k] >= keys[k-1], break
- if (keys[k-1] == null)
- break;
-
- if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
- break;
-
- swap (keys, items, k - 1, k);
- }
- }
-
- return;
- }
-
- // calculate the middle element
- mid = low + ((high - low) / 2);
+ // initialize our stack
+ stack[0].high = high0;
+ stack[0].low = low0;
- // once we re-order the lo, mid, and hi elements to be in
- // ascending order, we'll use mid as our pivot.
- QSortArrange<T, U> (keys, items, low, mid);
- if (QSortArrange<T, U> (keys, items, mid, high))
+ do {
+ // pop the stack
+ sp--;
+ high = stack[sp].high;
+ low = stack[sp].low;
+
+ if ((low + QSORT_THRESHOLD) > high) {
+ // switch to insertion sort
+ for (i = low + 1; i <= high; i++) {
+ for (k = i; k > low; k--) {
+ // if keys[k] >= keys[k-1], break
+ if (keys[k-1] == null)
+ break;
+
+ if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
+ break;
+
+ swap (keys, items, k - 1, k);
+ }
+ }
+
+ continue;
+ }
+
+ // calculate the middle element
+ mid = low + ((high - low) / 2);
+
+ // once we re-order the lo, mid, and hi elements to be in
+ // ascending order, we'll use mid as our pivot.
QSortArrange<T, U> (keys, items, low, mid);
+ if (QSortArrange<T, U> (keys, items, mid, high))
+ QSortArrange<T, U> (keys, items, low, mid);
+
+ key = keys[mid];
+
+ // since we've already guaranteed that lo <= mid and mid <= hi,
+ // we can skip comparing them again
+ k = high - 1;
+ i = low + 1;
+
+ do {
+ if (key != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && key.CompareTo (keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && key.CompareTo (keys[k]) < 0)
+ k--;
+ } else {
+ while (i < k && keys[i] == null)
+ i++;
+
+ while (k > i && keys[k] != null)
+ k--;
+ }
+
+ if (k <= i)
+ break;
+
+ swap (keys, items, i, k);
+
+ i++;
+ k--;
+ } while (true);
+
+ // push our partitions onto the stack, largest first
+ // (to make sure we don't run out of stack space)
+ if ((high - k) >= (k - low)) {
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+ } else {
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+ }
+ } while (sp > 0);
+ }
+
+ // Specialized version for items==null
+ private static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
+ {
+ QSortStack[] stack = new QSortStack[32];
+ const int QSORT_THRESHOLD = 7;
+ int high, low, mid, i, k;
+ int sp = 1;
+ T key;
- key = keys[mid];
-
- // since we've already guaranteed that lo <= mid and mid <= hi,
- // we can skip comparing them again
- k = high - 1;
- i = low + 1;
+ // initialize our stack
+ stack[0].high = high0;
+ stack[0].low = low0;
do {
- if (key != null) {
- // find the first element with a value > pivot value
- while (i < k && key.CompareTo (keys[i]) >= 0)
- i++;
-
- // find the last element with a value <= pivot value
- while (k >= i && key.CompareTo (keys[k]) < 0)
- k--;
- } else {
- while (i < k && keys[i] == null)
- i++;
+ // pop the stack
+ sp--;
+ high = stack[sp].high;
+ low = stack[sp].low;
+
+ if ((low + QSORT_THRESHOLD) > high) {
+ // switch to insertion sort
+ for (i = low + 1; i <= high; i++) {
+ for (k = i; k > low; k--) {
+ // if keys[k] >= keys[k-1], break
+ if (keys[k-1] == null)
+ break;
+
+ if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
+ break;
+
+ swap (keys, k - 1, k);
+ }
+ }
- while (k >= i && keys[k] != null)
- k--;
+ continue;
}
- if (k <= i)
- break;
+ // calculate the middle element
+ mid = low + ((high - low) / 2);
- swap (keys, items, i, k);
+ // once we re-order the lo, mid, and hi elements to be in
+ // ascending order, we'll use mid as our pivot.
+ QSortArrange<T> (keys, low, mid);
+ if (QSortArrange<T> (keys, mid, high))
+ QSortArrange<T> (keys, low, mid);
- // make sure we keep track of our pivot element
- if (mid == i)
- mid = k;
- else if (mid == k)
- mid = i;
+ key = keys[mid];
- i++;
- k--;
- } while (true);
-
- if (k != mid) {
- // swap the pivot with the last element in the first partition
- swap (keys, items, mid, k);
- }
-
- // recursively sort each partition
- if ((k + 1) < high)
- qsort (keys, items, k + 1, high);
-
- if ((k - 1) > low)
- qsort (keys, items, low, k - 1);
- }
+ // since we've already guaranteed that lo <= mid and mid <= hi,
+ // we can skip comparing them again
+ k = high - 1;
+ i = low + 1;
+
+ do {
+ if (key != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && key.CompareTo (keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k >= i && key.CompareTo (keys[k]) < 0)
+ k--;
+ } else {
+ while (i < k && keys[i] == null)
+ i++;
+
+ while (k >= i && keys[k] != null)
+ k--;
+ }
+
+ if (k <= i)
+ break;
+
+ swap (keys, i, k);
+
+ i++;
+ k--;
+ } while (true);
+
+ // push our partitions onto the stack, largest first
+ // (to make sure we don't run out of stack space)
+ if ((high - k) >= (k - low)) {
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+ } else {
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+ }
+ } while (sp > 0);
+ }
static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
{
return false;
}
+
+ // Specialized version for items==null
+ static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
+ {
+ IComparable<K> gcmp;
+ IComparable cmp;
+
+ if (comparer != null) {
+ if (comparer.Compare (keys[hi], keys[lo]) < 0) {
+ swap<K> (keys, lo, hi);
+ return true;
+ }
+ } else if (keys[lo] != null) {
+ if (keys[hi] == null) {
+ swap<K> (keys, lo, hi);
+ return true;
+ }
+
+ gcmp = keys[hi] as IComparable<K>;
+ if (gcmp != null) {
+ if (gcmp.CompareTo (keys[lo]) < 0) {
+ swap<K> (keys, lo, hi);
+ return true;
+ }
+
+ return false;
+ }
+
+ cmp = keys[hi] as IComparable;
+ if (cmp != null) {
+ if (cmp.CompareTo (keys[lo]) < 0) {
+ swap<K> (keys, lo, hi);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+ }
- private static void qsort<K, V> (K [] keys, V [] items, int low, int high, IComparer<K> comparer)
+ private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
{
+ QSortStack[] stack = new QSortStack[32];
const int QSORT_THRESHOLD = 7;
+ int high, low, mid, i, k;
IComparable<K> gcmp;
IComparable cmp;
- int mid, i, k;
+ int sp = 1;
K key;
- if ((low + QSORT_THRESHOLD) > high) {
- // switch to insertion sort
- for (i = low + 1; i <= high; i++) {
- for (k = i; k > low; k--) {
- // if keys[k] >= keys[k-1], break
- if (comparer != null) {
- if (comparer.Compare (keys[k], keys[k-1]) >= 0)
- break;
- } else {
- if (keys[k-1] == null)
- break;
-
- if (keys[k] != null) {
- gcmp = keys[k] as IComparable<K>;
- cmp = keys[k] as IComparable;
- if (gcmp != null) {
- if (gcmp.CompareTo (keys[k-1]) >= 0)
- break;
- } else {
- if (cmp.CompareTo (keys[k-1]) >= 0)
- break;
+ // initialize our stack
+ stack[0].high = high0;
+ stack[0].low = low0;
+
+ do {
+ // pop the stack
+ sp--;
+ high = stack[sp].high;
+ low = stack[sp].low;
+
+ if ((low + QSORT_THRESHOLD) > high) {
+ // switch to insertion sort
+ for (i = low + 1; i <= high; i++) {
+ for (k = i; k > low; k--) {
+ // if keys[k] >= keys[k-1], break
+ if (comparer != null) {
+ if (comparer.Compare (keys[k], keys[k-1]) >= 0)
+ break;
+ } else {
+ if (keys[k-1] == null)
+ break;
+
+ if (keys[k] != null) {
+ gcmp = keys[k] as IComparable<K>;
+ cmp = keys[k] as IComparable;
+ if (gcmp != null) {
+ if (gcmp.CompareTo (keys[k-1]) >= 0)
+ break;
+ } else {
+ if (cmp.CompareTo (keys[k-1]) >= 0)
+ break;
+ }
}
}
+
+ swap<K, V> (keys, items, k - 1, k);
}
-
- swap<K, V> (keys, items, k - 1, k);
}
+
+ continue;
}
- return;
- }
-
- // calculate the middle element
- mid = low + ((high - low) / 2);
-
- // once we re-order the low, mid, and high elements to be in
- // ascending order, we'll use mid as our pivot.
- QSortArrange<K, V> (keys, items, low, mid, comparer);
- if (QSortArrange<K, V> (keys, items, mid, high, comparer))
+ // calculate the middle element
+ mid = low + ((high - low) / 2);
+
+ // once we re-order the low, mid, and high elements to be in
+ // ascending order, we'll use mid as our pivot.
QSortArrange<K, V> (keys, items, low, mid, comparer);
-
- key = keys[mid];
- gcmp = key as IComparable<K>;
- cmp = key as IComparable;
-
- // since we've already guaranteed that lo <= mid and mid <= hi,
- // we can skip comparing them again.
- k = high - 1;
- i = low + 1;
-
- do {
- // Move the walls in
- if (comparer != null) {
- while (i < k && comparer.Compare (key, keys[i]) >= 0)
- i++;
-
- while (k >= i && comparer.Compare (key, keys[k]) < 0)
- k--;
- } else {
- if (gcmp != null) {
- while (i < k && gcmp.CompareTo (keys[i]) >= 0)
- i++;
-
- while (k >= i && gcmp.CompareTo (keys[k]) < 0)
- k--;
- } else if (cmp != null) {
- while (i < k && cmp.CompareTo (keys[i]) >= 0)
+ if (QSortArrange<K, V> (keys, items, mid, high, comparer))
+ QSortArrange<K, V> (keys, items, low, mid, comparer);
+
+ key = keys[mid];
+ gcmp = key as IComparable<K>;
+ cmp = key as IComparable;
+
+ // since we've already guaranteed that lo <= mid and mid <= hi,
+ // we can skip comparing them again.
+ k = high - 1;
+ i = low + 1;
+
+ do {
+ // Move the walls in
+ if (comparer != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && comparer.Compare (key, keys[i]) > 0)
i++;
- while (k >= i && cmp.CompareTo (keys[k]) < 0)
+ // find the last element with a value <= pivot value
+ while (k > i && comparer.Compare (key, keys[k]) < 0)
k--;
} else {
- while (i < k && keys[i] == null)
- i++;
-
- while (k >= i && keys[k] != null)
- k--;
+ if (gcmp != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && gcmp.CompareTo (keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && gcmp.CompareTo (keys[k]) < 0)
+ k--;
+ } else if (cmp != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && cmp.CompareTo (keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && cmp.CompareTo (keys[k]) < 0)
+ k--;
+ } else {
+ while (i < k && keys[i] == null)
+ i++;
+
+ while (k > i && keys[k] != null)
+ k--;
+ }
+ }
+
+ if (k <= i)
+ break;
+
+ swap<K, V> (keys, items, i, k);
+
+ i++;
+ k--;
+ } while (true);
+
+ // push our partitions onto the stack, largest first
+ // (to make sure we don't run out of stack space)
+ if ((high - k) >= (k - low)) {
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+ } else {
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
}
}
+ } while (sp > 0);
+ }
+
+ // Specialized version for items==null
+ private static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
+ {
+ QSortStack[] stack = new QSortStack[32];
+ const int QSORT_THRESHOLD = 7;
+ int high, low, mid, i, k;
+ IComparable<K> gcmp;
+ IComparable cmp;
+ int sp = 1;
+ K key;
+
+ // initialize our stack
+ stack[0].high = high0;
+ stack[0].low = low0;
+
+ do {
+ // pop the stack
+ sp--;
+ high = stack[sp].high;
+ low = stack[sp].low;
- if (k <= i)
- break;
+ if ((low + QSORT_THRESHOLD) > high) {
+ // switch to insertion sort
+ for (i = low + 1; i <= high; i++) {
+ for (k = i; k > low; k--) {
+ // if keys[k] >= keys[k-1], break
+ if (comparer != null) {
+ if (comparer.Compare (keys[k], keys[k-1]) >= 0)
+ break;
+ } else {
+ if (keys[k-1] == null)
+ break;
+
+ if (keys[k] != null) {
+ gcmp = keys[k] as IComparable<K>;
+ cmp = keys[k] as IComparable;
+ if (gcmp != null) {
+ if (gcmp.CompareTo (keys[k-1]) >= 0)
+ break;
+ } else {
+ if (cmp.CompareTo (keys[k-1]) >= 0)
+ break;
+ }
+ }
+ }
+
+ swap<K> (keys, k - 1, k);
+ }
+ }
+
+ continue;
+ }
- swap<K, V> (keys, items, i, k);
+ // calculate the middle element
+ mid = low + ((high - low) / 2);
- // make sure we keep track of our pivot element
- if (mid == i)
- mid = k;
- else if (mid == k)
- mid = i;
+ // once we re-order the low, mid, and high elements to be in
+ // ascending order, we'll use mid as our pivot.
+ QSortArrange<K> (keys, low, mid, comparer);
+ if (QSortArrange<K> (keys, mid, high, comparer))
+ QSortArrange<K> (keys, low, mid, comparer);
- i++;
- k--;
- } while (true);
-
- if (k != mid) {
- // swap the pivot with the last element in the first partition
- swap<K, V> (keys, items, mid, k);
- }
-
- // recursively sort each partition
- if ((k + 1) < high)
- qsort<K, V> (keys, items, k + 1, high, comparer);
- if ((k - 1) > low)
- qsort<K, V> (keys, items, low, k - 1, comparer);
+ key = keys[mid];
+ gcmp = key as IComparable<K>;
+ cmp = key as IComparable;
+
+ // since we've already guaranteed that lo <= mid and mid <= hi,
+ // we can skip comparing them again.
+ k = high - 1;
+ i = low + 1;
+
+ do {
+ // Move the walls in
+ if (comparer != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && comparer.Compare (key, keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && comparer.Compare (key, keys[k]) < 0)
+ k--;
+ } else {
+ if (gcmp != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && gcmp.CompareTo (keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && gcmp.CompareTo (keys[k]) < 0)
+ k--;
+ } else if (cmp != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && cmp.CompareTo (keys[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && cmp.CompareTo (keys[k]) < 0)
+ k--;
+ } else {
+ while (i < k && keys[i] == null)
+ i++;
+
+ while (k > i && keys[k] != null)
+ k--;
+ }
+ }
+
+ if (k <= i)
+ break;
+
+ swap<K> (keys, i, k);
+
+ i++;
+ k--;
+ } while (true);
+
+ // push our partitions onto the stack, largest first
+ // (to make sure we don't run out of stack space)
+ if ((high - k) >= (k - low)) {
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+ } else {
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+ }
+ } while (sp > 0);
}
static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
return false;
}
- private static void qsort<T> (T [] array, int low, int high, Comparison<T> compare)
+ private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
{
+ QSortStack[] stack = new QSortStack[32];
const int QSORT_THRESHOLD = 7;
- int mid, i, k;
+ int high, low, mid, i, k;
+ int sp = 1;
T key;
- if ((low + QSORT_THRESHOLD) > high) {
- // switch to insertion sort
- for (i = low + 1; i <= high; i++) {
- for (k = i; k > low; k--) {
- // if keys[k] >= keys[k-1], break
- if (array[k-1] == null)
- break;
-
- if (array[k] != null && compare (array[k], array[k-1]) >= 0)
- break;
-
- swap<T> (array, k - 1, k);
- }
- }
-
- return;
- }
-
- // calculate the middle element
- mid = low + ((high - low) / 2);
-
- // once we re-order the lo, mid, and hi elements to be in
- // ascending order, we'll use mid as our pivot.
- QSortArrange<T> (array, low, mid, compare);
- if (QSortArrange<T> (array, mid, high, compare))
- QSortArrange<T> (array, low, mid, compare);
-
- key = array[mid];
-
- // since we've already guaranteed that lo <= mid and mid <= hi,
- // we can skip comparing them again
- k = high - 1;
- i = low + 1;
+ // initialize our stack
+ stack[0].high = high0;
+ stack[0].low = low0;
do {
- // Move the walls in
- if (key != null) {
- // find the first element with a value > pivot value
- while (i < k && compare (key, array[i]) >= 0)
- i++;
-
- // find the last element with a value <= pivot value
- while (k >= i && compare (key, array[k]) < 0)
- k--;
- } else {
- while (i < k && array[i] == null)
- i++;
+ // pop the stack
+ sp--;
+ high = stack[sp].high;
+ low = stack[sp].low;
+
+ if ((low + QSORT_THRESHOLD) > high) {
+ // switch to insertion sort
+ for (i = low + 1; i <= high; i++) {
+ for (k = i; k > low; k--) {
+ if (compare (array[k], array[k-1]) >= 0)
+ break;
+
+ swap<T> (array, k - 1, k);
+ }
+ }
- while (k >= i && array[k] != null)
- k--;
+ continue;
}
- if (k <= i)
- break;
+ // calculate the middle element
+ mid = low + ((high - low) / 2);
- swap<T> (array, i, k);
+ // once we re-order the lo, mid, and hi elements to be in
+ // ascending order, we'll use mid as our pivot.
+ QSortArrange<T> (array, low, mid, compare);
+ if (QSortArrange<T> (array, mid, high, compare))
+ QSortArrange<T> (array, low, mid, compare);
- // make sure we keep track of our pivot element
- if (mid == i)
- mid = k;
- else if (mid == k)
- mid = i;
+ key = array[mid];
- i++;
- k--;
- } while (true);
-
- if (k != mid) {
- // swap the pivot with the last element in the first partition
- swap<T> (array, mid, k);
- }
-
- // recursively sort each partition
- if ((k + 1) < high)
- qsort<T> (array, k + 1, high, compare);
-
- if ((k - 1) > low)
- qsort<T> (array, low, k - 1, compare);
+ // since we've already guaranteed that lo <= mid and mid <= hi,
+ // we can skip comparing them again
+ k = high - 1;
+ i = low + 1;
+
+ do {
+ // Move the walls in
+ if (key != null) {
+ // find the first element with a value >= pivot value
+ while (i < k && compare (key, array[i]) > 0)
+ i++;
+
+ // find the last element with a value <= pivot value
+ while (k > i && compare (key, array[k]) < 0)
+ k--;
+ } else {
+ while (i < k && array[i] == null)
+ i++;
+
+ while (k > i && array[k] != null)
+ k--;
+ }
+
+ if (k <= i)
+ break;
+
+ swap<T> (array, i, k);
+
+ i++;
+ k--;
+ } while (true);
+
+ // push our partitions onto the stack, largest first
+ // (to make sure we don't run out of stack space)
+ if ((high - k) >= (k - low)) {
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+ } else {
+ if ((k - 1) > low) {
+ stack[sp].high = k;
+ stack[sp].low = low;
+ sp++;
+ }
+
+ if ((k + 1) < high) {
+ stack[sp].high = high;
+ stack[sp].low = k;
+ sp++;
+ }
+ }
+ } while (sp > 0);
}
private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
}
}
+ [MethodImpl ((MethodImplOptions)256)]
private static void swap<K, V> (K [] keys, V [] items, int i, int j)
{
K tmp;
}
}
+ [MethodImpl ((MethodImplOptions)256)]
private static void swap<T> (T [] array, int i, int j)
{
T tmp = array [i];
public static void Resize<T> (ref T [] array, int newSize)
{
if (newSize < 0)
- throw new ArgumentOutOfRangeException ();
+ throw new ArgumentOutOfRangeException ("newSize");
if (array == null) {
array = new T [newSize];
return;
}
- int length = array.Length;
+ var arr = array;
+ int length = arr.Length;
if (length == newSize)
return;
T [] a = new T [newSize];
- if (length != 0)
- FastCopy (array, 0, a, 0, Math.Min (newSize, length));
+ int tocopy = Math.Min (newSize, length);
+
+ if (tocopy < 9) {
+ for (int i = 0; i < tocopy; ++i)
+ UnsafeStore (a, i, UnsafeLoad (arr, i));
+ } else {
+ FastCopy (arr, 0, a, 0, tocopy);
+ }
array = a;
}
{
if (array == null)
throw new ArgumentNullException ("array");
+
+ if (match == null)
+ throw new ArgumentNullException ("match");
- return FindLastIndex<T> (array, 0, array.Length, match);
+ return GetLastIndex (array, 0, array.Length, match);
}
public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
{
if (array == null)
throw new ArgumentNullException ();
+
+ if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+ throw new ArgumentOutOfRangeException ("startIndex");
+
+ if (match == null)
+ throw new ArgumentNullException ("match");
- return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
+ return GetLastIndex (array, 0, startIndex + 1, match);
}
public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
{
if (array == null)
throw new ArgumentNullException ("array");
+
if (match == null)
throw new ArgumentNullException ("match");
+
+ if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+ throw new ArgumentOutOfRangeException ("startIndex");
- if (startIndex > array.Length || startIndex + count > array.Length)
- throw new ArgumentOutOfRangeException ();
-
- for (int i = startIndex + count - 1; i >= startIndex; i--)
- if (match (array [i]))
+ if (count < 0)
+ throw new ArgumentOutOfRangeException ("count");
+
+ if (startIndex - count + 1 < 0)
+ throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
+
+ return GetLastIndex (array, startIndex - count + 1, count, match);
+ }
+
+ internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
+ {
+ // unlike FindLastIndex, takes regular params for search range
+ for (int i = startIndex + count; i != startIndex;)
+ if (match (array [--i]))
return i;
-
+
return -1;
}
{
if (array == null)
throw new ArgumentNullException ("array");
+
+ if (match == null)
+ throw new ArgumentNullException ("match");
- return FindIndex<T> (array, 0, array.Length, match);
+ return GetIndex (array, 0, array.Length, match);
}
public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
{
if (array == null)
throw new ArgumentNullException ("array");
-
- return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
+
+ if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+ throw new ArgumentOutOfRangeException ("startIndex");
+
+ if (match == null)
+ throw new ArgumentNullException ("match");
+
+ return GetIndex (array, startIndex, array.Length - startIndex, match);
}
public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
if (array == null)
throw new ArgumentNullException ("array");
- if (match == null)
- throw new ArgumentNullException ("match");
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException ("startIndex");
- if (startIndex > array.Length || startIndex + count > array.Length)
- throw new ArgumentOutOfRangeException ();
-
- for (int i = startIndex; i < startIndex + count; i ++)
+ if (count < 0)
+ throw new ArgumentOutOfRangeException ("count");
+
+ if ((uint) startIndex + (uint) count > (uint) array.Length)
+ throw new ArgumentOutOfRangeException ("index and count exceed length of list");
+
+ return GetIndex (array, startIndex, count, match);
+ }
+
+ internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
+ {
+ int end = startIndex + count;
+ for (int i = startIndex; i < end; i ++)
if (match (array [i]))
return i;
while (iMin <= iMax) {
// Be careful with overflows
int iMid = iMin + ((iMax - iMin) / 2);
- iCmp = comparer.Compare (value, array [iMid]);
+ iCmp = comparer.Compare (array [iMid], value);
if (iCmp == 0)
return iMid;
- else if (iCmp < 0)
+
+ if (iCmp > 0)
iMax = iMid - 1;
else
iMin = iMid + 1; // compensate for the rounding down
{
Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
}
+
+ internal static T UnsafeLoad<T> (T[] array, int index) {
+ return array [index];
+ }
+
+ internal static void UnsafeStore<T> (T[] array, int index, T value) {
+ array [index] = value;
+ }
}
}