2009-03-08 00:21:10 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
2007-02-24 03:30:19 +03:00
|
|
|
#ifndef HASH_SET_H
|
|
|
|
#define HASH_SET_H
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
#include <util/OpenHashTable.h>
|
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
#include "AutoLocker.h"
|
|
|
|
#include "Locker.h"
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
|
|
|
|
// HashSetElement
|
|
|
|
template<typename Key>
|
2009-03-08 00:21:10 +03:00
|
|
|
class HashSetElement : public HashTableLink<HashSetElement<Key> > {
|
2007-02-24 03:30:19 +03:00
|
|
|
private:
|
|
|
|
typedef HashSetElement<Key> Element;
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
public:
|
|
|
|
HashSetElement()
|
|
|
|
:
|
|
|
|
fKey()
|
2007-02-24 03:30:19 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
HashSetElement(const Key& key)
|
|
|
|
:
|
|
|
|
fKey(key)
|
2007-02-24 03:30:19 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
Key fKey;
|
|
|
|
};
|
2007-02-24 03:30:19 +03:00
|
|
|
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
// HashSetTableDefinition
|
|
|
|
template<typename Key>
|
|
|
|
struct HashSetTableDefinition {
|
|
|
|
typedef Key KeyType;
|
|
|
|
typedef HashSetElement<Key> ValueType;
|
|
|
|
|
|
|
|
size_t HashKey(const KeyType& key) const
|
|
|
|
{ return key.GetHashCode(); }
|
|
|
|
size_t Hash(const ValueType* value) const
|
|
|
|
{ return HashKey(value->fKey); }
|
|
|
|
bool Compare(const KeyType& key, const ValueType* value) const
|
|
|
|
{ return value->fKey == key; }
|
|
|
|
HashTableLink<ValueType>* GetLink(ValueType* value) const
|
|
|
|
{ return value; }
|
2007-02-24 03:30:19 +03:00
|
|
|
};
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// HashSet
|
|
|
|
template<typename Key>
|
|
|
|
class HashSet {
|
|
|
|
public:
|
|
|
|
class Iterator {
|
|
|
|
private:
|
|
|
|
typedef HashSetElement<Key> Element;
|
|
|
|
public:
|
|
|
|
Iterator(const Iterator& other)
|
2009-03-08 00:21:10 +03:00
|
|
|
:
|
|
|
|
fSet(other.fSet),
|
|
|
|
fIterator(other.fIterator),
|
|
|
|
fElement(other.fElement)
|
2007-02-24 03:30:19 +03:00
|
|
|
{
|
|
|
|
}
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
bool HasNext() const
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
return fIterator.HasNext();
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
Key Next()
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
fElement = fIterator.Next();
|
|
|
|
if (fElement == NULL)
|
2007-02-24 03:30:19 +03:00
|
|
|
return Key();
|
2009-03-08 00:21:10 +03:00
|
|
|
|
|
|
|
return fElement->fKey;
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
bool Remove()
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
if (fElement == NULL)
|
2007-02-24 03:30:19 +03:00
|
|
|
return false;
|
2009-03-08 00:21:10 +03:00
|
|
|
|
|
|
|
fSet->fTable.RemoveUnchecked(fElement);
|
|
|
|
delete fElement;
|
|
|
|
fElement = NULL;
|
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
return true;
|
|
|
|
}
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
Iterator& operator=(const Iterator& other)
|
|
|
|
{
|
|
|
|
fSet = other.fSet;
|
2009-03-08 00:21:10 +03:00
|
|
|
fIterator = other.fIterator;
|
2007-02-24 03:30:19 +03:00
|
|
|
fElement = other.fElement;
|
|
|
|
return *this;
|
|
|
|
}
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
private:
|
2009-03-08 00:21:10 +03:00
|
|
|
Iterator(HashSet<Key>* set)
|
|
|
|
:
|
|
|
|
fSet(set),
|
|
|
|
fIterator(set->fTable.GetIterator()),
|
|
|
|
fElement(NULL)
|
2007-02-24 03:30:19 +03:00
|
|
|
{
|
|
|
|
}
|
2009-03-08 00:21:10 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
friend class HashMap<Key, Value>;
|
|
|
|
typedef OpenHashTable<HashSetTableDefinition<Key> > ElementTable;
|
|
|
|
|
|
|
|
HashSet<Key>* fSet;
|
|
|
|
ElementTable::Iterator fIterator;
|
|
|
|
Element* fElement;
|
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
private:
|
|
|
|
friend class HashSet<Key>;
|
|
|
|
};
|
|
|
|
|
|
|
|
HashSet();
|
|
|
|
~HashSet();
|
|
|
|
|
|
|
|
status_t InitCheck() const;
|
|
|
|
|
|
|
|
status_t Add(const Key& key);
|
|
|
|
bool Remove(const Key& key);
|
2009-03-08 00:21:10 +03:00
|
|
|
void Clear();
|
2007-02-24 03:30:19 +03:00
|
|
|
bool Contains(const Key& key) const;
|
|
|
|
|
|
|
|
int32 Size() const;
|
|
|
|
|
|
|
|
Iterator GetIterator();
|
|
|
|
|
|
|
|
protected:
|
2009-03-08 00:21:10 +03:00
|
|
|
typedef OpenHashTable<HashSetTableDefinition<Key> > ElementTable;
|
2007-02-24 03:30:19 +03:00
|
|
|
typedef HashSetElement<Key> Element;
|
|
|
|
friend class Iterator;
|
|
|
|
|
|
|
|
protected:
|
2009-03-08 00:21:10 +03:00
|
|
|
ElementTable fTable;
|
2007-02-24 03:30:19 +03:00
|
|
|
};
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// SynchronizedHashSet
|
|
|
|
template<typename Key>
|
|
|
|
class SynchronizedHashSet : public Locker {
|
|
|
|
public:
|
|
|
|
typedef HashSet<Key>::Iterator Iterator;
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
SynchronizedHashSet() : Locker("synchronized hash set") {}
|
2007-02-24 03:30:19 +03:00
|
|
|
~SynchronizedHashSet() { Lock(); }
|
|
|
|
|
|
|
|
status_t InitCheck() const
|
|
|
|
{
|
|
|
|
return fSet.InitCheck();
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t Add(const Key& key)
|
|
|
|
{
|
|
|
|
MapLocker locker(this);
|
|
|
|
if (!locker.IsLocked())
|
|
|
|
return B_ERROR;
|
|
|
|
return fSet.Add(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Remove(const Key& key)
|
|
|
|
{
|
|
|
|
MapLocker locker(this);
|
|
|
|
if (!locker.IsLocked())
|
|
|
|
return false;
|
|
|
|
return fSet.Remove(key);
|
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
MapLocker locker(this);
|
|
|
|
fSet.Clear();
|
|
|
|
}
|
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
bool Contains(const Key& key) const
|
|
|
|
{
|
|
|
|
const Locker* lock = this;
|
|
|
|
MapLocker locker(const_cast<Locker*>(lock));
|
|
|
|
if (!locker.IsLocked())
|
|
|
|
return false;
|
|
|
|
return fSet.Contains(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 Size() const
|
|
|
|
{
|
|
|
|
const Locker* lock = this;
|
|
|
|
MapLocker locker(const_cast<Locker*>(lock));
|
|
|
|
return fSet.Size();
|
|
|
|
}
|
|
|
|
|
|
|
|
Iterator GetIterator()
|
|
|
|
{
|
|
|
|
return fSet.GetIterator();
|
|
|
|
}
|
|
|
|
|
|
|
|
// for debugging only
|
|
|
|
const HashSet<Key>& GetUnsynchronizedSet() const { return fSet; }
|
|
|
|
HashSet<Key>& GetUnsynchronizedSet() { return fSet; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
typedef AutoLocker<Locker> MapLocker;
|
|
|
|
|
|
|
|
HashSet<Key> fSet;
|
|
|
|
};
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// HashSet
|
|
|
|
|
|
|
|
// constructor
|
|
|
|
template<typename Key>
|
|
|
|
HashSet<Key>::HashSet()
|
2009-03-08 00:21:10 +03:00
|
|
|
:
|
|
|
|
fTable()
|
2007-02-24 03:30:19 +03:00
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
fTable.Init();
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// destructor
|
|
|
|
template<typename Key>
|
|
|
|
HashSet<Key>::~HashSet()
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
Clear();
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// InitCheck
|
|
|
|
template<typename Key>
|
|
|
|
status_t
|
|
|
|
HashSet<Key>::InitCheck() const
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY);
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// Add
|
|
|
|
template<typename Key>
|
|
|
|
status_t
|
|
|
|
HashSet<Key>::Add(const Key& key)
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
Element* element = fTable.Lookup(key);
|
|
|
|
if (element) {
|
|
|
|
// already contains the value
|
2007-02-24 03:30:19 +03:00
|
|
|
return B_OK;
|
2009-03-08 00:21:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// does not contain the key yet: create an element and add it
|
|
|
|
element = new(std::nothrow) Element(key);
|
2007-02-24 03:30:19 +03:00
|
|
|
if (!element)
|
|
|
|
return B_NO_MEMORY;
|
2009-03-08 00:21:10 +03:00
|
|
|
|
|
|
|
status_t error = fTable.Insert(element);
|
|
|
|
if (error != B_OK)
|
|
|
|
delete element;
|
|
|
|
|
|
|
|
return error;
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// Remove
|
|
|
|
template<typename Key>
|
|
|
|
bool
|
|
|
|
HashSet<Key>::Remove(const Key& key)
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
Element* element = fTable.Lookup(key);
|
|
|
|
if (element == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
fTable.Remove(element);
|
|
|
|
delete element;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Clear
|
|
|
|
template<typename Key, typename Value>
|
|
|
|
void
|
|
|
|
HashSet<Key>::Clear()
|
|
|
|
{
|
|
|
|
// clear the table and delete the elements
|
|
|
|
Element* element = fTable.Clear(true);
|
|
|
|
while (element != NULL) {
|
|
|
|
Element* next = element->fNext;
|
|
|
|
delete element;
|
|
|
|
element = next;
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// Contains
|
|
|
|
template<typename Key>
|
|
|
|
bool
|
|
|
|
HashSet<Key>::Contains(const Key& key) const
|
|
|
|
{
|
2009-03-08 00:21:10 +03:00
|
|
|
return fTable.Lookup(key) != NULL;
|
2007-02-24 03:30:19 +03:00
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
// Size
|
|
|
|
template<typename Key>
|
|
|
|
int32
|
|
|
|
HashSet<Key>::Size() const
|
|
|
|
{
|
|
|
|
return fTable.CountElements();
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetIterator
|
|
|
|
template<typename Key>
|
|
|
|
HashSet<Key>::Iterator
|
|
|
|
HashSet<Key>::GetIterator()
|
|
|
|
{
|
|
|
|
return Iterator(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// _FindElement
|
|
|
|
template<typename Key>
|
|
|
|
HashSet<Key>::Element *
|
|
|
|
HashSet<Key>::_FindElement(const Key& key) const
|
|
|
|
{
|
|
|
|
Element* element = fTable.FindFirst(key.GetHashCode());
|
|
|
|
while (element && element->fKey != key) {
|
|
|
|
if (element->fNext >= 0)
|
|
|
|
element = fTable.ElementAt(element->fNext);
|
|
|
|
else
|
|
|
|
element = NULL;
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
2009-03-08 00:21:10 +03:00
|
|
|
|
2007-02-24 03:30:19 +03:00
|
|
|
#endif // HASH_SET_H
|