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)
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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
;
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
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 ()
64 internal bool InternalArray__ICollection_get_IsReadOnly ()
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
)
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
++) {
97 GetGenericValueImpl (i
, out value);
105 if (item
.Equals (value))
112 internal void InternalArray__ICollection_CopyTo
<T
> (T
[] array
, int index
)
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.
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 " +
126 throw new RankException (Locale
.GetText ("Only single dimension arrays are supported."));
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
)
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
++) {
152 GetGenericValueImpl (i
, out value);
155 return i
+ this.GetLowerBound (0);
158 return this.GetLowerBound (0) - 1;
162 if (value.Equals (item
))
163 // array index may not be zero-based.
165 return i
+ this.GetLowerBound (0);
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");
180 GetGenericValueImpl (index
, out 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
;
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;
216 internal InternalEnumerator (Array array
)
222 public void Dispose ()
227 public bool MoveNext ()
229 if (idx
== NOT_STARTED
)
232 return idx
!= FINISHED
&& -- idx
!= FINISHED
;
237 if (idx
== NOT_STARTED
)
238 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
240 throw new InvalidOperationException ("Enumeration already finished");
242 return array
.InternalArray__get_Item
<T
> (array
.Length
- 1 - idx
);
246 void IEnumerator
.Reset ()
251 object IEnumerator
.Current
{
260 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
262 int length
= this.GetLength (0);
264 for (int i
= 1; i
< this.Rank
; i
++) {
265 length
*= this.GetLength (i
);
272 public long LongLength
{
273 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
274 get { return Length; }
278 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
280 return this.GetRank ();
285 object IList
.this [int index
] {
287 if (unchecked ((uint) index
) >= unchecked ((uint) Length
))
288 throw new IndexOutOfRangeException ("index");
289 return GetValueImpl (index
);
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 ();
305 Array
.Clear (this, this.GetLowerBound (0), this.Length
);
308 bool IList
.Contains (object value)
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))
321 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
322 int IList
.IndexOf (object value)
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.
332 return i
+ this.GetLowerBound (0);
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
);
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
);
394 int ICollection
.Count
{
400 public bool IsSynchronized
{
406 public object SyncRoot
{
412 public bool IsFixedSize
{
418 public bool IsReadOnly
{
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
)
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
);
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
);
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
);
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
);
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
);
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
);
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
)
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");
593 throw new ArgumentNullException ("lengths");
595 if (lengths
.Length
> 255)
596 throw new TypeLoadException ();
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");
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
++) {
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
;
660 public static Array
CreateInstance (Type elementType
, params long [] lengths
)
663 throw new ArgumentNullException ("lengths");
664 return CreateInstance (elementType
, GetIntArray (lengths
));
668 public object GetValue (params long [] indices
)
671 throw new ArgumentNullException ("indices");
672 return GetValue (GetIntArray (indices
));
676 public void SetValue (object value, params long [] indices
)
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)
687 throw new ArgumentNullException ("array");
693 throw new RankException (Locale
.GetText ("Only single dimension arrays are supported."));
695 if (array
.Length
== 0)
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
)
708 throw new ArgumentNullException ("array");
711 throw new RankException (Locale
.GetText ("Only single dimension arrays are supported."));
713 if (array
.Length
== 0)
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)
727 throw new ArgumentNullException ("array");
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."));
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)
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
)
757 throw new ArgumentNullException ("array");
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."));
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)
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
;
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;
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);
808 iMin
= iMid
+ 1; // compensate for the rounding down
811 catch (Exception e
) {
812 throw new InvalidOperationException (Locale
.GetText ("Comparer threw an exception."), e
);
818 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
819 public static void Clear (Array array
, int index
, int length
)
822 throw new ArgumentNullException ("array");
824 throw new ArgumentOutOfRangeException ("length < 0");
826 int low
= array
.GetLowerBound (0);
828 throw new IndexOutOfRangeException ("index < lower bound");
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");
869 throw new ArgumentOutOfRangeException ("length", Locale
.GetText (
870 "Value has to be >= 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
))
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
);
907 destinationArray
.SetValueImpl (srcval
, dest_pos
+ i
);
909 if (src_type
.Equals (typeof (Object
)))
910 throw new InvalidCastException ();
912 throw new ArrayTypeMismatchException (String
.Format (Locale
.GetText (
913 "(Types: source={0}; target={1})"), src_type
.FullName
, dst_type
.FullName
));
918 for (int i
= length
- 1; i
>= 0; i
--) {
919 Object srcval
= sourceArray
.GetValueImpl (source_pos
+ i
);
922 destinationArray
.SetValueImpl (srcval
, dest_pos
+ i
);
924 if (src_type
.Equals (typeof (Object
)))
925 throw new InvalidCastException ();
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)
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
)
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
)
991 throw new ArgumentNullException ("array");
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))
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)
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
)
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
)
1040 throw new ArgumentNullException ("array");
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)
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))
1062 /* delegate used to swap array elements */
1063 delegate void Swapper (int i
, int j
);
1065 static Swapper
get_swapper (Array array
)
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
)
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
)
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
)
1102 throw new ArgumentNullException ("array");
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
];
1126 int[] iarray
= array
as int[];
1127 if (iarray
!= null) {
1128 while (index
< end
) {
1129 int tmp
= iarray
[index
];
1130 iarray
[index
] = iarray
[end
];
1137 double[] darray
= array
as double[];
1138 if (darray
!= null) {
1139 while (index
< end
) {
1140 double tmp
= darray
[index
];
1141 darray
[index
] = darray
[end
];
1149 Swapper swapper
= get_swapper (array
);
1150 while (index
< end
) {
1151 swapper (index
, 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
)
1173 throw new ArgumentNullException ("array");
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
);
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
)
1214 throw new ArgumentNullException ("array");
1217 throw new RankException (Locale
.GetText ("Only single dimension arrays are supported."));
1219 if (index
< array
.GetLowerBound (0))
1220 throw new ArgumentOutOfRangeException ("index");
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
);
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");
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
)
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
);
1273 if (keys
is int[]) {
1274 combsort (keys
as int[], index
, length
, iswapper
);
1277 if (keys
is char[]) {
1278 combsort (keys
as char[], index
, length
, iswapper
);
1284 int high
= index
+ length
- 1;
1285 low
= MoveNullKeysToFront (keys
, items
, low
, high
, comparer
== null);
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
];
1304 void obj_swapper (int i
, int j
) {
1305 object[] array
= this as object[];
1306 object val
= array
[i
];
1307 array
[i
] = array
[j
];
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
];
1324 static int new_gap (int gap
)
1326 gap
= (gap
* 10) / 13;
1327 if (gap
== 9 || gap
== 10)
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
)
1341 gap
= new_gap (gap
);
1342 bool swapped
= false;
1343 int end
= start
+ size
- gap
;
1344 for (int i
= start
; i
< end
; i
++) {
1346 if (array
[i
] > array
[j
]) {
1347 double val
= array
[i
];
1348 array
[i
] = array
[j
];
1351 if (swap_items
!= null)
1355 if (gap
== 1 && !swapped
)
1360 static void combsort (int[] array
, int start
, int size
, Swapper swap_items
)
1364 gap
= new_gap (gap
);
1365 bool swapped
= false;
1366 int end
= start
+ size
- gap
;
1367 for (int i
= start
; i
< end
; i
++) {
1369 if (array
[i
] > array
[j
]) {
1370 int val
= array
[i
];
1371 array
[i
] = array
[j
];
1374 if (swap_items
!= null)
1378 if (gap
== 1 && !swapped
)
1383 static void combsort (char[] array
, int start
, int size
, Swapper swap_items
)
1387 gap
= new_gap (gap
);
1388 bool swapped
= false;
1389 int end
= start
+ size
- gap
;
1390 for (int i
= start
; i
< end
; i
++) {
1392 if (array
[i
] > array
[j
]) {
1393 char val
= array
[i
];
1394 array
[i
] = array
[j
];
1397 if (swap_items
!= null)
1401 if (gap
== 1 && !swapped
)
1406 private static void qsort (Array keys
, Array items
, int low0
, int high0
, IComparer comparer
)
1411 // Be careful with overflows
1412 int mid
= low
+ ((high
- low
) / 2);
1413 object keyPivot
= keys
.GetValueImpl (mid
);
1414 IComparable cmpPivot
= keyPivot
as IComparable
;
1417 // Move the walls in
1418 if (comparer
!= null) {
1419 while (low
< high0
&& comparer
.Compare (keyPivot
, keys
.GetValueImpl (low
)) > 0)
1421 while (high
> low0
&& comparer
.Compare (keyPivot
, keys
.GetValueImpl (high
)) < 0)
1424 while (low
< high0
&& cmpPivot
.CompareTo (keys
.GetValueImpl (low
)) > 0)
1426 while (high
> low0
&& cmpPivot
.CompareTo (keys
.GetValueImpl (high
)) < 0)
1431 swap (keys
, items
, low
, high
);
1439 qsort (keys
, items
, low0
, high
, comparer
);
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)
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
);
1455 swap (keys
, items
, low
, i
);
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 ()));
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
)
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
);
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
)
1534 throw new ArgumentNullException ("array");
1537 throw new ArgumentOutOfRangeException ("index");
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
);
1558 throw new ArgumentNullException ("keys");
1561 throw new ArgumentOutOfRangeException ("index");
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)
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
);
1586 if (keys
is int[]) {
1587 combsort (keys
as int[], index
, length
, iswapper
);
1590 if (keys
is char[]) {
1591 combsort (keys
as char[], index
, length
, iswapper
);
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
;
1603 int high
= index
+ length
- 1;
1604 low
= MoveNullKeysToFront
<TKey
, TValue
> (keys
, items
, low
, high
, comparer
== null);
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
)
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
)
1634 int high0
= length
- 1;
1635 qsort
<T
> (array
, low0
, high0
, comparison
);
1636 } catch (InvalidOperationException
) {
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
)
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
;
1655 // Move the walls in
1656 if (comparer
!= null) {
1657 while (low
< high0
&& comparer
.Compare (keyPivot
, keys
[low
]) > 0)
1659 while (high
> low0
&& comparer
.Compare (keyPivot
, keys
[high
]) < 0)
1662 if (genCmpPivot
!= null) {
1663 while (low
< high0
&& genCmpPivot
.CompareTo (keys
[low
]) > 0)
1665 while (high
> low0
&& genCmpPivot
.CompareTo (keys
[high
]) < 0)
1668 while (low
< high0
&& cmpPivot
.CompareTo (keys
[low
]) > 0)
1670 while (high
> low0
&& cmpPivot
.CompareTo (keys
[high
]) < 0)
1676 swap
<K
, V
> (keys
, items
, low
, high
);
1684 qsort
<K
, V
> (keys
, items
, low0
, high
, comparer
);
1686 qsort
<K
, V
> (keys
, items
, low
, high0
, comparer
);
1689 private static void qsort
<T
> (T
[] array
, int low0
, int high0
, Comparison
<T
> comparison
)
1694 // Be careful with overflows
1695 int mid
= low
+ ((high
- low
) / 2);
1696 T keyPivot
= array
[mid
];
1699 // Move the walls in
1700 while (low
< high0
&& comparison (array
[low
], keyPivot
) < 0)
1702 while (high
> low0
&& comparison (keyPivot
, array
[high
]) < 0)
1706 swap
<T
> (array
, low
, high
);
1714 qsort
<T
> (array
, low0
, high
, comparison
);
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)
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
++) {
1730 swap
<K
, V
> (keys
, items
, low
, i
);
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 ()));
1742 private static void swap
<K
, V
> (K
[] keys
, V
[] items
, int i
, int j
)
1747 keys
[i
] = keys
[j
];
1750 if (items
!= null) {
1753 items
[i
] = items
[j
];
1758 private static void swap
<T
> (T
[] array
, int i
, int j
)
1761 array
[i
] = array
[j
];
1765 public void CopyTo (Array array
, int index
)
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.
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 " +
1779 throw new RankException (Locale
.GetText ("Only single dimension arrays are supported."));
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
1803 public SimpleEnumerator (Array arrayToEnumerate
)
1805 this.enumeratee
= arrayToEnumerate
;
1806 this.currentpos
= -1;
1807 this.length
= arrayToEnumerate
.Length
;
1810 public object Current
{
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
)
1831 if(currentpos
< length
)
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
)
1857 throw new ArgumentOutOfRangeException ();
1859 if (array
== null) {
1860 array
= new T
[newSize
];
1864 if (array
.Length
== newSize
)
1867 T
[] a
= new T
[newSize
];
1868 Array
.Copy (array
, a
, Math
.Min (newSize
, length
));
1872 public static bool TrueForAll
<T
> (T
[] array
, Predicate
<T
> match
)
1875 throw new ArgumentNullException ("array");
1877 throw new ArgumentNullException ("match");
1879 foreach (T t
in array
)
1886 public static void ForEach
<T
> (T
[] array
, Action
<T
> action
)
1889 throw new ArgumentNullException ("array");
1891 throw new ArgumentNullException ("action");
1893 foreach (T t
in array
)
1897 public static TOutput
[] ConvertAll
<TInput
, TOutput
> (TInput
[] array
, Converter
<TInput
, TOutput
> converter
)
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
]);
1911 public static int FindLastIndex
<T
> (T
[] array
, Predicate
<T
> match
)
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
)
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
)
1930 throw new ArgumentNullException ("array");
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
]))
1944 public static int FindIndex
<T
> (T
[] array
, Predicate
<T
> match
)
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
)
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
)
1963 throw new ArgumentNullException ("array");
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
]))
1978 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
1979 public static int BinarySearch
<T
> (T
[] array
, T
value)
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
)
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
)
2006 throw new ArgumentNullException ("array");
2008 throw new ArgumentOutOfRangeException ("index", Locale
.GetText (
2009 "index is less than the lower bound of array."));
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
;
2021 int iMax
= index
+ length
- 1;
2024 while (iMin
<= iMax
) {
2025 // Be careful with overflows
2026 int iMid
= iMin
+ ((iMax
- iMin
) / 2);
2027 iCmp
= comparer
.Compare (value, array
[iMid
]);
2034 iMin
= iMid
+ 1; // compensate for the rounding down
2036 } catch (Exception e
) {
2037 throw new InvalidOperationException (Locale
.GetText ("Comparer threw an exception."), e
);
2043 public static int IndexOf
<T
> (T
[] array
, T
value)
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
)
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
)
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))
2078 public static int LastIndexOf
<T
> (T
[] array
, T
value)
2081 throw new ArgumentNullException ("array");
2083 if (array
.Length
== 0)
2085 return LastIndexOf
<T
> (array
, value, array
.Length
- 1);
2088 public static int LastIndexOf
<T
> (T
[] array
, T
value, int startIndex
)
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
)
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))
2114 public static T
[] FindAll
<T
> (T
[] array
, Predicate
<T
> match
)
2117 throw new ArgumentNullException ("array");
2120 throw new ArgumentNullException ("match");
2123 T
[] d
= new T
[array
.Length
];
2124 foreach (T t
in array
)
2128 Resize
<T
> (ref d
, pos
);
2132 public static bool Exists
<T
> (T
[] array
, Predicate
<T
> match
)
2135 throw new ArgumentNullException ("array");
2138 throw new ArgumentNullException ("match");
2140 foreach (T t
in array
)
2146 public static ReadOnlyCollection
<T
> AsReadOnly
<T
> (T
[] array
)
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
)
2156 throw new ArgumentNullException ("array");
2159 throw new ArgumentNullException ("match");
2161 foreach (T t
in array
)
2168 public static T FindLast
<T
> (T
[] array
, Predicate
<T
> match
)
2171 throw new ArgumentNullException ("array");
2174 throw new ArgumentNullException ("match");
2176 for (int i
= array
.Length
- 1; i
>= 0; i
--)
2177 if (match (array
[i
]))
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
>
2197 public ArrayReadOnlyList (T
[] array
)
2202 public T
this [int index
] {
2204 if (unchecked ((uint) index
) >= unchecked ((uint) array
.Length
))
2205 throw new ArgumentOutOfRangeException ("index");
2206 return array
[index
];
2208 set { throw ReadOnlyError (); }
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.");