You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
343
mcs/class/referencesource/mscorlib/system/arraysegment.cs
Normal file
343
mcs/class/referencesource/mscorlib/system/arraysegment.cs
Normal file
@ -0,0 +1,343 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Class: ArraySegment<T>
|
||||
**
|
||||
**
|
||||
** Purpose: Convenient wrapper for an array, an offset, and
|
||||
** a count. Ideally used in streams & collections.
|
||||
** Net Classes will consume an array of these.
|
||||
**
|
||||
**
|
||||
===========================================================*/
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace System
|
||||
{
|
||||
// Note: users should make sure they copy the fields out of an ArraySegment onto their stack
|
||||
// then validate that the fields describe valid bounds within the array. This must be done
|
||||
// because assignments to value types are not atomic, and also because one thread reading
|
||||
// three fields from an ArraySegment may not see the same ArraySegment from one call to another
|
||||
// (ie, users could assign a new value to the old location).
|
||||
[Serializable]
|
||||
public struct ArraySegment<T> : IList<T>, IReadOnlyList<T>
|
||||
{
|
||||
private T[] _array;
|
||||
private int _offset;
|
||||
private int _count;
|
||||
|
||||
public ArraySegment(T[] array)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
_array = array;
|
||||
_offset = 0;
|
||||
_count = array.Length;
|
||||
}
|
||||
|
||||
public ArraySegment(T[] array, int offset, int count)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
|
||||
if (array.Length - offset < count)
|
||||
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
_array = array;
|
||||
_offset = offset;
|
||||
_count = count;
|
||||
}
|
||||
|
||||
public T[] Array
|
||||
{
|
||||
get
|
||||
{
|
||||
Contract.Assert( (null == _array && 0 == _offset && 0 == _count)
|
||||
|| (null != _array && _offset >= 0 && _count >= 0 && _offset + _count <= _array.Length),
|
||||
"ArraySegment is invalid");
|
||||
|
||||
return _array;
|
||||
}
|
||||
}
|
||||
|
||||
public int Offset
|
||||
{
|
||||
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);
|
||||
|
||||
Contract.Assert( (null == _array && 0 == _offset && 0 == _count)
|
||||
|| (null != _array && _offset >= 0 && _count >= 0 && _offset + _count <= _array.Length),
|
||||
"ArraySegment is invalid");
|
||||
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
// 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);
|
||||
|
||||
Contract.Assert( (null == _array && 0 == _offset && 0 == _count)
|
||||
|| (null != _array && _offset >= 0 && _count >= 0 && _offset + _count <= _array.Length),
|
||||
"ArraySegment is invalid");
|
||||
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return null == _array
|
||||
? 0
|
||||
: _array.GetHashCode() ^ _offset ^ _count;
|
||||
}
|
||||
|
||||
public override bool Equals(Object obj)
|
||||
{
|
||||
if (obj is ArraySegment<T>)
|
||||
return Equals((ArraySegment<T>)obj);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(ArraySegment<T> obj)
|
||||
{
|
||||
return obj._array == _array && obj._offset == _offset && obj._count == _count;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#region IList<T>
|
||||
T IList<T>.this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
if (index < 0 || index >= _count)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
return _array[_offset + index];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
if (index < 0 || index >= _count)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
_array[_offset + index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
int IList<T>.IndexOf(T item)
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
int index = System.Array.IndexOf<T>(_array, item, _offset, _count);
|
||||
|
||||
Contract.Assert(index == -1 ||
|
||||
(index >= _offset && index < _offset + _count));
|
||||
|
||||
return index >= 0 ? index - _offset : -1;
|
||||
}
|
||||
|
||||
void IList<T>.Insert(int index, T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
void IList<T>.RemoveAt(int index)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IReadOnlyList<T>
|
||||
T IReadOnlyList<T>.this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
if (index < 0 || index >= _count)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
Contract.EndContractBlock();
|
||||
|
||||
return _array[_offset + index];
|
||||
}
|
||||
}
|
||||
#endregion IReadOnlyList<T>
|
||||
|
||||
#region ICollection<T>
|
||||
bool ICollection<T>.IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
// the indexer setter does not throw an exception although IsReadOnly is true.
|
||||
// This is to match the behavior of arrays.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection<T>.Add(T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
void ICollection<T>.Clear()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
bool ICollection<T>.Contains(T item)
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
int index = System.Array.IndexOf<T>(_array, item, _offset, _count);
|
||||
|
||||
Contract.Assert(index == -1 ||
|
||||
(index >= _offset && index < _offset + _count));
|
||||
|
||||
return index >= 0;
|
||||
}
|
||||
|
||||
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
System.Array.Copy(_array, _offset, array, arrayIndex, _count);
|
||||
}
|
||||
|
||||
bool ICollection<T>.Remove(T item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<T>
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
return new ArraySegmentEnumerator(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
if (_array == null)
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullArray"));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
return new ArraySegmentEnumerator(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Serializable]
|
||||
private sealed class ArraySegmentEnumerator : IEnumerator<T>
|
||||
{
|
||||
private T[] _array;
|
||||
private int _start;
|
||||
private int _end;
|
||||
private int _current;
|
||||
|
||||
internal ArraySegmentEnumerator(ArraySegment<T> arraySegment)
|
||||
{
|
||||
Contract.Requires(arraySegment.Array != null);
|
||||
Contract.Requires(arraySegment.Offset >= 0);
|
||||
Contract.Requires(arraySegment.Count >= 0);
|
||||
Contract.Requires(arraySegment.Offset + arraySegment.Count <= arraySegment.Array.Length);
|
||||
|
||||
_array = arraySegment._array;
|
||||
_start = arraySegment._offset;
|
||||
_end = _start + arraySegment._count;
|
||||
_current = _start - 1;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_current < _end)
|
||||
{
|
||||
_current++;
|
||||
return (_current < _end);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_current < _start) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
|
||||
if (_current >= _end) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
|
||||
return _array[_current];
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
void IEnumerator.Reset()
|
||||
{
|
||||
_current = _start - 1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user