Hashtable.cs 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. //
  2. // System.Collections.Hashtable.cs
  3. //
  4. // Author:
  5. // Sergey Chaban ([email protected])
  6. //
  7. //
  8. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections;
  31. using System.Runtime.Serialization;
  32. #if NET_2_0
  33. using System.Runtime.ConstrainedExecution;
  34. using System.Runtime.InteropServices;
  35. #endif
  36. namespace System.Collections {
  37. #if NET_2_0
  38. [ComVisible(true)]
  39. #endif
  40. [Serializable]
  41. #if INSIDE_CORLIB
  42. public
  43. #else
  44. internal
  45. #endif
  46. class Hashtable : IDictionary, ICollection,
  47. IEnumerable, ICloneable, ISerializable, IDeserializationCallback
  48. {
  49. [Serializable]
  50. internal struct Slot {
  51. internal Object key;
  52. internal Object value;
  53. }
  54. [Serializable]
  55. internal class KeyMarker: IObjectReference
  56. {
  57. public readonly static KeyMarker Removed = new KeyMarker();
  58. public object GetRealObject (StreamingContext context)
  59. { return KeyMarker.Removed; }
  60. }
  61. //
  62. // Private data
  63. //
  64. const int CHAIN_MARKER = ~Int32.MaxValue;
  65. private int inUse;
  66. private int modificationCount;
  67. private float loadFactor;
  68. private Slot [] table;
  69. // Hashcodes of the corresponding entries in the slot table. Kept separate to
  70. // help the GC
  71. private int [] hashes;
  72. private int threshold;
  73. private HashKeys hashKeys;
  74. private HashValues hashValues;
  75. private IHashCodeProvider hcpRef;
  76. private IComparer comparerRef;
  77. private SerializationInfo serializationInfo;
  78. #if NET_2_0
  79. private IEqualityComparer equalityComparer;
  80. #endif
  81. private static readonly int [] primeTbl = {
  82. 11,
  83. 19,
  84. 37,
  85. 73,
  86. 109,
  87. 163,
  88. 251,
  89. 367,
  90. 557,
  91. 823,
  92. 1237,
  93. 1861,
  94. 2777,
  95. 4177,
  96. 6247,
  97. 9371,
  98. 14057,
  99. 21089,
  100. 31627,
  101. 47431,
  102. 71143,
  103. 106721,
  104. 160073,
  105. 240101,
  106. 360163,
  107. 540217,
  108. 810343,
  109. 1215497,
  110. 1823231,
  111. 2734867,
  112. 4102283,
  113. 6153409,
  114. 9230113,
  115. 13845163
  116. };
  117. //
  118. // Constructors
  119. //
  120. public Hashtable () : this (0, 1.0f) {}
  121. #if NET_2_0
  122. [Obsolete ("Please use Hashtable(int, float, IEqualityComparer) instead")]
  123. #endif
  124. public Hashtable (int capacity, float loadFactor, IHashCodeProvider hcp, IComparer comparer) {
  125. if (capacity<0)
  126. throw new ArgumentOutOfRangeException ("capacity", "negative capacity");
  127. if (loadFactor < 0.1f || loadFactor > 1.0f || Single.IsNaN (loadFactor))
  128. throw new ArgumentOutOfRangeException ("loadFactor", "load factor");
  129. if (capacity == 0) ++capacity;
  130. this.loadFactor = 0.75f*loadFactor;
  131. double tableSize = capacity / this.loadFactor;
  132. if (tableSize > Int32.MaxValue)
  133. throw new ArgumentException ("Size is too big");
  134. int size = (int) tableSize;
  135. size = ToPrime (size);
  136. this.SetTable (new Slot [size], new int [size]);
  137. this.hcp = hcp;
  138. this.comparer = comparer;
  139. this.inUse = 0;
  140. this.modificationCount = 0;
  141. }
  142. public Hashtable (int capacity, float loadFactor) :
  143. this (capacity, loadFactor, null, null)
  144. {
  145. }
  146. public Hashtable (int capacity) : this (capacity, 1.0f)
  147. {
  148. }
  149. #if NET_2_0
  150. [Obsolete ("Please use Hashtable(int, IEqualityComparer) instead")]
  151. #endif
  152. public Hashtable (int capacity,
  153. IHashCodeProvider hcp,
  154. IComparer comparer)
  155. : this (capacity, 1.0f, hcp, comparer)
  156. {
  157. }
  158. #if NET_2_0
  159. [Obsolete ("Please use Hashtable(IDictionary, float, IEqualityComparer) instead")]
  160. #endif
  161. public Hashtable (IDictionary d, float loadFactor,
  162. IHashCodeProvider hcp, IComparer comparer)
  163. : this (d!=null ? d.Count : 0,
  164. loadFactor, hcp, comparer)
  165. {
  166. if (d == null)
  167. throw new ArgumentNullException ("dictionary");
  168. IDictionaryEnumerator it = d.GetEnumerator ();
  169. while (it.MoveNext ()) {
  170. Add (it.Key, it.Value);
  171. }
  172. }
  173. public Hashtable (IDictionary d, float loadFactor)
  174. : this (d, loadFactor, null, null)
  175. {
  176. }
  177. public Hashtable (IDictionary d) : this (d, 1.0f)
  178. {
  179. }
  180. #if NET_2_0
  181. [Obsolete ("Please use Hashtable(IDictionary, IEqualityComparer) instead")]
  182. #endif
  183. public Hashtable (IDictionary d, IHashCodeProvider hcp, IComparer comparer)
  184. : this (d, 1.0f, hcp, comparer)
  185. {
  186. }
  187. #if NET_2_0
  188. [Obsolete ("Please use Hashtable(IEqualityComparer) instead")]
  189. #endif
  190. public Hashtable (IHashCodeProvider hcp, IComparer comparer)
  191. : this (1, 1.0f, hcp, comparer)
  192. {
  193. }
  194. protected Hashtable (SerializationInfo info, StreamingContext context)
  195. {
  196. serializationInfo = info;
  197. }
  198. #if NET_2_0
  199. public Hashtable (IDictionary d, IEqualityComparer equalityComparer) : this (d, 1.0f, equalityComparer)
  200. {
  201. }
  202. public Hashtable (IDictionary d, float loadFactor, IEqualityComparer equalityComparer) : this (d, loadFactor)
  203. {
  204. this.equalityComparer = equalityComparer;
  205. }
  206. public Hashtable (IEqualityComparer equalityComparer) : this (1, 1.0f, equalityComparer)
  207. {
  208. }
  209. public Hashtable (int capacity, IEqualityComparer equalityComparer) : this (capacity, 1.0f, equalityComparer)
  210. {
  211. }
  212. public Hashtable (int capacity, float loadFactor, IEqualityComparer equalityComparer) : this (capacity, loadFactor)
  213. {
  214. this.equalityComparer = equalityComparer;
  215. }
  216. #endif
  217. //
  218. // Properties
  219. //
  220. #if NET_2_0
  221. [Obsolete ("Please use EqualityComparer property.")]
  222. #endif
  223. protected IComparer comparer {
  224. set {
  225. comparerRef = value;
  226. }
  227. get {
  228. return comparerRef;
  229. }
  230. }
  231. #if NET_2_0
  232. [Obsolete ("Please use EqualityComparer property.")]
  233. #endif
  234. protected IHashCodeProvider hcp {
  235. set {
  236. hcpRef = value;
  237. }
  238. get {
  239. return hcpRef;
  240. }
  241. }
  242. #if NET_2_0
  243. protected IEqualityComparer EqualityComparer {
  244. get {
  245. return equalityComparer;
  246. }
  247. }
  248. #endif
  249. // ICollection
  250. public virtual int Count {
  251. get {
  252. return inUse;
  253. }
  254. }
  255. public virtual bool IsSynchronized {
  256. get {
  257. return false;
  258. }
  259. }
  260. public virtual Object SyncRoot {
  261. get {
  262. return this;
  263. }
  264. }
  265. // IDictionary
  266. public virtual bool IsFixedSize {
  267. get {
  268. return false;
  269. }
  270. }
  271. public virtual bool IsReadOnly {
  272. get {
  273. return false;
  274. }
  275. }
  276. public virtual ICollection Keys {
  277. get {
  278. if (this.hashKeys == null)
  279. this.hashKeys = new HashKeys (this);
  280. return this.hashKeys;
  281. }
  282. }
  283. public virtual ICollection Values {
  284. get {
  285. if (this.hashValues == null)
  286. this.hashValues = new HashValues (this);
  287. return this.hashValues;
  288. }
  289. }
  290. public virtual Object this [Object key] {
  291. get {
  292. if (key == null)
  293. throw new ArgumentNullException ("key", "null key");
  294. Slot [] table = this.table;
  295. int [] hashes = this.hashes;
  296. uint size = (uint) table.Length;
  297. int h = this.GetHash (key) & Int32.MaxValue;
  298. uint indx = (uint)h;
  299. uint step = (uint) ((h >> 5)+1) % (size-1)+1;
  300. for (uint i = size; i > 0; i--) {
  301. indx %= size;
  302. Slot entry = table [indx];
  303. int hashMix = hashes [indx];
  304. Object k = entry.key;
  305. if (k == null)
  306. break;
  307. if (k == key || ((hashMix & Int32.MaxValue) == h
  308. && this.KeyEquals (key, k))) {
  309. return entry.value;
  310. }
  311. if ((hashMix & CHAIN_MARKER) == 0)
  312. break;
  313. indx += step;
  314. }
  315. return null;
  316. }
  317. set {
  318. PutImpl (key, value, true);
  319. }
  320. }
  321. //
  322. // Interface methods
  323. //
  324. // IEnumerable
  325. IEnumerator IEnumerable.GetEnumerator ()
  326. {
  327. return new Enumerator (this, EnumeratorMode.ENTRY_MODE);
  328. }
  329. // ICollection
  330. public virtual void CopyTo (Array array, int arrayIndex)
  331. {
  332. if (null == array)
  333. throw new ArgumentNullException ("array");
  334. if (arrayIndex < 0)
  335. throw new ArgumentOutOfRangeException ("arrayIndex");
  336. if (array.Rank > 1)
  337. throw new ArgumentException ("array is multidimensional");
  338. if ((array.Length > 0) && (arrayIndex >= array.Length))
  339. throw new ArgumentException ("arrayIndex is equal to or greater than array.Length");
  340. if (arrayIndex + this.inUse > array.Length)
  341. throw new ArgumentException ("Not enough room from arrayIndex to end of array for this Hashtable");
  342. IDictionaryEnumerator it = GetEnumerator ();
  343. int i = arrayIndex;
  344. while (it.MoveNext ()) {
  345. array.SetValue (it.Entry, i++);
  346. }
  347. }
  348. // IDictionary
  349. public virtual void Add (Object key, Object value)
  350. {
  351. PutImpl (key, value, false);
  352. }
  353. #if NET_2_0
  354. [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
  355. #endif
  356. public virtual void Clear ()
  357. {
  358. for (int i = 0;i<table.Length;i++) {
  359. table [i].key = null;
  360. table [i].value = null;
  361. hashes [i] = 0;
  362. }
  363. inUse = 0;
  364. modificationCount++;
  365. }
  366. public virtual bool Contains (Object key)
  367. {
  368. return (Find (key) >= 0);
  369. }
  370. public virtual IDictionaryEnumerator GetEnumerator ()
  371. {
  372. return new Enumerator (this, EnumeratorMode.ENTRY_MODE);
  373. }
  374. #if NET_2_0
  375. [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
  376. #endif
  377. public virtual void Remove (Object key)
  378. {
  379. int i = Find (key);
  380. if (i >= 0) {
  381. Slot [] table = this.table;
  382. int h = hashes [i];
  383. h &= CHAIN_MARKER;
  384. hashes [i] = h;
  385. table [i].key = (h != 0)
  386. ? KeyMarker.Removed
  387. : null;
  388. table [i].value = null;
  389. --inUse;
  390. ++modificationCount;
  391. }
  392. }
  393. public virtual bool ContainsKey (object key)
  394. {
  395. return Contains (key);
  396. }
  397. public virtual bool ContainsValue (object value)
  398. {
  399. int size = this.table.Length;
  400. Slot [] table = this.table;
  401. if (value == null) {
  402. for (int i = 0; i < size; i++) {
  403. Slot entry = table [i];
  404. if (entry.key != null && entry.key!= KeyMarker.Removed
  405. && entry.value == null) {
  406. return true;
  407. }
  408. }
  409. } else {
  410. for (int i = 0; i < size; i++) {
  411. Slot entry = table [i];
  412. if (entry.key != null && entry.key!= KeyMarker.Removed
  413. && value.Equals (entry.value)) {
  414. return true;
  415. }
  416. }
  417. }
  418. return false;
  419. }
  420. // ICloneable
  421. public virtual object Clone ()
  422. {
  423. #if NET_2_0
  424. Hashtable ht = new Hashtable (Count, equalityComparer);
  425. ht.hcp = this.hcp;
  426. ht.comparer = this.comparer;
  427. #else
  428. Hashtable ht = new Hashtable (Count, hcp, comparer);
  429. #endif
  430. ht.inUse = 0;
  431. ht.loadFactor = this.loadFactor;
  432. // FIXME: maybe it's faster to simply
  433. // copy the back-end array?
  434. IDictionaryEnumerator it = GetEnumerator ();
  435. while (it.MoveNext ()) {
  436. ht [it.Key] = it.Value;
  437. }
  438. return ht;
  439. }
  440. public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
  441. {
  442. if (info == null)
  443. throw new ArgumentNullException ("info");
  444. info.AddValue ("LoadFactor", loadFactor);
  445. info.AddValue ("Version", modificationCount);
  446. #if NET_2_0
  447. if (equalityComparer != null)
  448. info.AddValue ("KeyComparer", equalityComparer);
  449. else
  450. info.AddValue ("Comparer", comparerRef);
  451. #else
  452. info.AddValue ("Comparer", comparerRef);
  453. #endif
  454. info.AddValue ("HashCodeProvider", hcpRef);
  455. info.AddValue ("HashSize", this.table.Length);
  456. // Create Keys
  457. Object [] keys = new Object[inUse];
  458. CopyToArray(keys, 0, EnumeratorMode.KEY_MODE);
  459. // Create Values
  460. Object [] values = new Object[inUse];
  461. CopyToArray(values, 0, EnumeratorMode.VALUE_MODE);
  462. info.AddValue ("Keys", keys);
  463. info.AddValue ("Values", values);
  464. #if NET_2_0
  465. info.AddValue ("equalityComparer", equalityComparer);
  466. #endif
  467. }
  468. #if NET_2_0
  469. [MonoTODO ("Serialize equalityComparer")]
  470. #endif
  471. public virtual void OnDeserialization (object sender)
  472. {
  473. if (serializationInfo == null) return;
  474. loadFactor = (float) serializationInfo.GetValue ("LoadFactor", typeof(float));
  475. modificationCount = (int) serializationInfo.GetValue ("Version", typeof(int));
  476. #if NET_2_0
  477. try {
  478. equalityComparer = (IEqualityComparer) serializationInfo.GetValue ("KeyComparer", typeof (object));
  479. } catch {
  480. // If not found, try to get "Comparer"
  481. }
  482. if (equalityComparer == null)
  483. comparerRef = (IComparer) serializationInfo.GetValue ("Comparer", typeof (object));
  484. #else
  485. comparerRef = (IComparer) serializationInfo.GetValue ("Comparer", typeof (object));
  486. #endif
  487. hcpRef = (IHashCodeProvider) serializationInfo.GetValue ("HashCodeProvider", typeof (object));
  488. int size = (int) serializationInfo.GetValue ("HashSize", typeof(int));
  489. Object [] keys = (Object []) serializationInfo.GetValue("Keys", typeof(Object [] ));
  490. Object [] values = (Object []) serializationInfo.GetValue("Values", typeof(Object [] ));
  491. if (keys.Length != values.Length)
  492. throw new SerializationException("Keys and values of uneven size");
  493. size = ToPrime (size);
  494. this.SetTable (new Slot [size], new int [size]);
  495. for(int i=0;i<keys.Length;i++)
  496. Add(keys[i], values[i]);
  497. AdjustThreshold();
  498. serializationInfo = null;
  499. }
  500. /// <summary>
  501. /// Returns a synchronized (thread-safe)
  502. /// wrapper for the Hashtable.
  503. /// </summary>
  504. public static Hashtable Synchronized (Hashtable table)
  505. {
  506. if (table == null)
  507. throw new ArgumentNullException("table");
  508. return new SyncHashtable (table);
  509. }
  510. //
  511. // Protected instance methods
  512. //
  513. /// <summary>Returns the hash code for the specified key.</summary>
  514. protected virtual int GetHash (Object key)
  515. {
  516. #if NET_2_0
  517. if (equalityComparer != null)
  518. return equalityComparer.GetHashCode (key);
  519. #endif
  520. if (hcpRef == null)
  521. return key.GetHashCode ();
  522. return hcpRef.GetHashCode (key);
  523. }
  524. /// <summary>
  525. /// Compares a specific Object with a specific key
  526. /// in the Hashtable.
  527. /// </summary>
  528. protected virtual bool KeyEquals (Object item, Object key)
  529. {
  530. if (key == KeyMarker.Removed)
  531. return false;
  532. #if NET_2_0
  533. if (equalityComparer != null)
  534. return equalityComparer.Equals (item, key);
  535. #endif
  536. if (comparerRef == null)
  537. return item.Equals (key);
  538. return comparerRef.Compare (item, key) == 0;
  539. }
  540. //
  541. // Private instance methods
  542. //
  543. private void AdjustThreshold ()
  544. {
  545. int size = table.Length;
  546. threshold = (int) (size*loadFactor);
  547. if (this.threshold >= size)
  548. threshold = size-1;
  549. }
  550. private void SetTable (Slot [] table, int[] hashes)
  551. {
  552. if (table == null)
  553. throw new ArgumentNullException ("table");
  554. this.table = table;
  555. this.hashes = hashes;
  556. AdjustThreshold ();
  557. }
  558. private int Find (Object key)
  559. {
  560. if (key == null)
  561. throw new ArgumentNullException ("key", "null key");
  562. Slot [] table = this.table;
  563. int [] hashes = this.hashes;
  564. uint size = (uint) table.Length;
  565. int h = this.GetHash (key) & Int32.MaxValue;
  566. uint indx = (uint)h;
  567. uint step = (uint) ((h >> 5)+1) % (size-1)+1;
  568. for (uint i = size; i > 0; i--) {
  569. indx %= size;
  570. Slot entry = table [indx];
  571. int hashMix = hashes [indx];
  572. Object k = entry.key;
  573. if (k == null)
  574. break;
  575. if (k == key || ((hashMix & Int32.MaxValue) == h
  576. && this.KeyEquals (key, k))) {
  577. return (int) indx;
  578. }
  579. if ((hashMix & CHAIN_MARKER) == 0)
  580. break;
  581. indx += step;
  582. }
  583. return -1;
  584. }
  585. private void Rehash ()
  586. {
  587. int oldSize = this.table.Length;
  588. // From the SDK docs:
  589. // Hashtable is automatically increased
  590. // to the smallest prime number that is larger
  591. // than twice the current number of Hashtable buckets
  592. uint newSize = (uint)ToPrime ((oldSize<<1)|1);
  593. Slot [] newTable = new Slot [newSize];
  594. Slot [] table = this.table;
  595. int [] newHashes = new int [newSize];
  596. int [] hashes = this.hashes;
  597. for (int i = 0;i<oldSize;i++) {
  598. Slot s = table [i];
  599. if (s.key!= null) {
  600. int h = hashes [i] & Int32.MaxValue;
  601. uint spot = (uint)h;
  602. uint step = ((uint) (h>>5)+1)% (newSize-1)+1;
  603. for (uint j = spot%newSize;;spot+= step, j = spot%newSize) {
  604. // No check for KeyMarker.Removed here,
  605. // because the table is just allocated.
  606. if (newTable [j].key == null) {
  607. newTable [j].key = s.key;
  608. newTable [j].value = s.value;
  609. newHashes [j] |= h;
  610. break;
  611. } else {
  612. newHashes [j] |= CHAIN_MARKER;
  613. }
  614. }
  615. }
  616. }
  617. ++this.modificationCount;
  618. this.SetTable (newTable, newHashes);
  619. }
  620. private void PutImpl (Object key, Object value, bool overwrite)
  621. {
  622. if (key == null)
  623. throw new ArgumentNullException ("key", "null key");
  624. if (this.inUse >= this.threshold)
  625. this.Rehash ();
  626. uint size = (uint)this.table.Length;
  627. int h = this.GetHash (key) & Int32.MaxValue;
  628. uint spot = (uint)h;
  629. uint step = (uint) ((spot>>5)+1)% (size-1)+1;
  630. Slot [] table = this.table;
  631. int [] hashes = this.hashes;
  632. Slot entry;
  633. int freeIndx = -1;
  634. for (int i = 0; i < size; i++) {
  635. int indx = (int) (spot % size);
  636. entry = table [indx];
  637. int hashMix = hashes [indx];
  638. if (freeIndx == -1
  639. && entry.key == KeyMarker.Removed
  640. && (hashMix & CHAIN_MARKER) != 0)
  641. freeIndx = indx;
  642. if (entry.key == null ||
  643. (entry.key == KeyMarker.Removed
  644. && (hashMix & CHAIN_MARKER) == 0)) {
  645. if (freeIndx == -1)
  646. freeIndx = indx;
  647. break;
  648. }
  649. if ((hashMix & Int32.MaxValue) == h && KeyEquals (key, entry.key)) {
  650. if (overwrite) {
  651. table [indx].value = value;
  652. ++this.modificationCount;
  653. } else {
  654. // Handle Add ():
  655. // An entry with the same key already exists in the Hashtable.
  656. throw new ArgumentException (
  657. "Key duplication when adding: " + key);
  658. }
  659. return;
  660. }
  661. if (freeIndx == -1) {
  662. hashes [indx] |= CHAIN_MARKER;
  663. }
  664. spot+= step;
  665. }
  666. if (freeIndx!= -1) {
  667. table [freeIndx].key = key;
  668. table [freeIndx].value = value;
  669. hashes [freeIndx] |= h;
  670. ++this.inUse;
  671. ++this.modificationCount;
  672. }
  673. }
  674. private void CopyToArray (Array arr, int i,
  675. EnumeratorMode mode)
  676. {
  677. IEnumerator it = new Enumerator (this, mode);
  678. while (it.MoveNext ()) {
  679. arr.SetValue (it.Current, i++);
  680. }
  681. }
  682. //
  683. // Private static methods
  684. //
  685. internal static bool TestPrime (int x)
  686. {
  687. if ((x & 1) != 0) {
  688. int top = (int)Math.Sqrt (x);
  689. for (int n = 3; n < top; n += 2) {
  690. if ((x % n) == 0)
  691. return false;
  692. }
  693. return true;
  694. }
  695. // There is only one even prime - 2.
  696. return (x == 2);
  697. }
  698. internal static int CalcPrime (int x)
  699. {
  700. for (int i = (x & (~1))-1; i< Int32.MaxValue; i += 2) {
  701. if (TestPrime (i)) return i;
  702. }
  703. return x;
  704. }
  705. internal static int ToPrime (int x)
  706. {
  707. for (int i = 0; i < primeTbl.Length; i++) {
  708. if (x <= primeTbl [i])
  709. return primeTbl [i];
  710. }
  711. return CalcPrime (x);
  712. }
  713. //
  714. // Inner classes
  715. //
  716. private enum EnumeratorMode : int {KEY_MODE = 0, VALUE_MODE, ENTRY_MODE};
  717. [Serializable]
  718. private sealed class Enumerator : IDictionaryEnumerator, IEnumerator {
  719. private Hashtable host;
  720. private int stamp;
  721. private int pos;
  722. private int size;
  723. private EnumeratorMode mode;
  724. private Object currentKey;
  725. private Object currentValue;
  726. private readonly static string xstr = "Hashtable.Enumerator: snapshot out of sync.";
  727. public Enumerator (Hashtable host, EnumeratorMode mode) {
  728. this.host = host;
  729. stamp = host.modificationCount;
  730. size = host.table.Length;
  731. this.mode = mode;
  732. Reset ();
  733. }
  734. public Enumerator (Hashtable host)
  735. : this (host, EnumeratorMode.KEY_MODE) {}
  736. private void FailFast ()
  737. {
  738. if (host.modificationCount != stamp) {
  739. throw new InvalidOperationException (xstr);
  740. }
  741. }
  742. public void Reset ()
  743. {
  744. FailFast ();
  745. pos = -1;
  746. currentKey = null;
  747. currentValue = null;
  748. }
  749. public bool MoveNext ()
  750. {
  751. FailFast ();
  752. if (pos < size) {
  753. while (++pos < size) {
  754. Slot entry = host.table [pos];
  755. if (entry.key != null && entry.key != KeyMarker.Removed) {
  756. currentKey = entry.key;
  757. currentValue = entry.value;
  758. return true;
  759. }
  760. }
  761. }
  762. currentKey = null;
  763. currentValue = null;
  764. return false;
  765. }
  766. public DictionaryEntry Entry
  767. {
  768. get {
  769. if (currentKey == null) throw new InvalidOperationException ();
  770. FailFast ();
  771. return new DictionaryEntry (currentKey, currentValue);
  772. }
  773. }
  774. public Object Key {
  775. get {
  776. if (currentKey == null) throw new InvalidOperationException ();
  777. FailFast ();
  778. return currentKey;
  779. }
  780. }
  781. public Object Value {
  782. get {
  783. if (currentKey == null) throw new InvalidOperationException ();
  784. FailFast ();
  785. return currentValue;
  786. }
  787. }
  788. public Object Current {
  789. get {
  790. if (currentKey == null) throw new InvalidOperationException ();
  791. switch (mode) {
  792. case EnumeratorMode.KEY_MODE:
  793. return currentKey;
  794. case EnumeratorMode.VALUE_MODE:
  795. return currentValue;
  796. case EnumeratorMode.ENTRY_MODE:
  797. return new DictionaryEntry (currentKey, currentValue);
  798. }
  799. throw new Exception ("should never happen");
  800. }
  801. }
  802. }
  803. [Serializable]
  804. private class HashKeys : ICollection, IEnumerable {
  805. private Hashtable host;
  806. public HashKeys (Hashtable host) {
  807. if (host == null)
  808. throw new ArgumentNullException ();
  809. this.host = host;
  810. }
  811. // ICollection
  812. public virtual int Count {
  813. get {
  814. return host.Count;
  815. }
  816. }
  817. public virtual bool IsSynchronized {
  818. get {
  819. return host.IsSynchronized;
  820. }
  821. }
  822. public virtual Object SyncRoot {
  823. get {return host.SyncRoot;}
  824. }
  825. public virtual void CopyTo (Array array, int arrayIndex)
  826. {
  827. if (array == null)
  828. throw new ArgumentNullException ("array");
  829. if (array.Rank != 1)
  830. throw new ArgumentException ("array");
  831. if (arrayIndex < 0)
  832. throw new ArgumentOutOfRangeException ("arrayIndex");
  833. if (array.Length - arrayIndex < Count)
  834. throw new ArgumentException ("not enough space");
  835. host.CopyToArray (array, arrayIndex, EnumeratorMode.KEY_MODE);
  836. }
  837. // IEnumerable
  838. public virtual IEnumerator GetEnumerator ()
  839. {
  840. return new Hashtable.Enumerator (host, EnumeratorMode.KEY_MODE);
  841. }
  842. }
  843. [Serializable]
  844. private class HashValues : ICollection, IEnumerable {
  845. private Hashtable host;
  846. public HashValues (Hashtable host) {
  847. if (host == null)
  848. throw new ArgumentNullException ();
  849. this.host = host;
  850. }
  851. // ICollection
  852. public virtual int Count {
  853. get {
  854. return host.Count;
  855. }
  856. }
  857. public virtual bool IsSynchronized {
  858. get {
  859. return host.IsSynchronized;
  860. }
  861. }
  862. public virtual Object SyncRoot {
  863. get {
  864. return host.SyncRoot;
  865. }
  866. }
  867. public virtual void CopyTo (Array array, int arrayIndex)
  868. {
  869. if (array == null)
  870. throw new ArgumentNullException ("array");
  871. if (array.Rank != 1)
  872. throw new ArgumentException ("array");
  873. if (arrayIndex < 0)
  874. throw new ArgumentOutOfRangeException ("arrayIndex");
  875. if (array.Length - arrayIndex < Count)
  876. throw new ArgumentException ("not enough space");
  877. host.CopyToArray (array, arrayIndex, EnumeratorMode.VALUE_MODE);
  878. }
  879. // IEnumerable
  880. public virtual IEnumerator GetEnumerator ()
  881. {
  882. return new Hashtable.Enumerator (host, EnumeratorMode.VALUE_MODE);
  883. }
  884. }
  885. [Serializable]
  886. private class SyncHashtable : Hashtable, IEnumerable {
  887. private Hashtable host;
  888. public SyncHashtable (Hashtable host) {
  889. if (host == null)
  890. throw new ArgumentNullException ();
  891. this.host = host;
  892. }
  893. internal SyncHashtable (SerializationInfo info, StreamingContext context)
  894. {
  895. host = (Hashtable) info.GetValue("ParentTable", typeof(Hashtable));
  896. }
  897. public override void GetObjectData (SerializationInfo info, StreamingContext context)
  898. {
  899. info.AddValue ("ParentTable", host);
  900. }
  901. // ICollection
  902. public override int Count {
  903. get {
  904. return host.Count;
  905. }
  906. }
  907. public override bool IsSynchronized {
  908. get {
  909. return true;
  910. }
  911. }
  912. public override Object SyncRoot {
  913. get {
  914. return host.SyncRoot;
  915. }
  916. }
  917. // IDictionary
  918. public override bool IsFixedSize {
  919. get {
  920. return host.IsFixedSize;
  921. }
  922. }
  923. public override bool IsReadOnly {
  924. get {
  925. return host.IsReadOnly;
  926. }
  927. }
  928. public override ICollection Keys {
  929. get {
  930. ICollection keys = null;
  931. lock (host.SyncRoot) {
  932. keys = host.Keys;
  933. }
  934. return keys;
  935. }
  936. }
  937. public override ICollection Values {
  938. get {
  939. ICollection vals = null;
  940. lock (host.SyncRoot) {
  941. vals = host.Values;
  942. }
  943. return vals;
  944. }
  945. }
  946. public override Object this [Object key] {
  947. get {
  948. return host [key];
  949. }
  950. set {
  951. lock (host.SyncRoot) {
  952. host [key] = value;
  953. }
  954. }
  955. }
  956. // IEnumerable
  957. IEnumerator IEnumerable.GetEnumerator ()
  958. {
  959. return new Enumerator (host, EnumeratorMode.ENTRY_MODE);
  960. }
  961. // ICollection
  962. public override void CopyTo (Array array, int arrayIndex)
  963. {
  964. host.CopyTo (array, arrayIndex);
  965. }
  966. // IDictionary
  967. public override void Add (Object key, Object value)
  968. {
  969. lock (host.SyncRoot) {
  970. host.Add (key, value);
  971. }
  972. }
  973. public override void Clear ()
  974. {
  975. lock (host.SyncRoot) {
  976. host.Clear ();
  977. }
  978. }
  979. public override bool Contains (Object key)
  980. {
  981. return (host.Find (key) >= 0);
  982. }
  983. public override IDictionaryEnumerator GetEnumerator ()
  984. {
  985. return new Enumerator (host, EnumeratorMode.ENTRY_MODE);
  986. }
  987. public override void Remove (Object key)
  988. {
  989. lock (host.SyncRoot) {
  990. host.Remove (key);
  991. }
  992. }
  993. public override bool ContainsKey (object key)
  994. {
  995. return host.Contains (key);
  996. }
  997. public override bool ContainsValue (object value)
  998. {
  999. return host.ContainsValue (value);
  1000. }
  1001. // ICloneable
  1002. public override object Clone ()
  1003. {
  1004. lock(host.SyncRoot) {
  1005. return new SyncHashtable( (Hashtable) host.Clone () );
  1006. }
  1007. }
  1008. } // SyncHashtable
  1009. } // Hashtable
  1010. }