(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System / System.Collections.Specialized / ListDictionary.cs
blobaf1f56cec28e04a6507d297c807ca917137dc5bb
2 //
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:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
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
24 [Serializable]
25 public class ListDictionary : IDictionary, ICollection, IEnumerable
27 private int count;
28 private int modCount;
29 private ListEntry root;
30 private IComparer comparer;
33 public ListDictionary()
35 count = 0;
36 modCount = 0;
37 comparer = null;
38 root = null;
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) {
50 return true;
52 } else {
53 if (obj1.Equals(obj2)) {
54 return true;
58 return false;
61 private ListEntry FindEntry(object key)
63 if (key == null) {
64 throw new ArgumentNullException("Attempted lookup for a null key.");
67 if (root == null) {
68 return null;
69 } else {
70 ListEntry entry = root;
72 while (entry != null) {
73 if (AreEqual(key, entry.key)) {
74 return entry;
77 entry = entry.next;
81 return null;
84 private void AddImpl(object key, object value)
86 if (key == null) {
87 throw new ArgumentNullException("Attempted add with a null key.");
90 if (root == null) {
91 root = new ListEntry();
92 root.key = key;
93 root.value = value;
94 } else {
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) {
103 break;
106 entry = entry.next;
109 entry.next = new ListEntry();
110 entry.next.key = key;
111 entry.next.value = value;
114 count++;
115 modCount++;
118 // IEnumerable Interface
119 IEnumerator IEnumerable.GetEnumerator()
121 return new ListEntryEnumerator(this);
124 // ICollection Interface
125 public int Count {
126 get {
127 return count;
131 public bool IsSynchronized {
132 get {
133 return false;
137 public object SyncRoot {
138 get {
139 return this;
143 public void CopyTo(Array array, int index)
145 if (array == null)
146 throw new ArgumentNullException(
147 "array",
148 "Array cannot be null.");
150 if (index < 0)
151 throw new ArgumentOutOfRangeException("index", "index is less than 0");
153 int i = index;
154 foreach ( DictionaryEntry entry in this )
155 array.SetValue( entry, i++ );
158 // IDictionary Interface
159 public bool IsFixedSize
161 get {
162 return false;
166 public bool IsReadOnly
168 get {
169 return false;
173 // Indexer
174 public object this[object key]
176 get {
177 ListEntry entry = FindEntry(key);
178 return entry == null ? entry : entry.value;
181 set {
182 ListEntry entry = FindEntry(key);
183 if (entry != null)
184 entry.value = value;
185 else
186 AddImpl(key, value);
190 public ICollection Keys
192 get {
193 return new ListEntryCollection(this, true);
197 public ICollection Values
199 get {
200 return new ListEntryCollection(this, false);
204 public void Add(object key, object value)
206 AddImpl(key, value);
209 public void Clear()
211 root = null;
212 count = 0;
213 modCount++;
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)
228 if (key == null)
229 throw new ArgumentNullException(
230 "key",
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)) {
238 if (prev != null) {
239 prev.next = entry.next;
240 } else {
241 root = entry.next;
244 entry.value = null;
245 count--;
246 modCount++;
252 [Serializable]
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;
266 private int version;
268 public ListEntryEnumerator(ListDictionary dict)
270 this.dict = dict;
271 version = dict.modCount;
272 Reset();
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()
285 FailFast();
287 if (isAtStart) {
288 current = dict.root;
289 isAtStart = false;
290 } else {
291 current = current.next;
294 return current != null ? true : false;
297 public void Reset()
299 FailFast();
301 isAtStart = true;
302 current = null;
305 public object Current
307 get {
308 FailFast();
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
322 get {
323 FailFast();
324 return (DictionaryEntry) Current;
328 public object Key
330 get {
331 FailFast();
333 if (isAtStart || current == null) {
334 throw new InvalidOperationException(
335 "Enumerator is positioned before the collection's first element or after the last element.");
338 return current.key;
342 public object Value
344 get {
345 FailFast();
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)
364 this.dict = dict;
365 this.isKeyList = isKeyList;
368 // ICollection Interface
369 public int Count {
370 get {
371 return dict.Count;
375 public bool IsSynchronized
377 get {
378 return false;
382 public object SyncRoot
384 get {
385 return dict.SyncRoot;
389 public void CopyTo(Array array, int index)
391 int i = 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;
407 private int version;
408 private ListEntry current;
410 public ListEntryCollectionEnumerator(ListDictionary dict, bool isKeyList)
412 this.dict = dict;
413 this.isKeyList = isKeyList;
414 isAtStart = true;
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
429 get {
430 FailFast();
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()
444 FailFast();
446 if (isAtStart) {
447 current = dict.root;
448 isAtStart = false;
449 } else {
450 current = current.next;
453 return current != null ? true : false;
456 public void Reset()
458 FailFast();
459 isAtStart = true;
460 current = null;