/*- * Copyright 2012 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef TINYSTL_UNORDERED_MAP_H #define TINYSTL_UNORDERED_MAP_H #include "buffer.h" #include "hash.h" #include "hash_base.h" namespace tinystl { template class unordered_map { public: unordered_map(); unordered_map(const unordered_map& other); ~unordered_map(); unordered_map& operator=(const unordered_map& other); typedef pair value_type; typedef unordered_hash_iterator > const_iterator; typedef unordered_hash_iterator > iterator; iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; void clear(); bool empty() const; size_t size() const; const_iterator find(const Key& key) const; iterator find(const Key& key); pair insert(const pair& p); void erase(const_iterator where); Value& operator[](const Key& key); void swap(unordered_map& other); private: typedef unordered_hash_node* pointer; size_t m_size; buffer m_buckets; }; template unordered_map::unordered_map() : m_size(0) { buffer_init(&m_buckets); buffer_resize(&m_buckets, 9, 0); } template unordered_map::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(&m_buckets); buffer_resize(&m_buckets, nbuckets, 0); for (pointer it = *other.m_buckets.first; it; it = it->next) { unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(it->first, it->second); newnode->next = newnode->prev = 0; unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); } } template unordered_map::~unordered_map() { clear(); buffer_destroy(&m_buckets); } template unordered_map& unordered_map::operator=(const unordered_map& other) { unordered_map(other).swap(*this); return *this; } template inline typename unordered_map::iterator unordered_map::begin() { iterator it; it.node = *m_buckets.first; return it; } template inline typename unordered_map::iterator unordered_map::end() { iterator it; it.node = 0; return it; } template inline typename unordered_map::const_iterator unordered_map::begin() const { const_iterator cit; cit.node = *m_buckets.first; return cit; } template inline typename unordered_map::const_iterator unordered_map::end() const { const_iterator cit; cit.node = 0; return cit; } template inline bool unordered_map::empty() const { return m_size == 0; } template inline size_t unordered_map::size() const { return m_size; } template inline void unordered_map::clear() { pointer it = *m_buckets.first; while (it) { const pointer next = it->next; it->~unordered_hash_node(); Alloc::static_deallocate(it, sizeof(unordered_hash_node)); it = next; } m_buckets.last = m_buckets.first; buffer_resize(&m_buckets, 9, 0); m_size = 0; } template inline typename unordered_map::iterator unordered_map::find(const Key& key) { iterator result; result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first)); return result; } template inline typename unordered_map::const_iterator unordered_map::find(const Key& key) const { iterator result; result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first)); return result; } template inline pair::iterator, bool> unordered_map::insert(const pair& p) { pair result; result.second = false; result.first = find(p.first); if (result.first.node != 0) return result; unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(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; 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(&m_buckets, newnbuckets + 1, 0); unordered_hash_node** buckets = m_buckets.first; while (root) { const pointer next = root->next; root->next = root->prev = 0; unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets); root = next; } } result.first.node = newnode; result.second = true; return result; } template void unordered_map::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(); Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node)); --m_size; } template Value& unordered_map::operator[](const Key& key) { return insert(pair(key, Value())).first->second; } template void unordered_map::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); } } #endif