/* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef NDB_HASHMAP_HPP #define NDB_HASHMAP_HPP #include #include #include /* Default implementation for extracting key_ptr and key_length from type K. Used when the entire type K should be used as key. NOTE! Optimized inside HashMap so that it's never actually called */ inline const void* HashMap__get_key(const void* key_ptr, size_t* key_length) { (void)key_length; return key_ptr; } /* Hash container for storing key value pairs */ template class HashMap { class Entry { public: K m_key; T m_value; Entry(const K& k, const T& v) : m_key(k), m_value(v) {}; }; HASH m_hash; static void free_element(void * ptr) { Entry* entry = (Entry*)ptr; delete entry; } /* Callback function which is installed into 'my_hash' and thus called once for each key in the hash that need to be compared. Should return a pointer to where the key start and the key's length. */ static uchar* _get_key(const uchar* ptr, size_t* key_length, my_bool first) { const Entry * entry = reinterpret_cast(ptr); const void* key_ptr = G(&entry->m_key, key_length); return (uchar*)key_ptr; } const void* get_key_ptr(const K* key, size_t *key_length) const { if (G == HashMap__get_key) return key; return _get_key((const uchar*)key, key_length, false); } public: HashMap(ulong initial_size = 1024, uint grow_size = 256) { assert(my_init_done); if (my_hash_init2(&m_hash, grow_size, &my_charset_bin, // charset initial_size, // default_array_elements 0, // key_offset sizeof(K), // key_length G == HashMap__get_key ? NULL : _get_key, // get_key, free_element, // free_element HASH_UNIQUE, // flags PSI_INSTRUMENT_ME )) abort(); } ~HashMap() { my_hash_free(&m_hash); } bool insert(const K& k, const T& v, bool replace = false) { Entry* entry = new Entry(k, v); if (my_hash_insert(&m_hash, (const uchar*)entry) != 0) { // An entry already existed delete entry; T* p; if (replace && search(k, &p)) { *p = v; return true; } return false; } return true; } bool search(const K& k, T& v) const { T* p; if (!search(k, &p)) return false; v = *p; return true; } bool search(const K& k, T** v) const { size_t key_length = sizeof(K); const void *key = get_key_ptr(&k, &key_length); Entry* entry= (Entry*)my_hash_search(&m_hash, (const uchar*)key, key_length); if (entry == NULL) return false; *v = &(entry->m_value); return true; } bool remove(const K& k) { size_t key_length = sizeof(K); const void *key = get_key_ptr(&k, &key_length); Entry* entry= (Entry*)my_hash_search(&m_hash, (const uchar*)key, key_length); if (entry == NULL) return false; if (my_hash_delete(&m_hash, (uchar*)entry)) return false; return true; } bool remove(size_t i) { Entry* entry = (Entry*)my_hash_element(&m_hash, (ulong)i); if (entry == NULL) return false; if (my_hash_delete(&m_hash, (uchar*)entry)) return false; return true; } size_t entries(void) const { return m_hash.records; } T* value(size_t i) const { Entry* entry = (Entry*)my_hash_element((HASH*)&m_hash, (ulong)i); if (entry == NULL) return NULL; return &(entry->m_value); } }; #endif