178 lines
4.5 KiB
C++

/* 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 <ndb_global.h>
#include <my_sys.h>
#include <hash.h>
/*
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<typename K, typename T,
const void* G(const void*, size_t*) = HashMap__get_key >
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<const Entry*>(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