poco/Foundation/include/Poco/SimpleHashTable.h
Guenter Obiltschnig 2d4078f392 submitted 1.2.0
2006-08-29 07:10:35 +00:00

408 lines
10 KiB
C++

//
// SimpleHashTable.h
//
// $Id: //poco/1.2/Foundation/include/Poco/SimpleHashTable.h#1 $
//
// Library: Foundation
// Package: Core
// Module: SimpleHashTable
//
// Definition of the SimpleHashTable class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef Foundation_SimpleHashTable_INCLUDED
#define Foundation_SimpleHashTable_INCLUDED
#include "Poco/Foundation.h"
#include "Poco/Exception.h"
#include "Poco/HashFunction.h"
#include "Poco/HashStatistic.h"
#include <vector>
#include <map>
#include <stddef.h>
namespace Poco {
template< class Key, class Value, class KeyHashFunction = HashFunction< Key> >
class SimpleHashTable
/// A SimpleHashTable stores a key value pair that can be looked up via a hashed key.
///
/// In comparision to a HashTable, this class handles collisions by sequentially searching the next
/// free location. This also means that the maximum size of this table is limited, i.e. if the hash table
/// is full, it will throw an exception and that this class does not support remove operations.
/// On the plus side it is faster than the HashTable.
///
/// This class is NOT thread safe.
{
public:
class HashEntry
{
public:
Key key;
Value value;
HashEntry(const Key k, const Value v):
key(k),
value(v)
{
}
};
typedef HashEntry** HashTableVector;
SimpleHashTable(UInt32 initialSize = 251): _entries(0), _size(0), _maxCapacity(initialSize)
/// Creates the SimpleHashTable.
{
_entries = new HashEntry*[initialSize];
memset(_entries, '\0', sizeof(HashEntry*)*initialSize);
}
SimpleHashTable(const SimpleHashTable& ht):
_entries (new HashEntry*[ht._maxCapacity]),
_size(ht._size),
_maxCapacity(ht._maxCapacity)
{
for (int i = 0; i < _maxCapacity; ++i)
{
if (ht._entries[i])
_entries[i] = new HashEntry(*ht._entries[i]);
else
_entries[i] = 0;
}
}
~SimpleHashTable()
/// Destroys the SimpleHashTable.
{
clear();
}
SimpleHashTable& operator = (const SimpleHashTable& ht)
{
if (this != &ht)
{
clear();
_maxCapacity = ht._maxCapacity;
delete[] _entries;
_entries = new HashEntry*[_maxCapacity];
_size = ht._size;
for (int i = 0; i < _maxCapacity; ++i)
{
if (ht._entries[i])
_entries[i] = new HashEntry(*ht._entries[i]);
else
_entries[i] = 0;
}
}
return *this;
}
void clear()
{
if (!_entries)
return;
for (int i = 0; i < _maxCapacity; ++i)
{
if (_entries[i])
delete _entries[i];
}
delete[] _entries;
_entries = 0;
_size = 0;
_maxCapacity = 0;
}
UInt32 insert(const Key& key, const Value& value)
/// Returns the hash value of the inserted item.
/// Throws an exception if the entry was already inserted
{
UInt32 hsh = hash(key);
insertRaw(key, hsh, value);
return hsh;
}
void insertRaw(const Key& key, UInt32 hsh, const Value& value)
/// Returns the hash value of the inserted item.
/// Throws an exception if the entry was already inserted
{
if (!_entries[hsh])
_entries[hsh] = new HashEntry(key, value);
else
{
UInt32 origHash = hsh;
while (_entries[hsh % _maxCapacity])
{
poco_assert_dbg(_entries[hsh % _maxCapacity]->key != key);
if (hsh - origHash > _maxCapacity)
throw PoolOverflowException("SimpleHashTable full");
hsh++;
}
_entries[hsh % _maxCapacity] = new HashEntry(key, value);
}
_size++;
}
UInt32 update(const Key& key, const Value& value)
/// Returns the hash value of the inserted item.
/// Replaces an existing entry if it finds one
{
UInt32 hsh = hash(key);
updateRaw(key, hsh, value);
return hsh;
}
void updateRaw(const Key& key, UInt32 hsh, const Value& value)
/// Returns the hash value of the inserted item.
/// Replaces an existing entry if it finds one
{
if (!_entries[hsh])
_entries[hsh] = new HashEntry(key, value);
else
{
UInt32 origHash = hsh;
while (_entries[hsh % _maxCapacity])
{
if(_entries[hsh % _maxCapacity]->key == key)
{
_entries[hsh % _maxCapacity]->value = value;
return;
}
if (hsh - origHash > _maxCapacity)
throw PoolOverflowException("SimpleHashTable full");
hsh++;
}
_entries[hsh % _maxCapacity] = new HashEntry(key, value);
}
_size++;
}
UInt32 hash(const Key& key) const
{
return KeyHashFunction::hash(key, _maxCapacity);
}
const Value& get(const Key& key) const
/// Throws an exception if the value does not exist
{
UInt32 hsh = hash(key);
return getRaw(key, hsh);
}
const Value& getRaw(const Key& key, UInt32 hsh) const
/// Throws an exception if the value does not exist
{
UInt32 origHash = hsh;
while (true)
{
if (_entries[hsh % _maxCapacity])
{
if(_entries[hsh % _maxCapacity]->key == key)
{
return _entries[hsh % _maxCapacity]->value;
}
}
else
throw InvalidArgumentException("value not found");
if (hsh - origHash > _maxCapacity)
throw InvalidArgumentException("value not found");
hsh++;
}
}
const Key& getKeyRaw(const Key& key, UInt32 hsh)
/// Throws an exception if the key does not exist. returns a reference to the internally
/// stored key. Useful when someone does an insert and wants for performance reason only to store
/// a pointer to the key in another collection
{
UInt32 origHash = hsh;
while (true)
{
if (_entries[hsh % _maxCapacity])
{
if(_entries[hsh % _maxCapacity]->key == key)
{
return _entries[hsh % _maxCapacity]->key;
}
}
else
throw InvalidArgumentException("key not found");
if (hsh - origHash > _maxCapacity)
throw InvalidArgumentException("key not found");
hsh++;
}
}
bool get(const Key& key, Value& v) const
/// Sets v to the found value, returns false if no value was found
{
UInt32 hsh = hash(key);
return getRaw(key, hsh, v);
}
bool getRaw(const Key& key, UInt32 hsh, Value& v) const
/// Sets v to the found value, returns false if no value was found
{
UInt32 origHash = hsh;
while (true)
{
if (_entries[hsh % _maxCapacity])
{
if(_entries[hsh % _maxCapacity]->key == key)
{
v = _entries[hsh % _maxCapacity]->value;
return true;
}
}
else
return false;
if (hsh - origHash > _maxCapacity)
return false;
hsh++;
}
}
bool exists(const Key& key)
{
UInt32 hsh = hash(key);
return existsRaw(key, hsh);
}
bool existsRaw(const Key& key, UInt32 hsh)
{
UInt32 origHash = hsh;
while (true)
{
if (_entries[hsh % _maxCapacity])
{
if(_entries[hsh % _maxCapacity]->key == key)
{
return true;
}
}
else
return false;
if (hsh - origHash > _maxCapacity)
return false;
hsh++;
}
}
size_t size() const
/// Returns the number of elements already inserted into the SimpleHashTable
{
return _size;
}
UInt32 maxCapacity() const
{
return _maxCapacity;
}
void resize(UInt32 newSize)
/// Resizes the hashtable, rehashes all existing entries. Expensive!
{
if (_maxCapacity != newSize)
{
HashTableVector cpy = _entries;
_entries = 0;
UInt32 oldSize = _maxCapacity;
_maxCapacity = newSize;
_entries = new HashEntry*[_maxCapacity];
memset(_entries, '\0', sizeof(HashEntry*)*_maxCapacity);
if (_size == 0)
{
// no data was yet inserted
delete[] cpy;
return;
}
_size = 0;
for (int i=0; i < oldSize; ++i)
{
if (cpy[i])
{
insert(cpy[i]->key, cpy[i]->value);
delete cpy[i];
}
}
delete[] cpy;
}
}
HashStatistic currentState(bool details = false) const
/// Returns the current internal state
{
UInt32 numberOfEntries = (UInt32)_size;
UInt32 numZeroEntries = 0;
UInt32 maxEntriesPerHash = 0;
std::vector<UInt32> detailedEntriesPerHash;
#ifdef _DEBUG
UInt32 totalSize = 0;
#endif
for (int i=0; i < _maxCapacity; ++i)
{
if (_entries[i])
{
maxEntriesPerHash = 1;
UInt32 size = 1;
if (details)
detailedEntriesPerHash.push_back(size);
#ifdef DEBUG
totalSize += size;
#endif
}
else
{
numZeroEntries++;
if (details)
detailedEntriesPerHash.push_back(0);
}
}
#ifdef DEBUG
poco_assert_dbg(totalSize == numberOfEntries);
#endif
return HashStatistic(_maxCapacity, numberOfEntries, numZeroEntries, maxEntriesPerHash, detailedEntriesPerHash);
}
private:
HashTableVector _entries;
size_t _size;
UInt32 _maxCapacity;
};
} // namespace Poco
#endif // Foundation_HashTable_INCLUDED