#pragma once
#include "common.hpp"
#include "config.hpp"
#include "test.hpp"
typedef uint32_t cachekey_t;
#define CACHEKEY_HEX_LEN 8
cachekey_t hash(const char*);
cachekey_t hash(const char*, size_t);
cachekey_t hash(const char*, size_t, cachekey_t);
void hash2str(cachekey_t, char*);
template <class T> class HashMap {
private:
T* map;
const size_t size;
public:
HashMap(size_t);
~HashMap();
INLINE T* begin() { return map; } ///< iterator: first valid entry
INLINE T* end() { return map + size; } ///< iterator: first invalid entry
INLINE T* at(cachekey_t pos) { return map + (pos % size); };
INLINE T* operator[](cachekey_t k) { return at(k); }
INLINE const T* at(cachekey_t pos) const { return map + (pos % size); };
INLINE const T* operator[](cachekey_t k) const { return at(k); }
void clean() { memset(map, 0, size*sizeof(T)); } ///< full reset to zeroes (slow)
};
template <class K, class T> class HashCache: public ConfigInst<size_t> {
private:
typedef struct {
K key;
T data;
} node_t;
HashMap<node_t> map;
cachekey_t revision;
public:
HashCache(size_t);
// allow cachekey versions, as well s.t. it is not always recomputed:
T* at(const K&); ///< returns entry if it exists NOTE: make sure to use strncpy ot sth similar s.t. keys are padded for hashing
const T* at(const K&) const; ///< returns entry if it exists NOTE: make sure to use strncpy ot sth similar s.t. keys are padded for hashing
T at(const K&, const T&) const; ///< returns entry or default value
T* get(const K&); ///< returns entry and overwrites hash
T* get(const K&, bool&); ///< returns entry and overwrites hash upon miss, signalling whether it was a hit or not
T* it(T* = NULL); ///< returns incremented "iterator"
void invalidate() { ++revision; } ; ///< cause cache misses (fast)
bool is_valid() const { return true; }
};
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
template <class T> HashMap<T>::HashMap(size_t _size): size(_size) {
assert(size);
map = (T*)calloc(size, sizeof(T));
}
template <class T> HashMap<T>::~HashMap() {
free(map);
}
template <class K, class T> HashCache<K, T>::HashCache(size_t size): map(size), revision(0) {
}
template <class K, class T> T* HashCache<K, T>::at(const K& key) {
node_t* node = map.at(hash((const char*)&key, sizeof(K)) + revision);
if (memcmp(&node->key, &key, sizeof(K)) != 0) {
return NULL;
}
return &node->data;
}
template <class K, class T> const T* HashCache<K, T>::at(const K& key) const {
const node_t* node = map.at(hash((const char*)&key, sizeof(K)) + revision);
if (memcmp(&node->key, &key, sizeof(K)) != 0) {
return NULL;
}
return &node->data;
}
template <class K, class T> T HashCache<K, T>::at(const K& key, const T& def) const {
const T* t = at(key);
return t? *t: def;
}
template <class K, class T> T* HashCache<K, T>::get(const K& key) {
node_t* node = map.at(hash((const char*)&key, sizeof(K)) + revision);
memcpy((void*)&node->key, (const void*)&key, sizeof(K));
return &node->data;
}
template <class K, class T> T* HashCache<K, T>::get(const K& key, bool& hit) {
node_t* node = map.at(hash((const char*)&key, sizeof(K)) + revision);
if (memcmp(&node->key, &key, sizeof(K)) != 0) {
memcpy(&node->key, &key, sizeof(K));
hit = false;
} else {
hit = true;
}
return &node->data;
}
template <class K, class T> T* HashCache<K, T>::it(T* last) {
if (!last) {
return &map.begin()->data;
}
last = (T*)((char*)last + sizeof(node_t));
return ((node_t*)last >= map.end())? NULL: last;
}