3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*=============================================================================
10 ** <OWNER>Microsoft</OWNER>
12 ** Purpose: An array implementation of a stack.
15 =============================================================================*/
16 namespace System.Collections {
18 using System.Security.Permissions;
19 using System.Diagnostics;
20 using System.Diagnostics.CodeAnalysis;
21 using System.Diagnostics.Contracts;
23 // A simple stack of objects. Internally it is implemented as an array,
24 // so Push can be O(n). Pop is O(1).
25 [DebuggerTypeProxy(typeof(System.Collections.Stack.StackDebugView))]
26 [DebuggerDisplay("Count = {Count}")]
27 [System.Runtime.InteropServices.ComVisible(true)]
29 public class Stack : ICollection, ICloneable {
30 private Object[] _array; // Storage for stack elements
31 [ContractPublicPropertyName("Count")]
32 private int _size; // Number of items in the stack.
33 private int _version; // Used to keep enumerator in sync w/ collection.
35 private Object _syncRoot;
37 private const int _defaultCapacity = 10;
40 _array = new Object[_defaultCapacity];
45 // Create a stack with a specific initial capacity. The initial capacity
46 // must be a non-negative number.
47 public Stack(int initialCapacity) {
48 if (initialCapacity < 0)
49 throw new ArgumentOutOfRangeException("initialCapacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
50 Contract.EndContractBlock();
51 if (initialCapacity < _defaultCapacity)
52 initialCapacity = _defaultCapacity; // Simplify doubling logic in Push.
53 _array = new Object[initialCapacity];
58 // Fills a Stack with the contents of a particular collection. The items are
59 // pushed onto the stack in the same order they are read by the enumerator.
61 public Stack(ICollection col) : this((col==null ? 32 : col.Count))
64 throw new ArgumentNullException("col");
65 Contract.EndContractBlock();
66 IEnumerator en = col.GetEnumerator();
71 public virtual int Count {
73 Contract.Ensures(Contract.Result<int>() >= 0);
78 public virtual bool IsSynchronized {
82 public virtual Object SyncRoot {
84 if( _syncRoot == null) {
85 System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
91 // Removes all Objects from the Stack.
92 public virtual void Clear() {
93 Array.Clear(_array, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
98 public virtual Object Clone() {
99 Contract.Ensures(Contract.Result<Object>() != null);
101 Stack s = new Stack(_size);
103 Array.Copy(_array, 0, s._array, 0, _size);
104 s._version = _version;
108 public virtual bool Contains(Object obj) {
111 while (count-- > 0) {
113 if (_array[count] == null)
116 else if (_array[count] != null && _array[count].Equals(obj)) {
123 // Copies the stack into an array.
124 public virtual void CopyTo(Array array, int index) {
126 throw new ArgumentNullException("array");
128 throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
130 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
131 if (array.Length - index < _size)
132 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
133 Contract.EndContractBlock();
136 if (array is Object[]) {
137 Object[] objArray = (Object[]) array;
139 objArray[i+index] = _array[_size-i-1];
145 array.SetValue(_array[_size-i-1], i+index);
151 // Returns an IEnumerator for this Stack.
152 public virtual IEnumerator GetEnumerator() {
153 Contract.Ensures(Contract.Result<IEnumerator>() != null);
154 return new StackEnumerator(this);
157 // Returns the top object on the stack without removing it. If the stack
158 // is empty, Peek throws an InvalidOperationException.
159 public virtual Object Peek() {
161 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
162 Contract.EndContractBlock();
163 return _array[_size-1];
166 // Pops an item from the top of the stack. If the stack is empty, Pop
167 // throws an InvalidOperationException.
168 public virtual Object Pop() {
170 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
171 //Contract.Ensures(Count == Contract.OldValue(Count) - 1);
172 Contract.EndContractBlock();
174 Object obj = _array[--_size];
175 _array[_size] = null; // Free memory quicker.
179 // Pushes an item to the top of the stack.
181 public virtual void Push(Object obj) {
182 //Contract.Ensures(Count == Contract.OldValue(Count) + 1);
183 if (_size == _array.Length) {
184 Object[] newArray = new Object[2*_array.Length];
185 Array.Copy(_array, 0, newArray, 0, _size);
188 _array[_size++] = obj;
192 // Returns a synchronized Stack.
194 [HostProtection(Synchronization=true)]
195 public static Stack Synchronized(Stack stack) {
197 throw new ArgumentNullException("stack");
198 Contract.Ensures(Contract.Result<Stack>() != null);
199 Contract.EndContractBlock();
200 return new SyncStack(stack);
204 // Copies the Stack to an array, in the same order Pop would return the items.
205 public virtual Object[] ToArray()
207 Contract.Ensures(Contract.Result<Object[]>() != null);
209 Object[] objArray = new Object[_size];
212 objArray[i] = _array[_size-i-1];
219 private class SyncStack : Stack
222 private Object _root;
224 internal SyncStack(Stack stack) {
226 _root = stack.SyncRoot;
229 public override bool IsSynchronized {
233 public override Object SyncRoot {
239 public override int Count {
247 public override bool Contains(Object obj) {
249 return _s.Contains(obj);
253 public override Object Clone()
256 return new SyncStack((Stack)_s.Clone());
260 public override void Clear() {
266 public override void CopyTo(Array array, int arrayIndex) {
268 _s.CopyTo(array, arrayIndex);
272 public override void Push(Object value) {
278 [SuppressMessage("Microsoft.Contracts", "CC1055")] // Thread safety problems with precondition - can't express the precondition as of Dev10.
279 public override Object Pop() {
285 public override IEnumerator GetEnumerator() {
287 return _s.GetEnumerator();
291 [SuppressMessage("Microsoft.Contracts", "CC1055")] // Thread safety problems with precondition - can't express the precondition as of Dev10.
292 public override Object Peek() {
298 public override Object[] ToArray() {
307 private class StackEnumerator : IEnumerator, ICloneable
309 private Stack _stack;
311 private int _version;
312 private Object currentElement;
314 internal StackEnumerator(Stack stack) {
316 _version = _stack._version;
318 currentElement = null;
321 public Object Clone()
323 return MemberwiseClone();
326 public virtual bool MoveNext() {
328 if (_version != _stack._version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
329 if (_index == -2) { // First call to enumerator.
330 _index = _stack._size-1;
331 retval = ( _index >= 0);
333 currentElement = _stack._array[_index];
336 if (_index == -1) { // End of enumeration.
340 retval = (--_index >= 0);
342 currentElement = _stack._array[_index];
344 currentElement = null;
348 public virtual Object Current {
350 if (_index == -2) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
351 if (_index == -1) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
352 return currentElement;
356 public virtual void Reset() {
357 if (_version != _stack._version) throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumFailedVersion));
359 currentElement = null;
363 internal class StackDebugView {
366 public StackDebugView( Stack stack) {
368 throw new ArgumentNullException("stack");
369 Contract.EndContractBlock();
374 [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
375 public Object[] Items {
377 return stack.ToArray();