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> ()
72 return EmptyInternalEnumerator<T>.Value;
74 return new InternalEnumerator<T> (this);
77 internal void InternalArray__ICollection_Clear ()
79 throw new NotSupportedException ("Collection is read-only");
82 internal void InternalArray__ICollection_Add<T> (T item)
84 throw new NotSupportedException ("Collection is of a fixed size");
87 internal bool InternalArray__ICollection_Remove<T> (T item)
89 throw new NotSupportedException ("Collection is of a fixed size");
92 internal bool InternalArray__ICollection_Contains<T> (T item)
95 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
97 int length = this.Length;
98 for (int i = 0; i < length; i++) {
100 GetGenericValueImpl (i, out value);
109 if (item.Equals (value)) {
117 internal void InternalArray__ICollection_CopyTo<T> (T[] array, int arrayIndex)
119 Copy (this, GetLowerBound (0), array, arrayIndex, Length);
122 internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
124 if (unchecked ((uint) index) >= unchecked ((uint) Length))
125 throw new ArgumentOutOfRangeException ("index");
128 GetGenericValueImpl (index, out value);
132 internal int InternalArray__IReadOnlyCollection_get_Count ()
137 internal void InternalArray__Insert<T> (int index, T item)
139 throw new NotSupportedException ("Collection is of a fixed size");
142 internal void InternalArray__RemoveAt (int index)
144 throw new NotSupportedException ("Collection is of a fixed size");
147 internal int InternalArray__IndexOf<T> (T item)
150 throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
152 int length = this.Length;
153 for (int i = 0; i < length; i++) {
155 GetGenericValueImpl (i, out value);
158 return i + this.GetLowerBound (0);
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;
213 readonly Array array;
216 internal InternalEnumerator (Array array)
222 public void Dispose ()
226 public bool MoveNext ()
228 if (idx == NOT_STARTED)
231 return idx != FINISHED && -- idx != FINISHED;
236 if (idx == NOT_STARTED)
237 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
239 throw new InvalidOperationException ("Enumeration already finished");
241 return array.InternalArray__get_Item<T> (array.Length - 1 - idx);
245 void IEnumerator.Reset ()
250 object IEnumerator.Current {
259 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
261 int length = this.GetLength (0);
263 for (int i = 1; i < this.Rank; i++) {
264 length *= this.GetLength (i);
271 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
273 return this.GetRank ();
277 internal class EmptyInternalEnumerator<T> : IEnumerator<T>
279 public static readonly EmptyInternalEnumerator<T> Value = new EmptyInternalEnumerator<T> ();
281 public void Dispose ()
286 public bool MoveNext ()
293 throw new InvalidOperationException ("Enumeration has not started. Call MoveNext");
297 object IEnumerator.Current {
303 void IEnumerator.Reset ()
309 // InternalCall Methods
310 [MethodImplAttribute (MethodImplOptions.InternalCall)]
311 extern int GetRank ();
313 [MethodImplAttribute (MethodImplOptions.InternalCall)]
314 public extern int GetLength (int dimension);
316 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
317 [MethodImplAttribute (MethodImplOptions.InternalCall)]
318 public extern int GetLowerBound (int dimension);
320 [MethodImplAttribute (MethodImplOptions.InternalCall)]
321 public extern object GetValue (params int[] indices);
323 [MethodImplAttribute (MethodImplOptions.InternalCall)]
324 public extern void SetValue (object value, params int[] indices);
326 // CAUTION! No bounds checking!
327 [MethodImplAttribute (MethodImplOptions.InternalCall)]
328 internal extern object GetValueImpl (int pos);
330 // CAUTION! No bounds checking!
331 [MethodImplAttribute (MethodImplOptions.InternalCall)]
332 internal extern void SetValueImpl (object value, int pos);
334 [MethodImplAttribute (MethodImplOptions.InternalCall)]
335 internal extern static bool FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);
337 [MethodImplAttribute (MethodImplOptions.InternalCall)]
338 internal extern static Array CreateInstanceImpl (Type elementType, int[] lengths, int[] bounds);
340 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
341 public int GetUpperBound (int dimension)
343 return GetLowerBound (dimension) + GetLength (dimension) - 1;
346 public object GetValue (int index)
349 throw new ArgumentException (SR.Arg_RankMultiDimNotSupported);
351 var lb = GetLowerBound (0);
352 if (index < lb || index > GetUpperBound (0))
353 throw new IndexOutOfRangeException (Locale.GetText (
354 "Index has to be between upper and lower bound of the array."));
356 if (GetType ().GetElementType ().IsPointer)
357 throw new NotSupportedException ("Type is not supported");
359 return GetValueImpl (index - lb);
362 public object GetValue (int index1, int index2)
364 int[] ind = {index1, index2};
365 return GetValue (ind);
368 public object GetValue (int index1, int index2, int index3)
370 int[] ind = {index1, index2, index3};
371 return GetValue (ind);
374 public void SetValue (object value, int index)
377 throw new ArgumentException (SR.Arg_RankMultiDimNotSupported);
379 var lb = GetLowerBound (0);
380 if (index < lb || index > GetUpperBound (0))
381 throw new IndexOutOfRangeException (Locale.GetText (
382 "Index has to be >= lower bound and <= upper bound of the array."));
384 if (GetType ().GetElementType ().IsPointer)
385 throw new NotSupportedException ("Type is not supported");
387 SetValueImpl (value, index - lb);
390 public void SetValue (object value, int index1, int index2)
392 int[] ind = {index1, index2};
393 SetValue (value, ind);
396 public void SetValue (object value, int index1, int index2, int index3)
398 int[] ind = {index1, index2, index3};
399 SetValue (value, ind);
402 internal static Array UnsafeCreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
404 return CreateInstance(elementType, lengths, lowerBounds);
407 internal static Array UnsafeCreateInstance (Type elementType, int length1, int length2)
409 return CreateInstance (elementType, length1, length2);
412 internal static Array UnsafeCreateInstance (Type elementType, params int[] lengths)
414 return CreateInstance(elementType, lengths);
417 public static Array CreateInstance (Type elementType, int length)
419 int[] lengths = {length};
421 return CreateInstance (elementType, lengths);
424 public static Array CreateInstance (Type elementType, int length1, int length2)
426 int[] lengths = {length1, length2};
428 return CreateInstance (elementType, lengths);
431 public static Array CreateInstance (Type elementType, int length1, int length2, int length3)
433 int[] lengths = {length1, length2, length3};
435 return CreateInstance (elementType, lengths);
438 public static Array CreateInstance (Type elementType, params int[] lengths)
440 if (elementType == null)
441 throw new ArgumentNullException ("elementType");
443 throw new ArgumentNullException ("lengths");
445 if (lengths.Length > 255)
446 throw new TypeLoadException ();
450 elementType = elementType.UnderlyingSystemType as RuntimeType;
451 if (elementType == null)
452 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
453 if (elementType.Equals (typeof (void)))
454 throw new NotSupportedException ("Array type can not be void");
455 if (elementType.ContainsGenericParameters)
456 throw new NotSupportedException ("Array type can not be an open generic type");
458 return CreateInstanceImpl (elementType, lengths, bounds);
461 public static Array CreateInstance (Type elementType, int[] lengths, int [] lowerBounds)
463 if (elementType == null)
464 throw new ArgumentNullException ("elementType");
466 throw new ArgumentNullException ("lengths");
467 if (lowerBounds == null)
468 throw new ArgumentNullException ("lowerBounds");
470 elementType = elementType.UnderlyingSystemType as RuntimeType;
471 if (elementType == null)
472 throw new ArgumentException ("Type must be a type provided by the runtime.", "elementType");
473 if (elementType.Equals (typeof (void)))
474 throw new NotSupportedException ("Array type can not be void");
475 if (elementType.ContainsGenericParameters)
476 throw new NotSupportedException ("Array type can not be an open generic type");
478 if (lengths.Length < 1)
479 throw new ArgumentException (Locale.GetText ("Arrays must contain >= 1 elements."));
481 if (lengths.Length != lowerBounds.Length)
482 throw new ArgumentException (Locale.GetText ("Arrays must be of same size."));
484 for (int j = 0; j < lowerBounds.Length; j ++) {
486 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
487 "Each value has to be >= 0."));
488 if ((long)lowerBounds [j] + (long)lengths [j] > (long)Int32.MaxValue)
489 throw new ArgumentOutOfRangeException ("lengths", Locale.GetText (
490 "Length + bound must not exceed Int32.MaxValue."));
493 if (lengths.Length > 255)
494 throw new TypeLoadException ();
496 return CreateInstanceImpl (elementType, lengths, lowerBounds);
499 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
500 public static void Clear (Array array, int index, int length)
503 throw new ArgumentNullException ("array");
505 throw new IndexOutOfRangeException ("length < 0");
507 int low = array.GetLowerBound (0);
509 throw new IndexOutOfRangeException ("index < lower bound");
512 // re-ordered to avoid possible integer overflow
513 if (index > array.Length - length)
514 throw new IndexOutOfRangeException ("index + length > size");
516 ClearInternal (array, index, length);
519 [MethodImplAttribute (MethodImplOptions.InternalCall)]
520 static extern void ClearInternal (Array a, int index, int count);
522 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
523 public static void Copy (Array sourceArray, Array destinationArray, int length)
525 // need these checks here because we are going to use
526 // GetLowerBound() on source and dest.
527 if (sourceArray == null)
528 throw new ArgumentNullException ("sourceArray");
530 if (destinationArray == null)
531 throw new ArgumentNullException ("destinationArray");
533 Copy (sourceArray, sourceArray.GetLowerBound (0), destinationArray,
534 destinationArray.GetLowerBound (0), length);
537 [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
538 public static void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
540 if (sourceArray == null)
541 throw new ArgumentNullException ("sourceArray");
543 if (destinationArray == null)
544 throw new ArgumentNullException ("destinationArray");
547 throw new ArgumentOutOfRangeException ("length", Locale.GetText (
548 "Value has to be >= 0."));;
550 if (sourceArray.Rank != destinationArray.Rank)
551 throw new RankException(SR.Rank_MultiDimNotSupported);
554 throw new ArgumentOutOfRangeException ("sourceIndex", Locale.GetText (
555 "Value has to be >= 0."));;
557 if (destinationIndex < 0)
558 throw new ArgumentOutOfRangeException ("destinationIndex", Locale.GetText (
559 "Value has to be >= 0."));;
561 if (FastCopy (sourceArray, sourceIndex, destinationArray, destinationIndex, length))
564 int source_pos = sourceIndex - sourceArray.GetLowerBound (0);
565 int dest_pos = destinationIndex - destinationArray.GetLowerBound (0);
568 throw new ArgumentOutOfRangeException ("destinationIndex", "Index was less than the array's lower bound in the first dimension.");
570 // re-ordered to avoid possible integer overflow
571 if (source_pos > sourceArray.Length - length)
572 throw new ArgumentException ("length");
574 if (dest_pos > destinationArray.Length - length) {
575 string msg = "Destination array was not long enough. Check " +
576 "destIndex and length, and the array's lower bounds";
577 throw new ArgumentException (msg, string.Empty);
580 Type src_type = sourceArray.GetType ().GetElementType ();
581 Type dst_type = destinationArray.GetType ().GetElementType ();
583 if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) {
584 for (int i = 0; i < length; i++) {
585 Object srcval = sourceArray.GetValueImpl (source_pos + i);
588 destinationArray.SetValueImpl (srcval, dest_pos + i);
589 } catch (ArgumentException) {
590 throw CreateArrayTypeMismatchException ();
592 if (CanAssignArrayElement (src_type, dst_type))
595 throw CreateArrayTypeMismatchException ();
600 for (int i = length - 1; i >= 0; i--) {
601 Object srcval = sourceArray.GetValueImpl (source_pos + i);
604 destinationArray.SetValueImpl (srcval, dest_pos + i);
605 } catch (ArgumentException) {
606 throw CreateArrayTypeMismatchException ();
608 if (CanAssignArrayElement (src_type, dst_type))
611 throw CreateArrayTypeMismatchException ();
617 static Exception CreateArrayTypeMismatchException ()
619 return new ArrayTypeMismatchException ();
622 static bool CanAssignArrayElement (Type source, Type target)
624 if (source.IsValueType)
625 return source.IsAssignableFrom (target);
627 if (source.IsInterface)
628 return !target.IsValueType;
630 if (target.IsInterface)
631 return !source.IsValueType;
633 return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
636 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
638 // The constrained copy should guarantee that if there is an exception thrown
639 // during the copy, the destination array remains unchanged.
640 // This is related to System.Runtime.Reliability.CER
641 public static void ConstrainedCopy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
643 Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
646 public static T[] Empty<T>()
648 return EmptyArray<T>.Value;
651 public void Initialize()
656 static int IndexOfImpl<T>(T[] array, T value, int startIndex, int count)
658 return EqualityComparer<T>.Default.IndexOf (array, value, startIndex, count);
661 static int LastIndexOfImpl<T>(T[] array, T value, int startIndex, int count)
663 return EqualityComparer<T>.Default.LastIndexOf (array, value, startIndex, count);
666 static void SortImpl (Array keys, Array items, int index, int length, IComparer comparer)
668 Object[] objKeys = keys as Object[];
669 Object[] objItems = null;
671 objItems = items as Object[];
673 if (objKeys != null && (items == null || objItems != null)) {
674 SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
675 sorter.Sort(index, length);
677 SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
678 sorter.Sort(index, length);
682 #region Unsafe array operations
685 // Loads array index with no safety checks (JIT intristics)
687 internal static T UnsafeLoad<T> (T[] array, int index) {
688 return array [index];
692 // Stores values at specified array index with no safety checks (JIT intristics)
694 internal static void UnsafeStore<T> (T[] array, int index, T value) {
695 array [index] = value;
699 // Moved value from instance into target of different type with no checks (JIT intristics)
703 // S and R must either:
704 // both be blitable valuetypes
705 // both be reference types (IOW, an unsafe cast)
706 // S and R cannot be float or double
707 // S and R must either:
710 // S and R must either:
712 // both be a scalar of size <= 4
714 internal static R UnsafeMov<S,R> (S instance) {
715 return (R)(object) instance;
720 internal sealed class FunctorComparer<T> : IComparer<T> {
721 Comparison<T> comparison;
723 public FunctorComparer(Comparison<T> comparison) {
724 this.comparison = comparison;
727 public int Compare(T x, T y) {
728 return comparison(x, y);
732 partial class ArrayEnumerator
734 public Object Current {
736 if (_index < 0) throw new InvalidOperationException (SR.InvalidOperation_EnumNotStarted);
737 if (_index >= _endIndex) throw new InvalidOperationException (SR.InvalidOperation_EnumEnded);
738 if (_index == 0 && _array.GetType ().GetElementType ().IsPointer) throw new NotSupportedException ("Type is not supported");
739 return _array.GetValueImpl(_index);