2006-05-12 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System / System.Collections.Generic / Stack.cs
1 //
2 // System.Collections.Generic.Stack
3 //
4 // Authors:
5 //      Martin Baulig (martin@ximian.com)
6 //      Ben Maurer (bmaurer@ximian.com)
7 //
8 // (C) 2003, 2004 Novell, Inc.
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 #if NET_2_0
35 using System;
36 using System.Runtime.InteropServices;
37
38 namespace System.Collections.Generic
39 {
40         [ComVisible (false)]
41         public class Stack <T> : IEnumerable <T>, ICollection, IEnumerable {
42                 
43                 T [] data;
44                 int size;
45                 int ver;
46                 int defaultCapacity;
47                 
48                 private readonly static int INITIAL_SIZE = 16;
49
50                 public Stack ()
51                 {
52                         defaultCapacity = INITIAL_SIZE;
53                 }
54                 
55                 public Stack (int count)
56                 {
57                         if (count < 0)
58                                 throw new ArgumentOutOfRangeException ("count");
59
60                         defaultCapacity = count;                        
61                         data = new T [count];
62                 }
63                 
64                 public Stack (IEnumerable <T> collection)
65                 {
66                         if (collection == null)
67                                 throw new ArgumentNullException ("collection");
68                         
69                         ICollection <T> col = collection as ICollection <T>;
70                                                 
71                         if (col != null) {
72                                 size = col.Count;
73                                 data = new T [size];
74                                 col.CopyTo (data, 0);
75                         } else {
76                                 foreach (T t in collection)
77                                         Push (t);
78                         }
79                         defaultCapacity = size;
80                 }
81                 
82                 public void Clear ()
83                 {
84                         if (data != null)
85                                 Array.Clear (data, 0, data.Length);
86                         
87                         size = 0;
88                         ver ++;
89                 }
90                 
91                 public bool Contains (T t)
92                 {               
93                         return data != null && Array.IndexOf (data, t, 0, size) != -1;
94                 }
95                 
96                 public void CopyTo (T [] dest, int idx)
97                 {
98                         // this gets copied in the order that it is poped
99                         if (data != null) {
100                                 Array.Copy (data, 0, dest, idx, size);
101                                 Array.Reverse (dest, idx, size);
102                         }
103                 }
104                 
105                 public T Peek ()
106                 {
107                         if (size == 0)
108                                 throw new InvalidOperationException ();
109                         
110                         ver ++;
111                         
112                         return data [size - 1];
113                 }
114                 
115                 public T Pop ()
116                 {
117                         if (size == 0)
118                                 throw new InvalidOperationException ();
119                         
120                         ver ++;
121                         
122                         return data [-- size];
123                 }
124
125                 public void Push (T t)
126                 {
127                         if (size == 0 || size == data.Length)
128                                 Array.Resize <T> (ref data, size == 0 ? INITIAL_SIZE : 2 * size);
129                         
130                         ver ++;
131                         
132                         data [size++] = t;
133                 }
134                 
135                 public T [] ToArray ()
136                 {
137                         T [] copy = new T [size];
138                         CopyTo (copy, 0);
139                         return copy;
140                 }
141
142                 public void TrimExcess ()
143                 {
144                         if (data != null && (size < data.Length * 0.9))
145                                 Array.Resize <T> (ref data, size == 0 ? defaultCapacity : size);
146                 }
147                 
148                 public int Count {
149                         get { return size; }
150                 }
151                 
152                 bool ICollection.IsSynchronized {
153                         get { return false; }
154                 }
155                 
156                 object ICollection.SyncRoot {
157                         get { return this; }
158                 }
159                 
160                 void ICollection.CopyTo (Array dest, int idx)
161                 {
162                         try {
163                                 if (data != null) {
164                                         data.CopyTo (dest, idx);
165                                         Array.Reverse (dest, idx, size);
166                                 }
167                         } catch (ArrayTypeMismatchException) {
168                                 throw new ArgumentException ();
169                         }
170                 }
171                 
172                 public Enumerator GetEnumerator ()
173                 {
174                         return new Enumerator (this);
175                 }
176
177                 IEnumerator <T> IEnumerable<T>.GetEnumerator ()
178                 {
179                         return GetEnumerator ();
180                 }
181
182                 IEnumerator IEnumerable.GetEnumerator ()
183                 {
184                         return GetEnumerator ();
185                 }
186                 
187                 public struct Enumerator : IEnumerator <T>, IEnumerator, IDisposable {
188                         const int NOT_STARTED = -2;
189                         
190                         // this MUST be -1, because we depend on it in move next.
191                         // we just decr the size, so, 0 - 1 == FINISHED
192                         const int FINISHED = -1;
193                         
194                         Stack <T> parent;
195                         int idx;
196                         int ver;
197                         
198                         internal Enumerator (Stack <T> t)
199                         {
200                                 parent = t;
201                                 idx = NOT_STARTED;
202                                 ver = t.ver;
203                         }
204                         
205                         // for some fucked up reason, MSFT added a useless dispose to this class
206                         // It means that in foreach, we must still do a try/finally. Broken, very
207                         // broken.
208                         public void Dispose ()
209                         {
210                                 idx = NOT_STARTED;
211                         }
212                         
213                         public bool MoveNext ()
214                         {
215                                 if (ver != parent.ver)
216                                         throw new InvalidOperationException ();
217                                 
218                                 if (idx == -2)
219                                         idx = parent.size;
220                                 
221                                 return idx != FINISHED && -- idx != FINISHED;
222                         }
223                         
224                         public T Current {
225                                 get {
226                                         if (idx < 0)
227                                                 throw new InvalidOperationException ();
228                                         
229                                         return parent.data [idx];
230                                 }
231                         }
232                         
233                         void IEnumerator.Reset ()
234                         {
235                                 if (ver != parent.ver)
236                                         throw new InvalidOperationException ();
237                                 
238                                 idx = NOT_STARTED;
239                         }
240                         
241                         object IEnumerator.Current {
242                                 get { return Current; }
243                         }
244                         
245                 }
246         }
247 }
248 #endif