unordered_map.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*-
  2. * Copyright 2012-2018 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_MAP_H
  27. #define TINYSTL_UNORDERED_MAP_H
  28. #include <tinystl/allocator.h>
  29. #include <tinystl/buffer.h>
  30. #include <tinystl/hash.h>
  31. #include <tinystl/hash_base.h>
  32. namespace tinystl {
  33. template<typename Key, typename Value, typename Alloc = TINYSTL_ALLOCATOR>
  34. class unordered_map {
  35. public:
  36. unordered_map();
  37. unordered_map(const unordered_map& other);
  38. unordered_map(unordered_map&& other);
  39. ~unordered_map();
  40. unordered_map& operator=(const unordered_map& other);
  41. unordered_map& operator=(unordered_map&& other);
  42. typedef pair<Key, Value> value_type;
  43. typedef unordered_hash_iterator<const unordered_hash_node<Key, Value> > const_iterator;
  44. typedef unordered_hash_iterator<unordered_hash_node<Key, Value> > iterator;
  45. iterator begin();
  46. iterator end();
  47. const_iterator begin() const;
  48. const_iterator end() const;
  49. void clear();
  50. bool empty() const;
  51. size_t size() const;
  52. const_iterator find(const Key& key) const;
  53. iterator find(const Key& key);
  54. pair<iterator, bool> insert(const pair<Key, Value>& p);
  55. pair<iterator, bool> emplace(pair<Key, Value>&& p);
  56. void erase(const_iterator where);
  57. Value& operator[](const Key& key);
  58. void swap(unordered_map& other);
  59. private:
  60. void rehash(size_t nbuckets);
  61. typedef unordered_hash_node<Key, Value>* pointer;
  62. size_t m_size;
  63. tinystl::buffer<pointer, Alloc> m_buckets;
  64. };
  65. template<typename Key, typename Value, typename Alloc>
  66. inline unordered_map<Key, Value, Alloc>::unordered_map()
  67. : m_size(0)
  68. {
  69. buffer_init<pointer, Alloc>(&m_buckets);
  70. }
  71. template<typename Key, typename Value, typename Alloc>
  72. inline unordered_map<Key, Value, Alloc>::unordered_map(const unordered_map& other)
  73. : m_size(other.m_size)
  74. {
  75. const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first);
  76. buffer_init<pointer, Alloc>(&m_buckets);
  77. buffer_resize<pointer, Alloc>(&m_buckets, nbuckets, 0);
  78. if (other.m_buckets.first) {
  79. for (pointer it = *other.m_buckets.first; it; it = it->next) {
  80. unordered_hash_node<Key, Value>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, Value>))) unordered_hash_node<Key, Value>(it->first, it->second);
  81. newnode->next = newnode->prev = 0;
  82. unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1);
  83. }
  84. }
  85. }
  86. template<typename Key, typename Value, typename Alloc>
  87. inline unordered_map<Key, Value, Alloc>::unordered_map(unordered_map&& other)
  88. : m_size(other.m_size)
  89. {
  90. buffer_move(&m_buckets, &other.m_buckets);
  91. other.m_size = 0;
  92. }
  93. template<typename Key, typename Value, typename Alloc>
  94. inline unordered_map<Key, Value, Alloc>::~unordered_map() {
  95. if (m_buckets.first != m_buckets.last)
  96. clear();
  97. buffer_destroy<pointer, Alloc>(&m_buckets);
  98. }
  99. template<typename Key, typename Value, typename Alloc>
  100. inline unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(const unordered_map<Key, Value, Alloc>& other) {
  101. unordered_map<Key, Value, Alloc>(other).swap(*this);
  102. return *this;
  103. }
  104. template<typename Key, typename Value, typename Alloc>
  105. inline unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(unordered_map&& other) {
  106. unordered_map(static_cast<unordered_map&&>(other)).swap(*this);
  107. return *this;
  108. }
  109. template<typename Key, typename Value, typename Alloc>
  110. inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::begin() {
  111. iterator it;
  112. if (m_buckets.first) {
  113. it.node = *m_buckets.first;
  114. } else {
  115. it.node = nullptr;
  116. }
  117. return it;
  118. }
  119. template<typename Key, typename Value, typename Alloc>
  120. inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::end() {
  121. iterator it;
  122. it.node = nullptr;
  123. return it;
  124. }
  125. template<typename Key, typename Value, typename Alloc>
  126. inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::begin() const {
  127. const_iterator cit;
  128. if (m_buckets.first) {
  129. cit.node = *m_buckets.first;
  130. } else {
  131. cit.node = nullptr;
  132. }
  133. return cit;
  134. }
  135. template<typename Key, typename Value, typename Alloc>
  136. inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::end() const {
  137. const_iterator cit;
  138. cit.node = nullptr;
  139. return cit;
  140. }
  141. template<typename Key, typename Value, typename Alloc>
  142. inline bool unordered_map<Key, Value, Alloc>::empty() const {
  143. return m_size == 0;
  144. }
  145. template<typename Key, typename Value, typename Alloc>
  146. inline size_t unordered_map<Key, Value, Alloc>::size() const {
  147. return m_size;
  148. }
  149. template<typename Key, typename Value, typename Alloc>
  150. inline void unordered_map<Key, Value, Alloc>::clear() {
  151. if (m_buckets.first) {
  152. pointer it = *m_buckets.first;
  153. while (it) {
  154. const pointer next = it->next;
  155. it->~unordered_hash_node<Key, Value>();
  156. Alloc::static_deallocate(it, sizeof(unordered_hash_node<Key, Value>));
  157. it = next;
  158. }
  159. }
  160. m_buckets.last = m_buckets.first;
  161. buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
  162. m_size = 0;
  163. }
  164. template<typename Key, typename Value, typename Alloc>
  165. inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::find(const Key& key) {
  166. iterator result;
  167. result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first));
  168. return result;
  169. }
  170. template<typename Key, typename Value, typename Alloc>
  171. inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::find(const Key& key) const {
  172. iterator result;
  173. result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first));
  174. return result;
  175. }
  176. template<typename Key, typename Value, typename Alloc>
  177. inline void unordered_map<Key, Value, Alloc>::rehash(size_t nbuckets) {
  178. if (!m_buckets.first) return;
  179. if (m_size + 1 > 4 * nbuckets) {
  180. pointer root = *m_buckets.first;
  181. const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8;
  182. m_buckets.last = m_buckets.first;
  183. buffer_resize<pointer, Alloc>(&m_buckets, newnbuckets + 1, 0);
  184. unordered_hash_node<Key, Value>** buckets = m_buckets.first;
  185. while (root) {
  186. const pointer next = root->next;
  187. root->next = root->prev = nullptr;
  188. unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets);
  189. root = next;
  190. }
  191. }
  192. }
  193. template<typename Key, typename Value, typename Alloc>
  194. inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::insert(const pair<Key, Value>& p) {
  195. pair<iterator, bool> result;
  196. result.second = false;
  197. result.first = find(p.first);
  198. if (result.first.node != nullptr)
  199. return result;
  200. unordered_hash_node<Key, Value>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, Value>))) unordered_hash_node<Key, Value>(p.first, p.second);
  201. newnode->next = newnode->prev = nullptr;
  202. if(!m_buckets.first) buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
  203. const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first);
  204. unordered_hash_node_insert(newnode, hash(p.first), m_buckets.first, nbuckets - 1);
  205. ++m_size;
  206. rehash(nbuckets);
  207. result.first.node = newnode;
  208. result.second = true;
  209. return result;
  210. }
  211. template<typename Key, typename Value, typename Alloc>
  212. inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::emplace(pair<Key, Value>&& p) {
  213. pair<iterator, bool> result;
  214. result.second = false;
  215. result.first = find(p.first);
  216. if (result.first.node != nullptr)
  217. return result;
  218. const size_t keyhash = hash(p.first);
  219. unordered_hash_node<Key, Value>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, Value>))) unordered_hash_node<Key, Value>(static_cast<Key&&>(p.first), static_cast<Value&&>(p.second));
  220. newnode->next = newnode->prev = 0;
  221. if (!m_buckets.first) buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
  222. const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first);
  223. unordered_hash_node_insert(newnode, keyhash, m_buckets.first, nbuckets - 1);
  224. ++m_size;
  225. rehash(nbuckets);
  226. result.first.node = newnode;
  227. result.second = true;
  228. return result;
  229. }
  230. template<typename Key, typename Value, typename Alloc>
  231. inline void unordered_map<Key, Value, Alloc>::erase(const_iterator where) {
  232. unordered_hash_node_erase(where.node, hash(where->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1);
  233. where->~unordered_hash_node<Key, Value>();
  234. Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node<Key, Value>));
  235. --m_size;
  236. }
  237. template<typename Key, typename Value, typename Alloc>
  238. inline Value& unordered_map<Key, Value, Alloc>::operator[](const Key& key) {
  239. return insert(pair<Key, Value>(key, Value())).first->second;
  240. }
  241. template<typename Key, typename Value, typename Alloc>
  242. inline void unordered_map<Key, Value, Alloc>::swap(unordered_map& other) {
  243. size_t tsize = other.m_size;
  244. other.m_size = m_size, m_size = tsize;
  245. buffer_swap(&m_buckets, &other.m_buckets);
  246. }
  247. }
  248. #endif