1/*
2[The "BSD licence"]
3Copyright (c) 2005-2007 Kunle Odutola
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions
8are met:
91. Redistributions of source code MUST RETAIN the above copyright
10   notice, this list of conditions and the following disclaimer.
112. 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.
153. The name of the author may not be used to endorse or promote products
16   derived from this software without specific prior WRITTEN permission.
174. 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
22THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
34
35namespace 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
72			internal HashListEnumerator()
73			{
74				_index = 0;
75				_key = null;
76				_value = null;
77			}
78
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
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
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
190			internal KeyCollection()
191			{
192			}
193
194			internal KeyCollection(HashList hashList)
195			{
196				_hashList = hashList;
197			}
198
199			#endregion
200
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
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
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
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
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
285			internal ValueCollection()
286			{
287			}
288
289			internal ValueCollection(HashList hashList)
290			{
291				_hashList = hashList;
292			}
293
294			#endregion
295
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
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
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
358		public HashList() : this(-1)
359		{
360		}
361
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
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
401		public void Remove(object key)
402		{
403			_dictionary.Remove(key);
404			_insertionOrderList.Remove(key);
405			_version++;
406		}
407
408		public bool Contains(object key)
409		{
410			return _dictionary.Contains(key);
411		}
412
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
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
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
475		IEnumerator System.Collections.IEnumerable.GetEnumerator()
476		{
477			return new HashListEnumerator(this, HashListEnumerator.EnumerationMode.Entry);
478		}
479
480		#endregion
481
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
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}