diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2017-04-13 14:17:19 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2017-04-13 14:17:19 +0900 |
commit | a56e30c8d33048216567753d9d3fefc2152af8ac (patch) | |
tree | 7e5d979695fc4a431740982eb1cfecc2898b23a5 /src/mscorlib/src/System/ArraySegment.cs | |
parent | 4b11dc566a5bbfa1378d6266525c281b028abcc8 (diff) | |
download | coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.tar.gz coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.tar.bz2 coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.zip |
Imported Upstream version 2.0.0.11353upstream/2.0.0.11353
Diffstat (limited to 'src/mscorlib/src/System/ArraySegment.cs')
-rw-r--r-- | src/mscorlib/src/System/ArraySegment.cs | 178 |
1 files changed, 106 insertions, 72 deletions
diff --git a/src/mscorlib/src/System/ArraySegment.cs b/src/mscorlib/src/System/ArraySegment.cs index 03556e492a..a18590d5d8 100644 --- a/src/mscorlib/src/System/ArraySegment.cs +++ b/src/mscorlib/src/System/ArraySegment.cs @@ -15,6 +15,7 @@ using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Contracts; namespace System @@ -27,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; @@ -45,8 +50,9 @@ namespace System public ArraySegment(T[] array, int offset, int count) { // Validate arguments, check is minimal instructions with reduced branching for inlinable fast-path + // Negative values discovered though conversion to high values when converted to unsigned // Failure should be rare and location determination and message is delegated to failure functions - if (array == null || (offset | count) < 0 || (array.Length - offset < count)) + if (array == null || (uint)offset > (uint)array.Length || (uint)count > (uint)(array.Length - offset)) ThrowHelper.ThrowArraySegmentCtorValidationFailedExceptions(array, offset, count); Contract.EndContractBlock(); @@ -55,62 +61,37 @@ namespace System _count = count; } - public T[] Array - { - get - { - Debug.Assert( (null == _array && 0 == _offset && 0 == _count) - || (null != _array && _offset >= 0 && _count >= 0 && _offset + _count <= _array.Length), - "ArraySegment is invalid"); + public T[] Array => _array; - return _array; - } - } + public int Offset => _offset; - public int Offset + public int Count => _count; + + public T this[int index] { get { - // Since copying value types is not atomic & callers cannot atomically - // read all three fields, we cannot guarantee that Offset is within - // the bounds of Array. That is our intent, but let's not specify - // it as a postcondition - force callers to re-verify this themselves - // after reading each field out of an ArraySegment into their stack. - Contract.Ensures(Contract.Result<int>() >= 0); - - Debug.Assert( (null == _array && 0 == _offset && 0 == _count) - || (null != _array && _offset >= 0 && _count >= 0 && _offset + _count <= _array.Length), - "ArraySegment is invalid"); - - return _offset; - } - } + if ((uint)index >= (uint)_count) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index); + } - public int Count - { - get + return _array[_offset + index]; + } + set { - // Since copying value types is not atomic & callers cannot atomically - // read all three fields, we cannot guarantee that Count is within - // the bounds of Array. That's our intent, but let's not specify - // it as a postcondition - force callers to re-verify this themselves - // after reading each field out of an ArraySegment into their stack. - Contract.Ensures(Contract.Result<int>() >= 0); - - Debug.Assert( (null == _array && 0 == _offset && 0 == _count) - || (null != _array && _offset >= 0 && _count >= 0 && _offset + _count <= _array.Length), - "ArraySegment is invalid"); - - return _count; + if ((uint)index >= (uint)_count) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index); + } + + _array[_offset + index] = value; } } public Enumerator GetEnumerator() { - if (_array == null) - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NullArray); - Contract.EndContractBlock(); - + ThrowInvalidOperationIfDefault(); return new Enumerator(this); } @@ -120,17 +101,38 @@ namespace System { return 0; } - + int hash = 5381; hash = System.Numerics.Hashing.HashHelpers.Combine(hash, _offset); hash = System.Numerics.Hashing.HashHelpers.Combine(hash, _count); - + // The array hash is expected to be an evenly-distributed mixture of bits, // so rather than adding the cost of another rotation we just xor it. hash ^= _array.GetHashCode(); 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>) @@ -138,30 +140,69 @@ namespace System else return false; } - + public bool Equals(ArraySegment<T> obj) { 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); } - + public static bool operator !=(ArraySegment<T> a, ArraySegment<T> b) { 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); - if (index < 0 || index >= _count) + ThrowInvalidOperationIfDefault(); + if (index < 0 || index >= _count) ThrowHelper.ThrowArgumentOutOfRange_IndexException(); Contract.EndContractBlock(); @@ -170,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(); @@ -182,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); @@ -210,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(); @@ -244,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); @@ -256,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(); @@ -282,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> { |