PageRenderTime 79ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/corlib/System.Collections.Generic/Dictionary.cs

https://bitbucket.org/cosi2/dotnetanywhere-wb
C# | 614 lines | 493 code | 106 blank | 15 comment | 46 complexity | 107ae653e84ec9331314068af46c2856 MD5 | raw file
  1. using System;
  2. #if LOCALTEST
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. namespace System_.Collections.Generic {
  6. #else
  7. namespace System.Collections.Generic {
  8. #endif
  9. public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>,
  10. IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable {
  11. public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>,
  12. IDisposable, IDictionaryEnumerator, IEnumerator {
  13. Dictionary<TKey, TValue> dict;
  14. private int curSlot, curItem;
  15. internal Enumerator(Dictionary<TKey, TValue> dictionary) {
  16. this.dict = dictionary;
  17. this.curSlot = -1;
  18. this.curItem = 0;
  19. }
  20. public bool MoveNext() {
  21. do {
  22. if (this.curSlot >= this.dict.capacity) {
  23. return false;
  24. }
  25. if (this.curSlot < 0 || this.dict.keys[this.curSlot] == null ||
  26. this.curItem > this.dict.keys[this.curSlot].Count) {
  27. this.curSlot++;
  28. this.curItem = 0;
  29. } else {
  30. this.curItem++;
  31. }
  32. if (this.curSlot >= this.dict.capacity) {
  33. return false;
  34. }
  35. } while (this.dict.keys[this.curSlot] == null || this.curItem >= dict.keys[this.curSlot].Count);
  36. return true;
  37. }
  38. public KeyValuePair<TKey, TValue> Current {
  39. get {
  40. return new KeyValuePair<TKey, TValue>(
  41. this.dict.keys[this.curSlot][this.curItem],
  42. this.dict.values[this.curSlot][this.curItem]
  43. );
  44. }
  45. }
  46. object IEnumerator.Current {
  47. get { return this.Current; }
  48. }
  49. void IEnumerator.Reset() {
  50. this.curSlot = -1;
  51. this.curItem = 0;
  52. }
  53. DictionaryEntry IDictionaryEnumerator.Entry {
  54. get {
  55. return new DictionaryEntry(
  56. this.dict.keys[this.curSlot][this.curItem],
  57. this.dict.values[this.curSlot][this.curItem]
  58. );
  59. }
  60. }
  61. object IDictionaryEnumerator.Key {
  62. get {
  63. return dict.keys[this.curSlot][this.curItem];
  64. }
  65. }
  66. object IDictionaryEnumerator.Value {
  67. get {
  68. return this.dict.values[this.curSlot][this.curItem];
  69. }
  70. }
  71. public void Dispose() {
  72. this.dict = null;
  73. }
  74. }
  75. public sealed class KeyCollection : ICollection<TKey>, IEnumerable<TKey>, ICollection, IEnumerable {
  76. public struct Enumerator : IEnumerator<TKey>, IDisposable, IEnumerator {
  77. private Dictionary<TKey, TValue>.Enumerator hostEnumerator;
  78. internal Enumerator(Dictionary<TKey, TValue> host) {
  79. this.hostEnumerator = host.GetEnumerator();
  80. }
  81. public void Dispose() {
  82. this.hostEnumerator.Dispose();
  83. }
  84. public bool MoveNext() {
  85. return this.hostEnumerator.MoveNext();
  86. }
  87. public TKey Current {
  88. get { return this.hostEnumerator.Current.Key; }
  89. }
  90. object IEnumerator.Current {
  91. get { return this.hostEnumerator.Current.Key; }
  92. }
  93. void IEnumerator.Reset() {
  94. ((IEnumerator)this.hostEnumerator).Reset();
  95. }
  96. }
  97. private Dictionary<TKey, TValue> dictionary;
  98. public KeyCollection(Dictionary<TKey, TValue> dictionary) {
  99. if (dictionary == null) {
  100. throw new ArgumentException("dictionary");
  101. }
  102. this.dictionary = dictionary;
  103. }
  104. public void CopyTo(TKey[] array, int index) {
  105. throw new NotImplementedException();
  106. }
  107. public Enumerator GetEnumerator() {
  108. return new Enumerator(this.dictionary);
  109. }
  110. void ICollection<TKey>.Add(TKey item) {
  111. throw new NotSupportedException("this is a read-only collection");
  112. }
  113. void ICollection<TKey>.Clear() {
  114. throw new NotSupportedException("this is a read-only collection");
  115. }
  116. bool ICollection<TKey>.Contains(TKey item) {
  117. return this.dictionary.ContainsKey(item);
  118. }
  119. bool ICollection<TKey>.Remove(TKey item) {
  120. throw new NotSupportedException("this is a read-only collection");
  121. }
  122. IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator() {
  123. return this.GetEnumerator();
  124. }
  125. void ICollection.CopyTo(Array array, int index) {
  126. this.CopyTo((TKey[])array, index);
  127. }
  128. IEnumerator IEnumerable.GetEnumerator() {
  129. return this.GetEnumerator();
  130. }
  131. public int Count {
  132. get {
  133. return this.dictionary.Count;
  134. }
  135. }
  136. bool ICollection<TKey>.IsReadOnly {
  137. get {
  138. return true;
  139. }
  140. }
  141. bool ICollection.IsSynchronized {
  142. get {
  143. return false;
  144. }
  145. }
  146. object ICollection.SyncRoot {
  147. get {
  148. return ((ICollection)this.dictionary).SyncRoot;
  149. }
  150. }
  151. }
  152. public sealed class ValueCollection : ICollection<TValue>, IEnumerable<TValue>, ICollection, IEnumerable {
  153. public struct Enumerator : IEnumerator<TValue>, IDisposable, IEnumerator {
  154. private Dictionary<TKey, TValue>.Enumerator hostEnumerator;
  155. internal Enumerator(Dictionary<TKey, TValue> host) {
  156. this.hostEnumerator = host.GetEnumerator();
  157. }
  158. public void Dispose() {
  159. this.hostEnumerator.Dispose();
  160. }
  161. public bool MoveNext() {
  162. return this.hostEnumerator.MoveNext();
  163. }
  164. public TValue Current {
  165. get { return this.hostEnumerator.Current.Value; }
  166. }
  167. object IEnumerator.Current {
  168. get { return this.hostEnumerator.Current.Value; }
  169. }
  170. void IEnumerator.Reset() {
  171. ((IEnumerator)this.hostEnumerator).Reset();
  172. }
  173. }
  174. private Dictionary<TKey, TValue> dictionary;
  175. public ValueCollection(Dictionary<TKey, TValue> dictionary) {
  176. if (dictionary == null) {
  177. throw new ArgumentException("dictionary");
  178. }
  179. this.dictionary = dictionary;
  180. }
  181. public void CopyTo(TValue[] array, int index) {
  182. throw new NotImplementedException();
  183. }
  184. public Enumerator GetEnumerator() {
  185. return new Enumerator(this.dictionary);
  186. }
  187. void ICollection<TValue>.Add(TValue item) {
  188. throw new NotSupportedException("this is a read-only collection");
  189. }
  190. void ICollection<TValue>.Clear() {
  191. throw new NotSupportedException("this is a read-only collection");
  192. }
  193. bool ICollection<TValue>.Contains(TValue item) {
  194. return this.dictionary.ContainsValue(item);
  195. }
  196. bool ICollection<TValue>.Remove(TValue item) {
  197. throw new NotSupportedException("this is a read-only collection");
  198. }
  199. IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() {
  200. return this.GetEnumerator();
  201. }
  202. void ICollection.CopyTo(Array array, int index) {
  203. this.CopyTo((TValue[])array, index);
  204. }
  205. IEnumerator IEnumerable.GetEnumerator() {
  206. return this.GetEnumerator();
  207. }
  208. public int Count {
  209. get {
  210. return this.dictionary.Count;
  211. }
  212. }
  213. bool ICollection<TValue>.IsReadOnly {
  214. get {
  215. return true;
  216. }
  217. }
  218. bool ICollection.IsSynchronized {
  219. get {
  220. return false;
  221. }
  222. }
  223. object ICollection.SyncRoot {
  224. get {
  225. return ((ICollection)this.dictionary).SyncRoot;
  226. }
  227. }
  228. }
  229. private static int[] capacities = {
  230. 11, 23, 47, 97, 191, 379, 757, 1511, 3023, 6047, 12097, 24179, 48353, 96731
  231. };
  232. private List<TKey>[] keys;
  233. private List<TValue>[] values;
  234. private int capacity, capacityIndex, count;
  235. private IEqualityComparer<TKey> comparer;
  236. public Dictionary() {
  237. this.Init(0, null);
  238. }
  239. public Dictionary(IDictionary<TKey, TValue> dictionary) : this(dictionary, null) { }
  240. public Dictionary(IEqualityComparer<TKey> comparer) {
  241. this.Init(0, comparer);
  242. }
  243. public Dictionary(int capacity) {
  244. this.Init(capacity, null);
  245. }
  246. public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) {
  247. this.Init(dictionary.Count, comparer);
  248. foreach (var item in dictionary) {
  249. this.Add(item.Key, item.Value);
  250. }
  251. }
  252. public Dictionary(int capacity, IEqualityComparer<TKey> comparer) {
  253. this.Init(capacity, comparer);
  254. }
  255. private void Init(int initialCapacity, IEqualityComparer<TKey> comparer) {
  256. // Initialise the comparer
  257. this.comparer = comparer ?? EqualityComparer<TKey>.Default;
  258. // Initialise the capacity of the dictionary
  259. this.capacityIndex = -1;
  260. for (int i = 0; i < capacities.Length; i++) {
  261. if (initialCapacity <= capacities[i]) {
  262. this.capacityIndex = i;
  263. this.capacity = capacities[i];
  264. break;
  265. }
  266. }
  267. if (this.capacityIndex == -1){
  268. // If the capacity is off the end of the scale, then just use the capacity given
  269. this.capacity = initialCapacity;
  270. this.capacityIndex = capacities.Length;
  271. }
  272. this.Clear();
  273. }
  274. private int GetSlot(TKey key) {
  275. uint hash = (uint)key.GetHashCode();
  276. return (int)(hash % (uint)this.capacity);
  277. }
  278. public void Add(TKey key, TValue value) {
  279. Add(key, value, false);
  280. }
  281. private void Add(TKey key, TValue value, bool replace) {
  282. if (key == null) {
  283. throw new ArgumentNullException();
  284. }
  285. int slot = this.GetSlot(key);
  286. List<TKey> keySlot = this.keys[slot];
  287. if (keySlot != null) {
  288. // There are element(s) at this index, so see if this key is already in this dictionary
  289. // Can't use keySlot.IndexOf() because it doesn't honour the comparer
  290. for (int i = keySlot.Count - 1; i >= 0; i--) {
  291. if (this.comparer.Equals(keySlot[i], key)) {
  292. // The key is already in this dictionary
  293. if (replace) {
  294. this.values[slot][i] = value;
  295. return;
  296. } else {
  297. throw new ArgumentException("Key already exists in dictionary");
  298. }
  299. }
  300. }
  301. // Key not already in dictionary, so carry on
  302. }
  303. this.count++;
  304. if (this.count > this.capacity) {
  305. // Increase capacity
  306. List<TKey>[] currentKeys = this.keys;
  307. List<TValue>[] currentValues = this.values;
  308. this.capacityIndex++;
  309. this.capacity = (this.capacityIndex >= capacities.Length) ?
  310. this.capacity * 2 + 1 : capacities[this.capacityIndex];
  311. this.Clear();
  312. // Add all the items in this dictionary to the enlarged dictionary lists.
  313. for (int slotIdx = currentKeys.Length - 1; slotIdx >= 0; slotIdx--) {
  314. List<TKey> currentKeySlot = currentKeys[slotIdx];
  315. if (currentKeySlot != null) {
  316. List<TValue> currentValueSlot = currentValues[slotIdx];
  317. for (int listIdx = currentKeySlot.Count - 1; listIdx >= 0; listIdx--) {
  318. this.Add(currentKeySlot[listIdx], currentValueSlot[listIdx], false);
  319. }
  320. }
  321. }
  322. // Reload these values, as they will have changed due to dictionary capacity resizing
  323. slot = key.GetHashCode() % this.capacity;
  324. keySlot = this.keys[slot];
  325. }
  326. List<TValue> valueSlot;
  327. if (keySlot == null) {
  328. // There are no elements at this index, so create a new list for the element being added
  329. this.keys[slot] = keySlot = new List<TKey>(1);
  330. this.values[slot] = valueSlot = new List<TValue>(1);
  331. } else {
  332. valueSlot = this.values[slot];
  333. }
  334. // Console.WriteLine("CHECK8\n");
  335. // Console.WriteLine("keySlot={0}, valueSlot={1}\n", keySlot, valueSlot);
  336. keySlot.Add(key);
  337. valueSlot.Add(value);
  338. }
  339. public TValue this[TKey key] {
  340. get {
  341. TValue value;
  342. if (this.TryGetValue(key, out value)) {
  343. return value;
  344. }
  345. throw new KeyNotFoundException(key.ToString());
  346. }
  347. set {
  348. Add(key, value, true);
  349. }
  350. }
  351. public bool TryGetValue(TKey key, out TValue value) {
  352. if (key == null) {
  353. throw new ArgumentNullException();
  354. }
  355. int slot = this.GetSlot(key);
  356. List<TKey> keySlot = this.keys[slot];
  357. if (keySlot != null) {
  358. // Can't use keySlot.IndexOf() because it doesn't honour the comparer
  359. for (int i = keySlot.Count - 1; i >= 0; i--) {
  360. if (this.comparer.Equals(keySlot[i], key)) {
  361. value = this.values[slot][i];
  362. return true;
  363. }
  364. }
  365. }
  366. value = default(TValue);
  367. return false;
  368. }
  369. public bool ContainsKey(TKey key) {
  370. TValue dummy;
  371. return (TryGetValue(key, out dummy));
  372. }
  373. public bool ContainsValue(TValue value) {
  374. Enumerator e = new Enumerator(this);
  375. while (e.MoveNext()) {
  376. if (e.Current.Value.Equals(value)) {
  377. return true;
  378. }
  379. }
  380. return false;
  381. }
  382. public bool Remove(TKey key) {
  383. int slot = this.GetSlot(key);
  384. List<TKey> keySlot = this.keys[slot];
  385. if (keySlot != null) {
  386. // Can't use keySlot.IndexOf() because it doesn't honour the comparer
  387. for (int i = keySlot.Count - 1; i >= 0; i--) {
  388. if (this.comparer.Equals(keySlot[i], key)) {
  389. keySlot.RemoveAt(i);
  390. this.values[slot].RemoveAt(i);
  391. this.count--;
  392. return true;
  393. }
  394. }
  395. }
  396. return false;
  397. }
  398. public IEqualityComparer<TKey> Comparer {
  399. get {
  400. return this.comparer;
  401. }
  402. }
  403. public int Count {
  404. get {
  405. return this.count;
  406. }
  407. }
  408. public KeyCollection Keys {
  409. get {
  410. return new KeyCollection(this);
  411. }
  412. }
  413. public ValueCollection Values {
  414. get {
  415. return new ValueCollection(this);
  416. }
  417. }
  418. public bool IsReadOnly {
  419. get {
  420. return false;
  421. }
  422. }
  423. public void Clear() {
  424. this.keys = new List<TKey>[this.capacity];
  425. this.values = new List<TValue>[this.capacity];
  426. this.count = 0;
  427. }
  428. public Enumerator GetEnumerator() {
  429. return new Enumerator(this);
  430. }
  431. ICollection<TKey> IDictionary<TKey, TValue>.Keys {
  432. get {
  433. return new KeyCollection(this);
  434. }
  435. }
  436. ICollection<TValue> IDictionary<TKey, TValue>.Values {
  437. get {
  438. return new ValueCollection(this);
  439. }
  440. }
  441. void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
  442. this.Add(item.Key, item.Value);
  443. }
  444. bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) {
  445. return this.ContainsKey(item.Key);
  446. }
  447. void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
  448. throw new Exception("The method or operation is not implemented.");
  449. }
  450. bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) {
  451. return this.Remove(item.Key);
  452. }
  453. IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() {
  454. return new Enumerator(this);
  455. }
  456. IEnumerator IEnumerable.GetEnumerator() {
  457. return new Enumerator(this);
  458. }
  459. public bool IsFixedSize {
  460. get {
  461. return false;
  462. }
  463. }
  464. object IDictionary.this[object key] {
  465. get {
  466. return this[(TKey)key];
  467. }
  468. set {
  469. this[(TKey)key] = (TValue)value;
  470. }
  471. }
  472. ICollection IDictionary.Keys {
  473. get {
  474. return Keys;
  475. }
  476. }
  477. ICollection IDictionary.Values {
  478. get {
  479. return Values;
  480. }
  481. }
  482. void IDictionary.Add(object key, object value) {
  483. Add((TKey)key, (TValue)value);
  484. }
  485. bool IDictionary.Contains(object key) {
  486. return ContainsKey((TKey)key);
  487. }
  488. IDictionaryEnumerator IDictionary.GetEnumerator() {
  489. return new Enumerator(this);
  490. }
  491. void IDictionary.Remove(object key) {
  492. Remove((TKey)key);
  493. }
  494. public bool IsSynchronized {
  495. get {
  496. return false;
  497. }
  498. }
  499. public object SyncRoot {
  500. get {
  501. return this;
  502. }
  503. }
  504. public void CopyTo(Array array, int index) {
  505. throw new Exception("The method or operation is not implemented.");
  506. }
  507. }
  508. }