in System.Collections.Generic:
[mono.git] / mcs / class / System / System.Collections.Generic / Queue.cs
1 //
2 // System.Collections.Generic.Queue
3 //
4 // Author:
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 using System;
35 using System.Runtime.InteropServices;
36 using System.Diagnostics;
37
38 namespace System.Collections.Generic
39 {
40         [ComVisible(false)]
41         [Serializable]
42         [DebuggerDisplay ("Count={Count}")]
43         [DebuggerTypeProxy (typeof (CollectionDebuggerView))]   
44         public class Queue<T> : IEnumerable <T>, ICollection, IEnumerable
45         {
46                 T [] _array;
47                 int _head;
48                 int _tail;
49                 int _size;
50                 int _version;
51
52                 private const int INITIAL_SIZE = 16;
53                 
54                 public Queue ()
55                 {
56                 }
57                 
58                 public Queue (int count)
59                 {
60                         if (count < 0)
61                                 throw new ArgumentOutOfRangeException ("count");
62
63                         _array = new T [count];
64                 }
65                 
66                 public Queue (IEnumerable <T> collection)
67                 {
68                         if (collection == null)
69                                 throw new ArgumentNullException ("collection");
70                         
71                         foreach (T t in collection)
72                                 Enqueue (t);
73                 }
74                 
75                 public void Clear ()
76                 {
77                         if (_array != null)
78                                 Array.Clear (_array, 0, _array.Length);
79                         
80                         _head = _tail = _size = 0;
81                         _version++;
82                 }
83                 
84                 public bool Contains (T item)
85                 {
86                         if (item == null) {
87                                 foreach (T t in this)
88                                         if (t == null)
89                                                 return true;
90                         } else {
91                                 foreach (T t in this)
92                                         if (item.Equals (t))
93                                                 return true;
94                         }
95                         
96                         return false;
97                 }
98                 
99                 public void CopyTo (T [] array, int idx)
100                 {
101                         if (array == null)
102                                 throw new ArgumentNullException ();
103
104                         ((ICollection) this).CopyTo (array, idx);
105                 }
106                 
107                 void ICollection.CopyTo (Array array, int idx)
108                 {
109                         if (array == null)
110                                 throw new ArgumentNullException ();
111                         
112                         if ((uint) idx > (uint) array.Length)
113                                 throw new ArgumentOutOfRangeException ();
114                         
115                         if (array.Length - idx < _size)
116                                 throw new ArgumentOutOfRangeException ();
117                         
118                         if (_size == 0)
119                                 return;
120                         
121                         try {
122                                 int contents_length = _array.Length;
123                                 int length_from_head = contents_length - _head;
124                                 
125                                 Array.Copy (_array, _head, array, idx, Math.Min (_size, length_from_head));
126                                 if (_size > length_from_head)
127                                         Array.Copy (_array, 0, array, 
128                                                     idx  + length_from_head,
129                                                     _size - length_from_head);
130                         } catch (ArrayTypeMismatchException) {
131                                 throw new ArgumentException ();
132                         }
133                 }
134                 
135                 public T Dequeue ()
136                 {
137                         T ret = Peek ();
138                         
139                         // clear stuff out to make the GC happy
140                         _array [_head] = default (T);
141                         
142                         if (++_head == _array.Length)
143                                 _head = 0;
144                         _size --;
145                         _version ++;
146                         
147                         return ret;
148                 }
149                 
150                 public T Peek ()
151                 {
152                         if (_size == 0)
153                                 throw new InvalidOperationException ();
154                         
155                         return _array [_head];
156                 }
157                 
158                 public void Enqueue (T item)
159                 {
160                         if (_array == null || _size == _array.Length)
161                                 SetCapacity (Math.Max (_size * 2, 4));
162                         
163                         _array [_tail] = item;
164                         
165                         if (++_tail == _array.Length)
166                                 _tail = 0;
167                         
168                         _size ++;
169                         _version ++;
170                 }
171                 
172                 public T [] ToArray ()
173                 {
174                         T [] t = new T [_size];
175                         CopyTo (t, 0);
176                         return t;
177                 }
178
179                 public void TrimExcess ()
180                 {
181                         if (_array != null && (_size < _array.Length * 0.9))
182                                 SetCapacity (_size);
183                 }
184                 
185                 void SetCapacity (int new_size)
186                 {
187                         if (_array != null && new_size == _array.Length)
188                                 return;
189                         
190                         if (new_size < _size)
191                                 throw new InvalidOperationException ("shouldnt happen");
192                         
193                         T [] new_data = new T [new_size];
194                         if (_size > 0)
195                                 CopyTo (new_data, 0);
196                         
197                         _array = new_data;
198                         _tail = _size;
199                         _head = 0;
200                         _version ++;
201                 }
202                 
203                 public int Count {
204                         get { return _size; }
205                 }
206                 
207                 bool ICollection.IsSynchronized {
208                         get { return false; }
209                 }
210                 
211                 object ICollection.SyncRoot {
212                         get { return this; }
213                 }
214                 
215                 public Enumerator GetEnumerator ()
216                 {
217                         return new Enumerator (this);
218                 }
219
220                 IEnumerator <T> IEnumerable<T>.GetEnumerator ()
221                 {
222                         return GetEnumerator ();
223                 }
224
225                 IEnumerator IEnumerable.GetEnumerator ()
226                 {
227                         return GetEnumerator ();
228                 }
229                 
230                 [Serializable]
231                 public struct Enumerator : IEnumerator <T>, IEnumerator, IDisposable {
232                         const int NOT_STARTED = -2;
233                         
234                         // this MUST be -1, because we depend on it in move next.
235                         // we just decr the _size, so, 0 - 1 == FINISHED
236                         const int FINISHED = -1;
237                         
238                         Queue <T> q;
239                         int idx;
240                         int ver;
241                         
242                         internal Enumerator (Queue <T> q)
243                         {
244                                 this.q = q;
245                                 idx = NOT_STARTED;
246                                 ver = q._version;
247                         }
248                         
249                         // for some fucked up reason, MSFT added a useless dispose to this class
250                         // It means that in foreach, we must still do a try/finally. Broken, very
251                         // broken.
252                         public void Dispose ()
253                         {
254                                 idx = NOT_STARTED;
255                         }
256                         
257                         public bool MoveNext ()
258                         {
259                                 if (ver != q._version)
260                                         throw new InvalidOperationException ();
261                                 
262                                 if (idx == NOT_STARTED)
263                                         idx = q._size;
264                                 
265                                 return idx != FINISHED && -- idx != FINISHED;
266                         }
267                         
268                         public T Current {
269                                 get {
270                                         if (idx < 0)
271                                                 throw new InvalidOperationException ();
272                                         
273                                         return q._array [(q._size - 1 - idx + q._head) % q._array.Length];
274                                 }
275                         }
276                         
277                         void IEnumerator.Reset ()
278                         {
279                                 if (ver != q._version)
280                                         throw new InvalidOperationException ();
281                                 
282                                 idx = NOT_STARTED;
283                         }
284                         
285                         object IEnumerator.Current {
286                                 get { return Current; }
287                         }
288                         
289                 }
290         }
291 }