Fix all CreateInstance overloads for void
[mcs.git] / class / corlib / System / Array.cs
blobd3ac6a9928950a023aa48c8c72045f0d82481664
1 //
2 // System.Array.cs
3 //
4 // Authors:
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 //
10 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
11 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
37 using System.Collections.Generic;
38 using System.Collections.ObjectModel;
39 using System.Runtime.ConstrainedExecution;
41 namespace System
43 [Serializable]
44 [ComVisible (true)]
45 // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
46 public abstract class Array : ICloneable, ICollection, IList, IEnumerable
48 // Constructor
49 private Array ()
54 * These methods are used to implement the implicit generic interfaces
55 * implemented by arrays in NET 2.0.
56 * Only make those methods generic which really need it, to avoid
57 * creating useless instantiations.
59 internal int InternalArray__ICollection_get_Count ()
61 return Length;
64 internal bool InternalArray__ICollection_get_IsReadOnly ()
66 return true;
69 internal IEnumerator<T> InternalArray__IEnumerable_GetEnumerator<T> ()
71 return new InternalEnumerator<T> (this);
74 internal void InternalArray__ICollection_Clear ()
76 throw new NotSupportedException ("Collection is read-only");
79 internal void InternalArray__ICollection_Add<T> (T item)
81 throw new NotSupportedException ("Collection is read-only");
84 internal bool InternalArray__ICollection_Remove<T> (T item)
86 throw new NotSupportedException ("Collection is read-only");
89 internal bool InternalArray__ICollection_Contains<T> (T item)
91 if (this.Rank > 1)
92 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
94 int length = this.Length;
95 for (int i = 0; i < length; i++) {
96 T value;
97 GetGenericValueImpl (i, out value);
98 if (item == null){
99 if (value == null)
100 return true;
101 else
102 return false;
105 if (item.Equals (value))
106 return true;
109 return false;
112 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int index)
114 if (array == null)
115 throw new ArgumentNullException ("array");
117 // The order of these exception checks may look strange,
118 // but that's how the microsoft runtime does it.
119 if (this.Rank > 1)
120 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
121 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
122 throw new ArgumentException ("Destination array was not long " +
123 "enough. Check destIndex and length, and the array's " +
124 "lower bounds.");
125 if (array.Rank > 1)
126 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
127 if (index < 0)
128 throw new ArgumentOutOfRangeException (
129 "index", Locale.GetText ("Value has to be >= 0."));
131 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
134 internal void InternalArray__Insert<T> (int index, T item)
136 throw new NotSupportedException ("Collection is read-only");
139 internal void InternalArray__RemoveAt (int index)
141 throw new NotSupportedException ("Collection is read-only");
144 internal int InternalArray__IndexOf<T> (T item)
146 if (this.Rank > 1)
147 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
149 int length = this.Length;
150 for (int i = 0; i < length; i++) {
151 T value;
152 GetGenericValueImpl (i, out value);
153 if (item == null){
154 if (value == null)
155 return i + this.GetLowerBound (0);
156 else {
157 unchecked {
158 return this.GetLowerBound (0) - 1;
162 if (value.Equals (item))
163 // array index may not be zero-based.
164 // use lower bound
165 return i + this.GetLowerBound (0);
168 unchecked {
169 // lower bound may be MinValue
170 return this.GetLowerBound (0) - 1;
174 internal T InternalArray__get_Item<T> (int index)
176 if (unchecked ((uint) index) >= unchecked ((uint) Length))
177 throw new ArgumentOutOfRangeException ("index");
179 T value;
180 GetGenericValueImpl (index, out value);
181 return value;
184 internal void InternalArray__set_Item<T> (int index, T item)
186 if (unchecked ((uint) index) >= unchecked ((uint) Length))
187 throw new ArgumentOutOfRangeException ("index");
189 object[] oarray = this as object [];
190 if (oarray != null) {
191 oarray [index] = (object)item;
192 return;
194 SetGenericValueImpl (index, ref item);
197 // CAUTION! No bounds checking!
198 [MethodImplAttribute (MethodImplOptions.InternalCall)]
199 internal extern void GetGenericValueImpl<T> (int pos, out T value);
201 // CAUTION! No bounds checking!
202 [MethodImplAttribute (MethodImplOptions.InternalCall)]
203 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
205 internal struct InternalEnumerator<T> : IEnumerator<T>
207 const int NOT_STARTED = -2;
209 // this MUST be -1, because we depend on it in move next.
210 // we just decr the size, so, 0 - 1 == FINISHED
211 const int FINISHED = -1;
213 Array array;
214 int idx;
216 internal InternalEnumerator (Array array)
218 this.array = array;
219 idx = NOT_STARTED;
222 public void Dispose ()
224 idx = NOT_STARTED;
227 public bool MoveNext ()
229 if (idx == NOT_STARTED)
230 idx = array.Length;
232 return idx != FINISHED && -- idx != FINISHED;
235 public T Current {
236 get {
237 if (idx == NOT_STARTED)
238 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
239 if (idx == FINISHED)
240 throw new InvalidOperationException ("Enumeration already finished");
242 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
246 void IEnumerator.Reset ()
248 idx = NOT_STARTED;
251 object IEnumerator.Current {
252 get {
253 return Current;
258 // Properties
259 public int Length {
260 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
261 get {
262 int length = this.GetLength (0);
264 for (int i = 1; i < this.Rank; i++) {
265 length *= this.GetLength (i);
267 return length;
271 [ComVisible (false)]
272 public long LongLength {
273 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
274 get { return Length; }
277 public int Rank {
278 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
279 get {
280 return this.GetRank ();
284 // IList interface
285 object IList.this [int index] {
286 get {
287 if (unchecked ((uint) index) >= unchecked ((uint) Length))
288 throw new IndexOutOfRangeException ("index");
289 return GetValueImpl (index);
291 set {
292 if (unchecked ((uint) index) >= unchecked ((uint) Length))
293 throw new IndexOutOfRangeException ("index");
294 SetValueImpl (value, index);
298 int IList.Add (object value)
300 throw new NotSupportedException ();
303 void IList.Clear ()
305 Array.Clear (this, this.GetLowerBound (0), this.Length);
308 bool IList.Contains (object value)
310 if (this.Rank > 1)
311 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
313 int length = this.Length;
314 for (int i = 0; i < length; i++) {
315 if (Object.Equals (this.GetValueImpl (i), value))
316 return true;
318 return false;
321 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
322 int IList.IndexOf (object value)
324 if (this.Rank > 1)
325 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
327 int length = this.Length;
328 for (int i = 0; i < length; i++) {
329 if (Object.Equals (this.GetValueImpl (i), value))
330 // array index may not be zero-based.
331 // use lower bound
332 return i + this.GetLowerBound (0);
335 unchecked {
336 // lower bound may be MinValue
337 return this.GetLowerBound (0) - 1;
341 void IList.Insert (int index, object value)
343 throw new NotSupportedException ();
346 void IList.Remove (object value)
348 throw new NotSupportedException ();
351 void IList.RemoveAt (int index)
353 throw new NotSupportedException ();
356 // InternalCall Methods
357 [MethodImplAttribute (MethodImplOptions.InternalCall)]
358 extern int GetRank ();
360 [MethodImplAttribute (MethodImplOptions.InternalCall)]
361 public extern int GetLength (int dimension);
363 [ComVisible (false)]
364 public long GetLongLength (int dimension)
366 return GetLength (dimension);
369 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
370 [MethodImplAttribute (MethodImplOptions.InternalCall)]
371 public extern int GetLowerBound (int dimension);
373 [MethodImplAttribute (MethodImplOptions.InternalCall)]
374 public extern object GetValue (params int[] indices);
376 [MethodImplAttribute (MethodImplOptions.InternalCall)]
377 public extern void SetValue (object value, params int[] indices);
379 // CAUTION! No bounds checking!
380 [MethodImplAttribute (MethodImplOptions.InternalCall)]
381 internal extern object GetValueImpl (int pos);
383 // CAUTION! No bounds checking!
384 [MethodImplAttribute (MethodImplOptions.InternalCall)]
385 internal extern void SetValueImpl (object value, int pos);
387 [MethodImplAttribute (MethodImplOptions.InternalCall)]
388 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
390 [MethodImplAttribute (MethodImplOptions.InternalCall)]
391 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
393 // Properties
394 int ICollection.Count {
395 get {
396 return Length;
400 public bool IsSynchronized {
401 get {
402 return false;
406 public object SyncRoot {
407 get {
408 return this;
412 public bool IsFixedSize {
413 get {
414 return true;
418 public bool IsReadOnly {
419 get {
420 return false;
424 public IEnumerator GetEnumerator ()
426 return new SimpleEnumerator (this);
429 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
430 public int GetUpperBound (int dimension)
432 return GetLowerBound (dimension) + GetLength (dimension) - 1;
435 public object GetValue (int index)
437 if (Rank != 1)
438 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
439 if (index < GetLowerBound (0) || index > GetUpperBound (0))
440 throw new IndexOutOfRangeException (Locale.GetText (
441 "Index has to be between upper and lower bound of the array."));
443 return GetValueImpl (index - GetLowerBound (0));
446 public object GetValue (int index1, int index2)
448 int[] ind = {index1, index2};
449 return GetValue (ind);
452 public object GetValue (int index1, int index2, int index3)
454 int[] ind = {index1, index2, index3};
455 return GetValue (ind);
458 [ComVisible (false)]
459 public object GetValue (long index)
461 if (index < 0 || index > Int32.MaxValue)
462 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
463 "Value must be >= 0 and <= Int32.MaxValue."));
465 return GetValue ((int) index);
468 [ComVisible (false)]
469 public object GetValue (long index1, long index2)
471 if (index1 < 0 || index1 > Int32.MaxValue)
472 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
473 "Value must be >= 0 and <= Int32.MaxValue."));
475 if (index2 < 0 || index2 > Int32.MaxValue)
476 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
477 "Value must be >= 0 and <= Int32.MaxValue."));
479 return GetValue ((int) index1, (int) index2);
482 [ComVisible (false)]
483 public object GetValue (long index1, long index2, long index3)
485 if (index1 < 0 || index1 > Int32.MaxValue)
486 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
487 "Value must be >= 0 and <= Int32.MaxValue."));
489 if (index2 < 0 || index2 > Int32.MaxValue)
490 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
491 "Value must be >= 0 and <= Int32.MaxValue."));
493 if (index3 < 0 || index3 > Int32.MaxValue)
494 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
495 "Value must be >= 0 and <= Int32.MaxValue."));
497 return GetValue ((int) index1, (int) index2, (int) index3);
500 [ComVisible (false)]
501 public void SetValue (object value, long index)
503 if (index < 0 || index > Int32.MaxValue)
504 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
505 "Value must be >= 0 and <= Int32.MaxValue."));
507 SetValue (value, (int) index);
510 [ComVisible (false)]
511 public void SetValue (object value, long index1, long index2)
513 if (index1 < 0 || index1 > Int32.MaxValue)
514 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
515 "Value must be >= 0 and <= Int32.MaxValue."));
517 if (index2 < 0 || index2 > Int32.MaxValue)
518 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
519 "Value must be >= 0 and <= Int32.MaxValue."));
521 int[] ind = {(int) index1, (int) index2};
522 SetValue (value, ind);
525 [ComVisible (false)]
526 public void SetValue (object value, long index1, long index2, long index3)
528 if (index1 < 0 || index1 > Int32.MaxValue)
529 throw new ArgumentOutOfRangeException ("index1", Locale.GetText (
530 "Value must be >= 0 and <= Int32.MaxValue."));
532 if (index2 < 0 || index2 > Int32.MaxValue)
533 throw new ArgumentOutOfRangeException ("index2", Locale.GetText (
534 "Value must be >= 0 and <= Int32.MaxValue."));
536 if (index3 < 0 || index3 > Int32.MaxValue)
537 throw new ArgumentOutOfRangeException ("index3", Locale.GetText (
538 "Value must be >= 0 and <= Int32.MaxValue."));
540 int[] ind = {(int) index1, (int) index2, (int) index3};
541 SetValue (value, ind);
544 public void SetValue (object value, int index)
546 if (Rank != 1)
547 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
548 if (index < GetLowerBound (0) || index > GetUpperBound (0))
549 throw new IndexOutOfRangeException (Locale.GetText (
550 "Index has to be >= lower bound and <= upper bound of the array."));
552 SetValueImpl (value, index - GetLowerBound (0));
555 public void SetValue (object value, int index1, int index2)
557 int[] ind = {index1, index2};
558 SetValue (value, ind);
561 public void SetValue (object value, int index1, int index2, int index3)
563 int[] ind = {index1, index2, index3};
564 SetValue (value, ind);
567 public static Array CreateInstance (Type elementType, int length)
569 int[] lengths = {length};
571 return CreateInstance (elementType, lengths);
574 public static Array CreateInstance (Type elementType, int length1, int length2)
576 int[] lengths = {length1, length2};
578 return CreateInstance (elementType, lengths);
581 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
583 int[] lengths = {length1, length2, length3};
585 return CreateInstance (elementType, lengths);
588 public static Array CreateInstance (Type elementType, params int[] lengths)
590 if (elementType == null)
591 throw new ArgumentNullException ("elementType");
592 if (lengths == null)
593 throw new ArgumentNullException ("lengths");
595 if (lengths.Length > 255)
596 throw new TypeLoadException ();
598 int[] bounds = null;
600 elementType = elementType.UnderlyingSystemType;
601 if (elementType.Equals (typeof (void)))
602 throw new NotSupportedException ("Array type can not be void");
603 if (!elementType.IsSystemType)
604 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
606 return CreateInstanceImpl (elementType, lengths, bounds);
609 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
611 if (elementType == null)
612 throw new ArgumentNullException ("elementType");
613 if (lengths == null)
614 throw new ArgumentNullException ("lengths");
615 if (lowerBounds == null)
616 throw new ArgumentNullException ("lowerBounds");
618 elementType = elementType.UnderlyingSystemType;
619 if (!elementType.IsSystemType)
620 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
621 if (elementType.Equals (typeof (void)))
622 throw new NotSupportedException ("Array type can not be void");
624 if (lengths.Length < 1)
625 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
627 if (lengths.Length != lowerBounds.Length)
628 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
630 for (int j = 0; j < lowerBounds.Length; j ++) {
631 if (lengths [j] < 0)
632 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
633 "Each value has to be >= 0."));
634 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
635 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
636 "Length + bound must not exceed Int32.MaxValue."));
639 if (lengths.Length > 255)
640 throw new TypeLoadException ();
642 return CreateInstanceImpl (elementType, lengths, lowerBounds);
645 static int [] GetIntArray (long [] values)
647 int len = values.Length;
648 int [] ints = new int [len];
649 for (int i = 0; i < len; i++) {
650 long current = values [i];
651 if (current < 0 || current > (long) Int32.MaxValue)
652 throw new ArgumentOutOfRangeException ("values", Locale.GetText (
653 "Each value has to be >= 0 and <= Int32.MaxValue."));
655 ints [i] = (int) current;
657 return ints;
660 public static Array CreateInstance (Type elementType, params long [] lengths)
662 if (lengths == null)
663 throw new ArgumentNullException ("lengths");
664 return CreateInstance (elementType, GetIntArray (lengths));
667 [ComVisible (false)]
668 public object GetValue (params long [] indices)
670 if (indices == null)
671 throw new ArgumentNullException ("indices");
672 return GetValue (GetIntArray (indices));
675 [ComVisible (false)]
676 public void SetValue (object value, params long [] indices)
678 if (indices == null)
679 throw new ArgumentNullException ("indices");
680 SetValue (value, GetIntArray (indices));
683 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
684 public static int BinarySearch (Array array, object value)
686 if (array == null)
687 throw new ArgumentNullException ("array");
689 if (value == null)
690 return -1;
692 if (array.Rank > 1)
693 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
695 if (array.Length == 0)
696 return -1;
698 if (!(value is IComparable))
699 throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
701 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
704 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
705 public static int BinarySearch (Array array, object value, IComparer comparer)
707 if (array == null)
708 throw new ArgumentNullException ("array");
710 if (array.Rank > 1)
711 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
713 if (array.Length == 0)
714 return -1;
716 if ((comparer == null) && (value != null) && !(value is IComparable))
717 throw new ArgumentException (Locale.GetText (
718 "comparer is null and value does not support IComparable."));
720 return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
723 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
724 public static int BinarySearch (Array array, int index, int length, object value)
726 if (array == null)
727 throw new ArgumentNullException ("array");
729 if (array.Rank > 1)
730 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
732 if (index < array.GetLowerBound (0))
733 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
734 "index is less than the lower bound of array."));
735 if (length < 0)
736 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
737 "Value has to be >= 0."));
738 // re-ordered to avoid possible integer overflow
739 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
740 throw new ArgumentException (Locale.GetText (
741 "index and length do not specify a valid range in array."));
743 if (array.Length == 0)
744 return -1;
746 if ((value != null) && (!(value is IComparable)))
747 throw new ArgumentException (Locale.GetText (
748 "value does not support IComparable"));
750 return DoBinarySearch (array, index, length, value, null);
753 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
754 public static int BinarySearch (Array array, int index, int length, object value, IComparer comparer)
756 if (array == null)
757 throw new ArgumentNullException ("array");
759 if (array.Rank > 1)
760 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
762 if (index < array.GetLowerBound (0))
763 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
764 "index is less than the lower bound of array."));
765 if (length < 0)
766 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
767 "Value has to be >= 0."));
768 // re-ordered to avoid possible integer overflow
769 if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
770 throw new ArgumentException (Locale.GetText (
771 "index and length do not specify a valid range in array."));
773 if (array.Length == 0)
774 return -1;
776 if ((comparer == null) && (value != null) && !(value is IComparable))
777 throw new ArgumentException (Locale.GetText (
778 "comparer is null and value does not support IComparable."));
780 return DoBinarySearch (array, index, length, value, comparer);
783 static int DoBinarySearch (Array array, int index, int length, object value, IComparer comparer)
785 // cache this in case we need it
786 if (comparer == null)
787 comparer = Comparer.Default;
789 int iMin = index;
790 // Comment from Tum (tum@veridicus.com):
791 // *Must* start at index + length - 1 to pass rotor test co2460binarysearch_iioi
792 int iMax = index + length - 1;
793 int iCmp = 0;
794 try {
795 while (iMin <= iMax) {
796 // Be careful with overflow
797 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
798 int iMid = iMin + ((iMax - iMin) / 2);
799 object elt = array.GetValueImpl (iMid);
801 iCmp = comparer.Compare (elt, value);
803 if (iCmp == 0)
804 return iMid;
805 else if (iCmp > 0)
806 iMax = iMid - 1;
807 else
808 iMin = iMid + 1; // compensate for the rounding down
811 catch (Exception e) {
812 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
815 return ~iMin;
818 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
819 public static void Clear (Array array, int index, int length)
821 if (array == null)
822 throw new ArgumentNullException ("array");
823 if (length < 0)
824 throw new ArgumentOutOfRangeException ("length < 0");
826 int low = array.GetLowerBound (0);
827 if (index < low)
828 throw new IndexOutOfRangeException ("index < lower bound");
829 index = index - low;
831 // re-ordered to avoid possible integer overflow
832 if (index > array.Length - length)
833 throw new IndexOutOfRangeException ("index + length > size");
835 ClearInternal (array, index, length);
838 [MethodImplAttribute (MethodImplOptions.InternalCall)]
839 static extern void ClearInternal (Array a, int index, int count);
841 [MethodImplAttribute (MethodImplOptions.InternalCall)]
842 public extern object Clone ();
844 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
845 public static void Copy (Array sourceArray, Array destinationArray, int length)
847 // need these checks here because we are going to use
848 // GetLowerBound() on source and dest.
849 if (sourceArray == null)
850 throw new ArgumentNullException ("sourceArray");
852 if (destinationArray == null)
853 throw new ArgumentNullException ("destinationArray");
855 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
856 destinationArray.GetLowerBound (0), length);
859 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
860 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
862 if (sourceArray == null)
863 throw new ArgumentNullException ("sourceArray");
865 if (destinationArray == null)
866 throw new ArgumentNullException ("destinationArray");
868 if (length < 0)
869 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
870 "Value has to be >= 0."));;
872 if (sourceIndex < 0)
873 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
874 "Value has to be >= 0."));;
876 if (destinationIndex < 0)
877 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
878 "Value has to be >= 0."));;
880 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
881 return;
883 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
884 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
886 // re-ordered to avoid possible integer overflow
887 if (source_pos > sourceArray.Length - length)
888 throw new ArgumentException ("length");
890 if (dest_pos > destinationArray.Length - length) {
891 string msg = "Destination array was not long enough. Check " +
892 "destIndex and length, and the array's lower bounds";
893 throw new ArgumentException (msg, string.Empty);
896 if (sourceArray.Rank != destinationArray.Rank)
897 throw new RankException (Locale.GetText ("Arrays must be of same size."));
899 Type src_type = sourceArray.GetType ().GetElementType ();
900 Type dst_type = destinationArray.GetType ().GetElementType ();
902 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
903 for (int i = 0; i < length; i++) {
904 Object srcval = sourceArray.GetValueImpl (source_pos + i);
906 try {
907 destinationArray.SetValueImpl (srcval, dest_pos + i);
908 } catch {
909 if (src_type.Equals (typeof (Object)))
910 throw new InvalidCastException ();
911 else
912 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
913 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
917 else {
918 for (int i = length - 1; i >= 0; i--) {
919 Object srcval = sourceArray.GetValueImpl (source_pos + i);
921 try {
922 destinationArray.SetValueImpl (srcval, dest_pos + i);
923 } catch {
924 if (src_type.Equals (typeof (Object)))
925 throw new InvalidCastException ();
926 else
927 throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
928 "(Types: source={0}; target={1})"), src_type.FullName, dst_type.FullName));
934 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
935 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
936 long destinationIndex, long length)
938 if (sourceArray == null)
939 throw new ArgumentNullException ("sourceArray");
941 if (destinationArray == null)
942 throw new ArgumentNullException ("destinationArray");
944 if (sourceIndex < Int32.MinValue || sourceIndex > Int32.MaxValue)
945 throw new ArgumentOutOfRangeException ("sourceIndex",
946 Locale.GetText ("Must be in the Int32 range."));
948 if (destinationIndex < Int32.MinValue || destinationIndex > Int32.MaxValue)
949 throw new ArgumentOutOfRangeException ("destinationIndex",
950 Locale.GetText ("Must be in the Int32 range."));
952 if (length < 0 || length > Int32.MaxValue)
953 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
954 "Value must be >= 0 and <= Int32.MaxValue."));
956 Copy (sourceArray, (int) sourceIndex, destinationArray, (int) destinationIndex, (int) length);
959 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
960 public static void Copy (Array sourceArray, Array destinationArray, long length)
962 if (length < 0 || length > Int32.MaxValue)
963 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
964 "Value must be >= 0 and <= Int32.MaxValue."));
966 Copy (sourceArray, destinationArray, (int) length);
969 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
970 public static int IndexOf (Array array, object value)
972 if (array == null)
973 throw new ArgumentNullException ("array");
975 return IndexOf (array, value, 0, array.Length);
978 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
979 public static int IndexOf (Array array, object value, int startIndex)
981 if (array == null)
982 throw new ArgumentNullException ("array");
984 return IndexOf (array, value, startIndex, array.Length - startIndex);
987 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
988 public static int IndexOf (Array array, object value, int startIndex, int count)
990 if (array == null)
991 throw new ArgumentNullException ("array");
993 if (array.Rank > 1)
994 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
996 // re-ordered to avoid possible integer overflow
997 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
998 throw new ArgumentOutOfRangeException ();
1000 int max = startIndex + count;
1001 for (int i = startIndex; i < max; i++) {
1002 if (Object.Equals (array.GetValueImpl (i), value))
1003 return i;
1006 return array.GetLowerBound (0) - 1;
1009 public void Initialize()
1011 //FIXME: We would like to find a compiler that uses
1012 // this method. It looks like this method do nothing
1013 // in C# so no exception is trown by the moment.
1016 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1017 public static int LastIndexOf (Array array, object value)
1019 if (array == null)
1020 throw new ArgumentNullException ("array");
1022 if (array.Length == 0)
1023 return array.GetLowerBound (0) - 1;
1024 return LastIndexOf (array, value, array.Length - 1);
1027 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1028 public static int LastIndexOf (Array array, object value, int startIndex)
1030 if (array == null)
1031 throw new ArgumentNullException ("array");
1033 return LastIndexOf (array, value, startIndex, startIndex - array.GetLowerBound (0) + 1);
1036 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1037 public static int LastIndexOf (Array array, object value, int startIndex, int count)
1039 if (array == null)
1040 throw new ArgumentNullException ("array");
1042 if (array.Rank > 1)
1043 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1045 int lb = array.GetLowerBound (0);
1046 // Empty arrays do not throw ArgumentOutOfRangeException
1047 if (array.Length == 0)
1048 return lb - 1;
1050 if (count < 0 || startIndex < lb ||
1051 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < lb)
1052 throw new ArgumentOutOfRangeException ();
1054 for (int i = startIndex; i >= startIndex - count + 1; i--) {
1055 if (Object.Equals (array.GetValueImpl (i), value))
1056 return i;
1059 return lb - 1;
1062 /* delegate used to swap array elements */
1063 delegate void Swapper (int i, int j);
1065 static Swapper get_swapper (Array array)
1067 if (array is int[])
1068 return new Swapper (array.int_swapper);
1069 if (array is double[])
1070 return new Swapper (array.double_swapper);
1071 if (array is object[]) {
1072 return new Swapper (array.obj_swapper);
1074 return new Swapper (array.slow_swapper);
1077 static Swapper get_swapper<T> (T [] array)
1079 if (array is int[])
1080 return new Swapper (array.int_swapper);
1081 if (array is double[])
1082 return new Swapper (array.double_swapper);
1084 // gmcs refuses to compile this
1085 //return new Swapper (array.generic_swapper<T>);
1086 return new Swapper (array.slow_swapper);
1089 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1090 public static void Reverse (Array array)
1092 if (array == null)
1093 throw new ArgumentNullException ("array");
1095 Reverse (array, array.GetLowerBound (0), array.GetLength (0));
1098 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1099 public static void Reverse (Array array, int index, int length)
1101 if (array == null)
1102 throw new ArgumentNullException ("array");
1104 if (array.Rank > 1)
1105 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1107 if (index < array.GetLowerBound (0) || length < 0)
1108 throw new ArgumentOutOfRangeException ();
1110 // re-ordered to avoid possible integer overflow
1111 if (index > array.GetUpperBound (0) + 1 - length)
1112 throw new ArgumentException ();
1114 int end = index + length - 1;
1115 object[] oarray = array as object[];
1116 if (oarray != null) {
1117 while (index < end) {
1118 object tmp = oarray [index];
1119 oarray [index] = oarray [end];
1120 oarray [end] = tmp;
1121 ++index;
1122 --end;
1124 return;
1126 int[] iarray = array as int[];
1127 if (iarray != null) {
1128 while (index < end) {
1129 int tmp = iarray [index];
1130 iarray [index] = iarray [end];
1131 iarray [end] = tmp;
1132 ++index;
1133 --end;
1135 return;
1137 double[] darray = array as double[];
1138 if (darray != null) {
1139 while (index < end) {
1140 double tmp = darray [index];
1141 darray [index] = darray [end];
1142 darray [end] = tmp;
1143 ++index;
1144 --end;
1146 return;
1148 // fallback
1149 Swapper swapper = get_swapper (array);
1150 while (index < end) {
1151 swapper (index, end);
1152 ++index;
1153 --end;
1157 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1158 public static void Sort (Array array)
1160 Sort (array, (IComparer)null);
1163 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1164 public static void Sort (Array keys, Array items)
1166 Sort (keys, items, (IComparer)null);
1169 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1170 public static void Sort (Array array, IComparer comparer)
1172 if (array == null)
1173 throw new ArgumentNullException ("array");
1175 if (array.Rank > 1)
1176 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1178 SortImpl (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
1181 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1182 public static void Sort (Array array, int index, int length)
1184 Sort (array, index, length, (IComparer)null);
1187 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1188 public static void Sort (Array keys, Array items, IComparer comparer)
1190 if (items == null) {
1191 Sort (keys, comparer);
1192 return;
1195 if (keys == null)
1196 throw new ArgumentNullException ("keys");
1198 if (keys.Rank > 1 || items.Rank > 1)
1199 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1201 SortImpl (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
1204 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1205 public static void Sort (Array keys, Array items, int index, int length)
1207 Sort (keys, items, index, length, (IComparer)null);
1210 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1211 public static void Sort (Array array, int index, int length, IComparer comparer)
1213 if (array == null)
1214 throw new ArgumentNullException ("array");
1216 if (array.Rank > 1)
1217 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1219 if (index < array.GetLowerBound (0))
1220 throw new ArgumentOutOfRangeException ("index");
1222 if (length < 0)
1223 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1224 "Value has to be >= 0."));
1226 if (array.Length - (array.GetLowerBound (0) + index) < length)
1227 throw new ArgumentException ();
1229 SortImpl (array, null, index, length, comparer);
1232 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1233 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
1235 if (items == null) {
1236 Sort (keys, index, length, comparer);
1237 return;
1240 if (keys == null)
1241 throw new ArgumentNullException ("keys");
1243 if (keys.Rank > 1 || items.Rank > 1)
1244 throw new RankException ();
1246 if (keys.GetLowerBound (0) != items.GetLowerBound (0))
1247 throw new ArgumentException ();
1249 if (index < keys.GetLowerBound (0))
1250 throw new ArgumentOutOfRangeException ("index");
1252 if (length < 0)
1253 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1254 "Value has to be >= 0."));
1256 if (keys.Length != items.Length || keys.Length - (index + keys.GetLowerBound (0)) < length)
1257 throw new ArgumentException ();
1259 SortImpl (keys, items, index, length, comparer);
1262 private static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
1264 if (length <= 1)
1265 return;
1267 if (comparer == null) {
1268 Swapper iswapper = (items != null ? get_swapper (items) : null);
1269 if (keys is double[]) {
1270 combsort (keys as double[], index, length, iswapper);
1271 return;
1273 if (keys is int[]) {
1274 combsort (keys as int[], index, length, iswapper);
1275 return;
1277 if (keys is char[]) {
1278 combsort (keys as char[], index, length, iswapper);
1279 return;
1283 int low = index;
1284 int high = index + length - 1;
1285 low = MoveNullKeysToFront (keys, items, low, high, comparer == null);
1286 if (low == high)
1287 return;
1289 try {
1290 qsort (keys, items, low, high, comparer);
1291 } catch (Exception e) {
1292 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1296 /* note, these are instance methods */
1297 void int_swapper (int i, int j) {
1298 int[] array = this as int[];
1299 int val = array [i];
1300 array [i] = array [j];
1301 array [j] = val;
1304 void obj_swapper (int i, int j) {
1305 object[] array = this as object[];
1306 object val = array [i];
1307 array [i] = array [j];
1308 array [j] = val;
1311 void slow_swapper (int i, int j) {
1312 object val = GetValueImpl (i);
1313 SetValueImpl (GetValue (j), i);
1314 SetValueImpl (val, j);
1317 void double_swapper (int i, int j) {
1318 double[] array = this as double[];
1319 double val = array [i];
1320 array [i] = array [j];
1321 array [j] = val;
1324 static int new_gap (int gap)
1326 gap = (gap * 10) / 13;
1327 if (gap == 9 || gap == 10)
1328 return 11;
1329 if (gap < 1)
1330 return 1;
1331 return gap;
1334 /* we use combsort because it's fast enough and very small, since we have
1335 * several specialized versions here.
1337 static void combsort (double[] array, int start, int size, Swapper swap_items)
1339 int gap = size;
1340 while (true) {
1341 gap = new_gap (gap);
1342 bool swapped = false;
1343 int end = start + size - gap;
1344 for (int i = start; i < end; i++) {
1345 int j = i + gap;
1346 if (array [i] > array [j]) {
1347 double val = array [i];
1348 array [i] = array [j];
1349 array [j] = val;
1350 swapped = true;
1351 if (swap_items != null)
1352 swap_items (i, j);
1355 if (gap == 1 && !swapped)
1356 break;
1360 static void combsort (int[] array, int start, int size, Swapper swap_items)
1362 int gap = size;
1363 while (true) {
1364 gap = new_gap (gap);
1365 bool swapped = false;
1366 int end = start + size - gap;
1367 for (int i = start; i < end; i++) {
1368 int j = i + gap;
1369 if (array [i] > array [j]) {
1370 int val = array [i];
1371 array [i] = array [j];
1372 array [j] = val;
1373 swapped = true;
1374 if (swap_items != null)
1375 swap_items (i, j);
1378 if (gap == 1 && !swapped)
1379 break;
1383 static void combsort (char[] array, int start, int size, Swapper swap_items)
1385 int gap = size;
1386 while (true) {
1387 gap = new_gap (gap);
1388 bool swapped = false;
1389 int end = start + size - gap;
1390 for (int i = start; i < end; i++) {
1391 int j = i + gap;
1392 if (array [i] > array [j]) {
1393 char val = array [i];
1394 array [i] = array [j];
1395 array [j] = val;
1396 swapped = true;
1397 if (swap_items != null)
1398 swap_items (i, j);
1401 if (gap == 1 && !swapped)
1402 break;
1406 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
1408 int low = low0;
1409 int high = high0;
1411 // Be careful with overflows
1412 int mid = low + ((high - low) / 2);
1413 object keyPivot = keys.GetValueImpl (mid);
1414 IComparable cmpPivot = keyPivot as IComparable;
1416 while (true) {
1417 // Move the walls in
1418 if (comparer != null) {
1419 while (low < high0 && comparer.Compare (keyPivot, keys.GetValueImpl (low)) > 0)
1420 ++low;
1421 while (high > low0 && comparer.Compare (keyPivot, keys.GetValueImpl (high)) < 0)
1422 --high;
1423 } else {
1424 while (low < high0 && cmpPivot.CompareTo (keys.GetValueImpl (low)) > 0)
1425 ++low;
1426 while (high > low0 && cmpPivot.CompareTo (keys.GetValueImpl (high)) < 0)
1427 --high;
1430 if (low <= high) {
1431 swap (keys, items, low, high);
1432 ++low;
1433 --high;
1434 } else
1435 break;
1438 if (low0 < high)
1439 qsort (keys, items, low0, high, comparer);
1440 if (low < high0)
1441 qsort (keys, items, low, high0, comparer);
1444 private static int MoveNullKeysToFront (Array keys, Array items, int low, int high, bool ensureComparable)
1446 // find first nun-null key
1447 while (low < high && keys.GetValueImpl (low) == null)
1448 low++;
1450 // move null keys to beginning of array,
1451 // ensure that non-null keys implement IComparable
1452 for (int i = low + 1; i <= high; i++) {
1453 object obj = keys.GetValueImpl (i);
1454 if (obj == null) {
1455 swap (keys, items, low, i);
1456 low++;
1457 } else {
1458 if (ensureComparable && !(obj is IComparable)) {
1459 string msg = Locale.GetText ("No IComparable interface found for type '{0}'.");
1460 throw new InvalidOperationException (String.Format (msg, obj.GetType ()));
1464 return low;
1467 private static void swap (Array keys, Array items, int i, int j)
1469 object tmp = keys.GetValueImpl (i);
1470 keys.SetValueImpl (keys.GetValueImpl (j), i);
1471 keys.SetValueImpl (tmp, j);
1473 if (items != null) {
1474 tmp = items.GetValueImpl (i);
1475 items.SetValueImpl (items.GetValueImpl (j), i);
1476 items.SetValueImpl (tmp, j);
1480 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1481 public static void Sort<T> (T [] array)
1483 Sort<T> (array, (IComparer<T>)null);
1486 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1487 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items)
1489 Sort<TKey, TValue> (keys, items, (IComparer<TKey>)null);
1492 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1493 public static void Sort<T> (T [] array, IComparer<T> comparer)
1495 if (array == null)
1496 throw new ArgumentNullException ("array");
1498 SortImpl<T, T> (array, null, 0, array.Length, comparer);
1501 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1502 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, IComparer<TKey> comparer)
1504 if (items == null) {
1505 Sort<TKey> (keys, comparer);
1506 return;
1509 if (keys == null)
1510 throw new ArgumentNullException ("keys");
1512 if (keys.Length != items.Length)
1513 throw new ArgumentException ("Length of keys and items does not match.");
1515 SortImpl<TKey, TValue> (keys, items, 0, keys.Length, comparer);
1518 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1519 public static void Sort<T> (T [] array, int index, int length)
1521 Sort<T> (array, index, length, (IComparer<T>)null);
1524 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1525 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length)
1527 Sort<TKey, TValue> (keys, items, index, length, (IComparer<TKey>)null);
1530 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1531 public static void Sort<T> (T [] array, int index, int length, IComparer<T> comparer)
1533 if (array == null)
1534 throw new ArgumentNullException ("array");
1536 if (index < 0)
1537 throw new ArgumentOutOfRangeException ("index");
1539 if (length < 0)
1540 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
1541 "Value has to be >= 0."));
1543 if (index + length > array.Length)
1544 throw new ArgumentException ();
1546 SortImpl<T, T> (array, null, index, length, comparer);
1549 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
1550 public static void Sort<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1552 if (items == null) {
1553 Sort<TKey> (keys, index, length, comparer);
1554 return;
1557 if (keys == null)
1558 throw new ArgumentNullException ("keys");
1560 if (index < 0)
1561 throw new ArgumentOutOfRangeException ("index");
1563 if (length < 0)
1564 throw new ArgumentOutOfRangeException ("length");
1566 if (keys.Length != items.Length || keys.Length - index < length)
1567 throw new ArgumentException ();
1569 SortImpl<TKey, TValue> (keys, items, index, length, comparer);
1572 private static void SortImpl<TKey, TValue> (TKey [] keys, TValue [] items, int index, int length, IComparer<TKey> comparer)
1574 if (keys.Length <= 1)
1575 return;
1578 // Check for value types which can be sorted without Compare () method
1580 if (comparer == null) {
1581 Swapper iswapper = (items != null ? get_swapper<TValue> (items) : null);
1582 if (keys is double[]) {
1583 combsort (keys as double[], index, length, iswapper);
1584 return;
1586 if (keys is int[]) {
1587 combsort (keys as int[], index, length, iswapper);
1588 return;
1590 if (keys is char[]) {
1591 combsort (keys as char[], index, length, iswapper);
1592 return;
1595 // Using Comparer<TKey> adds a small overload, but with value types it
1596 // helps us to not box them.
1597 if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
1598 typeof (TKey).IsValueType)
1599 comparer = Comparer<TKey>.Default;
1602 int low = index;
1603 int high = index + length - 1;
1604 low = MoveNullKeysToFront<TKey, TValue> (keys, items, low, high, comparer == null);
1605 if (low == high)
1606 return;
1608 try {
1609 qsort<TKey, TValue> (keys, items, low, high, comparer);
1610 } catch (Exception e) {
1611 throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
1615 public static void Sort<T> (T [] array, Comparison<T> comparison)
1617 if (array == null)
1618 throw new ArgumentNullException ("array");
1620 if (comparison == null)
1621 throw new ArgumentNullException ("comparison");
1623 SortImpl<T> (array, array.Length, comparison);
1626 // used by List<T>.Sort (Comparison <T>)
1627 internal static void SortImpl<T> (T [] array, int length, Comparison<T> comparison)
1629 if (length <= 1)
1630 return;
1632 try {
1633 int low0 = 0;
1634 int high0 = length - 1;
1635 qsort<T> (array, low0, high0, comparison);
1636 } catch (InvalidOperationException) {
1637 throw;
1638 } catch (Exception e) {
1639 throw new InvalidOperationException (Locale.GetText ("Comparison threw an exception."), e);
1643 private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
1645 int low = low0;
1646 int high = high0;
1648 // Be careful with overflows
1649 int mid = low + ((high - low) / 2);
1650 K keyPivot = keys [mid];
1651 IComparable<K> genCmpPivot = keyPivot as IComparable<K>;
1652 IComparable cmpPivot = keyPivot as IComparable;
1654 while (true) {
1655 // Move the walls in
1656 if (comparer != null) {
1657 while (low < high0 && comparer.Compare (keyPivot, keys [low]) > 0)
1658 ++low;
1659 while (high > low0 && comparer.Compare (keyPivot, keys [high]) < 0)
1660 --high;
1661 } else {
1662 if (genCmpPivot != null) {
1663 while (low < high0 && genCmpPivot.CompareTo (keys [low]) > 0)
1664 ++low;
1665 while (high > low0 && genCmpPivot.CompareTo (keys [high]) < 0)
1666 --high;
1667 } else {
1668 while (low < high0 && cmpPivot.CompareTo (keys [low]) > 0)
1669 ++low;
1670 while (high > low0 && cmpPivot.CompareTo (keys [high]) < 0)
1671 --high;
1675 if (low <= high) {
1676 swap<K, V> (keys, items, low, high);
1677 ++low;
1678 --high;
1679 } else
1680 break;
1683 if (low0 < high)
1684 qsort<K, V> (keys, items, low0, high, comparer);
1685 if (low < high0)
1686 qsort<K, V> (keys, items, low, high0, comparer);
1689 private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> comparison)
1691 int low = low0;
1692 int high = high0;
1694 // Be careful with overflows
1695 int mid = low + ((high - low) / 2);
1696 T keyPivot = array [mid];
1698 while (true) {
1699 // Move the walls in
1700 while (low < high0 && comparison (array [low], keyPivot) < 0)
1701 ++low;
1702 while (high > low0 && comparison (keyPivot, array [high]) < 0)
1703 --high;
1705 if (low <= high) {
1706 swap<T> (array, low, high);
1707 ++low;
1708 --high;
1709 } else
1710 break;
1713 if (low0 < high)
1714 qsort<T> (array, low0, high, comparison);
1715 if (low < high0)
1716 qsort<T> (array, low, high0, comparison);
1719 private static int MoveNullKeysToFront<K, V> (K [] keys, V [] items, int low, int high, bool ensureComparable)
1721 // find first nun-null key
1722 while (low < high && keys [low] == null)
1723 low++;
1725 // move null keys to beginning of array,
1726 // ensure that non-null keys implement IComparable
1727 for (int i = low + 1; i <= high; i++) {
1728 K key = keys [i];
1729 if (key == null) {
1730 swap<K, V> (keys, items, low, i);
1731 low++;
1732 } else {
1733 if (ensureComparable && !(key is IComparable<K>) && !(key is IComparable)) {
1734 string msg = Locale.GetText ("No IComparable<T> or IComparable interface found for type '{0}'.");
1735 throw new InvalidOperationException (String.Format (msg, key.GetType ()));
1739 return low;
1742 private static void swap<K, V> (K [] keys, V [] items, int i, int j)
1744 K tmp;
1746 tmp = keys [i];
1747 keys [i] = keys [j];
1748 keys [j] = tmp;
1750 if (items != null) {
1751 V itmp;
1752 itmp = items [i];
1753 items [i] = items [j];
1754 items [j] = itmp;
1758 private static void swap<T> (T [] array, int i, int j)
1760 T tmp = array [i];
1761 array [i] = array [j];
1762 array [j] = tmp;
1765 public void CopyTo (Array array, int index)
1767 if (array == null)
1768 throw new ArgumentNullException ("array");
1770 // The order of these exception checks may look strange,
1771 // but that's how the microsoft runtime does it.
1772 if (this.Rank > 1)
1773 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1774 if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
1775 throw new ArgumentException ("Destination array was not long " +
1776 "enough. Check destIndex and length, and the array's " +
1777 "lower bounds.");
1778 if (array.Rank > 1)
1779 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
1780 if (index < 0)
1781 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1782 "Value has to be >= 0."));
1784 Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
1787 [ComVisible (false)]
1788 public void CopyTo (Array array, long index)
1790 if (index < 0 || index > Int32.MaxValue)
1791 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
1792 "Value must be >= 0 and <= Int32.MaxValue."));
1794 CopyTo (array, (int) index);
1797 internal class SimpleEnumerator : IEnumerator, ICloneable
1799 Array enumeratee;
1800 int currentpos;
1801 int length;
1803 public SimpleEnumerator (Array arrayToEnumerate)
1805 this.enumeratee = arrayToEnumerate;
1806 this.currentpos = -1;
1807 this.length = arrayToEnumerate.Length;
1810 public object Current {
1811 get {
1812 // Exception messages based on MS implementation
1813 if (currentpos < 0 )
1814 throw new InvalidOperationException (Locale.GetText (
1815 "Enumeration has not started."));
1816 if (currentpos >= length)
1817 throw new InvalidOperationException (Locale.GetText (
1818 "Enumeration has already ended"));
1819 // Current should not increase the position. So no ++ over here.
1820 return enumeratee.GetValueImpl (currentpos);
1824 public bool MoveNext()
1826 //The docs say Current should throw an exception if last
1827 //call to MoveNext returned false. This means currentpos
1828 //should be set to length when returning false.
1829 if (currentpos < length)
1830 currentpos++;
1831 if(currentpos < length)
1832 return true;
1833 else
1834 return false;
1837 public void Reset()
1839 currentpos = -1;
1842 public object Clone ()
1844 return MemberwiseClone ();
1848 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1849 public static void Resize<T> (ref T [] array, int newSize)
1851 Resize<T> (ref array, array == null ? 0 : array.Length, newSize);
1854 internal static void Resize<T> (ref T[] array, int length, int newSize)
1856 if (newSize < 0)
1857 throw new ArgumentOutOfRangeException ();
1859 if (array == null) {
1860 array = new T [newSize];
1861 return;
1864 if (array.Length == newSize)
1865 return;
1867 T [] a = new T [newSize];
1868 Array.Copy (array, a, Math.Min (newSize, length));
1869 array = a;
1872 public static bool TrueForAll <T> (T [] array, Predicate <T> match)
1874 if (array == null)
1875 throw new ArgumentNullException ("array");
1876 if (match == null)
1877 throw new ArgumentNullException ("match");
1879 foreach (T t in array)
1880 if (! match (t))
1881 return false;
1883 return true;
1886 public static void ForEach<T> (T [] array, Action <T> action)
1888 if (array == null)
1889 throw new ArgumentNullException ("array");
1890 if (action == null)
1891 throw new ArgumentNullException ("action");
1893 foreach (T t in array)
1894 action (t);
1897 public static TOutput[] ConvertAll<TInput, TOutput> (TInput [] array, Converter<TInput, TOutput> converter)
1899 if (array == null)
1900 throw new ArgumentNullException ("array");
1901 if (converter == null)
1902 throw new ArgumentNullException ("converter");
1904 TOutput [] output = new TOutput [array.Length];
1905 for (int i = 0; i < array.Length; i ++)
1906 output [i] = converter (array [i]);
1908 return output;
1911 public static int FindLastIndex<T> (T [] array, Predicate <T> match)
1913 if (array == null)
1914 throw new ArgumentNullException ("array");
1916 return FindLastIndex<T> (array, 0, array.Length, match);
1919 public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
1921 if (array == null)
1922 throw new ArgumentNullException ();
1924 return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
1927 public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
1929 if (array == null)
1930 throw new ArgumentNullException ("array");
1931 if (match == null)
1932 throw new ArgumentNullException ("match");
1934 if (startIndex > array.Length || startIndex + count > array.Length)
1935 throw new ArgumentOutOfRangeException ();
1937 for (int i = startIndex + count - 1; i >= startIndex; i--)
1938 if (match (array [i]))
1939 return i;
1941 return -1;
1944 public static int FindIndex<T> (T [] array, Predicate<T> match)
1946 if (array == null)
1947 throw new ArgumentNullException ("array");
1949 return FindIndex<T> (array, 0, array.Length, match);
1952 public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
1954 if (array == null)
1955 throw new ArgumentNullException ("array");
1957 return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
1960 public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
1962 if (array == null)
1963 throw new ArgumentNullException ("array");
1965 if (match == null)
1966 throw new ArgumentNullException ("match");
1968 if (startIndex > array.Length || startIndex + count > array.Length)
1969 throw new ArgumentOutOfRangeException ();
1971 for (int i = startIndex; i < startIndex + count; i ++)
1972 if (match (array [i]))
1973 return i;
1975 return -1;
1978 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1979 public static int BinarySearch<T> (T [] array, T value)
1981 if (array == null)
1982 throw new ArgumentNullException ("array");
1984 return BinarySearch<T> (array, 0, array.Length, value, null);
1987 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1988 public static int BinarySearch<T> (T [] array, T value, IComparer<T> comparer)
1990 if (array == null)
1991 throw new ArgumentNullException ("array");
1993 return BinarySearch<T> (array, 0, array.Length, value, comparer);
1996 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
1997 public static int BinarySearch<T> (T [] array, int index, int length, T value)
1999 return BinarySearch<T> (array, index, length, value, null);
2002 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
2003 public static int BinarySearch<T> (T [] array, int index, int length, T value, IComparer<T> comparer)
2005 if (array == null)
2006 throw new ArgumentNullException ("array");
2007 if (index < 0)
2008 throw new ArgumentOutOfRangeException ("index", Locale.GetText (
2009 "index is less than the lower bound of array."));
2010 if (length < 0)
2011 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
2012 "Value has to be >= 0."));
2013 // re-ordered to avoid possible integer overflow
2014 if (index > array.Length - length)
2015 throw new ArgumentException (Locale.GetText (
2016 "index and length do not specify a valid range in array."));
2017 if (comparer == null)
2018 comparer = Comparer <T>.Default;
2020 int iMin = index;
2021 int iMax = index + length - 1;
2022 int iCmp = 0;
2023 try {
2024 while (iMin <= iMax) {
2025 // Be careful with overflows
2026 int iMid = iMin + ((iMax - iMin) / 2);
2027 iCmp = comparer.Compare (value, array [iMid]);
2029 if (iCmp == 0)
2030 return iMid;
2031 else if (iCmp < 0)
2032 iMax = iMid - 1;
2033 else
2034 iMin = iMid + 1; // compensate for the rounding down
2036 } catch (Exception e) {
2037 throw new InvalidOperationException (Locale.GetText ("Comparer threw an exception."), e);
2040 return ~iMin;
2043 public static int IndexOf<T> (T [] array, T value)
2045 if (array == null)
2046 throw new ArgumentNullException ("array");
2048 return IndexOf<T> (array, value, 0, array.Length);
2051 public static int IndexOf<T> (T [] array, T value, int startIndex)
2053 if (array == null)
2054 throw new ArgumentNullException ("array");
2056 return IndexOf<T> (array, value, startIndex, array.Length - startIndex);
2059 public static int IndexOf<T> (T [] array, T value, int startIndex, int count)
2061 if (array == null)
2062 throw new ArgumentNullException ("array");
2064 // re-ordered to avoid possible integer overflow
2065 if (count < 0 || startIndex < array.GetLowerBound (0) || startIndex - 1 > array.GetUpperBound (0) - count)
2066 throw new ArgumentOutOfRangeException ();
2068 int max = startIndex + count;
2069 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
2070 for (int i = startIndex; i < max; i++) {
2071 if (equalityComparer.Equals (array [i], value))
2072 return i;
2075 return -1;
2078 public static int LastIndexOf<T> (T [] array, T value)
2080 if (array == null)
2081 throw new ArgumentNullException ("array");
2083 if (array.Length == 0)
2084 return -1;
2085 return LastIndexOf<T> (array, value, array.Length - 1);
2088 public static int LastIndexOf<T> (T [] array, T value, int startIndex)
2090 if (array == null)
2091 throw new ArgumentNullException ("array");
2093 return LastIndexOf<T> (array, value, startIndex, startIndex + 1);
2096 public static int LastIndexOf<T> (T [] array, T value, int startIndex, int count)
2098 if (array == null)
2099 throw new ArgumentNullException ("array");
2101 if (count < 0 || startIndex < array.GetLowerBound (0) ||
2102 startIndex > array.GetUpperBound (0) || startIndex - count + 1 < array.GetLowerBound (0))
2103 throw new ArgumentOutOfRangeException ();
2105 EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
2106 for (int i = startIndex; i >= startIndex - count + 1; i--) {
2107 if (equalityComparer.Equals (array [i], value))
2108 return i;
2111 return -1;
2114 public static T [] FindAll<T> (T [] array, Predicate <T> match)
2116 if (array == null)
2117 throw new ArgumentNullException ("array");
2119 if (match == null)
2120 throw new ArgumentNullException ("match");
2122 int pos = 0;
2123 T [] d = new T [array.Length];
2124 foreach (T t in array)
2125 if (match (t))
2126 d [pos++] = t;
2128 Resize <T> (ref d, pos);
2129 return d;
2132 public static bool Exists<T> (T [] array, Predicate <T> match)
2134 if (array == null)
2135 throw new ArgumentNullException ("array");
2137 if (match == null)
2138 throw new ArgumentNullException ("match");
2140 foreach (T t in array)
2141 if (match (t))
2142 return true;
2143 return false;
2146 public static ReadOnlyCollection<T> AsReadOnly<T> (T[] array)
2148 if (array == null)
2149 throw new ArgumentNullException ("array");
2150 return new ReadOnlyCollection<T> (new ArrayReadOnlyList<T> (array));
2153 public static T Find<T> (T [] array, Predicate<T> match)
2155 if (array == null)
2156 throw new ArgumentNullException ("array");
2158 if (match == null)
2159 throw new ArgumentNullException ("match");
2161 foreach (T t in array)
2162 if (match (t))
2163 return t;
2165 return default (T);
2168 public static T FindLast<T> (T [] array, Predicate <T> match)
2170 if (array == null)
2171 throw new ArgumentNullException ("array");
2173 if (match == null)
2174 throw new ArgumentNullException ("match");
2176 for (int i = array.Length - 1; i >= 0; i--)
2177 if (match (array [i]))
2178 return array [i];
2180 return default (T);
2183 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
2185 // The constrained copy should guarantee that if there is an exception thrown
2186 // during the copy, the destination array remains unchanged.
2187 // This is related to System.Runtime.Reliability.CER
2188 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
2190 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
2193 class ArrayReadOnlyList<T> : IList<T>
2195 T [] array;
2197 public ArrayReadOnlyList (T [] array)
2199 this.array = array;
2202 public T this [int index] {
2203 get {
2204 if (unchecked ((uint) index) >= unchecked ((uint) array.Length))
2205 throw new ArgumentOutOfRangeException ("index");
2206 return array [index];
2208 set { throw ReadOnlyError (); }
2211 public int Count {
2212 get { return array.Length; }
2215 public bool IsReadOnly {
2216 get { return true; }
2219 public void Add (T item)
2221 throw ReadOnlyError ();
2224 public void Clear ()
2226 throw ReadOnlyError ();
2229 public bool Contains (T item)
2231 return Array.IndexOf<T> (array, item) >= 0;
2234 public void CopyTo (T [] array, int index)
2236 array.CopyTo (array, index);
2239 IEnumerator IEnumerable.GetEnumerator ()
2241 return GetEnumerator ();
2244 public IEnumerator<T> GetEnumerator ()
2246 for (int i = 0; i < array.Length; i++)
2247 yield return array [i];
2250 public int IndexOf (T item)
2252 return Array.IndexOf<T> (array, item);
2255 public void Insert (int index, T item)
2257 throw ReadOnlyError ();
2260 public bool Remove (T item)
2262 throw ReadOnlyError ();
2265 public void RemoveAt (int index)
2267 throw ReadOnlyError ();
2270 static Exception ReadOnlyError ()
2272 return new NotSupportedException ("This collection is read-only.");