5 // Joe Shaw (joe@ximian.com)
6 // Martin Baulig (martin@gnome.org)
7 // Dietmar Maurer (dietmar@ximian.com)
8 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // Jeffrey Stedfast (fejj@novell.com)
10 // Marek Safar (marek.safar@gmail.com)
12 // (C) 2001-2003 Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004-2011 Novell, Inc (http://www.novell.com)
14 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
40 using System.Collections.Generic;
41 using System.Collections.ObjectModel;
42 using System.Runtime.ConstrainedExecution;
46 public abstract partial class 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 ()
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 of a fixed size");
84 internal bool InternalArray__ICollection_Remove<T> (T item)
86 throw new NotSupportedException ("Collection is of a fixed size");
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);
106 if (item.Equals (value)) {
114 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int arrayIndex)
116 Copy (this, GetLowerBound (0), array, arrayIndex, Length);
119 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
121 if (unchecked ((uint) index) >= unchecked ((uint) Length))
122 throw new ArgumentOutOfRangeException ("index");
125 GetGenericValueImpl (index, out value);
129 internal int InternalArray__IReadOnlyCollection_get_Count ()
134 internal void InternalArray__Insert<T> (int index, T item)
136 throw new NotSupportedException ("Collection is of a fixed size");
139 internal void InternalArray__RemoveAt (int index)
141 throw new NotSupportedException ("Collection is of a fixed size");
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);
159 if (value.Equals (item))
160 // array index may not be zero-based.
162 return i + this.GetLowerBound (0);
166 // lower bound may be MinValue
167 return this.GetLowerBound (0) - 1;
171 internal T InternalArray__get_Item<T> (int index)
173 if (unchecked ((uint) index) >= unchecked ((uint) Length))
174 throw new ArgumentOutOfRangeException ("index");
177 GetGenericValueImpl (index, out value);
181 internal void InternalArray__set_Item<T> (int index, T item)
183 if (unchecked ((uint) index) >= unchecked ((uint) Length))
184 throw new ArgumentOutOfRangeException ("index");
186 object[] oarray = this as object [];
187 if (oarray != null) {
188 oarray [index] = (object)item;
191 SetGenericValueImpl (index, ref item);
194 // CAUTION! No bounds checking!
195 [MethodImplAttribute (MethodImplOptions.InternalCall)]
196 internal extern void GetGenericValueImpl<T> (int pos, out T value);
198 // CAUTION! No bounds checking!
199 [MethodImplAttribute (MethodImplOptions.InternalCall)]
200 internal extern void SetGenericValueImpl<T> (int pos, ref T value);
202 internal struct InternalEnumerator<T> : IEnumerator<T>
204 const int NOT_STARTED = -2;
206 // this MUST be -1, because we depend on it in move next.
207 // we just decr the size, so, 0 - 1 == FINISHED
208 const int FINISHED = -1;
213 internal InternalEnumerator (Array array)
219 public void Dispose ()
224 public bool MoveNext ()
226 if (idx == NOT_STARTED)
229 return idx != FINISHED && -- idx != FINISHED;
234 if (idx == NOT_STARTED)
235 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
237 throw new InvalidOperationException ("Enumeration already finished");
239 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
243 void IEnumerator.Reset ()
248 object IEnumerator.Current {
257 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
259 int length = this.GetLength (0);
261 for (int i = 1; i < this.Rank; i++) {
262 length *= this.GetLength (i);
269 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
271 return this.GetRank ();
275 // InternalCall Methods
276 [MethodImplAttribute (MethodImplOptions.InternalCall)]
277 extern int GetRank ();
279 [MethodImplAttribute (MethodImplOptions.InternalCall)]
280 public extern int GetLength (int dimension);
282 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
283 [MethodImplAttribute (MethodImplOptions.InternalCall)]
284 public extern int GetLowerBound (int dimension);
286 [MethodImplAttribute (MethodImplOptions.InternalCall)]
287 public extern object GetValue (params int[] indices);
289 [MethodImplAttribute (MethodImplOptions.InternalCall)]
290 public extern void SetValue (object value, params int[] indices);
292 // CAUTION! No bounds checking!
293 [MethodImplAttribute (MethodImplOptions.InternalCall)]
294 internal extern object GetValueImpl (int pos);
296 // CAUTION! No bounds checking!
297 [MethodImplAttribute (MethodImplOptions.InternalCall)]
298 internal extern void SetValueImpl (object value, int pos);
300 [MethodImplAttribute (MethodImplOptions.InternalCall)]
301 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
303 [MethodImplAttribute (MethodImplOptions.InternalCall)]
304 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
306 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
307 public int GetUpperBound (int dimension)
309 return GetLowerBound (dimension) + GetLength (dimension) - 1;
312 public object GetValue (int index)
315 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
316 if (index < GetLowerBound (0) || index > GetUpperBound (0))
317 throw new IndexOutOfRangeException (Locale.GetText (
318 "Index has to be between upper and lower bound of the array."));
320 return GetValueImpl (index - GetLowerBound (0));
323 public object GetValue (int index1, int index2)
325 int[] ind = {index1, index2};
326 return GetValue (ind);
329 public object GetValue (int index1, int index2, int index3)
331 int[] ind = {index1, index2, index3};
332 return GetValue (ind);
335 public void SetValue (object value, int index)
338 throw new ArgumentException (Locale.GetText ("Array was not a one-dimensional array."));
339 if (index < GetLowerBound (0) || index > GetUpperBound (0))
340 throw new IndexOutOfRangeException (Locale.GetText (
341 "Index has to be >= lower bound and <= upper bound of the array."));
343 SetValueImpl (value, index - GetLowerBound (0));
346 public void SetValue (object value, int index1, int index2)
348 int[] ind = {index1, index2};
349 SetValue (value, ind);
352 public void SetValue (object value, int index1, int index2, int index3)
354 int[] ind = {index1, index2, index3};
355 SetValue (value, ind);
358 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
360 return CreateInstance(elementType, lengths, lowerBounds);
363 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
365 return CreateInstance (elementType, length1, length2);
368 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
370 return CreateInstance(elementType, lengths);
373 public static Array CreateInstance (Type elementType, int length)
375 int[] lengths = {length};
377 return CreateInstance (elementType, lengths);
380 public static Array CreateInstance (Type elementType, int length1, int length2)
382 int[] lengths = {length1, length2};
384 return CreateInstance (elementType, lengths);
387 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
389 int[] lengths = {length1, length2, length3};
391 return CreateInstance (elementType, lengths);
394 public static Array CreateInstance (Type elementType, params int[] lengths)
396 if (elementType == null)
397 throw new ArgumentNullException ("elementType");
399 throw new ArgumentNullException ("lengths");
401 if (lengths.Length > 255)
402 throw new TypeLoadException ();
406 elementType = elementType.UnderlyingSystemType as RuntimeType;
407 if (elementType == null)
408 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
409 if (elementType.Equals (typeof (void)))
410 throw new NotSupportedException ("Array type can not be void");
411 if (elementType.ContainsGenericParameters)
412 throw new NotSupportedException ("Array type can not be an open generic type");
414 return CreateInstanceImpl (elementType, lengths, bounds);
417 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
419 if (elementType == null)
420 throw new ArgumentNullException ("elementType");
422 throw new ArgumentNullException ("lengths");
423 if (lowerBounds == null)
424 throw new ArgumentNullException ("lowerBounds");
426 elementType = elementType.UnderlyingSystemType as RuntimeType;
427 if (elementType == null)
428 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
429 if (elementType.Equals (typeof (void)))
430 throw new NotSupportedException ("Array type can not be void");
431 if (elementType.ContainsGenericParameters)
432 throw new NotSupportedException ("Array type can not be an open generic type");
434 if (lengths.Length < 1)
435 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
437 if (lengths.Length != lowerBounds.Length)
438 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
440 for (int j = 0; j < lowerBounds.Length; j ++) {
442 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
443 "Each value has to be >= 0."));
444 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
445 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
446 "Length + bound must not exceed Int32.MaxValue."));
449 if (lengths.Length > 255)
450 throw new TypeLoadException ();
452 return CreateInstanceImpl (elementType, lengths, lowerBounds);
455 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
456 public static void Clear (Array array, int index, int length)
459 throw new ArgumentNullException ("array");
461 throw new IndexOutOfRangeException ("length < 0");
463 int low = array.GetLowerBound (0);
465 throw new IndexOutOfRangeException ("index < lower bound");
468 // re-ordered to avoid possible integer overflow
469 if (index > array.Length - length)
470 throw new IndexOutOfRangeException ("index + length > size");
472 ClearInternal (array, index, length);
475 [MethodImplAttribute (MethodImplOptions.InternalCall)]
476 static extern void ClearInternal (Array a, int index, int count);
478 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
479 public static void Copy (Array sourceArray, Array destinationArray, int length)
481 // need these checks here because we are going to use
482 // GetLowerBound() on source and dest.
483 if (sourceArray == null)
484 throw new ArgumentNullException ("sourceArray");
486 if (destinationArray == null)
487 throw new ArgumentNullException ("destinationArray");
489 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
490 destinationArray.GetLowerBound (0), length);
493 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
494 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
496 if (sourceArray == null)
497 throw new ArgumentNullException ("sourceArray");
499 if (destinationArray == null)
500 throw new ArgumentNullException ("destinationArray");
503 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
504 "Value has to be >= 0."));;
506 if (sourceArray.Rank != destinationArray.Rank)
507 throw new RankException(SR.Rank_MultiDimNotSupported);
510 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
511 "Value has to be >= 0."));;
513 if (destinationIndex < 0)
514 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
515 "Value has to be >= 0."));;
517 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
520 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
521 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
524 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
526 // re-ordered to avoid possible integer overflow
527 if (source_pos > sourceArray.Length - length)
528 throw new ArgumentException ("length");
530 if (dest_pos > destinationArray.Length - length) {
531 string msg = "Destination array was not long enough. Check " +
532 "destIndex and length, and the array's lower bounds";
533 throw new ArgumentException (msg, string.Empty);
536 Type src_type = sourceArray.GetType ().GetElementType ();
537 Type dst_type = destinationArray.GetType ().GetElementType ();
539 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
540 for (int i = 0; i < length; i++) {
541 Object srcval = sourceArray.GetValueImpl (source_pos + i);
544 destinationArray.SetValueImpl (srcval, dest_pos + i);
545 } catch (ArgumentException) {
546 throw CreateArrayTypeMismatchException ();
548 if (CanAssignArrayElement (src_type, dst_type))
551 throw CreateArrayTypeMismatchException ();
556 for (int i = length - 1; i >= 0; i--) {
557 Object srcval = sourceArray.GetValueImpl (source_pos + i);
560 destinationArray.SetValueImpl (srcval, dest_pos + i);
561 } catch (ArgumentException) {
562 throw CreateArrayTypeMismatchException ();
564 if (CanAssignArrayElement (src_type, dst_type))
567 throw CreateArrayTypeMismatchException ();
573 static Exception CreateArrayTypeMismatchException ()
575 return new ArrayTypeMismatchException ();
578 static bool CanAssignArrayElement (Type source, Type target)
580 if (source.IsValueType)
581 return source.IsAssignableFrom (target);
583 if (source.IsInterface)
584 return !target.IsValueType;
586 if (target.IsInterface)
587 return !source.IsValueType;
589 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
592 public static T[] FindAll<T> (T[] array, Predicate<T> match)
595 throw new ArgumentNullException ("array");
598 throw new ArgumentNullException ("match");
602 for (int i = 0; i < array.Length; i++) {
603 if (match (array [i])) {
605 Resize (ref d, pos == 0 ? 4 : pos * 2);
607 d [pos++] = array [i];
617 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
619 // The constrained copy should guarantee that if there is an exception thrown
620 // during the copy, the destination array remains unchanged.
621 // This is related to System.Runtime.Reliability.CER
622 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
624 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
627 object GetValueWithFlattenedIndex_NoErrorCheck (int flattenedIndex)
629 return GetValueImpl (flattenedIndex);
632 #region Unsafe array operations
635 // Loads array index with no safety checks (JIT intristics)
637 internal static T UnsafeLoad<T> (T[] array, int index) {
638 return array [index];
642 // Stores values at specified array index with no safety checks (JIT intristics)
644 internal static void UnsafeStore<T> (T[] array, int index, T value) {
645 array [index] = value;
649 // Moved value from instance into target of different type with no checks (JIT intristics)
653 // S and R must either:
654 // both be blitable valuetypes
655 // both be reference types (IOW, an unsafe cast)
656 // S and R cannot be float or double
657 // S and R must either:
660 // S and R must either:
662 // both be a scalar of size <= 4
664 internal static R UnsafeMov<S,R> (S instance) {
665 return (R)(object) instance;
670 internal sealed class FunctorComparer<T> : IComparer<T> {
671 Comparison<T> comparison;
673 public FunctorComparer(Comparison<T> comparison) {
674 this.comparison = comparison;
677 public int Compare(T x, T y) {
678 return comparison(x, y);