Hashtable.cs 26 KB

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