Set.cs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Diagnostics.CodeAnalysis;
  7. // from https://github.com/dotnet/corefx/blob/ec2685715b01d12f16b08d0dfa326649b12db8ec/src/System.Linq/src/System/Linq/Set.cs
  8. namespace System.Linq
  9. {
  10. [ExcludeFromCodeCoverage]
  11. internal sealed class Set<TElement>
  12. {
  13. private readonly IEqualityComparer<TElement> _comparer;
  14. private int[] _buckets;
  15. private Slot[] _slots;
  16. public Set(IEqualityComparer<TElement> comparer)
  17. {
  18. _comparer = comparer ?? EqualityComparer<TElement>.Default;
  19. _buckets = new int[7];
  20. _slots = new Slot[7];
  21. }
  22. internal int Count { get; private set; }
  23. // If value is not in set, add it and return true; otherwise return false
  24. public bool Add(TElement value)
  25. {
  26. var hashCode = InternalGetHashCode(value);
  27. for (var i = _buckets[hashCode%_buckets.Length] - 1; i >= 0; i = _slots[i]._next)
  28. {
  29. if (_slots[i]._hashCode == hashCode && _comparer.Equals(_slots[i]._value, value))
  30. {
  31. return false;
  32. }
  33. }
  34. if (Count == _slots.Length)
  35. {
  36. Resize();
  37. }
  38. var index = Count;
  39. Count++;
  40. var bucket = hashCode%_buckets.Length;
  41. _slots[index]._hashCode = hashCode;
  42. _slots[index]._value = value;
  43. _slots[index]._next = _buckets[bucket] - 1;
  44. _buckets[bucket] = index + 1;
  45. return true;
  46. }
  47. internal int InternalGetHashCode(TElement value)
  48. {
  49. // Handle comparer implementations that throw when passed null
  50. return (value == null) ? 0 : _comparer.GetHashCode(value) & 0x7FFFFFFF;
  51. }
  52. private void Resize()
  53. {
  54. var newSize = checked((Count*2) + 1);
  55. var newBuckets = new int[newSize];
  56. var newSlots = new Slot[newSize];
  57. Array.Copy(_slots, 0, newSlots, 0, Count);
  58. for (var i = 0; i < Count; i++)
  59. {
  60. var bucket = newSlots[i]._hashCode%newSize;
  61. newSlots[i]._next = newBuckets[bucket] - 1;
  62. newBuckets[bucket] = i + 1;
  63. }
  64. _buckets = newBuckets;
  65. _slots = newSlots;
  66. }
  67. internal struct Slot
  68. {
  69. internal int _hashCode;
  70. internal int _next;
  71. internal TElement _value;
  72. }
  73. }
  74. }