Set.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Extracted from ../../../external/referencesource/System.Core/System/Linq/Enumerable.cs
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. namespace System.Linq
  7. {
  8. internal class Set<TElement>
  9. {
  10. int[] buckets;
  11. Slot[] slots;
  12. int count;
  13. int freeList;
  14. IEqualityComparer<TElement> comparer;
  15. public Set() : this(null) { }
  16. public Set(IEqualityComparer<TElement> comparer) {
  17. if (comparer == null) comparer = EqualityComparer<TElement>.Default;
  18. this.comparer = comparer;
  19. buckets = new int[7];
  20. slots = new Slot[7];
  21. freeList = -1;
  22. }
  23. // If value is not in set, add it and return true; otherwise return false
  24. public bool Add(TElement value) {
  25. return !Find(value, true);
  26. }
  27. // Check whether value is in set
  28. public bool Contains(TElement value) {
  29. return Find(value, false);
  30. }
  31. // If value is in set, remove it and return true; otherwise return false
  32. public bool Remove(TElement value) {
  33. int hashCode = InternalGetHashCode(value);
  34. int bucket = hashCode % buckets.Length;
  35. int last = -1;
  36. for (int i = buckets[bucket] - 1; i >= 0; last = i, i = slots[i].next) {
  37. if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value)) {
  38. if (last < 0) {
  39. buckets[bucket] = slots[i].next + 1;
  40. }
  41. else {
  42. slots[last].next = slots[i].next;
  43. }
  44. slots[i].hashCode = -1;
  45. slots[i].value = default(TElement);
  46. slots[i].next = freeList;
  47. freeList = i;
  48. return true;
  49. }
  50. }
  51. return false;
  52. }
  53. bool Find(TElement value, bool add) {
  54. int hashCode = InternalGetHashCode(value);
  55. for (int i = buckets[hashCode % buckets.Length] - 1; i >= 0; i = slots[i].next) {
  56. if (slots[i].hashCode == hashCode && comparer.Equals(slots[i].value, value)) return true;
  57. }
  58. if (add) {
  59. int index;
  60. if (freeList >= 0) {
  61. index = freeList;
  62. freeList = slots[index].next;
  63. }
  64. else {
  65. if (count == slots.Length) Resize();
  66. index = count;
  67. count++;
  68. }
  69. int bucket = hashCode % buckets.Length;
  70. slots[index].hashCode = hashCode;
  71. slots[index].value = value;
  72. slots[index].next = buckets[bucket] - 1;
  73. buckets[bucket] = index + 1;
  74. }
  75. return false;
  76. }
  77. void Resize() {
  78. int newSize = checked(count * 2 + 1);
  79. int[] newBuckets = new int[newSize];
  80. Slot[] newSlots = new Slot[newSize];
  81. Array.Copy(slots, 0, newSlots, 0, count);
  82. for (int i = 0; i < count; i++) {
  83. int bucket = newSlots[i].hashCode % newSize;
  84. newSlots[i].next = newBuckets[bucket] - 1;
  85. newBuckets[bucket] = i + 1;
  86. }
  87. buckets = newBuckets;
  88. slots = newSlots;
  89. }
  90. internal int InternalGetHashCode(TElement value)
  91. {
  92. //[....] DevDivBugs 171937. work around comparer implementations that throw when passed null
  93. return (value == null) ? 0 : comparer.GetHashCode(value) & 0x7FFFFFFF;
  94. }
  95. internal struct Slot
  96. {
  97. internal int hashCode;
  98. internal TElement value;
  99. internal int next;
  100. }
  101. }
  102. }