unordered_set.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*-
  2. * Copyright 2012 Matthew Endsley
  3. * All rights reserved
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted providing that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  18. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  22. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  23. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24. * POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #ifndef TINYSTL_UNORDERED_SET_H
  27. #define TINYSTL_UNORDERED_SET_H
  28. #include "allocator.h"
  29. #include "buffer.h"
  30. #include "hash.h"
  31. #include "hash_base.h"
  32. namespace tinystl {
  33. template<typename Key, typename Alloc = TINYSTL_ALLOCATOR>
  34. class unordered_set {
  35. public:
  36. unordered_set();
  37. unordered_set(const unordered_set& other);
  38. ~unordered_set();
  39. unordered_set& operator=(const unordered_set& other);
  40. typedef unordered_hash_iterator<const unordered_hash_node<Key, void> > const_iterator;
  41. typedef const_iterator iterator;
  42. iterator begin() const;
  43. iterator end() const;
  44. void clear();
  45. bool empty() const;
  46. size_t size() const;
  47. iterator find(const Key& key) const;
  48. pair<iterator, bool> insert(const Key& key);
  49. void erase(iterator where);
  50. size_t erase(const Key& key);
  51. void swap(unordered_set& other);
  52. private:
  53. typedef unordered_hash_node<Key, void>* pointer;
  54. size_t m_size;
  55. tinystl::buffer<pointer, Alloc> m_buckets;
  56. };
  57. template<typename Key, typename Alloc>
  58. unordered_set<Key, Alloc>::unordered_set()
  59. : m_size(0)
  60. {
  61. buffer_init<pointer, Alloc>(&m_buckets);
  62. buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
  63. }
  64. template<typename Key, typename Alloc>
  65. unordered_set<Key, Alloc>::unordered_set(const unordered_set& other)
  66. : m_size(other.m_size)
  67. {
  68. const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first);
  69. buffer_init<pointer, Alloc>(&m_buckets);
  70. buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
  71. for (pointer* it = *other.m_buckets.first; it; it = it->next) {
  72. unordered_hash_node<Key, void>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, void>))) unordered_hash_node<Key, void>(*it);
  73. newnode->next = newnode->prev = 0;
  74. unordered_hash_node_insert(newnode, hash(*it), m_buckets.first, nbuckets - 1);
  75. }
  76. }
  77. template<typename Key, typename Alloc>
  78. unordered_set<Key, Alloc>::~unordered_set() {
  79. clear();
  80. buffer_destroy<pointer, Alloc>(&m_buckets);
  81. }
  82. template<typename Key, typename Alloc>
  83. unordered_set<Key, Alloc>& unordered_set<Key, Alloc>::operator=(const unordered_set<Key, Alloc>& other) {
  84. unordered_set<Key, Alloc>(other).swap(*this);
  85. return *this;
  86. }
  87. template<typename Key, typename Alloc>
  88. inline typename unordered_set<Key, Alloc>::iterator unordered_set<Key, Alloc>::begin() const {
  89. iterator cit;
  90. cit.node = *m_buckets.first;
  91. return cit;
  92. }
  93. template<typename Key, typename Alloc>
  94. inline typename unordered_set<Key, Alloc>::iterator unordered_set<Key, Alloc>::end() const {
  95. iterator cit;
  96. cit.node = 0;
  97. return cit;
  98. }
  99. template<typename Key, typename Alloc>
  100. inline bool unordered_set<Key, Alloc>::empty() const {
  101. return m_size == 0;
  102. }
  103. template<typename Key, typename Alloc>
  104. inline size_t unordered_set<Key, Alloc>::size() const {
  105. return m_size;
  106. }
  107. template<typename Key, typename Alloc>
  108. inline void unordered_set<Key, Alloc>::clear() {
  109. pointer it = *m_buckets.first;
  110. while (it) {
  111. const pointer next = it->next;
  112. it->~unordered_hash_node<Key, void>();
  113. Alloc::static_deallocate(it, sizeof(unordered_hash_node<Key, void>));
  114. it = next;
  115. }
  116. m_buckets.last = m_buckets.first;
  117. buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
  118. m_size = 0;
  119. }
  120. template<typename Key, typename Alloc>
  121. inline typename unordered_set<Key, Alloc>::iterator unordered_set<Key, Alloc>::find(const Key& key) const {
  122. iterator result;
  123. result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first));
  124. return result;
  125. }
  126. template<typename Key, typename Alloc>
  127. inline pair<typename unordered_set<Key, Alloc>::iterator, bool> unordered_set<Key, Alloc>::insert(const Key& key) {
  128. pair<iterator, bool> result;
  129. result.second = false;
  130. result.first = find(key);
  131. if (result.first.node != 0)
  132. return result;
  133. unordered_hash_node<Key, void>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, void>))) unordered_hash_node<Key, void>(key);
  134. newnode->next = newnode->prev = 0;
  135. const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first);
  136. unordered_hash_node_insert(newnode, hash(key), m_buckets.first, nbuckets - 1);
  137. ++m_size;
  138. if (m_size + 1 > 4 * nbuckets) {
  139. pointer root = *m_buckets.first;
  140. const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8;
  141. m_buckets.last = m_buckets.first;
  142. buffer_resize<pointer, Alloc>(&m_buckets, newnbuckets + 1, 0);
  143. unordered_hash_node<Key, void>** buckets = m_buckets.first;
  144. while (root) {
  145. const pointer next = root->next;
  146. root->next = root->prev = 0;
  147. unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets);
  148. root = next;
  149. }
  150. }
  151. result.first.node = newnode;
  152. result.second = true;
  153. return result;
  154. }
  155. template<typename Key, typename Alloc>
  156. inline void unordered_set<Key, Alloc>::erase(iterator where) {
  157. unordered_hash_node_erase(where.node, hash(where.node->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1);
  158. where.node->~unordered_hash_node<Key, void>();
  159. Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node<Key, void>));
  160. --m_size;
  161. }
  162. template<typename Key, typename Alloc>
  163. inline size_t unordered_set<Key, Alloc>::erase(const Key& key) {
  164. const iterator it = find(key);
  165. if (it.node == 0)
  166. return 0;
  167. erase(it);
  168. return 1;
  169. }
  170. template <typename Key, typename Alloc>
  171. void unordered_set<Key, Alloc>::swap(unordered_set& other) {
  172. size_t tsize = other.m_size;
  173. other.m_size = m_size, m_size = tsize;
  174. buffer_swap(&m_buckets, &other.m_buckets);
  175. }
  176. }
  177. #endif