1 /*
2 [The "BSD licence"]
3 Copyright (c) 2005-2007 Kunle Odutola
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code MUST RETAIN the above copyright
10    notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form MUST REPRODUCE the above copyright
12    notice, this list of conditions and the following disclaimer in
13    the documentation and/or other materials provided with the
14    distribution.
15 3. The name of the author may not be used to endorse or promote products
16    derived from this software without specific prior WRITTEN permission.
17 4. Unless explicitly state otherwise, any contribution intentionally
18    submitted for inclusion in this work to the copyright owner or licensor
19    shall be under the terms and conditions of this license, without any
20    additional terms or conditions.
21 
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 
35 namespace Antlr.Runtime.Collections
36 {
37 	using System;
38 	using IDictionary				= System.Collections.IDictionary;
39 	using IDictionaryEnumerator		= System.Collections.IDictionaryEnumerator;
40 	using ICollection				= System.Collections.ICollection;
41 	using IEnumerator				= System.Collections.IEnumerator;
42 	using Hashtable					= System.Collections.Hashtable;
43 	using ArrayList					= System.Collections.ArrayList;
44 	using DictionaryEntry			= System.Collections.DictionaryEntry;
45 	using StringBuilder				= System.Text.StringBuilder;
46 
47 	/// <summary>
48 	/// An Hashtable-backed dictionary that enumerates Keys and Values in
49 	/// insertion order.
50 	/// </summary>
51 	public sealed class HashList : IDictionary
52 	{
53 		#region Helper classes
54 		private sealed class HashListEnumerator : IDictionaryEnumerator
55 		{
56 			internal enum EnumerationMode
57 			{
58 				Key,
59 				Value,
60 				Entry
61 			}
62 			private HashList _hashList;
63 			private ArrayList _orderList;
64 			private EnumerationMode _mode;
65 			private int _index;
66 			private int _version;
67 			private object _key;
68 			private object _value;
69 
70 			#region Constructors
71 
HashListEnumerator()72 			internal HashListEnumerator()
73 			{
74 				_index = 0;
75 				_key = null;
76 				_value = null;
77 			}
78 
HashListEnumerator(HashList hashList, EnumerationMode mode)79 			internal HashListEnumerator(HashList hashList, EnumerationMode mode)
80 			{
81 				_hashList = hashList;
82 				_mode = mode;
83 				_version = hashList._version;
84 				_orderList = hashList._insertionOrderList;
85 				_index = 0;
86 				_key = null;
87 				_value = null;
88 			}
89 
90 			#endregion
91 
92 			#region IDictionaryEnumerator Members
93 
94 			public object Key
95 			{
96 				get
97 				{
98 					if (_key == null)
99 					{
100 						throw new InvalidOperationException("Enumeration has either not started or has already finished.");
101 					}
102 					return _key;
103 				}
104 			}
105 
106 			public object Value
107 			{
108 				get
109 				{
110 					if (_key == null)
111 					{
112 						throw new InvalidOperationException("Enumeration has either not started or has already finished.");
113 					}
114 					return _value;
115 				}
116 			}
117 
118 			public DictionaryEntry Entry
119 			{
120 				get
121 				{
122 					if (_key == null)
123 					{
124 						throw new InvalidOperationException("Enumeration has either not started or has already finished.");
125 					}
126 					return new DictionaryEntry(_key, _value);
127 				}
128 			}
129 
130 			#endregion
131 
132 			#region IEnumerator Members
133 
Reset()134 			public void Reset()
135 			{
136 				if (_version != _hashList._version)
137 				{
138 					throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
139 				}
140 				_index = 0;
141 				_key = null;
142 				_value = null;
143 			}
144 
145 			public object Current
146 			{
147 				get
148 				{
149 					if (_key == null)
150 					{
151 						throw new InvalidOperationException("Enumeration has either not started or has already finished.");
152 					}
153 
154 					if (_mode == EnumerationMode.Key)
155 						return _key;
156 					else if (_mode == EnumerationMode.Value)
157 						return _value;
158 
159 					return new DictionaryEntry(_key, _value);
160 				}
161 			}
162 
MoveNext()163 			public bool MoveNext()
164 			{
165 				if (_version != _hashList._version)
166 				{
167 					throw new InvalidOperationException("Collection was modified; enumeration operation may not execute.");
168 				}
169 
170 				if (_index < _orderList.Count)
171 				{
172 					_key = _orderList[_index];
173 					_value = _hashList[_key];
174 					_index++;
175 					return true;
176 				}
177 				_key = null;
178 				return false;
179 			}
180 
181 			#endregion
182 		}
183 
184 		private sealed class KeyCollection : ICollection
185 		{
186 			private HashList _hashList;
187 
188 			#region Constructors
189 
KeyCollection()190 			internal KeyCollection()
191 			{
192 			}
193 
KeyCollection(HashList hashList)194 			internal KeyCollection(HashList hashList)
195 			{
196 				_hashList = hashList;
197 			}
198 
199 			#endregion
200 
ToString()201 			public override string ToString()
202 			{
203 				StringBuilder result = new StringBuilder();
204 
205 				result.Append("[");
206 				ArrayList keys = _hashList._insertionOrderList;
207 				for (int i = 0; i < keys.Count; i++)
208 				{
209 					if (i > 0)
210 					{
211 						result.Append(", ");
212 					}
213 					result.Append(keys[i]);
214 				}
215 				result.Append("]");
216 
217 				return result.ToString();
218 			}
219 
Equals(object o)220 			public override bool Equals(object o)
221 			{
222 				if (o is KeyCollection)
223 				{
224 					KeyCollection other = (KeyCollection) o;
225 					if ((Count == 0) && (other.Count == 0))
226 						return true;
227 					else if (Count == other.Count)
228 					{
229 						for (int i = 0; i < Count; i++)
230 						{
231 							if ((_hashList._insertionOrderList[i] == other._hashList._insertionOrderList[i]) ||
232 								(_hashList._insertionOrderList[i].Equals(other._hashList._insertionOrderList[i])))
233 								return true;
234 						}
235 					}
236 				}
237 				return false;
238 			}
239 
GetHashCode()240 			public override int GetHashCode()
241 			{
242 				return _hashList._insertionOrderList.GetHashCode();
243 			}
244 
245 			#region ICollection Members
246 
247 			public bool IsSynchronized
248 			{
249 				get { return _hashList.IsSynchronized; }
250 			}
251 
252 			public int Count
253 			{
254 				get { return _hashList.Count; }
255 			}
256 
CopyTo(Array array, int index)257 			public void CopyTo(Array array, int index)
258 			{
259 				_hashList.CopyKeysTo(array, index);
260 			}
261 
262 			public object SyncRoot
263 			{
264 				get { return _hashList.SyncRoot; }
265 			}
266 
267 			#endregion
268 
269 			#region IEnumerable Members
270 
GetEnumerator()271 			public IEnumerator GetEnumerator()
272 			{
273 				return new HashListEnumerator(_hashList, HashListEnumerator.EnumerationMode.Key);
274 			}
275 
276 			#endregion
277 		}
278 
279 		private sealed class ValueCollection : ICollection
280 		{
281 			private HashList _hashList;
282 
283 			#region Constructors
284 
ValueCollection()285 			internal ValueCollection()
286 			{
287 			}
288 
ValueCollection(HashList hashList)289 			internal ValueCollection(HashList hashList)
290 			{
291 				_hashList = hashList;
292 			}
293 
294 			#endregion
295 
ToString()296 			public override string ToString()
297 			{
298 				StringBuilder result = new StringBuilder();
299 
300 				result.Append("[");
301 				IEnumerator iter = new HashListEnumerator(_hashList, HashListEnumerator.EnumerationMode.Value);
302 				if (iter.MoveNext())
303 				{
304 					result.Append((iter.Current == null) ? "null" : iter.Current);
305 					while (iter.MoveNext())
306 					{
307 						result.Append(", ");
308 						result.Append((iter.Current == null) ? "null" : iter.Current);
309 					}
310 				}
311 				result.Append("]");
312 
313 				return result.ToString();
314 			}
315 
316 			#region ICollection Members
317 
318 			public bool IsSynchronized
319 			{
320 				get { return _hashList.IsSynchronized; }
321 			}
322 
323 			public int Count
324 			{
325 				get { return _hashList.Count; }
326 			}
327 
CopyTo(Array array, int index)328 			public void CopyTo(Array array, int index)
329 			{
330 				_hashList.CopyValuesTo(array, index);
331 			}
332 
333 			public object SyncRoot
334 			{
335 				get { return _hashList.SyncRoot; }
336 			}
337 
338 			#endregion
339 
340 			#region IEnumerable Members
341 
GetEnumerator()342 			public IEnumerator GetEnumerator()
343 			{
344 				return new HashListEnumerator(_hashList, HashListEnumerator.EnumerationMode.Value);
345 			}
346 
347 			#endregion
348 		}
349 
350 		#endregion
351 
352 		private Hashtable _dictionary = new Hashtable();
353 		private ArrayList _insertionOrderList = new ArrayList();
354 		private int _version;
355 
356 		#region Constructors
357 
HashList()358 		public HashList() : this(-1)
359 		{
360 		}
361 
HashList(int capacity)362 		public HashList(int capacity)
363 		{
364 			if (capacity < 0)
365 			{
366 				_dictionary = new Hashtable();
367 				_insertionOrderList = new ArrayList();
368 			}
369 			else
370 			{
371 				_dictionary = new Hashtable(capacity);
372 				_insertionOrderList = new ArrayList(capacity);
373 			}
374 			_version = 0;
375 		}
376 
377 		#endregion
378 
379 		#region IDictionary Members
380 
381 		public bool IsReadOnly		 { get {  return _dictionary.IsReadOnly; } }
382 
GetEnumerator()383 		public IDictionaryEnumerator GetEnumerator()
384 		{
385 			return new HashListEnumerator(this, HashListEnumerator.EnumerationMode.Entry);
386 		}
387 
388 		public object this[object key]
389 		{
390 			get { return _dictionary[key]; }
391 			set
392 			{
393 				bool isNewEntry = !_dictionary.Contains(key);
394 				_dictionary[key] = value;
395 				if (isNewEntry)
396 					_insertionOrderList.Add(key);
397 				_version++;
398 			}
399 		}
400 
Remove(object key)401 		public void Remove(object key)
402 		{
403 			_dictionary.Remove(key);
404 			_insertionOrderList.Remove(key);
405 			_version++;
406 		}
407 
Contains(object key)408 		public bool Contains(object key)
409 		{
410 			return _dictionary.Contains(key);
411 		}
412 
Clear()413 		public void Clear()
414 		{
415 			_dictionary.Clear();
416 			_insertionOrderList.Clear();
417 			_version++;
418 		}
419 
420 		public ICollection Values
421 		{
422 			get { return new ValueCollection(this); }
423 		}
424 
Add(object key, object value)425 		public void Add(object key, object value)
426 		{
427 			_dictionary.Add(key, value);
428 			_insertionOrderList.Add(key);
429 			_version++;
430 		}
431 
432 		public ICollection Keys
433 		{
434 			get { return new KeyCollection(this); }
435 		}
436 
437 		public bool IsFixedSize
438 		{
439 			get { return _dictionary.IsFixedSize; }
440 		}
441 
442 		#endregion
443 
444 		#region ICollection Members
445 
446 		public bool IsSynchronized
447 		{
448 			get { return _dictionary.IsSynchronized; }
449 		}
450 
451 		public int Count
452 		{
453 			get { return _dictionary.Count; }
454 		}
455 
CopyTo(Array array, int index)456 		public void CopyTo(Array array, int index)
457 		{
458 			int len = _insertionOrderList.Count;
459 			for (int i = 0; i < len; i++)
460 			{
461 				DictionaryEntry e = new DictionaryEntry(_insertionOrderList[i], _dictionary[_insertionOrderList[i]]);
462 				array.SetValue(e, index++);
463 			}
464 		}
465 
466 		public object SyncRoot
467 		{
468 			get { return _dictionary.SyncRoot; }
469 		}
470 
471 		#endregion
472 
473 		#region IEnumerable Members
474 
System.Collections.IEnumerable.GetEnumerator()475 		IEnumerator System.Collections.IEnumerable.GetEnumerator()
476 		{
477 			return new HashListEnumerator(this, HashListEnumerator.EnumerationMode.Entry);
478 		}
479 
480 		#endregion
481 
CopyKeysTo(Array array, int index)482 		private void CopyKeysTo(Array array, int index)
483 		{
484 			int len = _insertionOrderList.Count;
485 			for (int i = 0; i < len; i++)
486 			{
487 				array.SetValue(_insertionOrderList[i], index++);
488 			}
489 		}
490 
CopyValuesTo(Array array, int index)491 		private void CopyValuesTo(Array array, int index)
492 		{
493 			int len = _insertionOrderList.Count;
494 			for (int i = 0; i < len; i++)
495 			{
496 				array.SetValue(_dictionary[_insertionOrderList[i]], index++);
497 			}
498 		}
499 
500 	}
501 }