/* * PROGRAM: JRD Access Method * MODULE: Hash.h * DESCRIPTION: Hash of objects * * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * * Software distributed under the License is distributed AS IS, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights * and limitations under the License. * * The Original Code was created by Alexander Peshkoff * for the Firebird Open Source RDBMS project. * * Copyright (c) 2009 Alexander Peshkoff * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. * */ #ifndef CLASSES_HASH_H #define CLASSES_HASH_H #include "../common/classes/vector.h" namespace Firebird { template class DefaultHash { public: static FB_SIZE_T hash(const void* value, FB_SIZE_T length, FB_SIZE_T hashSize) { size_t sum = 0; size_t val; const char* data = static_cast(value); while (length >= sizeof(size_t)) { memcpy(&val, data, sizeof(size_t)); sum += val; data += sizeof(size_t); length -= sizeof(size_t); } if (length) { val = 0; memcpy(&val, data, length); sum += val; } size_t rc = 0; while (sum) { rc += (sum % hashSize); sum /= hashSize; } return rc % hashSize; } static FB_SIZE_T hash(const K& value, FB_SIZE_T hashSize) { return hash(&value, sizeof value, hashSize); } }; const FB_SIZE_T DEFAULT_HASH_SIZE = 97; // largest prime number < 100 template , // default keygen typename F = DefaultHash > // hash function definition class Hash { public: // This class is supposed to be used as a BASE class for class to be hashed class Entry { private: Entry** previousElement; Entry* nextElement; public: Entry() : previousElement(NULL) { } virtual ~Entry() { unLink(); } void link(Entry** where) { unLink(); // set our pointers previousElement = where; nextElement = previousElement ? *previousElement : NULL; // make next element (if present) to point to us if (nextElement) { nextElement->previousElement = &nextElement; } // make previous element point to us *previousElement = this; } void unLink() { // if we are linked if (previousElement) { if (nextElement) { // adjust previous pointer in next element ... nextElement->previousElement = previousElement; } // ... and next pointer in previous element *previousElement = nextElement; // finally mark ourselves not linked previousElement = NULL; } } Entry** nextPtr() { return &nextElement; } Entry* next() const { return nextElement; } C* next(const K& key) { Entry* e = next(); return (e && e->isEqual(key)) ? e->get() : NULL; } virtual bool isEqual(const K&) const = 0; virtual C* get() = 0; }; // class Entry private: Hash(const Hash&); // not implemented public: explicit Hash(MemoryPool&) : duplicates(false) { clean(); } Hash() : duplicates(false) { clean(); } ~Hash() { // by default we let hash entries be cleaned by someone else cleanup(NULL); } typedef void CleanupRoutine(C* toClean); void cleanup(CleanupRoutine* cleanupRoutine) { for (FB_SIZE_T n = 0; n < HASHSIZE; ++n) { while (data[n]) { Entry* entry = data[n]; entry->unLink(); if (cleanupRoutine) cleanupRoutine(entry->get()); } } } void enableDuplicates() { duplicates = true; } private: Entry* data[HASHSIZE]; bool duplicates; Entry** locate(const K& key, FB_SIZE_T h) { Entry** pointer = &data[h]; while (*pointer) { if ((*pointer)->isEqual(key)) { break; } pointer = (*pointer)->nextPtr(); } return pointer; } Entry** locate(const K& key) { FB_SIZE_T hashValue = F::hash(key, HASHSIZE); fb_assert(hashValue < HASHSIZE); return locate(key, hashValue % HASHSIZE); } public: bool add(C* value) { Entry** e = locate(KeyOfValue::generate(*value)); if ((!duplicates) && (*e)) { return false; // sorry, duplicate } value->link(e); return true; } C* lookup(const K& key) { Entry** e = locate(key); return (*e) ? (*e)->get() : NULL; } C* remove(const K& key) { Entry** e = locate(key); if (*e) { Entry* entry = *e; entry->unLink(); return entry->get(); } return NULL; } private: // disable use of default operator= Hash& operator= (const Hash&); void clean() { memset(data, 0, sizeof data); } public: class iterator { private: const Hash* hash; FB_SIZE_T elem; Entry* current; iterator(const iterator& i); iterator& operator= (const iterator& i); void next() { while (!current) { if (++elem >= HASHSIZE) { break; } current = hash->data[elem]; } } public: explicit iterator(const Hash& h) : hash(&h), elem(0), current(hash->data[elem]) { next(); } iterator& operator++() { if (hasData()) { current = current->next(); next(); } return *this; } bool hasData() const { return current ? true : false; } operator C*() const { fb_assert(hasData()); return current->get(); } C* operator ->() const { fb_assert(hasData()); return current->get(); } bool operator== (const iterator& h) const { return (hash == h.hash) && (elem == h.elem) && (current == h.current); } bool operator!= (const iterator& h) const { return !(*this == h); } }; // class iterator }; // class Hash } // namespace Firebird #endif // CLASSES_HASH_H