haiku/headers/private/kernel/util/VectorMap.h
Ingo Weinhold 83744ac99d Added the ImplicitKey entry strategy, which allows the key to be calculated on the fly.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3802 a95241bf-73f2-0310-859d-f6bbb57e9c96
2003-07-02 03:17:43 +00:00

793 lines
20 KiB
C++

// VectorMap.h
//
// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Except as contained in this notice, the name of a copyright holder shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization of the
// copyright holder.
#ifndef _VECTOR_MAP_H
#define _VECTOR_MAP_H
#include <new>
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
#include <KernelUtilsOrder.h>
#include <Vector.h>
namespace VectorMapEntryStrategy {
// Pair
template<typename Key, typename Value,
typename KeyOrder = KernelUtilsOrder::Ascending<Key> > class Pair;
// ImplicitKey
template<typename Key, typename Value, typename GetKey,
typename KeyOrder = KernelUtilsOrder::Ascending<Key> >
class ImplicitKey;
}
template<typename Entry, typename Parent, typename EntryIterator>
class VectorMapIterator;
template<typename _Key, typename _Value, typename Entry, typename Parent>
class VectorMapEntry;
// for convenience
#define _VECTOR_MAP_TEMPLATE_LIST template<typename Key, typename Value, \
typename EntryStrategy>
#define _VECTOR_MAP_CLASS_NAME VectorMap<Key, Value, EntryStrategy>
/*!
\class VectorMap
\brief A generic vector-based map implementation.
The map entries are ordered according to the supplied
compare function object. Default is ascending order.
Note that VectorMap::Entry is not the same class as EntryStrategy::Entry.
It is light-weight class, an object of which is returned when a iterator
is dereferenced. It features a Key() and a Value() method returning
references to the entry's key/value. This allows EntryStrategy::Entry
to be an arbitrary class, not needing to implement a certain interface.
*/
template<typename Key, typename Value,
typename EntryStrategy = VectorMapEntryStrategy::Pair<Key, Value> >
class VectorMap {
private:
typedef _VECTOR_MAP_CLASS_NAME Class;
typedef typename EntryStrategy::Entry _Entry;
typedef typename EntryStrategy::KeyReference KeyReference;
typedef Vector<_Entry> ElementVector;
public:
typedef VectorMapEntry<KeyReference, Value, _Entry, Class>
Entry;
typedef VectorMapEntry<KeyReference, const Value, const _Entry,
const Class> ConstEntry;
typedef VectorMapIterator<Entry, Class, ElementVector::Iterator>
Iterator;
typedef VectorMapIterator<ConstEntry, const Class,
ElementVector::ConstIterator> ConstIterator;
private:
static const size_t kDefaultChunkSize = 10;
static const size_t kMaximalChunkSize = 1024 * 1024;
public:
VectorMap(size_t chunkSize = kDefaultChunkSize);
// TODO: Copy constructor, assignment operator.
~VectorMap();
status_t Insert(const Key &key, const Value &value);
status_t Put(const Key &key, const Value &value);
Value &Get(const Key &key);
const Value &Get(const Key &key) const;
int32 Remove(const Key &key);
Iterator Erase(const Iterator &iterator);
inline int32 Count() const;
inline bool IsEmpty() const;
void MakeEmpty();
inline Iterator Begin();
inline ConstIterator Begin() const;
inline Iterator End();
inline ConstIterator End() const;
inline Iterator Null();
inline ConstIterator Null() const;
Iterator Find(const Key &key);
ConstIterator Find(const Key &key) const;
Iterator FindClose(const Key &key, bool less);
ConstIterator FindClose(const Key &key, bool less) const;
private:
int32 _FindInsertionIndex(const Key &key, bool &exists) const;
private:
friend class Entry;
friend class ConstEntry;
ElementVector fElements;
EntryStrategy fEntryStrategy;
};
// VectorMapEntry
template<typename KeyReference, typename _Value, typename Entry,
typename Parent>
class VectorMapEntry {
private:
typedef VectorMapEntry<KeyReference, _Value, Entry, Parent> Class;
public:
VectorMapEntry()
: fParent(NULL), fEntry(NULL) {}
inline KeyReference Key() const
{
return fParent->fEntryStrategy.GetKey(*fEntry);
}
inline _Value &Value() const
{
return fParent->fEntryStrategy.GetValue(*fEntry);
}
inline const Class *operator->() const
{
return this;
}
// private
public:
VectorMapEntry(Parent *parent, Entry *entry)
: fParent(parent), fEntry(entry) {}
private:
const Parent *fParent;
Entry *fEntry;
};
// VectorMapIterator
template<typename Entry, typename Parent, typename EntryIterator>
class VectorMapIterator {
private:
typedef VectorMapIterator<Entry, Parent, EntryIterator> Iterator;
public:
inline VectorMapIterator()
: fParent(NULL),
fIterator()
{
}
inline VectorMapIterator(
const Iterator &other)
: fParent(other.fParent),
fIterator(other.fIterator)
{
}
inline Iterator &operator++()
{
++fIterator;
return *this;
}
inline Iterator operator++(int)
{
Iterator it(*this);
++*this;
return it;
}
inline Iterator &operator--()
{
--fIterator;
return *this;
}
inline Iterator operator--(int)
{
Iterator it(*this);
--*this;
return it;
}
inline Iterator &operator=(const Iterator &other)
{
fParent = other.fParent;
fIterator = other.fIterator;
return *this;
}
inline bool operator==(const Iterator &other) const
{
return (fParent == other.fParent && fIterator == other.fIterator);
}
inline bool operator!=(const Iterator &other) const
{
return !(*this == other);
}
inline Entry operator*() const
{
return Entry(fParent, &*fIterator);
}
inline Entry operator->() const
{
return Entry(fParent, &*fIterator);
}
inline operator bool() const
{
return fIterator;
}
// private
public:
inline VectorMapIterator(Parent *parent, const EntryIterator &iterator)
: fParent(parent),
fIterator(iterator)
{
}
inline EntryIterator &GetIterator()
{
return fIterator;
}
inline const EntryIterator &GetIterator() const
{
return fIterator;
}
protected:
Parent *fParent;
EntryIterator fIterator;
};
// VectorMap
// constructor
/*! \brief Creates an empty map.
\param chunkSize The granularity for the underlying vector's capacity,
i.e. the minimal number of elements the capacity grows or shrinks
when necessary.
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::VectorMap(size_t chunkSize)
: fElements(chunkSize)
{
}
// destructor
/*! \brief Frees all resources associated with the object.
The contained keys and values are destroyed. Note, that for pointer
types only the pointer is destroyed, not the object it points to.
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::~VectorMap()
{
}
// Insert
/*! \brief Associates a key with a value.
If there is already a value associated with the key, the old entry
is replaced.
\param key The key to which a value shall be associated.
\param value The value to be associated with the key.
\return
- \c B_OK: Everything went fine.
- \c B_NO_MEMORY: Insufficient memory for this operation.
- \c B_BAD_VALUE: The map's EntryStrategy requires some special
relationship between key and value, that \a key and \a value haven't
(doesn't apply to the default strategy).
*/
_VECTOR_MAP_TEMPLATE_LIST
status_t
_VECTOR_MAP_CLASS_NAME::Insert(const Key &key, const Value &value)
{
if (!fEntryStrategy.AreCompatible(key, value))
return B_BAD_VALUE;
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
if (exists) {
fElements[index] = fEntryStrategy.MakeEntry(key, value);
return B_OK;
}
return fElements.Insert(fEntryStrategy.MakeEntry(key, value), index);
}
// Put
/*! \brief Equivalent to Insert().
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
status_t
_VECTOR_MAP_CLASS_NAME::Put(const Key &key, const Value &value)
{
return Insert(key, value);
}
// Get
/*! \brief Returns the value associated with a given key.
\note Invoking this method for a key not know to the map is dangerous!
The behavior is unspecified. It may even crash.
\param key The key to be looked up.
\return The value associated with \a key.
*/
_VECTOR_MAP_TEMPLATE_LIST
Value &
_VECTOR_MAP_CLASS_NAME::Get(const Key &key)
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
if (!exists)
return fEntryStrategy.GetValue(fElements[0]);
return fEntryStrategy.GetValue(fElements[index]);
}
// Get
/*! \brief Returns the value associated with a given key.
\note Invoking this method for a key not know to the map is dangerous!
The behavior is unspecified. It may even crash.
\param key The key to be looked up.
\return The value associated with \a key.
*/
_VECTOR_MAP_TEMPLATE_LIST
const Value &
_VECTOR_MAP_CLASS_NAME::Get(const Key &key) const
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
if (!exists)
return fEntryStrategy.GetValue(fElements[0]);
return fEntryStrategy.GetValue(fElements[index]);
}
// Remove
/*! \brief Removes the entry with the supplied key.
\param key The key to be removed.
\return The number of removed occurrences, i.e. \c 1, if the map
contained an entry with that key, \c 0 otherwise.
*/
_VECTOR_MAP_TEMPLATE_LIST
int32
_VECTOR_MAP_CLASS_NAME::Remove(const Key &key)
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
if (!exists)
return 0;
fElements.Erase(index);
return 1;
}
// Erase
/*! \brief Removes the entry at the given position.
\param iterator An iterator referring to the entry to be removed.
\return An iterator referring to the entry succeeding the removed
one (End(), if it was the last element that has been
removed), or Null(), if \a iterator was an invalid iterator
(in this case including End()).
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::Iterator
_VECTOR_MAP_CLASS_NAME::Erase(const Iterator &iterator)
{
return Iterator(this, fElements.Erase(iterator.GetIterator()));
}
// Count
/*! \brief Returns the number of entry the map contains.
\return The number of entries the map contains.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
int32
_VECTOR_MAP_CLASS_NAME::Count() const
{
return fElements.Count();
}
// IsEmpty
/*! \brief Returns whether the map is empty.
\return \c true, if the map is empty, \c false otherwise.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
bool
_VECTOR_MAP_CLASS_NAME::IsEmpty() const
{
return fElements.IsEmpty();
}
// MakeEmpty
/*! \brief Removes all entries from the map.
*/
_VECTOR_MAP_TEMPLATE_LIST
void
_VECTOR_MAP_CLASS_NAME::MakeEmpty()
{
fElements.MakeEmpty();
}
// Begin
/*! \brief Returns an iterator referring to the beginning of the map.
If the map is not empty, Begin() refers to its first entry,
otherwise it is equal to End() and must not be dereferenced!
\return An iterator referring to the beginning of the map.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
_VECTOR_MAP_CLASS_NAME::Iterator
_VECTOR_MAP_CLASS_NAME::Begin()
{
return Iterator(this, fElements.Begin());
}
// Begin
/*! \brief Returns an iterator referring to the beginning of the map.
If the map is not empty, Begin() refers to its first entry,
otherwise it is equal to End() and must not be dereferenced!
\return An iterator referring to the beginning of the map.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
_VECTOR_MAP_CLASS_NAME::ConstIterator
_VECTOR_MAP_CLASS_NAME::Begin() const
{
return ConstIterator(this, fElements.Begin());
}
// End
/*! \brief Returns an iterator referring to the end of the map.
The position identified by End() is the one succeeding the last
entry, i.e. it must not be dereferenced!
\return An iterator referring to the end of the map.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
_VECTOR_MAP_CLASS_NAME::Iterator
_VECTOR_MAP_CLASS_NAME::End()
{
return Iterator(this, fElements.End());
}
// End
/*! \brief Returns an iterator referring to the end of the map.
The position identified by End() is the one succeeding the last
entry, i.e. it must not be dereferenced!
\return An iterator referring to the end of the map.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
_VECTOR_MAP_CLASS_NAME::ConstIterator
_VECTOR_MAP_CLASS_NAME::End() const
{
return ConstIterator(this, fElements.End());
}
// Null
/*! \brief Returns an invalid iterator.
Null() is used as a return value, if something went wrong. It must
neither be incremented or decremented nor dereferenced!
\return An invalid iterator.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
_VECTOR_MAP_CLASS_NAME::Iterator
_VECTOR_MAP_CLASS_NAME::Null()
{
return Iterator(this, fElements.Null());
}
// Null
/*! \brief Returns an invalid iterator.
Null() is used as a return value, if something went wrong. It must
neither be incremented or decremented nor dereferenced!
\return An invalid iterator.
*/
_VECTOR_MAP_TEMPLATE_LIST
inline
_VECTOR_MAP_CLASS_NAME::ConstIterator
_VECTOR_MAP_CLASS_NAME::Null() const
{
return ConstIterator(this, fElements.Null());
}
// Find
/*! \brief Returns an iterator referring to the entry with the
specified key.
\param key The key of the entry to be found.
\return An iterator referring to the found entry, or End(), if the
map doesn't contain any entry with the given value.
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::Iterator
_VECTOR_MAP_CLASS_NAME::Find(const Key &key)
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
if (!exists)
return End();
return Iterator(this, fElements.IteratorForIndex(index));
}
// Find
/*! \brief Returns an iterator referring to the entry with the
specified key.
\param key The key of the entry to be found.
\return An iterator referring to the found entry, or End(), if the
map doesn't contain any entry with the given value.
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::ConstIterator
_VECTOR_MAP_CLASS_NAME::Find(const Key &key) const
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
if (!exists)
return End();
return ConstIterator(this, fElements.IteratorForIndex(index));
}
// FindClose
/*! \brief Returns an iterator referring to the entry with a key closest
to the specified one.
If the map contains an entry with the specified key, an iterator
to it is returned. Otherwise \a less indicates whether an iterator to
the entry with an directly smaller or greater key shall be returned.
If \a less is \c true and the first entry in the map has a greater
key than the specified one, End() is returned. Similarly, when \a less
is \c false and the last entry's key is smaller. Find() invoked on an
empty map always returns End().
Note, that the key order used for the set is specified as template
argument to the class. Default is ascending order. Descending order
inverts the meaning of \a less, i.e. if \c true, greater values will
be returned, since they are smaller ones according to the order.
\param value The key of the entry to be found.
\return An iterator referring to the found entry, or End(), if the
map doesn't contain any entry with the given key or a close
one according to \a less.
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::Iterator
_VECTOR_MAP_CLASS_NAME::FindClose(const Key &key, bool less)
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
// If not found, the index _FindInsertionIndex() returns will point to
// an element with a greater value or to End(). So, no special handling
// is needed for !less.
if (exists || !less)
return Iterator(this, fElements.IteratorForIndex(index));
// An element with a smaller value is desired. The previous one (if any)
// will do.
if (index > 0)
return Iterator(this, fElements.IteratorForIndex(index - 1));
return End();
}
// FindClose
/*! \brief Returns an iterator referring to the entry with a key closest
to the specified one.
If the map contains an entry with the specified key, an iterator
to it is returned. Otherwise \a less indicates whether an iterator to
the entry with an directly smaller or greater key shall be returned.
If \a less is \c true and the first entry in the map has a greater
key than the specified one, End() is returned. Similarly, when \a less
is \c false and the last entry's key is smaller. Find() invoked on an
empty map always returns End().
Note, that the key order used for the set is specified as template
argument to the class. Default is ascending order. Descending order
inverts the meaning of \a less, i.e. if \c true, greater values will
be returned, since they are smaller ones according to the order.
\param value The key of the entry to be found.
\return An iterator referring to the found entry, or End(), if the
map doesn't contain any entry with the given key or a close
one according to \a less.
*/
_VECTOR_MAP_TEMPLATE_LIST
_VECTOR_MAP_CLASS_NAME::ConstIterator
_VECTOR_MAP_CLASS_NAME::FindClose(const Key &key, bool less) const
{
bool exists = false;
int32 index = _FindInsertionIndex(key, exists);
// If not found, the index _FindInsertionIndex() returns will point to
// an element with a greater value or to End(). So, no special handling
// is needed for !less.
if (exists || !less)
return ConstIterator(this, fElements.IteratorForIndex(index));
// An element with a smaller value is desired. The previous one (if any)
// will do.
if (index > 0)
return ConstIterator(this, fElements.IteratorForIndex(index - 1));
return End();
}
// _FindInsertionIndex
/*! \brief Finds the index at which the entry with the supplied key is
located or at which it would need to be inserted.
\param key The key.
\param exists Is set to \c true, if the map does already contain an
entry with that key, to \c false otherwise.
\return The index at which the entry with the supplied key is
located or at which it would need to be inserted.
*/
_VECTOR_MAP_TEMPLATE_LIST
int32
_VECTOR_MAP_CLASS_NAME::_FindInsertionIndex(const Key &key,
bool &exists) const
{
// binary search
int32 lower = 0;
int32 upper = Count();
while (lower < upper) {
int32 mid = (lower + upper) / 2;
int cmp = fEntryStrategy.Compare(fEntryStrategy.GetKey(fElements[mid]),
key);
if (cmp < 0)
lower = mid + 1;
else
upper = mid;
}
exists = (lower < Count() && fEntryStrategy.Compare(key,
fEntryStrategy.GetKey(fElements[lower])) == 0);
return lower;
}
// entry strategies
namespace VectorMapEntryStrategy {
// Pair
template<typename Key, typename Value, typename KeyOrder>
class Pair {
public:
typedef const Key &KeyReference;
class Entry {
public:
Entry(const Key &key, const Value &value)
: key(key), value(value) {}
Key key;
Value value;
};
inline KeyReference GetKey(const Entry &entry) const
{
return entry.key;
}
inline const Value &GetValue(const Entry &entry) const
{
return entry.value;
}
inline Value &GetValue(Entry &entry) const
{
return entry.value;
}
inline Entry MakeEntry(const Key &key, const Value &value) const
{
return Entry(key, value);
}
inline bool AreCompatible(const Key &, const Value &) const
{
return true;
}
inline int Compare(const Key &a, const Key &b) const
{
return fCompare(a, b);
}
private:
KeyOrder fCompare;
};
// ImplicitKey
template<typename Key, typename Value, typename _GetKey, typename KeyOrder>
class ImplicitKey {
public:
typedef Key KeyReference;
typedef Value Entry;
inline KeyReference GetKey(const Entry &entry) const
{
return fGetKey(entry);
}
inline const Value &GetValue(const Entry &entry) const
{
return entry;
}
inline Value &GetValue(Entry &entry) const
{
return entry;
}
inline Entry MakeEntry(const Key &, const Value &value) const
{
return value;
}
inline bool AreCompatible(const Key &key, const Value &value) const
{
return (fGetKey(value) == key);
}
inline int Compare(const Key &a, const Key &b) const
{
return fCompare(a, b);
}
private:
KeyOrder fCompare;
_GetKey fGetKey;
};
} // VectorMapEntryStrategy
#endif // _VECTOR_MAP_H