Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,148 @@
using System;
using System.Collections;
using System.Text;
namespace System.Collections.Generic {
/// <summary>
/// ABOUT:
/// Helps with operations that rely on bit marking to indicate whether an item in the
/// collection should be added, removed, visited already, etc.
///
/// BitHelper doesn't allocate the array; you must pass in an array or ints allocated on the
/// stack or heap. ToIntArrayLength() tells you the int array size you must allocate.
///
/// USAGE:
/// Suppose you need to represent a bit array of length (i.e. logical bit array length)
/// BIT_ARRAY_LENGTH. Then this is the suggested way to instantiate BitHelper:
/// ***************************************************************************
/// int intArrayLength = BitHelper.ToIntArrayLength(BIT_ARRAY_LENGTH);
/// BitHelper bitHelper;
/// if (intArrayLength less than stack alloc threshold)
/// int* m_arrayPtr = stackalloc int[intArrayLength];
/// bitHelper = new BitHelper(m_arrayPtr, intArrayLength);
/// else
/// int[] m_arrayPtr = new int[intArrayLength];
/// bitHelper = new BitHelper(m_arrayPtr, intArrayLength);
/// ***************************************************************************
///
/// IMPORTANT:
/// The second ctor args, length, should be specified as the length of the int array, not
/// the logical bit array. Because length is used for bounds checking into the int array,
/// it's especially important to get this correct for the stackalloc version. See the code
/// samples above; this is the value gotten from ToIntArrayLength().
///
/// The length ctor argument is the only exception; for other methods -- MarkBit and
/// IsMarked -- pass in values as indices into the logical bit array, and it will be mapped
/// to the position within the array of ints.
///
///
unsafe internal class BitHelper { // should not be serialized
private const byte MarkedBitFlag = 1;
private const byte IntSize = 32;
// m_length of underlying int array (not logical bit array)
private int m_length;
// ptr to stack alloc'd array of ints
[System.Security.SecurityCritical]
private int* m_arrayPtr;
// array of ints
private int[] m_array;
// whether to operate on stack alloc'd or heap alloc'd array
private bool useStackAlloc;
/// <summary>
/// Instantiates a BitHelper with a heap alloc'd array of ints
/// </summary>
/// <param name="bitArray">int array to hold bits</param>
/// <param name="length">length of int array</param>
// <SecurityKernel Critical="True" Ring="0">
// <UsesUnsafeCode Name="Field: m_arrayPtr" />
// <UsesUnsafeCode Name="Parameter bitArrayPtr of type: Int32*" />
// </SecurityKernel>
[System.Security.SecurityCritical]
internal BitHelper(int* bitArrayPtr, int length) {
this.m_arrayPtr = bitArrayPtr;
this.m_length = length;
useStackAlloc = true;
}
/// <summary>
/// Instantiates a BitHelper with a heap alloc'd array of ints
/// </summary>
/// <param name="bitArray">int array to hold bits</param>
/// <param name="length">length of int array</param>
internal BitHelper(int[] bitArray, int length) {
this.m_array = bitArray;
this.m_length = length;
}
/// <summary>
/// Mark bit at specified position
/// </summary>
/// <param name="bitPosition"></param>
// <SecurityKernel Critical="True" Ring="0">
// <UsesUnsafeCode Name="Field: m_arrayPtr" />
// </SecurityKernel>
[System.Security.SecurityCritical]
internal unsafe void MarkBit(int bitPosition) {
if (useStackAlloc) {
int bitArrayIndex = bitPosition / IntSize;
if (bitArrayIndex < m_length && bitArrayIndex >= 0) {
m_arrayPtr[bitArrayIndex] |= (MarkedBitFlag << (bitPosition % IntSize));
}
}
else {
int bitArrayIndex = bitPosition / IntSize;
if (bitArrayIndex < m_length && bitArrayIndex >= 0) {
m_array[bitArrayIndex] |= (MarkedBitFlag << (bitPosition % IntSize));
}
}
}
/// <summary>
/// Is bit at specified position marked?
/// </summary>
/// <param name="bitPosition"></param>
/// <returns></returns>
// <SecurityKernel Critical="True" Ring="0">
// <UsesUnsafeCode Name="Field: m_arrayPtr" />
// </SecurityKernel>
[System.Security.SecurityCritical]
internal unsafe bool IsMarked(int bitPosition) {
if (useStackAlloc) {
int bitArrayIndex = bitPosition / IntSize;
if (bitArrayIndex < m_length && bitArrayIndex >= 0) {
return ((m_arrayPtr[bitArrayIndex] & (MarkedBitFlag << (bitPosition % IntSize))) != 0);
}
return false;
}
else {
int bitArrayIndex = bitPosition / IntSize;
if (bitArrayIndex < m_length && bitArrayIndex >= 0) {
return ((m_array[bitArrayIndex] & (MarkedBitFlag << (bitPosition % IntSize))) != 0);
}
return false;
}
}
/// <summary>
/// How many ints must be allocated to represent n bits. Returns (n+31)/32, but
/// avoids overflow
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
internal static int ToIntArrayLength(int n) {
return n > 0 ? ((n - 1) / IntSize + 1) : 0;
}
}
}

View File

@@ -0,0 +1,141 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*=============================================================================
**
**
**
** Purpose: DebugView class for generic collections
**
** Date: Mar 09, 2004
**
=============================================================================*/
namespace System.Collections.Generic {
using System;
using System.Security.Permissions;
using System.Diagnostics;
internal sealed class System_CollectionDebugView<T> {
private ICollection<T> collection;
public System_CollectionDebugView(ICollection<T> collection) {
if (collection == null) {
throw new ArgumentNullException("collection");
}
this.collection = collection;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items {
get {
T[] items = new T[collection.Count];
collection.CopyTo(items, 0);
return items;
}
}
}
internal sealed class System_QueueDebugView<T> {
private Queue<T> queue;
public System_QueueDebugView(Queue<T> queue) {
if (queue == null) {
throw new ArgumentNullException("queue");
}
this.queue = queue;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items {
get {
return queue.ToArray();
}
}
}
internal sealed class System_StackDebugView<T> {
private Stack<T> stack;
public System_StackDebugView(Stack<T> stack) {
if (stack == null) {
throw new ArgumentNullException("stack");
}
this.stack = stack;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items {
get {
return stack.ToArray();
}
}
}
#if !SILVERLIGHT || FEATURE_NETCORE
internal sealed class System_DictionaryDebugView<K, V> {
private IDictionary<K, V> dict;
public System_DictionaryDebugView(IDictionary<K, V> dictionary) {
if (dictionary == null)
throw new ArgumentNullException("dictionary");
this.dict = dictionary;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<K, V>[] Items {
get {
KeyValuePair<K, V>[] items = new KeyValuePair<K, V>[dict.Count];
dict.CopyTo(items, 0);
return items;
}
}
}
internal sealed class System_DictionaryKeyCollectionDebugView<TKey, TValue> {
private ICollection<TKey> collection;
public System_DictionaryKeyCollectionDebugView(ICollection<TKey> collection) {
if (collection == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
this.collection = collection;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public TKey[] Items {
get {
TKey[] items = new TKey[collection.Count];
collection.CopyTo(items, 0);
return items;
}
}
}
internal sealed class System_DictionaryValueCollectionDebugView<TKey, TValue> {
private ICollection<TValue> collection;
public System_DictionaryValueCollectionDebugView(ICollection<TValue> collection) {
if (collection == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
this.collection = collection;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public TValue[] Items {
get {
TValue[] items = new TValue[collection.Count];
collection.CopyTo(items, 0);
return items;
}
}
}
#endif // !SILVERLIGHT || FEATURE_NETCORE
}

View File

@@ -0,0 +1,67 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Interface: ISet
**
** <OWNER>[....]</OWNER>
**
**
** Purpose: Base interface for all generic sets.
**
**
===========================================================*/
namespace System.Collections.Generic {
using System;
using System.Runtime.CompilerServices;
/// <summary>
/// Generic collection that guarantees the uniqueness of its elements, as defined
/// by some comparer. It also supports basic set operations such as Union, Intersection,
/// Complement and Exclusive Complement.
/// </summary>
public interface ISet<T> : ICollection<T> {
//Add ITEM to the set, return true if added, false if duplicate
new bool Add(T item);
//Transform this set into its union with the IEnumerable<T> other
void UnionWith(IEnumerable<T> other);
//Transform this set into its intersection with the IEnumberable<T> other
void IntersectWith(IEnumerable<T> other);
//Transform this set so it contains no elements that are also in other
void ExceptWith(IEnumerable<T> other);
//Transform this set so it contains elements initially in this or in other, but not both
void SymmetricExceptWith(IEnumerable<T> other);
//Check if this set is a subset of other
bool IsSubsetOf(IEnumerable<T> other);
//Check if this set is a superset of other
bool IsSupersetOf(IEnumerable<T> other);
//Check if this set is a subset of other, but not the same as it
bool IsProperSupersetOf(IEnumerable<T> other);
//Check if this set is a superset of other, but not the same as it
bool IsProperSubsetOf(IEnumerable<T> other);
//Check if this set has any elements in common with other
bool Overlaps(IEnumerable<T> other);
//Check if this set contains the same and only the same elements as other
bool SetEquals(IEnumerable<T> other);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,419 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*=============================================================================
**
** Class: Queue
**
** Purpose: A circular-array implementation of a generic queue.
**
** Date: January 28, 2003
**
=============================================================================*/
namespace System.Collections.Generic {
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security.Permissions;
// A simple Queue of generic objects. Internally it is implemented as a
// circular buffer, so Enqueue can be O(n). Dequeue is O(1).
[DebuggerTypeProxy(typeof(System_QueueDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
#if !SILVERLIGHT
[Serializable()]
#endif
[System.Runtime.InteropServices.ComVisible(false)]
public class Queue<T> : IEnumerable<T>,
System.Collections.ICollection {
private T[] _array;
private int _head; // First valid element in the queue
private int _tail; // Last valid element in the queue
private int _size; // Number of elements.
private int _version;
#if !SILVERLIGHT
[NonSerialized]
#endif
private Object _syncRoot;
private const int _MinimumGrow = 4;
private const int _ShrinkThreshold = 32;
private const int _GrowFactor = 200; // double each time
private const int _DefaultCapacity = 4;
static T[] _emptyArray = new T[0];
// Creates a queue with room for capacity objects. The default initial
// capacity and grow factor are used.
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue"]/*' />
public Queue() {
_array = _emptyArray;
}
// Creates a queue with room for capacity objects. The default grow factor
// is used.
//
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue1"]/*' />
public Queue(int capacity) {
if (capacity < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired);
_array = new T[capacity];
_head = 0;
_tail = 0;
_size = 0;
}
// Fills a Queue with the elements of an ICollection. Uses the enumerator
// to get each of the elements.
//
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue3"]/*' />
public Queue(IEnumerable<T> collection)
{
if (collection == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
_array = new T[_DefaultCapacity];
_size = 0;
_version = 0;
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Enqueue(en.Current);
}
}
}
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Count"]/*' />
public int Count {
get { return _size; }
}
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.IsSynchronized"]/*' />
bool System.Collections.ICollection.IsSynchronized {
get { return false; }
}
Object System.Collections.ICollection.SyncRoot {
get {
if( _syncRoot == null) {
System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
}
return _syncRoot;
}
}
// Removes all Objects from the queue.
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Clear"]/*' />
public void Clear() {
if (_head < _tail)
Array.Clear(_array, _head, _size);
else {
Array.Clear(_array, _head, _array.Length - _head);
Array.Clear(_array, 0, _tail);
}
_head = 0;
_tail = 0;
_size = 0;
_version++;
}
// CopyTo copies a collection into an Array, starting at a particular
// index into the array.
//
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.CopyTo"]/*' />
public void CopyTo(T[] array, int arrayIndex)
{
if (array==null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (arrayIndex < 0 || arrayIndex > array.Length) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_Index);
}
int arrayLen = array.Length;
if (arrayLen - arrayIndex < _size) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
}
int numToCopy = (arrayLen - arrayIndex < _size) ? (arrayLen - arrayIndex) : _size;
if (numToCopy == 0) return;
int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
Array.Copy(_array, _head, array, arrayIndex, firstPart);
numToCopy -= firstPart;
if (numToCopy > 0) {
Array.Copy(_array, 0, array, arrayIndex+_array.Length - _head, numToCopy);
}
}
void System.Collections.ICollection.CopyTo(Array array, int index)
{
if (array == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (array.Rank != 1) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
}
if( array.GetLowerBound(0) != 0 ) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
}
int arrayLen = array.Length;
if (index < 0 || index > arrayLen) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
}
if (arrayLen - index < _size) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
}
int numToCopy = (arrayLen-index < _size) ? arrayLen-index : _size;
if (numToCopy == 0) return;
try {
int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
Array.Copy(_array, _head, array, index, firstPart);
numToCopy -= firstPart;
if (numToCopy > 0) {
Array.Copy(_array, 0, array, index+_array.Length - _head, numToCopy);
}
}
catch(ArrayTypeMismatchException) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
}
}
// Adds item to the tail of the queue.
//
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Enqueue"]/*' />
public void Enqueue(T item) {
if (_size == _array.Length) {
int newcapacity = (int)((long)_array.Length * (long)_GrowFactor / 100);
if (newcapacity < _array.Length + _MinimumGrow) {
newcapacity = _array.Length + _MinimumGrow;
}
SetCapacity(newcapacity);
}
_array[_tail] = item;
_tail = (_tail + 1) % _array.Length;
_size++;
_version++;
}
// GetEnumerator returns an IEnumerator over this Queue. This
// Enumerator will support removing.
//
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.GetEnumerator"]/*' />
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.IEnumerable.GetEnumerator"]/*' />
/// <internalonly/>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new Enumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new Enumerator(this);
}
// Removes the object at the head of the queue and returns it. If the queue
// is empty, this method simply returns null.
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Dequeue"]/*' />
public T Dequeue() {
if (_size == 0)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyQueue);
T removed = _array[_head];
_array[_head] = default(T);
_head = (_head + 1) % _array.Length;
_size--;
_version++;
return removed;
}
// Returns the object at the head of the queue. The object remains in the
// queue. If the queue is empty, this method throws an
// InvalidOperationException.
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Peek"]/*' />
public T Peek() {
if (_size == 0)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyQueue);
return _array[_head];
}
// Returns true if the queue contains at least one object equal to item.
// Equality is determined using item.Equals().
//
// Exceptions: ArgumentNullException if item == null.
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Contains"]/*' />
public bool Contains(T item) {
int index = _head;
int count = _size;
EqualityComparer<T> c = EqualityComparer<T>.Default;
while (count-- > 0) {
if (((Object) item) == null) {
if (((Object) _array[index]) == null)
return true;
}
else if (_array[index] != null && c.Equals(_array[index], item)) {
return true;
}
index = (index + 1) % _array.Length;
}
return false;
}
internal T GetElement(int i)
{
return _array[(_head + i) % _array.Length];
}
// Iterates over the objects in the queue, returning an array of the
// objects in the Queue, or an empty array if the queue is empty.
// The order of elements in the array is first in to last in, the same
// order produced by successive calls to Dequeue.
/// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.ToArray"]/*' />
public T[] ToArray()
{
T[] arr = new T[_size];
if (_size==0)
return arr;
if (_head < _tail) {
Array.Copy(_array, _head, arr, 0, _size);
} else {
Array.Copy(_array, _head, arr, 0, _array.Length - _head);
Array.Copy(_array, 0, arr, _array.Length - _head, _tail);
}
return arr;
}
// PRIVATE Grows or shrinks the buffer to hold capacity objects. Capacity
// must be >= _size.
private void SetCapacity(int capacity) {
T[] newarray = new T[capacity];
if (_size > 0) {
if (_head < _tail) {
Array.Copy(_array, _head, newarray, 0, _size);
} else {
Array.Copy(_array, _head, newarray, 0, _array.Length - _head);
Array.Copy(_array, 0, newarray, _array.Length - _head, _tail);
}
}
_array = newarray;
_head = 0;
_tail = (_size == capacity) ? 0 : _size;
_version++;
}
public void TrimExcess() {
int threshold = (int)(((double)_array.Length) * 0.9);
if( _size < threshold ) {
SetCapacity(_size);
}
}
// Implements an enumerator for a Queue. The enumerator uses the
// internal version number of the list to ensure that no modifications are
// made to the list while an enumeration is in progress.
/// <include file='doc\Queue.uex' path='docs/doc[@for="QueueEnumerator"]/*' />
#if !SILVERLIGHT
[Serializable()]
#endif
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")]
public struct Enumerator : IEnumerator<T>,
System.Collections.IEnumerator
{
private Queue<T> _q;
private int _index; // -1 = not started, -2 = ended/disposed
private int _version;
private T _currentElement;
internal Enumerator(Queue<T> q) {
_q = q;
_version = _q._version;
_index = -1;
_currentElement = default(T);
}
/// <include file='doc\Queue.uex' path='docs/doc[@for="QueueEnumerator.Dispose"]/*' />
public void Dispose()
{
_index = -2;
_currentElement = default(T);
}
/// <include file='doc\Queue.uex' path='docs/doc[@for="QueueEnumerator.MoveNext"]/*' />
public bool MoveNext() {
if (_version != _q._version) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
if (_index == -2)
return false;
_index++;
if (_index == _q._size) {
_index = -2;
_currentElement = default(T);
return false;
}
_currentElement = _q.GetElement(_index);
return true;
}
/// <include file='doc\Queue.uex' path='docs/doc[@for="QueueEnumerator.Current"]/*' />
public T Current {
get {
if (_index < 0)
{
if (_index == -1)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted);
else
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded);
}
return _currentElement;
}
}
Object System.Collections.IEnumerator.Current {
get {
if (_index < 0)
{
if (_index == -1)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted);
else
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded);
}
return _currentElement;
}
}
void System.Collections.IEnumerator.Reset() {
if (_version != _q._version) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
_index = -1;
_currentElement = default(T);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace System.Collections.Generic {
/// <summary>
/// Debug view for SortedSet
/// </summary>
/// <typeparam name="T"></typeparam>
internal class SortedSetDebugView<T> {
private SortedSet<T> set;
public SortedSetDebugView(SortedSet<T> set) {
if (set == null) {
throw new ArgumentNullException("set");
}
this.set = set;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items {
get {
return set.ToArray();
}
}
}
}

View File

@@ -0,0 +1,328 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*=============================================================================
**
** Class: Stack
**
** Purpose: An array implementation of a generic stack.
**
** Date: January 28, 2003
**
=============================================================================*/
namespace System.Collections.Generic {
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security.Permissions;
// A simple stack of objects. Internally it is implemented as an array,
// so Push can be O(n). Pop is O(1).
[DebuggerTypeProxy(typeof(System_StackDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
#if !SILVERLIGHT
[Serializable()]
#endif
[System.Runtime.InteropServices.ComVisible(false)]
public class Stack<T> : IEnumerable<T>,
System.Collections.ICollection {
private T[] _array; // Storage for stack elements
private int _size; // Number of items in the stack.
private int _version; // Used to keep enumerator in [....] w/ collection.
#if !SILVERLIGHT
[NonSerialized]
#endif
private Object _syncRoot;
private const int _defaultCapacity = 4;
static T[] _emptyArray = new T[0];
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Stack"]/*' />
public Stack() {
_array = _emptyArray;
_size = 0;
_version = 0;
}
// Create a stack with a specific initial capacity. The initial capacity
// must be a non-negative number.
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Stack1"]/*' />
public Stack(int capacity) {
if (capacity < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired);
_array = new T[capacity];
_size = 0;
_version = 0;
}
// Fills a Stack with the contents of a particular collection. The items are
// pushed onto the stack in the same order they are read by the enumerator.
//
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Stack2"]/*' />
public Stack(IEnumerable<T> collection)
{
if (collection==null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
_array = new T[count];
c.CopyTo(_array, 0);
_size = count;
}
else {
_size = 0;
_array = new T[_defaultCapacity];
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Push(en.Current);
}
}
}
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Count"]/*' />
public int Count {
get { return _size; }
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.IsSynchronized"]/*' />
bool System.Collections.ICollection.IsSynchronized {
get { return false; }
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.SyncRoot"]/*' />
Object System.Collections.ICollection.SyncRoot {
get {
if( _syncRoot == null) {
System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
}
return _syncRoot;
}
}
// Removes all Objects from the Stack.
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Clear"]/*' />
public void Clear() {
Array.Clear(_array, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
_size = 0;
_version++;
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Contains"]/*' />
public bool Contains(T item) {
int count = _size;
EqualityComparer<T> c = EqualityComparer<T>.Default;
while (count-- > 0) {
if (((Object) item) == null) {
if (((Object) _array[count]) == null)
return true;
}
else if (_array[count] != null && c.Equals(_array[count], item) ) {
return true;
}
}
return false;
}
// Copies the stack into an array.
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.CopyTo"]/*' />
public void CopyTo(T[] array, int arrayIndex) {
if (array==null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (arrayIndex < 0 || arrayIndex > array.Length) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if (array.Length - arrayIndex < _size) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
}
Array.Copy(_array, 0, array, arrayIndex, _size);
Array.Reverse(array, arrayIndex, _size);
}
void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) {
if (array==null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (array.Rank != 1) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
}
if( array.GetLowerBound(0) != 0 ) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
}
if (arrayIndex < 0 || arrayIndex > array.Length) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if (array.Length - arrayIndex < _size) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
}
try {
Array.Copy(_array, 0, array, arrayIndex, _size);
Array.Reverse(array, arrayIndex, _size);
}
catch(ArrayTypeMismatchException){
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
}
}
// Returns an IEnumerator for this Stack.
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.GetEnumerator"]/*' />
public Enumerator GetEnumerator() {
return new Enumerator(this);
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.IEnumerable.GetEnumerator"]/*' />
/// <internalonly/>
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new Enumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return new Enumerator(this);
}
public void TrimExcess() {
int threshold = (int)(((double)_array.Length) * 0.9);
if( _size < threshold ) {
T[] newarray = new T[_size];
Array.Copy(_array, 0, newarray, 0, _size);
_array = newarray;
_version++;
}
}
// Returns the top object on the stack without removing it. If the stack
// is empty, Peek throws an InvalidOperationException.
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Peek"]/*' />
public T Peek() {
if (_size==0)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);
return _array[_size-1];
}
// Pops an item from the top of the stack. If the stack is empty, Pop
// throws an InvalidOperationException.
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Pop"]/*' />
public T Pop() {
if (_size == 0)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);
_version++;
T item = _array[--_size];
_array[_size] = default(T); // Free memory quicker.
return item;
}
// Pushes an item to the top of the stack.
//
/// <include file='doc\Stack.uex' path='docs/doc[@for="Stack.Push"]/*' />
public void Push(T item) {
if (_size == _array.Length) {
T[] newArray = new T[(_array.Length == 0) ? _defaultCapacity : 2*_array.Length];
Array.Copy(_array, 0, newArray, 0, _size);
_array = newArray;
}
_array[_size++] = item;
_version++;
}
// Copies the Stack to an array, in the same order Pop would return the items.
public T[] ToArray()
{
T[] objArray = new T[_size];
int i = 0;
while(i < _size) {
objArray[i] = _array[_size-i-1];
i++;
}
return objArray;
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator"]/*' />
#if !SILVERLIGHT
[Serializable()]
#endif
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")]
public struct Enumerator : IEnumerator<T>,
System.Collections.IEnumerator
{
private Stack<T> _stack;
private int _index;
private int _version;
private T currentElement;
internal Enumerator(Stack<T> stack) {
_stack = stack;
_version = _stack._version;
_index = -2;
currentElement = default(T);
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator.Dispose"]/*' />
public void Dispose()
{
_index = -1;
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator.MoveNext"]/*' />
public bool MoveNext() {
bool retval;
if (_version != _stack._version) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
if (_index == -2) { // First call to enumerator.
_index = _stack._size-1;
retval = ( _index >= 0);
if (retval)
currentElement = _stack._array[_index];
return retval;
}
if (_index == -1) { // End of enumeration.
return false;
}
retval = (--_index >= 0);
if (retval)
currentElement = _stack._array[_index];
else
currentElement = default(T);
return retval;
}
/// <include file='doc\Stack.uex' path='docs/doc[@for="StackEnumerator.Current"]/*' />
public T Current {
get {
if (_index == -2) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted);
if (_index == -1) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded);
return currentElement;
}
}
Object System.Collections.IEnumerator.Current {
get {
if (_index == -2) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted);
if (_index == -1) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded);
return currentElement;
}
}
void System.Collections.IEnumerator.Reset() {
if (_version != _stack._version) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
_index = -2;
currentElement = default(T);
}
}
}
}

View File

@@ -0,0 +1,357 @@
namespace System {
// This file defines an internal class used to throw exceptions in BCL code.
// The main purpose is to reduce code size.
//
// The old way to throw an exception generates quite a lot IL code and assembly code.
// Following is an example:
// C# source
// throw new ArgumentNullException("key", SR.GetString("ArgumentNull_Key"));
// IL code:
// IL_0003: ldstr "key"
// IL_0008: ldstr "ArgumentNull_Key"
// IL_000d: call string System.Environment::GetResourceString(string)
// IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string)
// IL_0017: throw
// which is 21bytes in IL.
//
// So we want to get rid of the ldstr and call to Environment.GetResource in IL.
// In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
// argument name and resource name in a small integer. The source code will be changed to
// ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
//
// The IL code will be 7 bytes.
// IL_0008: ldc.i4.4
// IL_0009: ldc.i4.4
// IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
// IL_000f: ldarg.0
//
// This will also reduce the Jitted code size a lot.
//
// It is very important we do this for generic classes because we can easily generate the same code
// multiple times for different instantiation.
//
// <STRIP>
// Jit will generates the code to throw exception at the end of a method, thus we can reduce working
// set if the user code will never throw an exception. However Jit doesn't know anything about the
// methods in ThrowHelper, so it will not moves the instructions to the end.
// This is not a problem for ngened code because we will probably move the code based on profile data(hopefully.)
//
// For jitted code, it doesn't make much difference. The only advantage of moving the code to the end is to
// improve cache locality. Patrick pointed out this doesn't make much different on newer processor like P4.
// </STRIP>
#if !SILVERLIGHT
using System.Runtime.Serialization;
#endif
using System.Diagnostics;
internal static class ThrowHelper {
internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType) {
throw new ArgumentException(SR.GetString(SR.Arg_WrongType, key, targetType), "key");
}
internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType) {
throw new ArgumentException(SR.GetString(SR.Arg_WrongType, value, targetType), "value");
}
internal static void ThrowKeyNotFoundException() {
throw new System.Collections.Generic.KeyNotFoundException();
}
internal static void ThrowArgumentException(ExceptionResource resource) {
throw new ArgumentException(SR.GetString(GetResourceName(resource)));
}
internal static void ThrowArgumentNullException(ExceptionArgument argument) {
throw new ArgumentNullException(GetArgumentName(argument));
}
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) {
throw new ArgumentOutOfRangeException(GetArgumentName(argument));
}
internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) {
throw new ArgumentOutOfRangeException(GetArgumentName(argument), SR.GetString(GetResourceName(resource)));
}
internal static void ThrowInvalidOperationException(ExceptionResource resource) {
throw new InvalidOperationException(SR.GetString(GetResourceName(resource)));
}
#if !SILVERLIGHT
internal static void ThrowSerializationException(ExceptionResource resource) {
throw new SerializationException(SR.GetString(GetResourceName(resource)));
}
#endif
internal static void ThrowNotSupportedException(ExceptionResource resource) {
throw new NotSupportedException(SR.GetString(GetResourceName(resource)));
}
// Allow nulls for reference types and Nullable<U>, but not for value types.
internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) {
// Note that default(T) is not equal to null for value types except when T is Nullable<U>.
if (value == null && !(default(T) == null))
ThrowHelper.ThrowArgumentNullException(argName);
}
//
// This function will convert an ExceptionArgument enum value to the argument name string.
//
internal static string GetArgumentName(ExceptionArgument argument) {
string argumentName = null;
switch (argument) {
case ExceptionArgument.array:
argumentName = "array";
break;
case ExceptionArgument.arrayIndex:
argumentName = "arrayIndex";
break;
case ExceptionArgument.capacity:
argumentName = "capacity";
break;
case ExceptionArgument.collection:
argumentName = "collection";
break;
case ExceptionArgument.converter:
argumentName = "converter";
break;
case ExceptionArgument.count:
argumentName = "count";
break;
case ExceptionArgument.dictionary:
argumentName = "dictionary";
break;
case ExceptionArgument.index:
argumentName = "index";
break;
case ExceptionArgument.info:
argumentName = "info";
break;
case ExceptionArgument.key:
argumentName = "key";
break;
case ExceptionArgument.match:
argumentName = "match";
break;
case ExceptionArgument.obj:
argumentName = "obj";
break;
case ExceptionArgument.queue:
argumentName = "queue";
break;
case ExceptionArgument.stack:
argumentName = "stack";
break;
case ExceptionArgument.startIndex:
argumentName = "startIndex";
break;
case ExceptionArgument.value:
argumentName = "value";
break;
case ExceptionArgument.item:
argumentName = "item";
break;
default:
Debug.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
return string.Empty;
}
return argumentName;
}
//
// This function will convert an ExceptionResource enum value to the resource string.
//
internal static string GetResourceName(ExceptionResource resource) {
string resourceName = null;
switch (resource) {
case ExceptionResource.Argument_ImplementIComparable:
resourceName = SR.Argument_ImplementIComparable;
break;
case ExceptionResource.Argument_AddingDuplicate:
resourceName = SR.Argument_AddingDuplicate;
break;
case ExceptionResource.ArgumentOutOfRange_Index:
resourceName = SR.ArgumentOutOfRange_Index;
break;
case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
resourceName = SR.ArgumentOutOfRange_NeedNonNegNum;
break;
case ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired:
resourceName = SR.ArgumentOutOfRange_NeedNonNegNumRequired;
break;
case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
resourceName = SR.ArgumentOutOfRange_SmallCapacity;
break;
case ExceptionResource.Arg_ArrayPlusOffTooSmall:
resourceName = SR.Arg_ArrayPlusOffTooSmall;
break;
case ExceptionResource.Arg_RankMultiDimNotSupported:
resourceName = SR.Arg_MultiRank;
break;
case ExceptionResource.Arg_NonZeroLowerBound:
resourceName = SR.Arg_NonZeroLowerBound;
break;
case ExceptionResource.Argument_InvalidArrayType:
resourceName = SR.Invalid_Array_Type;
break;
case ExceptionResource.Argument_InvalidOffLen:
resourceName = SR.Argument_InvalidOffLen;
break;
case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue:
resourceName = SR.InvalidOperation_CannotRemoveFromStackOrQueue;
break;
case ExceptionResource.InvalidOperation_EmptyCollection:
resourceName = SR.InvalidOperation_EmptyCollection;
break;
case ExceptionResource.InvalidOperation_EmptyQueue:
resourceName = SR.InvalidOperation_EmptyQueue;
break;
case ExceptionResource.InvalidOperation_EnumOpCantHappen:
resourceName = SR.InvalidOperation_EnumOpCantHappen;
break;
case ExceptionResource.InvalidOperation_EnumFailedVersion:
resourceName = SR.InvalidOperation_EnumFailedVersion;
break;
case ExceptionResource.InvalidOperation_EmptyStack:
resourceName = SR.InvalidOperation_EmptyStack;
break;
case ExceptionResource.InvalidOperation_EnumNotStarted:
resourceName = SR.InvalidOperation_EnumNotStarted;
break;
case ExceptionResource.InvalidOperation_EnumEnded:
resourceName = SR.InvalidOperation_EnumEnded;
break;
case ExceptionResource.NotSupported_KeyCollectionSet:
resourceName = SR.NotSupported_KeyCollectionSet;
break;
case ExceptionResource.NotSupported_SortedListNestedWrite:
resourceName = SR.NotSupported_SortedListNestedWrite;
break;
#if !SILVERLIGHT
case ExceptionResource.Serialization_InvalidOnDeser:
resourceName = SR.Serialization_InvalidOnDeser;
break;
case ExceptionResource.Serialization_MissingValues:
resourceName = SR.Serialization_MissingValues;
break;
case ExceptionResource.Serialization_MismatchedCount:
resourceName = SR.Serialization_MismatchedCount;
break;
#endif
case ExceptionResource.NotSupported_ValueCollectionSet:
resourceName = SR.NotSupported_ValueCollectionSet;
break;
default:
Debug.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
return string.Empty;
}
return resourceName;
}
}
//
// The convention for this enum is using the argument name as the enum name
//
internal enum ExceptionArgument {
obj,
dictionary,
array,
info,
key,
collection,
match,
converter,
queue,
stack,
capacity,
index,
startIndex,
value,
count,
arrayIndex,
item,
}
//
// The convention for this enum is using the resource name as the enum name
//
internal enum ExceptionResource {
Argument_ImplementIComparable,
ArgumentOutOfRange_NeedNonNegNum,
ArgumentOutOfRange_NeedNonNegNumRequired,
Arg_ArrayPlusOffTooSmall,
Argument_AddingDuplicate,
Serialization_InvalidOnDeser,
Serialization_MismatchedCount,
Serialization_MissingValues,
Arg_RankMultiDimNotSupported,
Arg_NonZeroLowerBound,
Argument_InvalidArrayType,
NotSupported_KeyCollectionSet,
ArgumentOutOfRange_SmallCapacity,
ArgumentOutOfRange_Index,
Argument_InvalidOffLen,
NotSupported_ReadOnlyCollection,
InvalidOperation_CannotRemoveFromStackOrQueue,
InvalidOperation_EmptyCollection,
InvalidOperation_EmptyQueue,
InvalidOperation_EnumOpCantHappen,
InvalidOperation_EnumFailedVersion,
InvalidOperation_EmptyStack,
InvalidOperation_EnumNotStarted,
InvalidOperation_EnumEnded,
NotSupported_SortedListNestedWrite,
NotSupported_ValueCollectionSet,
}
}