This source file includes following definitions.
- Clear
- GetEntry
- Put
- Get
- HasValue
- Erase
- AllocateBuckets
- AdjustBuckets
- Clear
- GetEntries
- GetEntry
- AddEntry
- Put
- Get
- HasValue
- Erase
#ifndef _NPT_MAP_H_
#define _NPT_MAP_H_
#include "NptTypes.h"
#include "NptResults.h"
#include "NptList.h"
#include "NptHash.h"
template <typename K, typename V>
class NPT_Map
{
public:
class Entry {
public:
Entry(const K& key, const V& value) : m_Key(key), m_Value(value) {}
Entry(const K& key) : m_Key(key) {}
const K& GetKey() const { return m_Key; }
const V& GetValue() const { return m_Value; }
bool operator==(const Entry& other) const {
return m_Key == other.m_Key && m_Value == other.m_Value;
}
protected:
void SetValue(const V& value) { m_Value = value; }
K m_Key;
V m_Value;
friend class NPT_Map<K,V>;
};
NPT_Map<K,V>() {}
NPT_Map<K,V>(const NPT_Map<K,V>& copy);
~NPT_Map<K,V>();
NPT_Result Put(const K& key, const V& value);
NPT_Result Get(const K& key, V*& value) const;
bool HasKey(const K& key) const { return GetEntry(key) != NULL; }
bool HasValue(const V& value) const;
NPT_Result Erase(const K& key);
NPT_Cardinal GetEntryCount() const { return m_Entries.GetItemCount(); }
const NPT_List<Entry*>& GetEntries() const { return m_Entries; }
NPT_Result Clear();
V& operator[](const K& key);
const NPT_Map<K,V>& operator=(const NPT_Map<K,V>& copy);
bool operator==(const NPT_Map<K,V>& other) const;
bool operator!=(const NPT_Map<K,V>& other) const;
private:
typedef typename NPT_List<Entry*>::Iterator ListIterator;
Entry* GetEntry(const K& key) const;
NPT_List<Entry*> m_Entries;
};
template <typename K, typename V>
NPT_Map<K,V>::NPT_Map(const NPT_Map<K,V>& copy)
{
*this = copy;
}
template <typename K, typename V>
NPT_Map<K,V>::~NPT_Map()
{
Clear();
}
template <typename K, typename V>
NPT_Result
NPT_Map<K,V>::Clear()
{
m_Entries.Apply(NPT_ObjectDeleter<Entry>());
m_Entries.Clear();
return NPT_SUCCESS;
}
template <typename K, typename V>
typename NPT_Map<K,V>::Entry*
NPT_Map<K,V>::GetEntry(const K& key) const
{
typename NPT_List<Entry*>::Iterator entry = m_Entries.GetFirstItem();
while (entry) {
if ((*entry)->GetKey() == key) {
return *entry;
}
++entry;
}
return NULL;
}
template <typename K, typename V>
NPT_Result
NPT_Map<K,V>::Put(const K& key, const V& value)
{
Entry* entry = GetEntry(key);
if (entry == NULL) {
m_Entries.Add(new Entry(key, value));
} else {
entry->SetValue(value);
}
return NPT_SUCCESS;
}
template <typename K, typename V>
NPT_Result
NPT_Map<K,V>::Get(const K& key, V*& value) const
{
Entry* entry = GetEntry(key);
if (entry == NULL) {
value = NULL;
return NPT_ERROR_NO_SUCH_ITEM;
} else {
value = &entry->m_Value;
return NPT_SUCCESS;
}
}
template <typename K, typename V>
bool
NPT_Map<K,V>::HasValue(const V& value) const
{
ListIterator entry = m_Entries.GetFirstItem();
while (entry) {
if (value == (*entry)->m_Value) {
return true;
}
++entry;
}
return false;
}
template <typename K, typename V>
const NPT_Map<K,V>&
NPT_Map<K,V>::operator=(const NPT_Map<K,V>& copy)
{
if (this == ©) return copy;
Clear();
ListIterator entry = copy.m_Entries.GetFirstItem();
while (entry) {
m_Entries.Add(new Entry((*entry)->GetKey(), (*entry)->GetValue()));
++entry;
}
return *this;
}
template <typename K, typename V>
NPT_Result
NPT_Map<K,V>::Erase(const K& key)
{
ListIterator entry = m_Entries.GetFirstItem();
while (entry) {
if ((*entry)->GetKey() == key) {
delete *entry;
m_Entries.Erase(entry);
return NPT_SUCCESS;
}
++entry;
}
return NPT_ERROR_NO_SUCH_ITEM;
}
template <typename K, typename V>
bool
NPT_Map<K,V>::operator==(const NPT_Map<K,V>& other) const
{
if (m_Entries.GetItemCount() != other.m_Entries.GetItemCount()) return false;
ListIterator entry = m_Entries.GetFirstItem();
while (entry) {
V* value;
if (NPT_SUCCEEDED(other.Get((*entry)->m_Key, value))) {
if (!(*value == (*entry)->m_Value)) return false;
} else {
return false;
}
++entry;
}
return true;
}
template <typename K, typename V>
bool
NPT_Map<K,V>::operator!=(const NPT_Map<K,V>& other) const
{
return !(*this == other);
}
template <typename K, typename V>
V&
NPT_Map<K,V>::operator[](const K& key)
{
Entry* entry = GetEntry(key);
if (entry == NULL) {
entry = new Entry(key);
m_Entries.Add(entry);
}
return entry->m_Value;
}
template <typename K, typename V, typename HF = NPT_Hash<K> >
class NPT_HashMap
{
public:
class Entry {
public:
Entry(NPT_UInt32 hash_value, const K& key, const V& value) : m_HashValue(hash_value), m_Key(key), m_Value(value) {}
Entry(NPT_UInt32 hash_value, const K& key) : m_HashValue(hash_value), m_Key(key) {}
const K& GetKey() const { return m_Key; }
const V& GetValue() const { return m_Value; }
NPT_UInt32 GetHashValue() const { return m_HashValue; }
bool operator==(const Entry& other) const {
return m_HashValue == other.m_HashValue && m_Key == other.m_Key && m_Value == other.m_Value;
}
protected:
void SetValue(const V& value) { m_Value = value; }
NPT_UInt32 m_HashValue;
K m_Key;
V m_Value;
friend class NPT_HashMap<K,V,HF>;
};
class Iterator {
public:
Iterator() : m_Entry(NULL), m_Map(NULL) {}
Iterator(Entry** entry, const NPT_HashMap<K,V,HF>* map) : m_Entry(entry), m_Map(map) {}
Iterator(const Iterator& copy) : m_Entry(copy.m_Entry), m_Map(copy.m_Map) {}
const Entry& operator*() const { return **m_Entry; }
Iterator& operator++() {
if (m_Map && m_Entry) {
do {
++m_Entry;
if (m_Entry >= &m_Map->m_Buckets[1<<m_Map->m_BucketCountLog]) {
m_Entry = NULL;
} else {
if (*m_Entry) break;
}
} while (m_Entry);
}
return (*this);
}
Iterator operator++(int) {
Iterator saved_this = *this;
++(*this);
return saved_this;
}
operator bool() const {
return m_Entry != NULL;
}
bool operator==(const Iterator& other) const {
return m_Map == other.m_Map && m_Entry == other.m_Entry;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
void operator=(const Iterator& other) {
m_Entry = other.m_Entry;
m_Map = other.m_Map;
}
private:
friend class NPT_HashMap<K,V,HF>;
Entry** m_Entry;
const NPT_HashMap<K,V,HF>* m_Map;
};
NPT_HashMap<K,V,HF>();
NPT_HashMap<K,V,HF>(const HF& hasher);
NPT_HashMap<K,V,HF>(const NPT_HashMap<K,V,HF>& copy);
~NPT_HashMap<K,V,HF>();
NPT_Result Put(const K& key, const V& value);
NPT_Result Get(const K& key, V*& value) const;
bool HasKey(const K& key) const { return GetEntry(key) != NULL; }
bool HasValue(const V& value) const;
NPT_Result Erase(const K& key);
NPT_Cardinal GetEntryCount() const { return m_EntryCount; }
Iterator GetEntries() const;
NPT_Result Clear();
template <typename X>
NPT_Result Apply(const X& function) const
{
for (int i=0; i<(1<<m_BucketCountLog); i++) {
if (m_Buckets[i]) {
function(m_Buckets[i]);
}
}
return NPT_SUCCESS;
}
V& operator[](const K& key);
const NPT_HashMap<K,V,HF>& operator=(const NPT_HashMap<K,V,HF>& copy);
bool operator==(const NPT_HashMap<K,V,HF>& other) const;
bool operator!=(const NPT_HashMap<K,V,HF>& other) const;
private:
Entry* GetEntry(const K& key, NPT_UInt32* position=NULL) const;
NPT_Result AddEntry(Entry* entry);
void AllocateBuckets(unsigned int count_log);
void AdjustBuckets(NPT_Cardinal entry_count, bool allow_shrink=false);
HF m_Hasher;
Entry** m_Buckets;
NPT_Cardinal m_BucketCountLog;
NPT_Cardinal m_EntryCount;
};
template <typename K, typename V, typename HF>
NPT_HashMap<K,V,HF>::NPT_HashMap() :
m_Buckets(NULL),
m_EntryCount(0)
{
AllocateBuckets(4);
}
template <typename K, typename V, typename HF>
NPT_HashMap<K,V,HF>::NPT_HashMap(const HF& hasher) :
m_Hasher(hasher),
m_Buckets(NULL),
m_EntryCount(0)
{
AllocateBuckets(4);
}
template <typename K, typename V, typename HF>
NPT_HashMap<K,V,HF>::NPT_HashMap(const NPT_HashMap<K,V,HF>& copy) :
m_Buckets(NULL),
m_BucketCountLog(0),
m_EntryCount(0)
{
*this = copy;
}
template <typename K, typename V, typename HF>
NPT_HashMap<K,V,HF>::~NPT_HashMap()
{
for (int i=0; i<(1<<m_BucketCountLog); i++) {
delete m_Buckets[i];
}
delete[] m_Buckets;
}
template <typename K, typename V, typename HF>
void
NPT_HashMap<K,V,HF>::AllocateBuckets(unsigned int count_log)
{
m_Buckets = new Entry*[1<<count_log];
m_BucketCountLog = count_log;
for (int i=0; i<(1<<count_log); i++) {
m_Buckets[i] = NULL;
}
}
template <typename K, typename V, typename HF>
void
NPT_HashMap<K,V,HF>::AdjustBuckets(NPT_Cardinal entry_count, bool allow_shrink)
{
Entry** buckets = NULL;
unsigned int bucket_count = 1<<m_BucketCountLog;
if (2*entry_count >= bucket_count) {
buckets = m_Buckets;
AllocateBuckets(m_BucketCountLog+1);
} else if (allow_shrink && (5*entry_count < bucket_count) && m_BucketCountLog > 4) {
buckets = m_Buckets;
AllocateBuckets(m_BucketCountLog-1);
}
if (buckets) {
m_EntryCount = 0;
for (unsigned int i=0; i<bucket_count; i++) {
if (buckets[i]) AddEntry(buckets[i]);
}
delete[] buckets;
}
}
template <typename K, typename V, typename HF>
NPT_Result
NPT_HashMap<K,V,HF>::Clear()
{
if (m_Buckets) {
for (int i=0; i<(1<<m_BucketCountLog); i++) {
delete m_Buckets[i];
}
delete[] m_Buckets;
}
m_EntryCount = 0;
AllocateBuckets(4);
return NPT_SUCCESS;
}
template <typename K, typename V, typename HF>
typename NPT_HashMap<K,V,HF>::Iterator
NPT_HashMap<K,V,HF>::GetEntries() const
{
for (int i=0; i<(1<<m_BucketCountLog); i++) {
if (m_Buckets[i]) {
return Iterator(&m_Buckets[i], this);
}
}
return Iterator(NULL, this);
}
template <typename K, typename V, typename HF>
typename NPT_HashMap<K,V,HF>::Entry*
NPT_HashMap<K,V,HF>::GetEntry(const K& key, NPT_UInt32* position) const
{
NPT_UInt32 hash_value = m_Hasher(key);
NPT_UInt32 mask = (1<<m_BucketCountLog)-1;
NPT_UInt32 cursor = hash_value & mask;
while (m_Buckets[cursor]) {
Entry* entry = m_Buckets[cursor];
if (entry->m_HashValue == hash_value &&
entry->m_Key == key) {
if (position) *position = cursor;
return entry;
}
cursor = (cursor + 1) & mask;
}
return NULL;
}
template <typename K, typename V, typename HF>
NPT_Result
NPT_HashMap<K,V,HF>::AddEntry(Entry* entry)
{
AdjustBuckets(m_EntryCount+1);
NPT_UInt32 hash_value = entry->m_HashValue;
NPT_UInt32 mask = (1<<m_BucketCountLog)-1;
NPT_UInt32 cursor = hash_value & mask;
while (m_Buckets[cursor]) {
cursor = (cursor + 1) & mask;
}
m_Buckets[cursor] = entry;
++m_EntryCount;
return NPT_SUCCESS;
}
template <typename K, typename V, typename HF>
NPT_Result
NPT_HashMap<K,V,HF>::Put(const K& key, const V& value)
{
Entry* entry = GetEntry(key);
if (entry == NULL) {
return AddEntry(new Entry(m_Hasher(key), key, value));
} else {
entry->SetValue(value);
}
return NPT_SUCCESS;
}
template <typename K, typename V, typename HF>
NPT_Result
NPT_HashMap<K,V,HF>::Get(const K& key, V*& value) const
{
Entry* entry = GetEntry(key);
if (entry == NULL) {
value = NULL;
return NPT_ERROR_NO_SUCH_ITEM;
} else {
value = &entry->m_Value;
return NPT_SUCCESS;
}
}
template <typename K, typename V, typename HF>
bool
NPT_HashMap<K,V,HF>::HasValue(const V& value) const
{
for (int i=0; i<(1<<m_BucketCountLog); i++) {
if (m_Buckets[i] && m_Buckets[i]->m_Value == value) {
return true;
}
}
return false;
}
template <typename K, typename V, typename HF>
NPT_Result
NPT_HashMap<K,V,HF>::Erase(const K& key)
{
NPT_UInt32 position;
Entry* entry = GetEntry(key, &position);
if (entry == NULL) {
return NPT_ERROR_NO_SUCH_ITEM;
}
m_Buckets[position] = NULL;
NPT_UInt32 mask = (1<<m_BucketCountLog)-1;
for (NPT_UInt32 cursor = (position+1) & mask; m_Buckets[cursor]; cursor = (cursor + 1) & mask) {
NPT_UInt32 target = m_Buckets[cursor]->m_HashValue & mask;
if ( (position <= cursor) ?
((position < target) && (target <= cursor)) :
((position < target) || (target <= cursor)) ) {
continue;
}
m_Buckets[position] = m_Buckets[cursor];
m_Buckets[cursor] = NULL;
position = cursor;
}
delete entry;
--m_EntryCount;
AdjustBuckets(m_EntryCount, true);
return NPT_SUCCESS;
}
template <typename K, typename V, typename HF>
const NPT_HashMap<K,V,HF>&
NPT_HashMap<K,V,HF>::operator=(const NPT_HashMap<K,V,HF>& copy)
{
if (this == ©) return copy;
Clear();
AdjustBuckets(copy.m_EntryCount);
for (int i=0; i<1<<copy.m_BucketCountLog; i++) {
if (copy.m_Buckets[i]) {
AddEntry(new Entry(m_Hasher(copy.m_Buckets[i]->GetKey()),
copy.m_Buckets[i]->GetKey(),
copy.m_Buckets[i]->GetValue()));
}
}
return *this;
}
template <typename K, typename V, typename HF>
bool
NPT_HashMap<K,V,HF>::operator==(const NPT_HashMap<K,V,HF>& other) const
{
if (m_EntryCount != other.m_EntryCount) return false;
for (int i=0; i<(1<<m_BucketCountLog); i++) {
Entry* entry = m_Buckets[i];
if (entry == NULL) continue;
Entry* other_entry = other.GetEntry(entry->m_Key);
if (other_entry == NULL || !(other_entry->m_Value == entry->m_Value)) {
return false;
}
}
return true;
}
template <typename K, typename V, typename HF>
bool
NPT_HashMap<K,V,HF>::operator!=(const NPT_HashMap<K,V,HF>& other) const
{
return !(*this == other);
}
template <typename K, typename V, typename HF>
V&
NPT_HashMap<K,V,HF>::operator[](const K& key)
{
Entry* entry = GetEntry(key);
if (entry == NULL) {
entry = new Entry(m_Hasher(key), key);
AddEntry(entry);
}
return entry->m_Value;
}
template <class T>
class NPT_MapEntryValueDeleter {
public:
void operator()(T* entry) const {
delete entry->GetValue();
}
};
#endif