Implement slicing APIs for ArraySegment<T> (dotnet/coreclr#9926)
authorJames Ko <jamesqko@gmail.com>
Mon, 10 Apr 2017 17:26:12 +0000 (13:26 -0400)
committerJan Kotas <jkotas@microsoft.com>
Mon, 10 Apr 2017 17:26:12 +0000 (10:26 -0700)
Commit migrated from https://github.com/dotnet/coreclr/commit/40ecbb723552407044b57edaf3e5a1408bf99aab

src/coreclr/src/mscorlib/src/System/ArraySegment.cs

index e0118c2..a18590d 100644 (file)
@@ -28,6 +28,10 @@ namespace System
     [Serializable]
     public struct ArraySegment<T> : IList<T>, IReadOnlyList<T>
     {
+        // Do not replace the array allocation with Array.Empty. We don't want to have the overhead of
+        // instantiating another generic type in addition to ArraySegment<T> for new type parameters.
+        public static ArraySegment<T> Empty { get; } = new ArraySegment<T>(new T[0]);
+
         private readonly T[] _array;
         private readonly int _offset;
         private readonly int _count;
@@ -63,12 +67,31 @@ namespace System
 
         public int Count => _count;
 
-        public Enumerator GetEnumerator()
+        public T this[int index]
         {
-            if (_array == null)
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
-            Contract.EndContractBlock();
+            get
+            {
+                if ((uint)index >= (uint)_count)
+                {
+                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
+                }
 
+                return _array[_offset + index];
+            }
+            set
+            {
+                if ((uint)index >= (uint)_count)
+                {
+                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
+                }
+
+                _array[_offset + index] = value;
+            }
+        }
+
+        public Enumerator GetEnumerator()
+        {
+            ThrowInvalidOperationIfDefault();
             return new Enumerator(this);
         }
 
@@ -89,6 +112,27 @@ namespace System
             return hash;
         }
 
+        public void CopyTo(T[] destination) => CopyTo(destination, 0);
+
+        public void CopyTo(T[] destination, int destinationIndex)
+        {
+            ThrowInvalidOperationIfDefault();
+            System.Array.Copy(_array, _offset, destination, destinationIndex, _count);
+        }
+
+        public void CopyTo(ArraySegment<T> destination)
+        {
+            ThrowInvalidOperationIfDefault();
+            destination.ThrowInvalidOperationIfDefault();
+
+            if (_count > destination._count)
+            {
+                ThrowHelper.ThrowArgumentException_DestinationTooShort();
+            }
+
+            System.Array.Copy(_array, _offset, destination._array, destination._offset, _count);
+        }
+
         public override bool Equals(Object obj)
         {
             if (obj is ArraySegment<T>)
@@ -102,6 +146,44 @@ namespace System
             return obj._array == _array && obj._offset == _offset && obj._count == _count;
         }
 
+        public ArraySegment<T> Slice(int index)
+        {
+            ThrowInvalidOperationIfDefault();
+            
+            if ((uint)index > (uint)_count)
+            {
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
+            }
+
+            return new ArraySegment<T>(_array, _offset + index, _count - index);
+        }
+
+        public ArraySegment<T> Slice(int index, int count)
+        {
+            ThrowInvalidOperationIfDefault();
+
+            if ((uint)index > (uint)_count || (uint)count > (uint)(_count - index))
+            {
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
+            }
+
+            return new ArraySegment<T>(_array, _offset + index, count);
+        }
+
+        public T[] ToArray()
+        {
+            ThrowInvalidOperationIfDefault();
+
+            if (_count == 0)
+            {
+                return Empty._array;
+            }
+
+            var array = new T[_count];
+            System.Array.Copy(_array, _offset, array, 0, _count);
+            return array;
+        }
+
         public static bool operator ==(ArraySegment<T> a, ArraySegment<T> b)
         {
             return a.Equals(b);
@@ -112,13 +194,14 @@ namespace System
             return !(a == b);
         }
 
+        public static implicit operator ArraySegment<T>(T[] array) => new ArraySegment<T>(array);
+
         #region IList<T>
         T IList<T>.this[int index]
         {
             get
             {
-                if (_array == null)
-                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
+                ThrowInvalidOperationIfDefault();
                 if (index < 0 || index >= _count)
                     ThrowHelper.ThrowArgumentOutOfRange_IndexException();
                 Contract.EndContractBlock();
@@ -128,8 +211,7 @@ namespace System
 
             set
             {
-                if (_array == null)
-                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
+                ThrowInvalidOperationIfDefault();
                 if (index < 0 || index >= _count)
                     ThrowHelper.ThrowArgumentOutOfRange_IndexException();
                 Contract.EndContractBlock();
@@ -140,9 +222,7 @@ namespace System
 
         int IList<T>.IndexOf(T item)
         {
-            if (_array == null)
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
-            Contract.EndContractBlock();
+            ThrowInvalidOperationIfDefault();
 
             int index = System.Array.IndexOf<T>(_array, item, _offset, _count);
 
@@ -168,8 +248,7 @@ namespace System
         {
             get
             {
-                if (_array == null)
-                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
+                ThrowInvalidOperationIfDefault();
                 if (index < 0 || index >= _count)
                     ThrowHelper.ThrowArgumentOutOfRange_IndexException();
                 Contract.EndContractBlock();
@@ -202,9 +281,7 @@ namespace System
 
         bool ICollection<T>.Contains(T item)
         {
-            if (_array == null)
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
-            Contract.EndContractBlock();
+            ThrowInvalidOperationIfDefault();
 
             int index = System.Array.IndexOf<T>(_array, item, _offset, _count);
 
@@ -214,15 +291,6 @@ namespace System
             return index >= 0;
         }
 
-        void ICollection<T>.CopyTo(T[] array, int arrayIndex)
-        {
-            if (_array == null)
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
-            Contract.EndContractBlock();
-
-            System.Array.Copy(_array, _offset, array, arrayIndex, _count);
-        }
-
         bool ICollection<T>.Remove(T item)
         {
             ThrowHelper.ThrowNotSupportedException();
@@ -240,6 +308,14 @@ namespace System
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
         #endregion
 
+        private void ThrowInvalidOperationIfDefault()
+        {
+            if (_array == null)
+            {
+                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray);
+            }
+        }
+
         [Serializable]
         public struct Enumerator : IEnumerator<T>
         {