/*- * 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_SET_H #define TINYSTL_UNORDERED_SET_H #include "buffer.h" #include "hash.h" #include "hash_base.h" namespace tinystl { template class unordered_set { public: unordered_set(); unordered_set(const unordered_set& other); ~unordered_set(); unordered_set& operator=(const unordered_set& other); typedef unordered_hash_iterator > const_iterator; typedef const_iterator iterator; iterator begin() const; iterator end() const; void clear(); bool empty() const; size_t size() const; iterator find(const Key& key) const; pair insert(const Key& key); void erase(iterator where); size_t erase(const Key& key); void swap(unordered_set& other); private: typedef unordered_hash_node* pointer; size_t m_size; buffer m_buckets; }; template unordered_set::unordered_set() : m_size(0) { buffer_init(&m_buckets); buffer_resize(&m_buckets, 9, 0); } template unordered_set::unordered_set(const unordered_set& 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); newnode->next = newnode->prev = 0; unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); } } template unordered_set::~unordered_set() { clear(); buffer_destroy(&m_buckets); } template unordered_set& unordered_set::operator=(const unordered_set& other) { unordered_set(other).swap(*this); return *this; } template inline typename unordered_set::iterator unordered_set::begin() const { iterator cit; cit.node = *m_buckets.first; return cit; } template inline typename unordered_set::iterator unordered_set::end() const { iterator cit; cit.node = 0; return cit; } template inline bool unordered_set::empty() const { return m_size == 0; } template inline size_t unordered_set::size() const { return m_size; } template inline void unordered_set::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_set::iterator unordered_set::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_set::insert(const Key& key) { pair result; result.second = false; result.first = find(key); if (result.first.node != 0) return result; unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(key); newnode->next = newnode->prev = 0; const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); unordered_hash_node_insert(newnode, hash(key), 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 inline void unordered_set::erase(iterator where) { unordered_hash_node_erase(where.node, hash(where.node->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1); where.node->~unordered_hash_node(); Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node)); --m_size; } template inline size_t unordered_set::erase(const Key& key) { const iterator it = find(key); if (it.node == 0) return 0; erase(it); return 1; } template void unordered_set::swap(unordered_set& other) { size_t tsize = other.m_size; other.m_size = m_size, m_size = tsize; buffer_swap(&m_buckets, &other.m_buckets); } } #endif