Hashtable.cs 19 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. //
  2. // System.Collections.Hashtable
  3. //
  4. // Author:
  5. // Sergey Chaban ([email protected])
  6. //
  7. using System;
  8. using System.Collections;
  9. using System.Runtime.Serialization;
  10. namespace System.Collections {
  11. [Serializable]
  12. public class Hashtable : IDictionary, ICollection,
  13. IEnumerable, ICloneable, ISerializable, IDeserializationCallback
  14. {
  15. [Serializable]
  16. internal struct Slot {
  17. internal Object key;
  18. internal Object value;
  19. // Hashcode. Chains are also marked through this.
  20. internal int hashMix;
  21. }
  22. //
  23. // Private data
  24. //
  25. private readonly static int CHAIN_MARKER = ~Int32.MaxValue;
  26. // Used as indicator for the removed parts of a chain.
  27. private readonly static Object REMOVED_MARKER = new Object ();
  28. private int inUse;
  29. private int modificationCount;
  30. private float loadFactor;
  31. private Slot [] table;
  32. private int threshold;
  33. private IHashCodeProvider hcpRef;
  34. private IComparer comparerRef;
  35. private static int [] primeTbl = {
  36. 11,
  37. 19,
  38. 37,
  39. 73,
  40. 109,
  41. 163,
  42. 251,
  43. 367,
  44. 557,
  45. 823,
  46. 1237,
  47. 1861,
  48. 2777,
  49. 4177,
  50. 6247,
  51. 9371,
  52. 14057,
  53. 21089,
  54. 31627,
  55. 47431,
  56. 71143,
  57. 106721,
  58. 160073,
  59. 240101,
  60. 360163,
  61. 540217,
  62. 810343,
  63. 1215497,
  64. 1823231,
  65. 2734867,
  66. 4102283,
  67. 6153409,
  68. 9230113,
  69. 13845163
  70. };
  71. // Class constructor
  72. static Hashtable () {
  73. // NOTE: previously this static constructor was used
  74. // to calculate primeTbl, now primeTbl is
  75. // hardcoded and constructor does nothing
  76. // useful except for forcing compiler to
  77. // eliminate beforefieldinit from signature.
  78. }
  79. //
  80. // Constructors
  81. //
  82. public Hashtable () : this (0, 1.0f) {}
  83. public Hashtable (int capacity, float loadFactor, IHashCodeProvider hcp, IComparer comparer) {
  84. if (capacity<0)
  85. throw new ArgumentOutOfRangeException ("negative capacity");
  86. if (loadFactor<0.1 || loadFactor>1)
  87. throw new ArgumentOutOfRangeException ("load factor");
  88. if (capacity == 0) ++capacity;
  89. this.loadFactor = 0.75f*loadFactor;
  90. int size = (int) (capacity/this.loadFactor);
  91. size = ToPrime (size);
  92. this.SetTable (new Slot [size]);
  93. this.hcp = hcp;
  94. this.comparer = comparer;
  95. this.inUse = 0;
  96. this.modificationCount = 0;
  97. }
  98. public Hashtable (int capacity, float loadFactor) :
  99. this (capacity, loadFactor, null, null)
  100. {
  101. }
  102. public Hashtable (int capacity) : this (capacity, 1.0f)
  103. {
  104. }
  105. public Hashtable (int capacity,
  106. IHashCodeProvider hcp,
  107. IComparer comparer)
  108. : this (capacity, 1.0f, hcp, comparer)
  109. {
  110. }
  111. public Hashtable (IDictionary d, float loadFactor,
  112. IHashCodeProvider hcp, IComparer comparer)
  113. : this (d!=null ? d.Count : 0,
  114. loadFactor, hcp, comparer)
  115. {
  116. if (d == null)
  117. throw new ArgumentNullException ("dictionary");
  118. IDictionaryEnumerator it = d.GetEnumerator ();
  119. while (it.MoveNext ()) {
  120. Add (it.Key, it.Value);
  121. }
  122. }
  123. public Hashtable (IDictionary d, float loadFactor)
  124. : this (d, loadFactor, null, null)
  125. {
  126. }
  127. public Hashtable (IDictionary d) : this (d, 1.0f)
  128. {
  129. }
  130. public Hashtable (IDictionary d, IHashCodeProvider hcp, IComparer comparer)
  131. : this (d, 1.0f, hcp, comparer)
  132. {
  133. }
  134. public Hashtable (IHashCodeProvider hcp, IComparer comparer)
  135. : this (1, 1.0f, hcp, comparer)
  136. {
  137. }
  138. protected Hashtable (SerializationInfo info, StreamingContext context)
  139. {
  140. loadFactor = (float) info.GetValue ("LoadFactor", typeof(float));
  141. modificationCount = (int) info.GetValue ("Version", typeof(int));
  142. comparerRef = (IComparer) info.GetValue ("Comparer", typeof (object));
  143. hcpRef = (IHashCodeProvider) info.GetValue ("HashCodeProvider", typeof (object));
  144. inUse = (int) info.GetValue ("HashSize", typeof(int));
  145. table = (Slot[]) info.GetValue("Table", typeof(Slot[]));
  146. threshold = (int) info.GetValue("Treshold", typeof(int));
  147. }
  148. //
  149. // Properties
  150. //
  151. protected IComparer comparer {
  152. set {
  153. comparerRef = value;
  154. }
  155. get {
  156. return comparerRef;
  157. }
  158. }
  159. protected IHashCodeProvider hcp {
  160. set {
  161. hcpRef = value;
  162. }
  163. get {
  164. return hcpRef;
  165. }
  166. }
  167. // ICollection
  168. public virtual int Count {
  169. get {
  170. return inUse;
  171. }
  172. }
  173. public virtual bool IsSynchronized {
  174. get {
  175. return false;
  176. }
  177. }
  178. public virtual Object SyncRoot {
  179. get {
  180. return this;
  181. }
  182. }
  183. // IDictionary
  184. public virtual bool IsFixedSize {
  185. get {
  186. return false;
  187. }
  188. }
  189. public virtual bool IsReadOnly {
  190. get {
  191. return false;
  192. }
  193. }
  194. public virtual ICollection Keys {
  195. get {
  196. return new HashKeys (this);
  197. }
  198. }
  199. public virtual ICollection Values {
  200. get {
  201. return new HashValues (this);
  202. }
  203. }
  204. public virtual Object this [Object key] {
  205. get {
  206. return GetImpl (key);
  207. }
  208. set {
  209. PutImpl (key, value, true);
  210. }
  211. }
  212. //
  213. // Interface methods
  214. //
  215. // IEnumerable
  216. IEnumerator IEnumerable.GetEnumerator ()
  217. {
  218. return new Enumerator (this, EnumeratorMode.KEY_MODE);
  219. }
  220. // ICollection
  221. public virtual void CopyTo (Array array, int arrayIndex)
  222. {
  223. if (null == array)
  224. throw new ArgumentNullException ("array");
  225. if (arrayIndex < 0)
  226. throw new ArgumentOutOfRangeException ("arrayIndex");
  227. if (array.Rank > 1)
  228. throw new ArgumentException ("array is multidimensional");
  229. if (arrayIndex >= array.Length)
  230. throw new ArgumentException ("arrayIndex is equal to or greater than array.Length");
  231. if (arrayIndex + this.inUse > array.Length)
  232. throw new ArgumentException ("Not enough room from arrayIndex to end of array for this Hashtable");
  233. IDictionaryEnumerator it = GetEnumerator ();
  234. int i = arrayIndex;
  235. while (it.MoveNext ()) {
  236. array.SetValue (it.Entry, i++);
  237. }
  238. }
  239. // IDictionary
  240. public virtual void Add (Object key, Object value)
  241. {
  242. PutImpl (key, value, false);
  243. }
  244. public virtual void Clear ()
  245. {
  246. for (int i = 0;i<table.Length;i++) {
  247. table [i].key = null;
  248. table [i].value = null;
  249. table [i].hashMix = 0;
  250. }
  251. inUse = 0;
  252. modificationCount++;
  253. }
  254. public virtual bool Contains (Object key)
  255. {
  256. return (Find (key) >= 0);
  257. }
  258. public virtual IDictionaryEnumerator GetEnumerator ()
  259. {
  260. return new Enumerator (this, EnumeratorMode.ENTRY_MODE);
  261. }
  262. public virtual void Remove (Object key)
  263. {
  264. int i = Find (key);
  265. Slot [] table = this.table;
  266. if (i >= 0) {
  267. int h = table [i].hashMix;
  268. h &= CHAIN_MARKER;
  269. table [i].hashMix = h;
  270. table [i].key = (h != 0)
  271. ? REMOVED_MARKER
  272. : null;
  273. table [i].value = null;
  274. --inUse;
  275. ++modificationCount;
  276. }
  277. }
  278. public virtual bool ContainsKey (object key)
  279. {
  280. return Contains (key);
  281. }
  282. public virtual bool ContainsValue (object value)
  283. {
  284. int size = this.table.Length;
  285. Slot [] table = this.table;
  286. for (int i = 0; i < size; i++) {
  287. Slot entry = table [i];
  288. if (entry.key != null && entry.key!= REMOVED_MARKER
  289. && value.Equals (entry.value)) {
  290. return true;
  291. }
  292. }
  293. return false;
  294. }
  295. // ICloneable
  296. public virtual object Clone ()
  297. {
  298. Hashtable ht = new Hashtable (Count, hcp, comparer);
  299. ht.modificationCount = this.modificationCount;
  300. ht.inUse = this.inUse;
  301. ht.AdjustThreshold ();
  302. // FIXME: maybe it's faster to simply
  303. // copy the back-end array?
  304. IDictionaryEnumerator it = GetEnumerator ();
  305. while (it.MoveNext ()) {
  306. ht [it.Key] = it.Value;
  307. }
  308. return ht;
  309. }
  310. public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
  311. {
  312. info.AddValue ("LoadFactor", loadFactor);
  313. info.AddValue ("Version", modificationCount);
  314. info.AddValue ("Comparer", comparerRef);
  315. info.AddValue ("HashCodeProvider", hcpRef);
  316. info.AddValue ("HashSize", inUse);
  317. info.AddValue ("Table", table);
  318. info.AddValue ("Treshold", threshold);
  319. }
  320. public virtual void OnDeserialization (object sender)
  321. {
  322. }
  323. /// <summary>
  324. /// Returns a synchronized (thread-safe)
  325. /// wrapper for the Hashtable.
  326. /// </summary>
  327. public static Hashtable Synchronized (Hashtable table)
  328. {
  329. return new SynchedHashtable (table);
  330. }
  331. //
  332. // Protected instance methods
  333. //
  334. /// <summary>Returns the hash code for the specified key.</summary>
  335. protected virtual int GetHash (Object key)
  336. {
  337. IHashCodeProvider hcp = this.hcp;
  338. return (hcp!= null)
  339. ? hcp.GetHashCode (key)
  340. : key.GetHashCode ();
  341. }
  342. /// <summary>
  343. /// Compares a specific Object with a specific key
  344. /// in the Hashtable.
  345. /// </summary>
  346. protected virtual bool KeyEquals (Object item, Object key)
  347. {
  348. IComparer c = this.comparer;
  349. if (c!= null)
  350. return (c.Compare (item, key) == 0);
  351. else
  352. return item.Equals (key);
  353. }
  354. //
  355. // Private instance methods
  356. //
  357. private void AdjustThreshold ()
  358. {
  359. int size = table.Length;
  360. threshold = (int) (size*loadFactor);
  361. if (this.threshold >= size)
  362. threshold = size-1;
  363. }
  364. private void SetTable (Slot [] table)
  365. {
  366. if (table == null)
  367. throw new ArgumentNullException ("table");
  368. this.table = table;
  369. AdjustThreshold ();
  370. }
  371. private Object GetImpl (Object key)
  372. {
  373. int i = Find (key);
  374. if (i >= 0)
  375. return table [i].value;
  376. else
  377. return null;
  378. }
  379. private int Find (Object key)
  380. {
  381. if (key == null)
  382. throw new ArgumentNullException ("null key");
  383. uint size = (uint) this.table.Length;
  384. int h = this.GetHash (key) & Int32.MaxValue;
  385. uint spot = (uint)h;
  386. uint step = (uint) ((h >> 5)+1) % (size-1)+1;
  387. Slot[] table = this.table;
  388. for (int i = 0; i < size;i++) {
  389. int indx = (int) (spot % size);
  390. Slot entry = table [indx];
  391. Object k = entry.key;
  392. if (k == null)
  393. return -1;
  394. if ((entry.hashMix & Int32.MaxValue) == h
  395. && this.KeyEquals (key, k)) {
  396. return indx;
  397. }
  398. if ((entry.hashMix & CHAIN_MARKER) == 0)
  399. return -1;
  400. spot+= step;
  401. }
  402. return -1;
  403. }
  404. private void Rehash ()
  405. {
  406. int oldSize = this.table.Length;
  407. // From the SDK docs:
  408. // Hashtable is automatically increased
  409. // to the smallest prime number that is larger
  410. // than twice the current number of Hashtable buckets
  411. uint newSize = (uint)ToPrime ((oldSize<<1)|1);
  412. Slot [] newTable = new Slot [newSize];
  413. Slot [] table = this.table;
  414. for (int i = 0;i<oldSize;i++) {
  415. Slot s = table [i];
  416. if (s.key!= null) {
  417. int h = s.hashMix & Int32.MaxValue;
  418. uint spot = (uint)h;
  419. uint step = ((uint) (h>>5)+1)% (newSize-1)+1;
  420. for (uint j = spot%newSize;;spot+= step, j = spot%newSize) {
  421. // No check for REMOVED_MARKER here,
  422. // because the table is just allocated.
  423. if (newTable [j].key == null) {
  424. newTable [j].key = s.key;
  425. newTable [j].value = s.value;
  426. newTable [j].hashMix |= h;
  427. break;
  428. } else {
  429. newTable [j].hashMix |= CHAIN_MARKER;
  430. }
  431. }
  432. }
  433. }
  434. ++this.modificationCount;
  435. this.SetTable (newTable);
  436. }
  437. private void PutImpl (Object key, Object value, bool overwrite)
  438. {
  439. if (key == null)
  440. throw new ArgumentNullException ("null key");
  441. uint size = (uint)this.table.Length;
  442. if (this.inUse >= this.threshold) {
  443. this.Rehash ();
  444. size = (uint)this.table.Length;
  445. }
  446. int h = this.GetHash (key) & Int32.MaxValue;
  447. uint spot = (uint)h;
  448. uint step = (uint) ((spot>>5)+1)% (size-1)+1;
  449. Slot [] table = this.table;
  450. Slot entry;
  451. int freeIndx = -1;
  452. for (int i = 0; i < size; i++) {
  453. int indx = (int) (spot % size);
  454. entry = table [indx];
  455. if (freeIndx == -1
  456. && entry.key == REMOVED_MARKER
  457. && (entry.hashMix & CHAIN_MARKER)!= 0)
  458. freeIndx = indx;
  459. if (entry.key == null ||
  460. (entry.key == REMOVED_MARKER
  461. && (entry.hashMix & CHAIN_MARKER)!= 0)) {
  462. if (freeIndx == -1)
  463. freeIndx = indx;
  464. break;
  465. }
  466. if ((entry.hashMix & Int32.MaxValue) == h && KeyEquals (key, entry.key)) {
  467. if (overwrite) {
  468. table [indx].value = value;
  469. ++this.modificationCount;
  470. } else {
  471. // Handle Add ():
  472. // An entry with the same key already exists in the Hashtable.
  473. throw new ArgumentException (
  474. "Key duplication when adding: " + key);
  475. }
  476. return;
  477. }
  478. if (freeIndx == -1) {
  479. table [indx].hashMix |= CHAIN_MARKER;
  480. }
  481. spot+= step;
  482. }
  483. if (freeIndx!= -1) {
  484. table [freeIndx].key = key;
  485. table [freeIndx].value = value;
  486. table [freeIndx].hashMix |= h;
  487. ++this.inUse;
  488. ++this.modificationCount;
  489. }
  490. }
  491. private void CopyToArray (Array arr, int i,
  492. EnumeratorMode mode)
  493. {
  494. IEnumerator it = new Enumerator (this, mode);
  495. while (it.MoveNext ()) {
  496. arr.SetValue (it.Current, i++);
  497. }
  498. }
  499. //
  500. // Private static methods
  501. //
  502. private static bool TestPrime (int x)
  503. {
  504. if ((x & 1) != 0) {
  505. for (int n = 3; n< (int)Math.Sqrt (x); n += 2) {
  506. if ((x % n) == 0)
  507. return false;
  508. }
  509. return true;
  510. }
  511. // There is only one even prime - 2.
  512. return (x == 2);
  513. }
  514. private static int CalcPrime (int x)
  515. {
  516. for (int i = (x & (~1))-1; i< Int32.MaxValue; i += 2) {
  517. if (TestPrime (i)) return i;
  518. }
  519. return x;
  520. }
  521. private static int ToPrime (int x)
  522. {
  523. for (int i = 0; i < primeTbl.Length; i++) {
  524. if (x <= primeTbl [i])
  525. return primeTbl [i];
  526. }
  527. return CalcPrime (x);
  528. }
  529. //
  530. // Inner classes
  531. //
  532. public enum EnumeratorMode : int {KEY_MODE = 0, VALUE_MODE, ENTRY_MODE};
  533. protected sealed class Enumerator : IDictionaryEnumerator, IEnumerator {
  534. private Hashtable host;
  535. private int stamp;
  536. private int pos;
  537. private int size;
  538. private EnumeratorMode mode;
  539. private Object currentKey;
  540. private Object currentValue;
  541. private readonly static string xstr = "Hashtable.Enumerator: snapshot out of sync.";
  542. public Enumerator (Hashtable host, EnumeratorMode mode) {
  543. this.host = host;
  544. stamp = host.modificationCount;
  545. size = host.table.Length;
  546. this.mode = mode;
  547. Reset ();
  548. }
  549. public Enumerator (Hashtable host)
  550. : this (host, EnumeratorMode.KEY_MODE) {}
  551. private void FailFast ()
  552. {
  553. if (host.modificationCount != stamp) {
  554. throw new InvalidOperationException (xstr);
  555. }
  556. }
  557. public void Reset ()
  558. {
  559. FailFast ();
  560. pos = -1;
  561. currentKey = null;
  562. currentValue = null;
  563. }
  564. public bool MoveNext ()
  565. {
  566. FailFast ();
  567. if (pos < size) {
  568. while (++pos < size) {
  569. Slot entry = host.table [pos];
  570. if (entry.key != null && entry.key != REMOVED_MARKER) {
  571. currentKey = entry.key;
  572. currentValue = entry.value;
  573. return true;
  574. }
  575. }
  576. }
  577. currentKey = null;
  578. currentValue = null;
  579. return false;
  580. }
  581. public DictionaryEntry Entry
  582. {
  583. get {
  584. FailFast ();
  585. return new DictionaryEntry (currentKey, currentValue);
  586. }
  587. }
  588. public Object Key {
  589. get {
  590. FailFast ();
  591. return currentKey;
  592. }
  593. }
  594. public Object Value {
  595. get {
  596. FailFast ();
  597. return currentValue;
  598. }
  599. }
  600. public Object Current {
  601. get {
  602. FailFast ();
  603. switch (mode) {
  604. case EnumeratorMode.KEY_MODE:
  605. return currentKey;
  606. case EnumeratorMode.VALUE_MODE:
  607. return currentValue;
  608. case EnumeratorMode.ENTRY_MODE:
  609. return new DictionaryEntry (currentKey, currentValue);
  610. }
  611. throw new Exception ("should never happen");
  612. }
  613. }
  614. }
  615. protected class HashKeys : ICollection, IEnumerable {
  616. private Hashtable host;
  617. private int count;
  618. public HashKeys (Hashtable host) {
  619. if (host == null)
  620. throw new ArgumentNullException ();
  621. this.host = host;
  622. this.count = host.Count;
  623. }
  624. // ICollection
  625. public virtual int Count {
  626. get {
  627. return count;
  628. }
  629. }
  630. public virtual bool IsSynchronized {
  631. get {
  632. return host.IsSynchronized;
  633. }
  634. }
  635. public virtual Object SyncRoot {
  636. get {return host.SyncRoot;}
  637. }
  638. public virtual void CopyTo (Array array, int arrayIndex)
  639. {
  640. host.CopyToArray (array, arrayIndex, EnumeratorMode.KEY_MODE);
  641. }
  642. // IEnumerable
  643. public virtual IEnumerator GetEnumerator ()
  644. {
  645. return new Hashtable.Enumerator (host, EnumeratorMode.KEY_MODE);
  646. }
  647. }
  648. protected class HashValues : ICollection, IEnumerable {
  649. private Hashtable host;
  650. private int count;
  651. public HashValues (Hashtable host) {
  652. if (host == null)
  653. throw new ArgumentNullException ();
  654. this.host = host;
  655. this.count = host.Count;
  656. }
  657. // ICollection
  658. public virtual int Count {
  659. get {
  660. return count;
  661. }
  662. }
  663. public virtual bool IsSynchronized {
  664. get {
  665. return host.IsSynchronized;
  666. }
  667. }
  668. public virtual Object SyncRoot {
  669. get {
  670. return host.SyncRoot;
  671. }
  672. }
  673. public virtual void CopyTo (Array array, int arrayIndex)
  674. {
  675. host.CopyToArray (array, arrayIndex, EnumeratorMode.VALUE_MODE);
  676. }
  677. // IEnumerable
  678. public virtual IEnumerator GetEnumerator ()
  679. {
  680. return new Hashtable.Enumerator (host, EnumeratorMode.VALUE_MODE);
  681. }
  682. }
  683. protected class SynchedHashtable : Hashtable, IEnumerable {
  684. private Hashtable host;
  685. public SynchedHashtable (Hashtable host) {
  686. if (host == null)
  687. throw new ArgumentNullException ();
  688. this.host = host;
  689. }
  690. // ICollection
  691. public override int Count {
  692. get {
  693. return host.Count;
  694. }
  695. }
  696. public override bool IsSynchronized {
  697. get {
  698. return true;
  699. }
  700. }
  701. public override Object SyncRoot {
  702. get {
  703. return host.SyncRoot;
  704. }
  705. }
  706. // IDictionary
  707. public override bool IsFixedSize {
  708. get {
  709. return host.IsFixedSize;
  710. }
  711. }
  712. public override bool IsReadOnly {
  713. get {
  714. return host.IsReadOnly;
  715. }
  716. }
  717. public override ICollection Keys {
  718. get {
  719. ICollection keys = null;
  720. lock (host.SyncRoot) {
  721. keys = host.Keys;
  722. }
  723. return keys;
  724. }
  725. }
  726. public override ICollection Values {
  727. get {
  728. ICollection vals = null;
  729. lock (host.SyncRoot) {
  730. vals = host.Values;
  731. }
  732. return vals;
  733. }
  734. }
  735. public override Object this [Object key] {
  736. get {
  737. return host.GetImpl (key);
  738. }
  739. set {
  740. lock (host.SyncRoot) {
  741. host.PutImpl (key, value, true);
  742. }
  743. }
  744. }
  745. // IEnumerable
  746. IEnumerator IEnumerable.GetEnumerator ()
  747. {
  748. return new Enumerator (host, EnumeratorMode.KEY_MODE);
  749. }
  750. // ICollection
  751. public override void CopyTo (Array array, int arrayIndex)
  752. {
  753. host.CopyTo (array, arrayIndex);
  754. }
  755. // IDictionary
  756. public override void Add (Object key, Object value)
  757. {
  758. lock (host.SyncRoot) {
  759. host.PutImpl (key, value, false);
  760. }
  761. }
  762. public override void Clear ()
  763. {
  764. lock (host.SyncRoot) {
  765. host.Clear ();
  766. }
  767. }
  768. public override bool Contains (Object key)
  769. {
  770. return (host.Find (key) >= 0);
  771. }
  772. public override IDictionaryEnumerator GetEnumerator ()
  773. {
  774. return new Enumerator (host, EnumeratorMode.ENTRY_MODE);
  775. }
  776. public override void Remove (Object key)
  777. {
  778. lock (host.SyncRoot) {
  779. host.Remove (key);
  780. }
  781. }
  782. public override bool ContainsKey (object key)
  783. {
  784. return host.Contains (key);
  785. }
  786. public override bool ContainsValue (object value)
  787. {
  788. return host.ContainsValue (value);
  789. }
  790. // ICloneable
  791. public override object Clone ()
  792. {
  793. return (host.Clone () as Hashtable);
  794. }
  795. } // SynchedHashtable
  796. } // Hashtable
  797. }