haiku/headers/private/shared/HashSet.h
Augustin Cavalier b7598b65ba HashSet: Make iterator const.
Nothing that uses this API at present needs a const iterator (and
as far as I could see, nothing ever called Remove() on the iterator.)
But this is now how HashMap's API works, so let's be consistent.
2019-02-14 20:43:49 -05:00

344 lines
5.5 KiB
C++

/*
* Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2019, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef HASH_SET_H
#define HASH_SET_H
#include <OpenHashTable.h>
#include <Locker.h>
#include "AutoLocker.h"
namespace BPrivate {
// HashSetElement
template<typename Key>
class HashSetElement {
private:
typedef HashSetElement<Key> Element;
public:
HashSetElement()
:
fKey(),
fNext(NULL)
{
}
HashSetElement(const Key& key)
:
fKey(key),
fNext(NULL)
{
}
Key fKey;
HashSetElement* fNext;
};
// 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; }
ValueType*& GetLink(ValueType* value) const
{ return value->fNext; }
};
// HashSet
template<typename Key>
class HashSet {
public:
class Iterator {
private:
typedef HashSetElement<Key> Element;
public:
Iterator(const Iterator& other)
:
fSet(other.fSet),
fIterator(other.fIterator),
fElement(other.fElement)
{
}
bool HasNext() const
{
return fIterator.HasNext();
}
Key Next()
{
fElement = fIterator.Next();
if (fElement == NULL)
return Key();
return fElement->fKey;
}
Iterator& operator=(const Iterator& other)
{
fSet = other.fSet;
fIterator = other.fIterator;
fElement = other.fElement;
return *this;
}
private:
Iterator(const HashSet<Key>* set)
:
fSet(set),
fIterator(set->fTable.GetIterator()),
fElement(NULL)
{
}
private:
typedef BOpenHashTable<HashSetTableDefinition<Key> > ElementTable;
const HashSet<Key>* fSet;
typename ElementTable::Iterator fIterator;
Element* fElement;
private:
friend class HashSet<Key>;
};
HashSet();
~HashSet();
status_t InitCheck() const;
status_t Add(const Key& key);
bool Remove(const Key& key);
bool Remove(Iterator& it);
void Clear();
bool Contains(const Key& key) const;
int32 Size() const;
Iterator GetIterator() const;
protected:
typedef BOpenHashTable<HashSetTableDefinition<Key> > ElementTable;
typedef HashSetElement<Key> Element;
friend class Iterator;
protected:
ElementTable fTable;
};
// SynchronizedHashSet
template<typename Key, typename Locker = BLocker>
class SynchronizedHashSet : public Locker {
public:
typedef typename HashSet<Key>::Iterator Iterator;
SynchronizedHashSet() : Locker("synchronized hash set") {}
~SynchronizedHashSet() { Locker::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);
}
void Clear()
{
MapLocker locker(this);
fSet.Clear();
}
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() const
{
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;
};
// HashSet
// constructor
template<typename Key>
HashSet<Key>::HashSet()
:
fTable()
{
fTable.Init();
}
// destructor
template<typename Key>
HashSet<Key>::~HashSet()
{
Clear();
}
// InitCheck
template<typename Key>
status_t
HashSet<Key>::InitCheck() const
{
return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY);
}
// Add
template<typename Key>
status_t
HashSet<Key>::Add(const Key& key)
{
Element* element = fTable.Lookup(key);
if (element) {
// already contains the value
return B_OK;
}
// does not contain the key yet: create an element and add it
element = new(std::nothrow) Element(key);
if (!element)
return B_NO_MEMORY;
status_t error = fTable.Insert(element);
if (error != B_OK)
delete element;
return error;
}
// Remove
template<typename Key>
bool
HashSet<Key>::Remove(const Key& key)
{
Element* element = fTable.Lookup(key);
if (element == NULL)
return false;
fTable.Remove(element);
delete element;
return true;
}
// Remove
template<typename Key>
bool
HashSet<Key>::Remove(Iterator& it)
{
Element* element = it.fElement;
if (element == NULL)
return false;
fTable.RemoveUnchecked(element);
delete element;
it.fElement = NULL;
return true;
}
// Clear
template<typename Key>
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;
}
}
// Contains
template<typename Key>
bool
HashSet<Key>::Contains(const Key& key) const
{
return fTable.Lookup(key) != NULL;
}
// Size
template<typename Key>
int32
HashSet<Key>::Size() const
{
return fTable.CountElements();
}
// GetIterator
template<typename Key>
typename HashSet<Key>::Iterator
HashSet<Key>::GetIterator() const
{
return Iterator(this);
}
} // namespace BPrivate
using BPrivate::HashSet;
#endif // HASH_SET_H