哈希模块替换为 kshk123/hashMap 但还未适配
This commit is contained in:
parent
8faa9baa38
commit
e55eee77a6
|
@ -1,72 +1,135 @@
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
|
||||||
|
using namespace CTSL;
|
||||||
|
|
||||||
// template <typename T>
|
namespace CTSL //Concurrent Thread Safe Library
|
||||||
// HashMap<T>(uint64_t capacity, uint64_t size, T *pool)
|
|
||||||
// {
|
|
||||||
// this->capacity = capacity;
|
|
||||||
// size = size;
|
|
||||||
// //HashMap<T>::construct();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool HashMap<T>::construct()
|
|
||||||
{
|
{
|
||||||
HashMap<T>::pool = new T[capacity];
|
// Function to find an entry in the bucket matching the key
|
||||||
|
// If key is found, the corresponding value is copied into the parameter "value" and function returns true.
|
||||||
|
// If key is not found, function returns false
|
||||||
|
template <typename K, typename V>
|
||||||
|
bool HashBucket<K, V>::find(const K &key, V &value) const
|
||||||
|
{
|
||||||
|
// A shared mutex is used to enable mutiple concurrent reads
|
||||||
|
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
|
||||||
|
HashNode<K, V> *node = head;
|
||||||
|
|
||||||
if (HashMap<T>::pool == nullptr) {
|
while (node != nullptr) {
|
||||||
return false;
|
if (node->getKey() == key) {
|
||||||
|
value = node->getValue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to insert into the bucket
|
||||||
|
// If key already exists, update the value, else insert a new node in the bucket with the <key, value> pair
|
||||||
|
template <typename K, typename V>
|
||||||
|
void HashBucket<K, V>::insert(const K &key, const V &value)
|
||||||
|
{
|
||||||
|
// Exclusive lock to enable single write in the bucket
|
||||||
|
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||||
|
HashNode<K, V> *prev = nullptr;
|
||||||
|
HashNode<K, V> *node = head;
|
||||||
|
|
||||||
|
while (node != nullptr && node->getKey() != key) {
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (nullptr == node) // New entry, create a node and add to bucket
|
||||||
}
|
{
|
||||||
|
if (nullptr == head) {
|
||||||
|
head = new HashNode<K, V>(key, value);
|
||||||
|
} else {
|
||||||
template <typename T>
|
prev->next = new HashNode<K, V>(key, value);
|
||||||
T& HashMap<T>::at(uint64_t i)
|
}
|
||||||
{
|
} else {
|
||||||
if (i >= capacity) {
|
node->setValue(value); // Key found in bucket, update the value
|
||||||
qDebug() << "Error";
|
|
||||||
return HashMap<T>::pool[0];
|
|
||||||
}
|
}
|
||||||
return HashMap<T>::pool[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Function to remove an entry from the bucket, if found
|
||||||
size_t HashMap<T>::getSize()
|
template <typename K, typename V>
|
||||||
|
void HashBucket<K, V>::erase(const K &key)
|
||||||
{
|
{
|
||||||
return size;
|
// Exclusive lock to enable single write in the bucket
|
||||||
|
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||||
|
HashNode<K, V> *prev = nullptr;
|
||||||
|
HashNode<K, V> *node = head;
|
||||||
|
|
||||||
|
while (node != nullptr && node->getKey() != key) {
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullptr == node) //Key not found, nothing to be done
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
} else //Remove the node from the bucket
|
||||||
|
{
|
||||||
|
if (head == node) {
|
||||||
|
head = node->next;
|
||||||
|
} else {
|
||||||
|
prev->next = node->next;
|
||||||
|
}
|
||||||
|
delete node; //Free up the memory
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Function to clear the bucket
|
||||||
uint64_t HashMap<T>::getCapacity()
|
template <typename K, typename V>
|
||||||
|
void HashBucket<K, V>::clear()
|
||||||
{
|
{
|
||||||
return capacity;
|
// Exclusive lock to enable single write in the bucket
|
||||||
|
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||||
|
HashNode<K, V> *prev = nullptr;
|
||||||
|
HashNode<K, V> *node = head;
|
||||||
|
while (node != nullptr) {
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
|
delete prev;
|
||||||
|
}
|
||||||
|
head = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
uint64_t HashMap<T>::hashToAddr(uint64_t hash)
|
|
||||||
|
// Function to find an entry in the hash map matching the key.
|
||||||
|
// If key is found, the corresponding value is copied into the parameter "value" and function returns true.
|
||||||
|
// If key is not found, function returns false.
|
||||||
|
template <typename K, typename V, typename F>
|
||||||
|
bool HashMap<K, V, F>::find(const K &key, V &value) const
|
||||||
{
|
{
|
||||||
return hash << 32 >> 32;
|
size_t hashValue = hashFn(key) % hashSize;
|
||||||
|
return hashTable[hashValue].find(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Function to insert into the hash map.
|
||||||
void HashMap<T>::insert(uint64_t hash, T &hashValue)
|
// If key already exists, update the value, else insert a new node in the bucket with the <key, value> pair.
|
||||||
|
template <typename K, typename V, typename F>
|
||||||
|
void HashMap<K, V, F>::insert(const K &key, const V &value)
|
||||||
{
|
{
|
||||||
uint64_t addr = hashToAddr(hash);
|
size_t hashValue = hashFn(key) % hashSize;
|
||||||
|
hashTable[hashValue].insert(key, value);
|
||||||
pool[addr] = hashValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Function to remove an entry from the bucket, if found
|
||||||
void HashMap<T>::clear()
|
template <typename K, typename V, typename F>
|
||||||
|
void HashMap<K, V, F>::erase(const K &key)
|
||||||
{
|
{
|
||||||
delete[] pool;
|
size_t hashValue = hashFn(key) % hashSize;
|
||||||
pool = nullptr;
|
hashTable[hashValue].erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
// Function to clean up the hasp map, i.e., remove all entries from it
|
||||||
HashMap<T>* HashMap<T>::instance = new HashMap<T>(capacity = 1024, size = 0);
|
template <typename K, typename V, typename F>
|
||||||
|
void HashMap<K, V, F>::clear()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < hashSize; i++) {
|
||||||
|
(hashTable[i]).clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,88 +1,134 @@
|
||||||
#ifndef HASHMAP_H
|
#ifndef HASH_MAP_H_
|
||||||
#define HASHMAP_H
|
#define HASH_MAP_H_
|
||||||
|
|
||||||
#include <limits>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <iostream>
|
||||||
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <qDebug>
|
#include <shared_mutex>
|
||||||
|
|
||||||
template <typename T>
|
constexpr size_t HASH_SIZE_DEFAULT = 1031; // A prime number as hash size gives a better distribution of values in buckets
|
||||||
class HashMap
|
|
||||||
|
namespace CTSL //Concurrent Thread Safe Library
|
||||||
|
{
|
||||||
|
// Class representing a templatized hash node
|
||||||
|
template <typename K, typename V>
|
||||||
|
class HashNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//HashMap(size_t capacity, size_t size, T* pool);
|
HashNode() : next(nullptr)
|
||||||
//~HashMap();
|
|
||||||
HashMap() = default;
|
|
||||||
|
|
||||||
static HashMap *getInstance()
|
|
||||||
{
|
{
|
||||||
#if 0
|
}
|
||||||
static std::once_flag s_flag;
|
HashNode(K key_, V value_) : next(nullptr), key(key_), value(value_)
|
||||||
std::call_once(s_flag, [&]() {
|
{
|
||||||
instance.reset(new HashMap);
|
}
|
||||||
});
|
~HashNode()
|
||||||
#endif
|
{
|
||||||
if (instance)
|
next = nullptr;
|
||||||
|
|
||||||
return *instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lock()
|
const K &getKey() const
|
||||||
{
|
{
|
||||||
hashMapMutex.lock();
|
return key;
|
||||||
|
}
|
||||||
|
void setValue(V value_)
|
||||||
|
{
|
||||||
|
value = value_;
|
||||||
|
}
|
||||||
|
const V &getValue() const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unlock()
|
HashNode *next; // Pointer to the next node in the same bucket
|
||||||
{
|
private:
|
||||||
hashMapMutex.unlock();
|
K key; // the hash key
|
||||||
}
|
V value; // the value corresponding to the key
|
||||||
|
|
||||||
static T& at(uint64_t i);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
T& operator[](uint64_t hash)
|
|
||||||
{
|
|
||||||
uint64_t addr = hashToAddr(hash);
|
|
||||||
|
|
||||||
return pool[addr];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint64_t hashToAddr(uint64_t hash);
|
|
||||||
|
|
||||||
static char* find(uint64_t hash)
|
|
||||||
{
|
|
||||||
// uint64_t addr = hashToAddr(hash);
|
|
||||||
|
|
||||||
return pool[hash <<32 >>32];
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t getSize();
|
|
||||||
static size_t getCapacity();
|
|
||||||
|
|
||||||
static void clear();
|
|
||||||
|
|
||||||
static void insert(uint64_t hash, T &hashValue);
|
|
||||||
|
|
||||||
static bool construct();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const uint64_t capacity;
|
|
||||||
static uint64_t size;
|
|
||||||
|
|
||||||
static char *pool;
|
|
||||||
|
|
||||||
static std::mutex hashMapMutex;
|
|
||||||
|
|
||||||
//static std::auto_ptr<HashMap<T>> instance;
|
|
||||||
static HashMap<T>* instance;
|
|
||||||
public:
|
|
||||||
// 防止外部构造。
|
|
||||||
//HashMap() = default;
|
|
||||||
// 防止拷贝和赋值。
|
|
||||||
HashMap &operator=(const HashMap &) = delete; HashMap(const HashMap &another) = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Class representing a hash bucket. The bucket is implemented as a singly linked list.
|
||||||
|
// A bucket is always constructed with a dummy head node
|
||||||
|
template <typename K, typename V>
|
||||||
|
class HashBucket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashBucket() : head(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif // HASHMAP_H
|
~HashBucket() //delete the bucket
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to find an entry in the bucket matching the key
|
||||||
|
// If key is found, the corresponding value is copied into the parameter "value" and function returns true.
|
||||||
|
// If key is not found, function returns false
|
||||||
|
bool find(const K &key, V &value) const;
|
||||||
|
|
||||||
|
// Function to insert into the bucket
|
||||||
|
// If key already exists, update the value, else insert a new node in the bucket with the <key, value> pair
|
||||||
|
void insert(const K &key, const V &value);
|
||||||
|
|
||||||
|
// Function to remove an entry from the bucket, if found
|
||||||
|
void erase(const K &key);
|
||||||
|
|
||||||
|
// Function to clear the bucket
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashNode<K, V> *head; //The head node of the bucket
|
||||||
|
mutable std::shared_timed_mutex mutex_; //The mutex for this bucket
|
||||||
|
};
|
||||||
|
|
||||||
|
// The class represting the hash map.
|
||||||
|
// It is expected for user defined types, the hash function will be provided.
|
||||||
|
// By default, the std::hash function will be used
|
||||||
|
// If the hash size is not provided, then a defult size of 1031 will be used
|
||||||
|
// The hash table itself consists of an array of hash buckets.
|
||||||
|
// Each hash bucket is implemented as singly linked list with the head as a dummy node created
|
||||||
|
// during the creation of the bucket. All the hash buckets are created during the construction of the map.
|
||||||
|
// Locks are taken per bucket, hence multiple threads can write simultaneously in different buckets in the hash map
|
||||||
|
template <typename K, typename V, typename F = std::hash<K> >
|
||||||
|
class HashMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashMap(size_t hashSize_ = HASH_SIZE_DEFAULT) : hashSize(hashSize_)
|
||||||
|
{
|
||||||
|
hashTable = new HashBucket<K, V>[hashSize]; // create the hash table as an array of hash buckets
|
||||||
|
}
|
||||||
|
|
||||||
|
~HashMap()
|
||||||
|
{
|
||||||
|
delete[] hashTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and Move of the HashMap are not supported at this moment
|
||||||
|
HashMap(const HashMap &) = delete;
|
||||||
|
HashMap(HashMap &&) = delete;
|
||||||
|
HashMap &operator=(const HashMap &) = delete;
|
||||||
|
HashMap &operator=(HashMap &&) = delete;
|
||||||
|
|
||||||
|
// Function to find an entry in the hash map matching the key.
|
||||||
|
// If key is found, the corresponding value is copied into the parameter "value" and function returns true.
|
||||||
|
// If key is not found, function returns false.
|
||||||
|
bool find(const K &key, V &value) const;
|
||||||
|
|
||||||
|
// Function to insert into the hash map.
|
||||||
|
// If key already exists, update the value, else insert a new node in the bucket with the <key, value> pair.
|
||||||
|
void insert(const K &key, const V &value);
|
||||||
|
|
||||||
|
// Function to remove an entry from the bucket, if found
|
||||||
|
void erase(const K &key);
|
||||||
|
|
||||||
|
// Function to clean up the hasp map, i.e., remove all entries from it
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashBucket<K, V> *hashTable;
|
||||||
|
F hashFn;
|
||||||
|
const size_t hashSize;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif /* HASH_MAP_H_ */
|
||||||
|
|
Loading…
Reference in New Issue