2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Collections / Hashtable.cs
blobfe922cfea175df92b0db062d072a871707642b22
1 //
2 // System.Collections.Hashtable.cs
3 //
4 // Author:
5 // Sergey Chaban (serge@wildwestsoftware.com)
6 //
8 //
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.Collections;
33 using System.Runtime.Serialization;
35 using System.Runtime.ConstrainedExecution;
36 using System.Runtime.InteropServices;
37 using System.Diagnostics;
39 namespace System.Collections {
41 [ComVisible(true)]
42 [DebuggerDisplay ("Count={Count}")]
43 [DebuggerTypeProxy (typeof (CollectionDebuggerView))]
44 [Serializable]
45 #if INSIDE_CORLIB
46 public
47 #else
48 internal
49 #endif
50 class Hashtable : IDictionary, ICollection,
51 IEnumerable, ICloneable, ISerializable, IDeserializationCallback
54 [Serializable]
55 internal struct Slot {
56 internal Object key;
58 internal Object value;
61 [Serializable]
62 internal class KeyMarker
63 #if !NET_2_1
64 : IObjectReference
65 #endif
67 public readonly static KeyMarker Removed = new KeyMarker();
68 #if !NET_2_1
69 public object GetRealObject (StreamingContext context)
71 return KeyMarker.Removed;
73 #endif
77 // Private data
80 const int CHAIN_MARKER = ~Int32.MaxValue;
83 private int inUse;
84 private int modificationCount;
85 private float loadFactor;
86 private Slot [] table;
87 // Hashcodes of the corresponding entries in the slot table. Kept separate to
88 // help the GC
89 private int [] hashes;
91 private int threshold;
93 private HashKeys hashKeys;
94 private HashValues hashValues;
96 private IHashCodeProvider hcpRef;
97 private IComparer comparerRef;
98 private SerializationInfo serializationInfo;
100 private IEqualityComparer equalityComparer;
102 private static readonly int [] primeTbl = {
107 109,
108 163,
109 251,
110 367,
111 557,
112 823,
113 1237,
114 1861,
115 2777,
116 4177,
117 6247,
118 9371,
119 14057,
120 21089,
121 31627,
122 47431,
123 71143,
124 106721,
125 160073,
126 240101,
127 360163,
128 540217,
129 810343,
130 1215497,
131 1823231,
132 2734867,
133 4102283,
134 6153409,
135 9230113,
136 13845163
140 // Constructors
143 public Hashtable () : this (0, 1.0f) {}
145 [Obsolete ("Please use Hashtable(int, float, IEqualityComparer) instead")]
146 public Hashtable (int capacity, float loadFactor, IHashCodeProvider hcp, IComparer comparer) {
147 if (capacity<0)
148 throw new ArgumentOutOfRangeException ("capacity", "negative capacity");
150 if (loadFactor < 0.1f || loadFactor > 1.0f || Single.IsNaN (loadFactor))
151 throw new ArgumentOutOfRangeException ("loadFactor", "load factor");
153 if (capacity == 0) ++capacity;
154 this.loadFactor = 0.75f*loadFactor;
155 double tableSize = capacity / this.loadFactor;
157 if (tableSize > Int32.MaxValue)
158 throw new ArgumentException ("Size is too big");
160 int size = (int) tableSize;
161 size = ToPrime (size);
162 this.SetTable (new Slot [size], new int [size]);
164 this.hcp = hcp;
165 this.comparer = comparer;
167 this.inUse = 0;
168 this.modificationCount = 0;
171 public Hashtable (int capacity, float loadFactor) :
172 this (capacity, loadFactor, null, null)
176 public Hashtable (int capacity) : this (capacity, 1.0f)
181 // Used as a faster Clone
183 internal Hashtable (Hashtable source)
185 inUse = source.inUse;
186 loadFactor = source.loadFactor;
188 table = (Slot []) source.table.Clone ();
189 hashes = (int []) source.hashes.Clone ();
190 threshold = source.threshold;
191 hcpRef = source.hcpRef;
192 comparerRef = source.comparerRef;
193 equalityComparer = source.equalityComparer;
196 [Obsolete ("Please use Hashtable(int, IEqualityComparer) instead")]
197 public Hashtable (int capacity,
198 IHashCodeProvider hcp,
199 IComparer comparer)
200 : this (capacity, 1.0f, hcp, comparer)
204 [Obsolete ("Please use Hashtable(IDictionary, float, IEqualityComparer) instead")]
205 public Hashtable (IDictionary d, float loadFactor,
206 IHashCodeProvider hcp, IComparer comparer)
207 : this (d!=null ? d.Count : 0,
208 loadFactor, hcp, comparer)
211 if (d == null)
212 throw new ArgumentNullException ("dictionary");
214 IDictionaryEnumerator it = d.GetEnumerator ();
215 while (it.MoveNext ()) {
216 Add (it.Key, it.Value);
221 public Hashtable (IDictionary d, float loadFactor)
222 : this (d, loadFactor, null, null)
227 public Hashtable (IDictionary d) : this (d, 1.0f)
231 [Obsolete ("Please use Hashtable(IDictionary, IEqualityComparer) instead")]
232 public Hashtable (IDictionary d, IHashCodeProvider hcp, IComparer comparer)
233 : this (d, 1.0f, hcp, comparer)
237 [Obsolete ("Please use Hashtable(IEqualityComparer) instead")]
238 public Hashtable (IHashCodeProvider hcp, IComparer comparer)
239 : this (1, 1.0f, hcp, comparer)
243 protected Hashtable (SerializationInfo info, StreamingContext context)
245 serializationInfo = info;
248 public Hashtable (IDictionary d, IEqualityComparer equalityComparer) : this (d, 1.0f, equalityComparer)
252 public Hashtable (IDictionary d, float loadFactor, IEqualityComparer equalityComparer) : this (d, loadFactor)
254 this.equalityComparer = equalityComparer;
257 public Hashtable (IEqualityComparer equalityComparer) : this (1, 1.0f, equalityComparer)
261 public Hashtable (int capacity, IEqualityComparer equalityComparer) : this (capacity, 1.0f, equalityComparer)
265 public Hashtable (int capacity, float loadFactor, IEqualityComparer equalityComparer) : this (capacity, loadFactor)
267 this.equalityComparer = equalityComparer;
271 // Properties
274 [Obsolete ("Please use EqualityComparer property.")]
275 protected IComparer comparer {
276 set {
277 comparerRef = value;
279 get {
280 return comparerRef;
284 [Obsolete ("Please use EqualityComparer property.")]
285 protected IHashCodeProvider hcp {
286 set {
287 hcpRef = value;
289 get {
290 return hcpRef;
294 protected IEqualityComparer EqualityComparer {
295 get {
296 return equalityComparer;
300 // ICollection
302 public virtual int Count {
303 get {
304 return inUse;
308 public virtual bool IsSynchronized {
309 get {
310 return false;
314 public virtual Object SyncRoot {
315 get {
316 return this;
322 // IDictionary
324 public virtual bool IsFixedSize {
325 get {
326 return false;
331 public virtual bool IsReadOnly {
332 get {
333 return false;
337 public virtual ICollection Keys {
338 get {
339 if (this.hashKeys == null)
340 this.hashKeys = new HashKeys (this);
341 return this.hashKeys;
345 public virtual ICollection Values {
346 get {
347 if (this.hashValues == null)
348 this.hashValues = new HashValues (this);
349 return this.hashValues;
355 public virtual Object this [Object key] {
356 get {
357 if (key == null)
358 throw new ArgumentNullException ("key", "null key");
360 Slot [] table = this.table;
361 int [] hashes = this.hashes;
362 uint size = (uint) table.Length;
363 int h = this.GetHash (key) & Int32.MaxValue;
364 uint indx = (uint)h;
365 uint step = (uint) ((h >> 5)+1) % (size-1)+1;
368 for (uint i = size; i > 0; i--) {
369 indx %= size;
370 Slot entry = table [indx];
371 int hashMix = hashes [indx];
372 Object k = entry.key;
373 if (k == null)
374 break;
376 if (k == key || ((hashMix & Int32.MaxValue) == h
377 && this.KeyEquals (key, k))) {
378 return entry.value;
381 if ((hashMix & CHAIN_MARKER) == 0)
382 break;
384 indx += step;
387 return null;
390 set {
391 PutImpl (key, value, true);
399 // Interface methods
403 // IEnumerable
405 IEnumerator IEnumerable.GetEnumerator ()
407 return new Enumerator (this, EnumeratorMode.ENTRY_MODE);
411 // ICollection
412 public virtual void CopyTo (Array array, int arrayIndex)
414 if (null == array)
415 throw new ArgumentNullException ("array");
417 if (arrayIndex < 0)
418 throw new ArgumentOutOfRangeException ("arrayIndex");
420 if (array.Rank > 1)
421 throw new ArgumentException ("array is multidimensional");
423 if ((array.Length > 0) && (arrayIndex >= array.Length))
424 throw new ArgumentException ("arrayIndex is equal to or greater than array.Length");
426 if (arrayIndex + this.inUse > array.Length)
427 throw new ArgumentException ("Not enough room from arrayIndex to end of array for this Hashtable");
429 IDictionaryEnumerator it = GetEnumerator ();
430 int i = arrayIndex;
432 while (it.MoveNext ()) {
433 array.SetValue (it.Entry, i++);
438 // IDictionary
440 public virtual void Add (Object key, Object value)
442 PutImpl (key, value, false);
445 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
446 public virtual void Clear ()
448 for (int i = 0;i<table.Length;i++) {
449 table [i].key = null;
450 table [i].value = null;
451 hashes [i] = 0;
454 inUse = 0;
455 modificationCount++;
458 public virtual bool Contains (Object key)
460 return (Find (key) >= 0);
463 public virtual IDictionaryEnumerator GetEnumerator ()
465 return new Enumerator (this, EnumeratorMode.ENTRY_MODE);
468 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
469 public virtual void Remove (Object key)
471 int i = Find (key);
472 if (i >= 0) {
473 Slot [] table = this.table;
474 int h = hashes [i];
475 h &= CHAIN_MARKER;
476 hashes [i] = h;
477 table [i].key = (h != 0)
478 ? KeyMarker.Removed
479 : null;
480 table [i].value = null;
481 --inUse;
482 ++modificationCount;
486 public virtual bool ContainsKey (object key)
488 return Contains (key);
491 public virtual bool ContainsValue (object value)
493 int size = this.table.Length;
494 Slot [] table = this.table;
495 if (value == null) {
496 for (int i = 0; i < size; i++) {
497 Slot entry = table [i];
498 if (entry.key != null && entry.key!= KeyMarker.Removed
499 && entry.value == null) {
500 return true;
503 } else {
504 for (int i = 0; i < size; i++) {
505 Slot entry = table [i];
506 if (entry.key != null && entry.key!= KeyMarker.Removed
507 && value.Equals (entry.value)) {
508 return true;
512 return false;
516 // ICloneable
518 public virtual object Clone ()
520 return new Hashtable (this);
523 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
525 if (info == null)
526 throw new ArgumentNullException ("info");
528 info.AddValue ("LoadFactor", loadFactor);
529 info.AddValue ("Version", modificationCount);
530 if (equalityComparer != null)
531 info.AddValue ("KeyComparer", equalityComparer);
532 else
533 info.AddValue ("Comparer", comparerRef);
534 if (hcpRef != null)
535 info.AddValue ("HashCodeProvider", hcpRef);
536 info.AddValue ("HashSize", this.table.Length);
537 // Create Keys
538 Object [] keys = new Object[inUse];
539 CopyToArray(keys, 0, EnumeratorMode.KEY_MODE);
541 // Create Values
542 Object [] values = new Object[inUse];
543 CopyToArray(values, 0, EnumeratorMode.VALUE_MODE);
545 info.AddValue ("Keys", keys);
546 info.AddValue ("Values", values);
548 info.AddValue ("equalityComparer", equalityComparer);
551 [MonoTODO ("Serialize equalityComparer")]
552 public virtual void OnDeserialization (object sender)
554 if (serializationInfo == null) return;
556 loadFactor = (float) serializationInfo.GetValue ("LoadFactor", typeof(float));
557 modificationCount = (int) serializationInfo.GetValue ("Version", typeof(int));
558 try {
559 equalityComparer = (IEqualityComparer) serializationInfo.GetValue ("KeyComparer", typeof (object));
560 } catch {
561 // If not found, try to get "Comparer"
564 if (equalityComparer == null)
565 comparerRef = (IComparer) serializationInfo.GetValue ("Comparer", typeof (object));
566 try {
567 hcpRef = (IHashCodeProvider) serializationInfo.GetValue ("HashCodeProvider", typeof (object));
568 } catch {} // Missing value => null
569 int size = (int) serializationInfo.GetValue ("HashSize", typeof(int));
571 Object [] keys = (Object []) serializationInfo.GetValue("Keys", typeof(Object [] ));
572 Object [] values = (Object []) serializationInfo.GetValue("Values", typeof(Object [] ));
574 if (keys.Length != values.Length)
575 throw new SerializationException("Keys and values of uneven size");
577 size = ToPrime (size);
578 this.SetTable (new Slot [size], new int [size]);
580 for(int i=0;i<keys.Length;i++)
581 Add(keys[i], values[i]);
583 AdjustThreshold();
585 serializationInfo = null;
588 /// <summary>
589 /// Returns a synchronized (thread-safe)
590 /// wrapper for the Hashtable.
591 /// </summary>
592 public static Hashtable Synchronized (Hashtable table)
594 if (table == null)
595 throw new ArgumentNullException("table");
596 return new SyncHashtable (table);
602 // Protected instance methods
605 /// <summary>Returns the hash code for the specified key.</summary>
606 protected virtual int GetHash (Object key)
608 if (equalityComparer != null)
609 return equalityComparer.GetHashCode (key);
610 if (hcpRef == null)
611 return key.GetHashCode ();
613 return hcpRef.GetHashCode (key);
616 /// <summary>
617 /// Compares a specific Object with a specific key
618 /// in the Hashtable.
619 /// </summary>
620 protected virtual bool KeyEquals (Object item, Object key)
622 if (key == KeyMarker.Removed)
623 return false;
624 if (equalityComparer != null)
625 return equalityComparer.Equals (item, key);
626 if (comparerRef == null)
627 return item.Equals (key);
629 return comparerRef.Compare (item, key) == 0;
635 // Private instance methods
638 private void AdjustThreshold ()
640 int size = table.Length;
642 threshold = (int) (size*loadFactor);
643 if (this.threshold >= size)
644 threshold = size-1;
647 private void SetTable (Slot [] table, int[] hashes)
649 if (table == null)
650 throw new ArgumentNullException ("table");
652 this.table = table;
653 this.hashes = hashes;
654 AdjustThreshold ();
657 private int Find (Object key)
659 if (key == null)
660 throw new ArgumentNullException ("key", "null key");
662 Slot [] table = this.table;
663 int [] hashes = this.hashes;
664 uint size = (uint) table.Length;
665 int h = this.GetHash (key) & Int32.MaxValue;
666 uint indx = (uint)h;
667 uint step = (uint) ((h >> 5)+1) % (size-1)+1;
670 for (uint i = size; i > 0; i--) {
671 indx %= size;
672 Slot entry = table [indx];
673 int hashMix = hashes [indx];
674 Object k = entry.key;
675 if (k == null)
676 break;
678 if (k == key || ((hashMix & Int32.MaxValue) == h
679 && this.KeyEquals (key, k))) {
680 return (int) indx;
683 if ((hashMix & CHAIN_MARKER) == 0)
684 break;
686 indx += step;
688 return -1;
692 private void Rehash ()
694 int oldSize = this.table.Length;
696 // From the SDK docs:
697 // Hashtable is automatically increased
698 // to the smallest prime number that is larger
699 // than twice the current number of Hashtable buckets
700 uint newSize = (uint)ToPrime ((oldSize<<1)|1);
703 Slot [] newTable = new Slot [newSize];
704 Slot [] table = this.table;
705 int [] newHashes = new int [newSize];
706 int [] hashes = this.hashes;
708 for (int i = 0;i<oldSize;i++) {
709 Slot s = table [i];
710 if (s.key!= null) {
711 int h = hashes [i] & Int32.MaxValue;
712 uint spot = (uint)h;
713 uint step = ((uint) (h>>5)+1)% (newSize-1)+1;
714 for (uint j = spot%newSize;;spot+= step, j = spot%newSize) {
715 // No check for KeyMarker.Removed here,
716 // because the table is just allocated.
717 if (newTable [j].key == null) {
718 newTable [j].key = s.key;
719 newTable [j].value = s.value;
720 newHashes [j] |= h;
721 break;
722 } else {
723 newHashes [j] |= CHAIN_MARKER;
729 ++this.modificationCount;
731 this.SetTable (newTable, newHashes);
735 private void PutImpl (Object key, Object value, bool overwrite)
737 if (key == null)
738 throw new ArgumentNullException ("key", "null key");
740 if (this.inUse >= this.threshold)
741 this.Rehash ();
743 uint size = (uint)this.table.Length;
745 int h = this.GetHash (key) & Int32.MaxValue;
746 uint spot = (uint)h;
747 uint step = (uint) ((spot>>5)+1)% (size-1)+1;
748 Slot [] table = this.table;
749 int [] hashes = this.hashes;
750 Slot entry;
752 int freeIndx = -1;
753 for (int i = 0; i < size; i++) {
754 int indx = (int) (spot % size);
755 entry = table [indx];
756 int hashMix = hashes [indx];
758 if (freeIndx == -1
759 && entry.key == KeyMarker.Removed
760 && (hashMix & CHAIN_MARKER) != 0)
761 freeIndx = indx;
763 if (entry.key == null ||
764 (entry.key == KeyMarker.Removed
765 && (hashMix & CHAIN_MARKER) == 0)) {
767 if (freeIndx == -1)
768 freeIndx = indx;
769 break;
772 if ((hashMix & Int32.MaxValue) == h && KeyEquals (key, entry.key)) {
773 if (overwrite) {
774 table [indx].value = value;
775 ++this.modificationCount;
776 } else {
777 // Handle Add ():
778 // An entry with the same key already exists in the Hashtable.
779 throw new ArgumentException (
780 "Key duplication when adding: " + key);
782 return;
785 if (freeIndx == -1) {
786 hashes [indx] |= CHAIN_MARKER;
789 spot+= step;
793 if (freeIndx!= -1) {
794 table [freeIndx].key = key;
795 table [freeIndx].value = value;
796 hashes [freeIndx] |= h;
798 ++this.inUse;
799 ++this.modificationCount;
804 private void CopyToArray (Array arr, int i,
805 EnumeratorMode mode)
807 IEnumerator it = new Enumerator (this, mode);
809 while (it.MoveNext ()) {
810 arr.SetValue (it.Current, i++);
817 // Private static methods
819 internal static bool TestPrime (int x)
821 if ((x & 1) != 0) {
822 int top = (int)Math.Sqrt (x);
824 for (int n = 3; n < top; n += 2) {
825 if ((x % n) == 0)
826 return false;
828 return true;
830 // There is only one even prime - 2.
831 return (x == 2);
834 internal static int CalcPrime (int x)
836 for (int i = (x & (~1))-1; i< Int32.MaxValue; i += 2) {
837 if (TestPrime (i)) return i;
839 return x;
842 internal static int ToPrime (int x)
844 for (int i = 0; i < primeTbl.Length; i++) {
845 if (x <= primeTbl [i])
846 return primeTbl [i];
848 return CalcPrime (x);
855 // Inner classes
858 private enum EnumeratorMode : int {KEY_MODE = 0, VALUE_MODE, ENTRY_MODE};
860 [Serializable]
861 private sealed class Enumerator : IDictionaryEnumerator, IEnumerator {
863 private Hashtable host;
864 private int stamp;
865 private int pos;
866 private int size;
867 private EnumeratorMode mode;
869 private Object currentKey;
870 private Object currentValue;
872 private readonly static string xstr = "Hashtable.Enumerator: snapshot out of sync.";
874 public Enumerator (Hashtable host, EnumeratorMode mode) {
875 this.host = host;
876 stamp = host.modificationCount;
877 size = host.table.Length;
878 this.mode = mode;
879 Reset ();
882 public Enumerator (Hashtable host)
883 : this (host, EnumeratorMode.KEY_MODE) {}
886 private void FailFast ()
888 if (host.modificationCount != stamp) {
889 throw new InvalidOperationException (xstr);
893 public void Reset ()
895 FailFast ();
897 pos = -1;
898 currentKey = null;
899 currentValue = null;
902 public bool MoveNext ()
904 FailFast ();
906 if (pos < size) {
907 while (++pos < size) {
908 Slot entry = host.table [pos];
910 if (entry.key != null && entry.key != KeyMarker.Removed) {
911 currentKey = entry.key;
912 currentValue = entry.value;
913 return true;
918 currentKey = null;
919 currentValue = null;
920 return false;
923 public DictionaryEntry Entry
925 get {
926 if (currentKey == null) throw new InvalidOperationException ();
927 FailFast ();
928 return new DictionaryEntry (currentKey, currentValue);
932 public Object Key {
933 get {
934 if (currentKey == null) throw new InvalidOperationException ();
935 FailFast ();
936 return currentKey;
940 public Object Value {
941 get {
942 if (currentKey == null) throw new InvalidOperationException ();
943 FailFast ();
944 return currentValue;
948 public Object Current {
949 get {
950 if (currentKey == null) throw new InvalidOperationException ();
952 switch (mode) {
953 case EnumeratorMode.KEY_MODE:
954 return currentKey;
955 case EnumeratorMode.VALUE_MODE:
956 return currentValue;
957 case EnumeratorMode.ENTRY_MODE:
958 return new DictionaryEntry (currentKey, currentValue);
960 throw new Exception ("should never happen");
965 [Serializable]
966 [DebuggerDisplay ("Count={Count}")]
967 [DebuggerTypeProxy (typeof (CollectionDebuggerView))]
968 private class HashKeys : ICollection, IEnumerable {
970 private Hashtable host;
972 public HashKeys (Hashtable host) {
973 if (host == null)
974 throw new ArgumentNullException ();
976 this.host = host;
979 // ICollection
981 public virtual int Count {
982 get {
983 return host.Count;
987 public virtual bool IsSynchronized {
988 get {
989 return host.IsSynchronized;
993 public virtual Object SyncRoot {
994 get {return host.SyncRoot;}
997 public virtual void CopyTo (Array array, int arrayIndex)
999 if (array == null)
1000 throw new ArgumentNullException ("array");
1001 if (array.Rank != 1)
1002 throw new ArgumentException ("array");
1003 if (arrayIndex < 0)
1004 throw new ArgumentOutOfRangeException ("arrayIndex");
1005 if (array.Length - arrayIndex < Count)
1006 throw new ArgumentException ("not enough space");
1008 host.CopyToArray (array, arrayIndex, EnumeratorMode.KEY_MODE);
1011 // IEnumerable
1013 public virtual IEnumerator GetEnumerator ()
1015 return new Hashtable.Enumerator (host, EnumeratorMode.KEY_MODE);
1019 [Serializable]
1020 [DebuggerDisplay ("Count={Count}")]
1021 [DebuggerTypeProxy (typeof (CollectionDebuggerView))]
1022 private class HashValues : ICollection, IEnumerable {
1024 private Hashtable host;
1026 public HashValues (Hashtable host) {
1027 if (host == null)
1028 throw new ArgumentNullException ();
1030 this.host = host;
1033 // ICollection
1035 public virtual int Count {
1036 get {
1037 return host.Count;
1041 public virtual bool IsSynchronized {
1042 get {
1043 return host.IsSynchronized;
1047 public virtual Object SyncRoot {
1048 get {
1049 return host.SyncRoot;
1053 public virtual void CopyTo (Array array, int arrayIndex)
1055 if (array == null)
1056 throw new ArgumentNullException ("array");
1057 if (array.Rank != 1)
1058 throw new ArgumentException ("array");
1059 if (arrayIndex < 0)
1060 throw new ArgumentOutOfRangeException ("arrayIndex");
1061 if (array.Length - arrayIndex < Count)
1062 throw new ArgumentException ("not enough space");
1064 host.CopyToArray (array, arrayIndex, EnumeratorMode.VALUE_MODE);
1067 // IEnumerable
1069 public virtual IEnumerator GetEnumerator ()
1071 return new Hashtable.Enumerator (host, EnumeratorMode.VALUE_MODE);
1076 [Serializable]
1077 private class SyncHashtable : Hashtable, IEnumerable {
1079 private Hashtable host;
1081 public SyncHashtable (Hashtable host) {
1082 if (host == null)
1083 throw new ArgumentNullException ();
1085 this.host = host;
1088 internal SyncHashtable (SerializationInfo info, StreamingContext context)
1090 host = (Hashtable) info.GetValue("ParentTable", typeof(Hashtable));
1093 public override void GetObjectData (SerializationInfo info, StreamingContext context)
1095 info.AddValue ("ParentTable", host);
1098 // ICollection
1100 public override int Count {
1101 get {
1102 return host.Count;
1106 public override bool IsSynchronized {
1107 get {
1108 return true;
1112 public override Object SyncRoot {
1113 get {
1114 return host.SyncRoot;
1120 // IDictionary
1122 public override bool IsFixedSize {
1123 get {
1124 return host.IsFixedSize;
1129 public override bool IsReadOnly {
1130 get {
1131 return host.IsReadOnly;
1135 public override ICollection Keys {
1136 get {
1137 ICollection keys = null;
1138 lock (host.SyncRoot) {
1139 keys = host.Keys;
1141 return keys;
1145 public override ICollection Values {
1146 get {
1147 ICollection vals = null;
1148 lock (host.SyncRoot) {
1149 vals = host.Values;
1151 return vals;
1157 public override Object this [Object key] {
1158 get {
1159 return host [key];
1161 set {
1162 lock (host.SyncRoot) {
1163 host [key] = value;
1168 // IEnumerable
1170 IEnumerator IEnumerable.GetEnumerator ()
1172 return new Enumerator (host, EnumeratorMode.ENTRY_MODE);
1178 // ICollection
1180 public override void CopyTo (Array array, int arrayIndex)
1182 host.CopyTo (array, arrayIndex);
1186 // IDictionary
1188 public override void Add (Object key, Object value)
1190 lock (host.SyncRoot) {
1191 host.Add (key, value);
1195 public override void Clear ()
1197 lock (host.SyncRoot) {
1198 host.Clear ();
1202 public override bool Contains (Object key)
1204 return (host.Find (key) >= 0);
1207 public override IDictionaryEnumerator GetEnumerator ()
1209 return new Enumerator (host, EnumeratorMode.ENTRY_MODE);
1212 public override void Remove (Object key)
1214 lock (host.SyncRoot) {
1215 host.Remove (key);
1221 public override bool ContainsKey (object key)
1223 return host.Contains (key);
1226 public override bool ContainsValue (object value)
1228 return host.ContainsValue (value);
1232 // ICloneable
1234 public override object Clone ()
1236 lock(host.SyncRoot) {
1237 return new SyncHashtable( (Hashtable) host.Clone () );
1241 } // SyncHashtable
1244 } // Hashtable