/*- * Copyright 2012-2018 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_HASH_BASE_H #define TINYSTL_HASH_BASE_H #include #include namespace tinystl { template struct pair { pair(); pair(const pair& other); pair(pair&& other); pair(const Key& key, const Value& value); pair(Key&& key, Value&& value); pair& operator=(const pair& other); pair& operator=(pair&& other); Key first; Value second; using first_type = Key; using second_type = Value; }; template inline pair::pair() { } template inline pair::pair(const pair& other) : first(other.first) , second(other.second) { } template inline pair::pair(pair&& other) : first(static_cast(other.first)) , second(static_cast(other.second)) { } template inline pair::pair(const Key& key, const Value& value) : first(key) , second(value) { } template inline pair::pair(Key&& key, Value&& value) : first(static_cast(key)) , second(static_cast(value)) { } template inline pair& pair::operator=(const pair& other) { first = other.first; second = other.second; return *this; } template inline pair& pair::operator=(pair&& other) { first = static_cast(other.first); second = static_cast(other.second); return *this; } template static inline pair::type, typename remove_const_reference::type> make_pair(Key&& key, Value&& value) { return pair::type, typename remove_const_reference::type>( static_cast(key) , static_cast(value) ); } template struct unordered_hash_node { unordered_hash_node(const Key& key, const Value& value); unordered_hash_node(Key&& key, Value&& value); const Key first; Value second; unordered_hash_node* next; unordered_hash_node* prev; }; template inline unordered_hash_node::unordered_hash_node(const Key& key, const Value& value) : first(key) , second(value) { } template inline unordered_hash_node::unordered_hash_node(Key&& key, Value&& value) : first(static_cast(key)) , second(static_cast(value)) { } template struct unordered_hash_node { explicit unordered_hash_node(const Key& key); explicit unordered_hash_node(Key&& key); const Key first; unordered_hash_node* next; unordered_hash_node* prev; }; template inline unordered_hash_node::unordered_hash_node(const Key& key) : first(key) { } template inline unordered_hash_node::unordered_hash_node(Key&& key) : first(static_cast(key)) { } template static inline void unordered_hash_node_insert(unordered_hash_node* node, size_t hash, unordered_hash_node** buckets, size_t nbuckets) { size_t bucket = hash & (nbuckets - 1); unordered_hash_node* it = buckets[bucket + 1]; node->next = it; if (it) { node->prev = it->prev; it->prev = node; if (node->prev) node->prev->next = node; } else { size_t newbucket = bucket; while (newbucket && !buckets[newbucket]) --newbucket; unordered_hash_node* prev = buckets[newbucket]; while (prev && prev->next) prev = prev->next; node->prev = prev; if (prev) prev->next = node; } // propagate node through buckets for (; it == buckets[bucket]; --bucket) { buckets[bucket] = node; if (!bucket) break; } } template static inline void unordered_hash_node_erase(const unordered_hash_node* where, size_t hash, unordered_hash_node** buckets, size_t nbuckets) { size_t bucket = hash & (nbuckets - 1); unordered_hash_node* next = where->next; for (; buckets[bucket] == where; --bucket) { buckets[bucket] = next; if (!bucket) break; } if (where->prev) where->prev->next = where->next; if (next) next->prev = where->prev; } template struct unordered_hash_iterator { Node* operator->() const; Node& operator*() const; Node* node; }; template struct unordered_hash_iterator { unordered_hash_iterator() {} unordered_hash_iterator(unordered_hash_iterator other) : node(other.node) { } const Node* operator->() const; const Node& operator*() const; const Node* node; }; template struct unordered_hash_iterator > { const Key* operator->() const; const Key& operator*() const; unordered_hash_node* node; }; template static inline bool operator==(const unordered_hash_iterator& lhs, const unordered_hash_iterator& rhs) { return lhs.node == rhs.node; } template static inline bool operator!=(const unordered_hash_iterator& lhs, const unordered_hash_iterator& rhs) { return lhs.node != rhs.node; } template static inline void operator++(unordered_hash_iterator& lhs) { lhs.node = lhs.node->next; } template inline Node* unordered_hash_iterator::operator->() const { return node; } template inline Node& unordered_hash_iterator::operator*() const { return *node; } template inline const Node* unordered_hash_iterator::operator->() const { return node; } template inline const Node& unordered_hash_iterator::operator*() const { return *node; } template inline const Key* unordered_hash_iterator >::operator->() const { return &node->first; } template inline const Key& unordered_hash_iterator >::operator*() const { return node->first; } template static inline Node unordered_hash_find(const Key& key, Node* buckets, size_t nbuckets) { if (!buckets) return 0; const size_t bucket = hash(key) & (nbuckets - 2); for (Node it = buckets[bucket], end = buckets[bucket+1]; it != end; it = it->next) if (it->first == key) return it; return 0; } } #endif