3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 namespace System
.Collections
.Specialized
25 public class ListDictionary
: IDictionary
, ICollection
, IEnumerable
29 private ListEntry root
;
30 private IComparer comparer
;
33 public ListDictionary()
41 public ListDictionary(IComparer comparer
) : this()
43 this.comparer
= comparer
;
46 private bool AreEqual(object obj1
, object obj2
)
48 if (comparer
!= null) {
49 if (comparer
.Compare(obj1
, obj2
) == 0) {
53 if (obj1
.Equals(obj2
)) {
61 private ListEntry
FindEntry(object key
)
64 throw new ArgumentNullException("Attempted lookup for a null key.");
70 ListEntry entry
= root
;
72 while (entry
!= null) {
73 if (AreEqual(key
, entry
.key
)) {
84 private void AddImpl(object key
, object value)
87 throw new ArgumentNullException("Attempted add with a null key.");
91 root
= new ListEntry();
95 ListEntry entry
= root
;
97 while (entry
!= null) {
98 if (AreEqual(key
, entry
.key
)) {
99 throw new ArgumentException("Duplicate key in add.");
102 if (entry
.next
== null) {
109 entry
.next
= new ListEntry();
110 entry
.next
.key
= key
;
111 entry
.next
.value = value;
118 // IEnumerable Interface
119 IEnumerator IEnumerable
.GetEnumerator()
121 return new ListEntryEnumerator(this);
124 // ICollection Interface
131 public bool IsSynchronized
{
137 public object SyncRoot
{
143 public void CopyTo(Array array
, int index
)
146 throw new ArgumentNullException(
148 "Array cannot be null.");
151 throw new ArgumentOutOfRangeException("index", "index is less than 0");
154 foreach ( DictionaryEntry entry
in this )
155 array
.SetValue( entry
, i
++ );
158 // IDictionary Interface
159 public bool IsFixedSize
166 public bool IsReadOnly
174 public object this[object key
]
177 ListEntry entry
= FindEntry(key
);
178 return entry
== null ? entry
: entry
.value;
182 ListEntry entry
= FindEntry(key
);
190 public ICollection Keys
193 return new ListEntryCollection(this, true);
197 public ICollection Values
200 return new ListEntryCollection(this, false);
204 public void Add(object key
, object value)
216 public bool Contains(object key
)
218 return FindEntry(key
) != null ? true : false;
221 public IDictionaryEnumerator
GetEnumerator()
223 return new ListEntryEnumerator(this);
226 public void Remove(object key
)
229 throw new ArgumentNullException(
231 "Key cannot be null.");
234 ListEntry entry
= root
;
236 for (ListEntry prev
= null; entry
!= null; prev
= entry
, entry
= entry
.next
) {
237 if (AreEqual(key
, entry
.key
)) {
239 prev
.next
= entry
.next
;
253 private class ListEntry
255 public object key
= null;
256 public object value = null;
257 public ListEntry next
= null;
261 private class ListEntryEnumerator
: IEnumerator
, IDictionaryEnumerator
263 private ListDictionary dict
;
264 private bool isAtStart
;
265 private ListEntry current
;
268 public ListEntryEnumerator(ListDictionary dict
)
271 version
= dict
.modCount
;
275 private void FailFast()
277 if (version
!= dict
.modCount
) {
278 throw new InvalidOperationException(
279 "The ListDictionary's contents changed after this enumerator was instantiated.");
283 public bool MoveNext()
291 current
= current
.next
;
294 return current
!= null ? true : false;
305 public object Current
310 if (isAtStart
|| current
== null) {
311 throw new InvalidOperationException(
312 "Enumerator is positioned before the collection's first element or after the last element.");
315 return new DictionaryEntry(current
.key
, current
.value);
319 // IDictionaryEnumerator
320 public DictionaryEntry Entry
324 return (DictionaryEntry
) Current
;
333 if (isAtStart
|| current
== null) {
334 throw new InvalidOperationException(
335 "Enumerator is positioned before the collection's first element or after the last element.");
347 if (isAtStart
|| current
== null) {
348 throw new InvalidOperationException(
349 "Enumerator is positioned before the collection's first element or after the last element.");
352 return current
.value;
357 private class ListEntryCollection
: ICollection
359 private ListDictionary dict
;
360 private bool isKeyList
;
362 public ListEntryCollection(ListDictionary dict
, bool isKeyList
)
365 this.isKeyList
= isKeyList
;
368 // ICollection Interface
375 public bool IsSynchronized
382 public object SyncRoot
385 return dict
.SyncRoot
;
389 public void CopyTo(Array array
, int index
)
392 foreach ( object obj
in this )
393 array
.SetValue( obj
, i
++ );
396 // IEnumerable Interface
397 public IEnumerator
GetEnumerator()
399 return new ListEntryCollectionEnumerator(dict
, isKeyList
);
402 private class ListEntryCollectionEnumerator
: IEnumerator
404 private ListDictionary dict
;
405 private bool isKeyList
;
406 private bool isAtStart
;
408 private ListEntry current
;
410 public ListEntryCollectionEnumerator(ListDictionary dict
, bool isKeyList
)
413 this.isKeyList
= isKeyList
;
415 version
= dict
.modCount
;
418 private void FailFast()
420 if (version
!= dict
.modCount
) {
421 throw new InvalidOperationException(
422 "The Collection's contents changed after this " +
423 "enumerator was instantiated.");
427 public object Current
432 if (isAtStart
|| current
== null) {
433 throw new InvalidOperationException(
434 "Enumerator is positioned before the collection's " +
435 "first element or after the last element.");
438 return isKeyList
? current
.key
: current
.value;
442 public bool MoveNext()
450 current
= current
.next
;
453 return current
!= null ? true : false;