hashset.hpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #pragma once
  2. //hashset
  3. //
  4. //search: O(1) average; O(n) worst
  5. //insert: O(1) average; O(n) worst
  6. //remove: O(1) average; O(n) worst
  7. //
  8. //requirements:
  9. // auto T::hash() const -> uint;
  10. // auto T::operator==(const T&) const -> bool;
  11. namespace nall {
  12. template<typename T>
  13. struct hashset {
  14. hashset() = default;
  15. hashset(uint length) : length(bit::round(length)) {}
  16. hashset(const hashset& source) { operator=(source); }
  17. hashset(hashset&& source) { operator=(move(source)); }
  18. ~hashset() { reset(); }
  19. auto operator=(const hashset& source) -> hashset& {
  20. reset();
  21. if(source.pool) {
  22. for(uint n : range(source.count)) {
  23. insert(*source.pool[n]);
  24. }
  25. }
  26. return *this;
  27. }
  28. auto operator=(hashset&& source) -> hashset& {
  29. reset();
  30. pool = source.pool;
  31. length = source.length;
  32. count = source.count;
  33. source.pool = nullptr;
  34. source.length = 8;
  35. source.count = 0;
  36. return *this;
  37. }
  38. explicit operator bool() const { return count; }
  39. auto capacity() const -> uint { return length; }
  40. auto size() const -> uint { return count; }
  41. auto reset() -> void {
  42. if(pool) {
  43. for(uint n : range(length)) {
  44. if(pool[n]) {
  45. delete pool[n];
  46. pool[n] = nullptr;
  47. }
  48. }
  49. delete pool;
  50. pool = nullptr;
  51. }
  52. length = 8;
  53. count = 0;
  54. }
  55. auto reserve(uint size) -> void {
  56. //ensure all items will fit into pool (with <= 50% load) and amortize growth
  57. size = bit::round(max(size, count << 1));
  58. T** copy = new T*[size]();
  59. if(pool) {
  60. for(uint n : range(length)) {
  61. if(pool[n]) {
  62. uint hash = (*pool[n]).hash() & (size - 1);
  63. while(copy[hash]) if(++hash >= size) hash = 0;
  64. copy[hash] = pool[n];
  65. pool[n] = nullptr;
  66. }
  67. }
  68. }
  69. delete pool;
  70. pool = copy;
  71. length = size;
  72. }
  73. auto find(const T& value) -> maybe<T&> {
  74. if(!pool) return nothing;
  75. uint hash = value.hash() & (length - 1);
  76. while(pool[hash]) {
  77. if(value == *pool[hash]) return *pool[hash];
  78. if(++hash >= length) hash = 0;
  79. }
  80. return nothing;
  81. }
  82. auto insert(const T& value) -> maybe<T&> {
  83. if(!pool) pool = new T*[length]();
  84. //double pool size when load is >= 50%
  85. if(count >= (length >> 1)) reserve(length << 1);
  86. count++;
  87. uint hash = value.hash() & (length - 1);
  88. while(pool[hash]) if(++hash >= length) hash = 0;
  89. pool[hash] = new T(value);
  90. return *pool[hash];
  91. }
  92. auto remove(const T& value) -> bool {
  93. if(!pool) return false;
  94. uint hash = value.hash() & (length - 1);
  95. while(pool[hash]) {
  96. if(value == *pool[hash]) {
  97. delete pool[hash];
  98. pool[hash] = nullptr;
  99. count--;
  100. return true;
  101. }
  102. if(++hash >= length) hash = 0;
  103. }
  104. return false;
  105. }
  106. protected:
  107. T** pool = nullptr;
  108. uint length = 8; //length of pool
  109. uint count = 0; //number of objects inside of the pool
  110. };
  111. }