Hashtable.cs 26 KB

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