|
|
@@ -1,5 +1,5 @@
|
|
|
/*-
|
|
|
- * Copyright 2012 Matthew Endsley
|
|
|
+ * Copyright 2012-2018 Matthew Endsley
|
|
|
* All rights reserved
|
|
|
*
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
@@ -27,9 +27,10 @@
|
|
|
#ifndef TINYSTL_UNORDERED_MAP_H
|
|
|
#define TINYSTL_UNORDERED_MAP_H
|
|
|
|
|
|
-#include "buffer.h"
|
|
|
-#include "hash.h"
|
|
|
-#include "hash_base.h"
|
|
|
+#include <tinystl/allocator.h>
|
|
|
+#include <tinystl/buffer.h>
|
|
|
+#include <tinystl/hash.h>
|
|
|
+#include <tinystl/hash_base.h>
|
|
|
|
|
|
namespace tinystl {
|
|
|
|
|
|
@@ -38,13 +39,14 @@ namespace tinystl {
|
|
|
public:
|
|
|
unordered_map();
|
|
|
unordered_map(const unordered_map& other);
|
|
|
+ unordered_map(unordered_map&& other);
|
|
|
~unordered_map();
|
|
|
|
|
|
unordered_map& operator=(const unordered_map& other);
|
|
|
-
|
|
|
+ unordered_map& operator=(unordered_map&& other);
|
|
|
|
|
|
typedef pair<Key, Value> value_type;
|
|
|
-
|
|
|
+
|
|
|
typedef unordered_hash_iterator<const unordered_hash_node<Key, Value> > const_iterator;
|
|
|
typedef unordered_hash_iterator<unordered_hash_node<Key, Value> > iterator;
|
|
|
|
|
|
@@ -61,6 +63,7 @@ namespace tinystl {
|
|
|
const_iterator find(const Key& key) const;
|
|
|
iterator find(const Key& key);
|
|
|
pair<iterator, bool> insert(const pair<Key, Value>& p);
|
|
|
+ pair<iterator, bool> emplace(pair<Key, Value>&& p);
|
|
|
void erase(const_iterator where);
|
|
|
|
|
|
Value& operator[](const Key& key);
|
|
|
@@ -69,73 +72,99 @@ namespace tinystl {
|
|
|
|
|
|
private:
|
|
|
|
|
|
+ void rehash(size_t nbuckets);
|
|
|
+
|
|
|
typedef unordered_hash_node<Key, Value>* pointer;
|
|
|
|
|
|
size_t m_size;
|
|
|
- buffer<pointer, Alloc> m_buckets;
|
|
|
+ tinystl::buffer<pointer, Alloc> m_buckets;
|
|
|
};
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- unordered_map<Key, Value, Alloc>::unordered_map()
|
|
|
+ inline unordered_map<Key, Value, Alloc>::unordered_map()
|
|
|
: m_size(0)
|
|
|
{
|
|
|
buffer_init<pointer, Alloc>(&m_buckets);
|
|
|
- buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- unordered_map<Key, Value, Alloc>::unordered_map(const unordered_map& other)
|
|
|
+ inline unordered_map<Key, Value, Alloc>::unordered_map(const unordered_map& other)
|
|
|
: m_size(other.m_size)
|
|
|
{
|
|
|
const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first);
|
|
|
buffer_init<pointer, Alloc>(&m_buckets);
|
|
|
buffer_resize<pointer, Alloc>(&m_buckets, nbuckets, 0);
|
|
|
|
|
|
- for (pointer it = *other.m_buckets.first; it; it = it->next) {
|
|
|
- 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);
|
|
|
- newnode->next = newnode->prev = 0;
|
|
|
+ if (other.m_buckets.first) {
|
|
|
+ for (pointer it = *other.m_buckets.first; it; it = it->next) {
|
|
|
+ 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);
|
|
|
+ newnode->next = newnode->prev = 0;
|
|
|
|
|
|
- unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1);
|
|
|
+ unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- unordered_map<Key, Value, Alloc>::~unordered_map() {
|
|
|
- clear();
|
|
|
+ inline unordered_map<Key, Value, Alloc>::unordered_map(unordered_map&& other)
|
|
|
+ : m_size(other.m_size)
|
|
|
+ {
|
|
|
+ buffer_move(&m_buckets, &other.m_buckets);
|
|
|
+ other.m_size = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename Key, typename Value, typename Alloc>
|
|
|
+ inline unordered_map<Key, Value, Alloc>::~unordered_map() {
|
|
|
+ if (m_buckets.first != m_buckets.last)
|
|
|
+ clear();
|
|
|
buffer_destroy<pointer, Alloc>(&m_buckets);
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(const unordered_map<Key, Value, Alloc>& other) {
|
|
|
+ inline unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(const unordered_map<Key, Value, Alloc>& other) {
|
|
|
unordered_map<Key, Value, Alloc>(other).swap(*this);
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
+ template<typename Key, typename Value, typename Alloc>
|
|
|
+ inline unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(unordered_map&& other) {
|
|
|
+ unordered_map(static_cast<unordered_map&&>(other)).swap(*this);
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::begin() {
|
|
|
iterator it;
|
|
|
- it.node = *m_buckets.first;
|
|
|
+ if (m_buckets.first) {
|
|
|
+ it.node = *m_buckets.first;
|
|
|
+ } else {
|
|
|
+ it.node = nullptr;
|
|
|
+ }
|
|
|
return it;
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::end() {
|
|
|
iterator it;
|
|
|
- it.node = 0;
|
|
|
+ it.node = nullptr;
|
|
|
return it;
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::begin() const {
|
|
|
const_iterator cit;
|
|
|
- cit.node = *m_buckets.first;
|
|
|
+ if (m_buckets.first) {
|
|
|
+ cit.node = *m_buckets.first;
|
|
|
+ } else {
|
|
|
+ cit.node = nullptr;
|
|
|
+ }
|
|
|
return cit;
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::end() const {
|
|
|
const_iterator cit;
|
|
|
- cit.node = 0;
|
|
|
+ cit.node = nullptr;
|
|
|
return cit;
|
|
|
}
|
|
|
|
|
|
@@ -151,13 +180,15 @@ namespace tinystl {
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
inline void unordered_map<Key, Value, Alloc>::clear() {
|
|
|
- pointer it = *m_buckets.first;
|
|
|
- while (it) {
|
|
|
- const pointer next = it->next;
|
|
|
- it->~unordered_hash_node<Key, Value>();
|
|
|
- Alloc::static_deallocate(it, sizeof(unordered_hash_node<Key, Value>));
|
|
|
-
|
|
|
- it = next;
|
|
|
+ if (m_buckets.first) {
|
|
|
+ pointer it = *m_buckets.first;
|
|
|
+ while (it) {
|
|
|
+ const pointer next = it->next;
|
|
|
+ it->~unordered_hash_node<Key, Value>();
|
|
|
+ Alloc::static_deallocate(it, sizeof(unordered_hash_node<Key, Value>));
|
|
|
+
|
|
|
+ it = next;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
m_buckets.last = m_buckets.first;
|
|
|
@@ -180,24 +211,11 @@ namespace tinystl {
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::insert(const pair<Key, Value>& p) {
|
|
|
- pair<iterator, bool> result;
|
|
|
- result.second = false;
|
|
|
-
|
|
|
- result.first = find(p.first);
|
|
|
- if (result.first.node != 0)
|
|
|
- return result;
|
|
|
-
|
|
|
- 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);
|
|
|
- newnode->next = newnode->prev = 0;
|
|
|
-
|
|
|
- const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first);
|
|
|
- unordered_hash_node_insert(newnode, hash(p.first), m_buckets.first, nbuckets - 1);
|
|
|
-
|
|
|
- ++m_size;
|
|
|
+ inline void unordered_map<Key, Value, Alloc>::rehash(size_t nbuckets) {
|
|
|
+ if (!m_buckets.first) return;
|
|
|
if (m_size + 1 > 4 * nbuckets) {
|
|
|
pointer root = *m_buckets.first;
|
|
|
-
|
|
|
+
|
|
|
const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8;
|
|
|
m_buckets.last = m_buckets.first;
|
|
|
buffer_resize<pointer, Alloc>(&m_buckets, newnbuckets + 1, 0);
|
|
|
@@ -205,11 +223,56 @@ namespace tinystl {
|
|
|
|
|
|
while (root) {
|
|
|
const pointer next = root->next;
|
|
|
- root->next = root->prev = 0;
|
|
|
+ root->next = root->prev = nullptr;
|
|
|
unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets);
|
|
|
root = next;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename Key, typename Value, typename Alloc>
|
|
|
+ inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::insert(const pair<Key, Value>& p) {
|
|
|
+ pair<iterator, bool> result;
|
|
|
+ result.second = false;
|
|
|
+
|
|
|
+ result.first = find(p.first);
|
|
|
+ if (result.first.node != nullptr)
|
|
|
+ return result;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ newnode->next = newnode->prev = nullptr;
|
|
|
+
|
|
|
+ if(!m_buckets.first) buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
|
|
+ const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first);
|
|
|
+ unordered_hash_node_insert(newnode, hash(p.first), m_buckets.first, nbuckets - 1);
|
|
|
+
|
|
|
+ ++m_size;
|
|
|
+ rehash(nbuckets);
|
|
|
+
|
|
|
+ result.first.node = newnode;
|
|
|
+ result.second = true;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename Key, typename Value, typename Alloc>
|
|
|
+ inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::emplace(pair<Key, Value>&& p) {
|
|
|
+ pair<iterator, bool> result;
|
|
|
+ result.second = false;
|
|
|
+
|
|
|
+ result.first = find(p.first);
|
|
|
+ if (result.first.node != nullptr)
|
|
|
+ return result;
|
|
|
+
|
|
|
+ const size_t keyhash = hash(p.first);
|
|
|
+ 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));
|
|
|
+ newnode->next = newnode->prev = 0;
|
|
|
+
|
|
|
+ if (!m_buckets.first) buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
|
|
+ const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first);
|
|
|
+ unordered_hash_node_insert(newnode, keyhash, m_buckets.first, nbuckets - 1);
|
|
|
+
|
|
|
+ ++m_size;
|
|
|
+ rehash(nbuckets);
|
|
|
|
|
|
result.first.node = newnode;
|
|
|
result.second = true;
|
|
|
@@ -217,7 +280,7 @@ namespace tinystl {
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- void unordered_map<Key, Value, Alloc>::erase(const_iterator where) {
|
|
|
+ inline void unordered_map<Key, Value, Alloc>::erase(const_iterator where) {
|
|
|
unordered_hash_node_erase(where.node, hash(where->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1);
|
|
|
|
|
|
where->~unordered_hash_node<Key, Value>();
|
|
|
@@ -226,12 +289,12 @@ namespace tinystl {
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- Value& unordered_map<Key, Value, Alloc>::operator[](const Key& key) {
|
|
|
+ inline Value& unordered_map<Key, Value, Alloc>::operator[](const Key& key) {
|
|
|
return insert(pair<Key, Value>(key, Value())).first->second;
|
|
|
}
|
|
|
|
|
|
template<typename Key, typename Value, typename Alloc>
|
|
|
- void unordered_map<Key, Value, Alloc>::swap(unordered_map& other) {
|
|
|
+ inline void unordered_map<Key, Value, Alloc>::swap(unordered_map& other) {
|
|
|
size_t tsize = other.m_size;
|
|
|
other.m_size = m_size, m_size = tsize;
|
|
|
buffer_swap(&m_buckets, &other.m_buckets);
|