1
0

Set.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Linq;
  9. using System.Threading.Tasks;
  10. // from https://github.com/dotnet/corefx/blob/ec2685715b01d12f16b08d0dfa326649b12db8ec/src/System.Linq/src/System/Linq/Set.cs
  11. namespace System.Linq
  12. {
  13. [ExcludeFromCodeCoverage]
  14. internal sealed class Set<TElement>
  15. {
  16. private readonly IEqualityComparer<TElement> _comparer;
  17. private int[] _buckets;
  18. #if DEBUG
  19. private bool _haveRemoved;
  20. #endif
  21. private Slot[] _slots;
  22. public Set(IEqualityComparer<TElement> comparer)
  23. {
  24. _comparer = comparer ?? EqualityComparer<TElement>.Default;
  25. _buckets = new int[7];
  26. _slots = new Slot[7];
  27. }
  28. internal int Count { get; private set; }
  29. // If value is not in set, add it and return true; otherwise return false
  30. public bool Add(TElement value)
  31. {
  32. #if DEBUG
  33. Debug.Assert(!_haveRemoved, "This class is optimised for never calling Add after Remove. If your changes need to do so, undo that optimization.");
  34. #endif
  35. var hashCode = InternalGetHashCode(value);
  36. for (var i = _buckets[hashCode%_buckets.Length] - 1; i >= 0; i = _slots[i]._next)
  37. {
  38. if (_slots[i]._hashCode == hashCode && _comparer.Equals(_slots[i]._value, value))
  39. {
  40. return false;
  41. }
  42. }
  43. if (Count == _slots.Length)
  44. {
  45. Resize();
  46. }
  47. var index = Count;
  48. Count++;
  49. var bucket = hashCode%_buckets.Length;
  50. _slots[index]._hashCode = hashCode;
  51. _slots[index]._value = value;
  52. _slots[index]._next = _buckets[bucket] - 1;
  53. _buckets[bucket] = index + 1;
  54. return true;
  55. }
  56. // If value is in set, remove it and return true; otherwise return false
  57. public bool Remove(TElement value)
  58. {
  59. #if DEBUG
  60. _haveRemoved = true;
  61. #endif
  62. var hashCode = InternalGetHashCode(value);
  63. var bucket = hashCode%_buckets.Length;
  64. var last = -1;
  65. for (var i = _buckets[bucket] - 1; i >= 0; last = i, i = _slots[i]._next)
  66. {
  67. if (_slots[i]._hashCode == hashCode && _comparer.Equals(_slots[i]._value, value))
  68. {
  69. if (last < 0)
  70. {
  71. _buckets[bucket] = _slots[i]._next + 1;
  72. }
  73. else
  74. {
  75. _slots[last]._next = _slots[i]._next;
  76. }
  77. _slots[i]._hashCode = -1;
  78. _slots[i]._value = default(TElement);
  79. _slots[i]._next = -1;
  80. return true;
  81. }
  82. }
  83. return false;
  84. }
  85. internal int InternalGetHashCode(TElement value)
  86. {
  87. // Handle comparer implementations that throw when passed null
  88. return (value == null) ? 0 : _comparer.GetHashCode(value) & 0x7FFFFFFF;
  89. }
  90. internal TElement[] ToArray()
  91. {
  92. #if DEBUG
  93. Debug.Assert(!_haveRemoved, "Optimised ToArray cannot be called if Remove has been called.");
  94. #endif
  95. var array = new TElement[Count];
  96. for (var i = 0; i != array.Length; ++i)
  97. {
  98. array[i] = _slots[i]._value;
  99. }
  100. return array;
  101. }
  102. internal List<TElement> ToList()
  103. {
  104. #if DEBUG
  105. Debug.Assert(!_haveRemoved, "Optimised ToList cannot be called if Remove has been called.");
  106. #endif
  107. var count = Count;
  108. var list = new List<TElement>(count);
  109. for (var i = 0; i != count; ++i)
  110. {
  111. list.Add(_slots[i]._value);
  112. }
  113. return list;
  114. }
  115. private void Resize()
  116. {
  117. var newSize = checked((Count*2) + 1);
  118. var newBuckets = new int[newSize];
  119. var newSlots = new Slot[newSize];
  120. Array.Copy(_slots, 0, newSlots, 0, Count);
  121. for (var i = 0; i < Count; i++)
  122. {
  123. var bucket = newSlots[i]._hashCode%newSize;
  124. newSlots[i]._next = newBuckets[bucket] - 1;
  125. newBuckets[bucket] = i + 1;
  126. }
  127. _buckets = newBuckets;
  128. _slots = newSlots;
  129. }
  130. internal struct Slot
  131. {
  132. internal int _hashCode;
  133. internal int _next;
  134. internal TElement _value;
  135. }
  136. }
  137. }