Move most headers containing generic template classes out of kernel/util.
This follows on the move of BitUtils. Many of these headers were already used in userspace. Fixes #19849.
This commit is contained in:
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_UTIL_ATOMICS_HASH_TABLE_H
|
||||
#define _KERNEL_UTIL_ATOMICS_HASH_TABLE_H
|
||||
|
||||
|
||||
#include <util/OpenHashTable.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
|
||||
// AtomicsHashTable extends BOpenHashTable with some atomic operations.
|
||||
|
||||
template<typename Definition, bool AutoExpand = true,
|
||||
bool CheckDuplicates = false>
|
||||
class AtomicsHashTable : public BOpenHashTable<Definition,
|
||||
AutoExpand, CheckDuplicates> {
|
||||
public:
|
||||
typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
|
||||
|
||||
typedef typename Definition::KeyType KeyType;
|
||||
typedef typename Definition::ValueType ValueType;
|
||||
|
||||
AtomicsHashTable()
|
||||
: HashTable() {}
|
||||
|
||||
AtomicsHashTable(const Definition& definition)
|
||||
: HashTable(definition) {}
|
||||
|
||||
/*! \brief Inserts a value atomically.
|
||||
|
||||
If there's another item with an identical key, the new value will not
|
||||
be inserted, and that value will be returned instead. If there's no
|
||||
other value with the same key, the passed value will be inserted,
|
||||
and NULL will be returned.
|
||||
|
||||
The caller is responsible for ensuring that no Remove()s or Resize()s
|
||||
are invoked concurrently with this method.
|
||||
*/
|
||||
ValueType* InsertAtomic(ValueType* value)
|
||||
{
|
||||
KeyType key = HashTable::fDefinition.Key(value);
|
||||
size_t index = HashTable::fDefinition.Hash(value) & (HashTable::fTableSize - 1);
|
||||
HashTable::_Link(value) = NULL;
|
||||
|
||||
ValueType** link = &HashTable::fTable[index];
|
||||
while (true) {
|
||||
ValueType* existing = atomic_pointer_get(link);
|
||||
if (existing == NULL) {
|
||||
existing = atomic_pointer_test_and_set(link, value, existing);
|
||||
if (existing == NULL) {
|
||||
size_t& count = HashTable::fItemCount;
|
||||
sizeof(size_t) == 4 ?
|
||||
atomic_add((int32*)&count, 1) :
|
||||
atomic_add64((int64*)&count, 1);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (HashTable::fDefinition.Compare(key, existing))
|
||||
return existing;
|
||||
|
||||
link = &HashTable::_Link(existing);
|
||||
}
|
||||
}
|
||||
|
||||
bool ResizeIfNeeded()
|
||||
{
|
||||
size_t resizeNeeded = HashTable::ResizeNeeded();
|
||||
if (resizeNeeded == 0)
|
||||
return true;
|
||||
|
||||
return HashTable::_Resize(resizeNeeded);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // _KERNEL_UTIL_ATOMICS_HASH_TABLE_H
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _BUMP_ALLOCATOR_H
|
||||
#define _BUMP_ALLOCATOR_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
template<size_t InlineDataSize = (16 * sizeof(void*)), size_t SlabSize = 4096>
|
||||
class BumpAllocator {
|
||||
public:
|
||||
BumpAllocator()
|
||||
:
|
||||
fCurrentSlab((Slab*)fInlineData)
|
||||
{
|
||||
fCurrentSlab->previous = NULL;
|
||||
fCurrentSlab->total = sizeof(fInlineData) - sizeof(Slab);
|
||||
fCurrentSlab->remaining = fCurrentSlab->total;
|
||||
}
|
||||
|
||||
~BumpAllocator()
|
||||
{
|
||||
if (fCurrentSlab != (Slab*)fInlineData)
|
||||
Free(NULL);
|
||||
|
||||
if (!IsEmpty())
|
||||
debugger("BumpAllocator: deleted with allocations still active!");
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return fCurrentSlab == (Slab*)fInlineData
|
||||
&& fCurrentSlab->remaining == fCurrentSlab->total;
|
||||
}
|
||||
|
||||
void* Allocate(size_t _size)
|
||||
{
|
||||
const size_t size = _size + sizeof(Allocation);
|
||||
if (size > SlabSize)
|
||||
debugger("BumpAllocator: can't allocate larger than the slab size");
|
||||
if (fCurrentSlab->remaining < size) {
|
||||
// We need a new slab.
|
||||
Slab* newSlab = (Slab*)malloc(SlabSize);
|
||||
if (newSlab == NULL)
|
||||
return NULL;
|
||||
|
||||
newSlab->previous = fCurrentSlab;
|
||||
newSlab->total = SlabSize - sizeof(Slab);
|
||||
newSlab->remaining = newSlab->total;
|
||||
fCurrentSlab = newSlab;
|
||||
}
|
||||
|
||||
fCurrentSlab->remaining -= size;
|
||||
uint8* pointer = fCurrentSlab->data + fCurrentSlab->remaining;
|
||||
|
||||
Allocation* allocation = (Allocation*)pointer;
|
||||
allocation->size = size;
|
||||
return allocation->data;
|
||||
}
|
||||
|
||||
void Free(void* _pointer)
|
||||
{
|
||||
if (fCurrentSlab->remaining == fCurrentSlab->total) {
|
||||
// Free the current slab.
|
||||
Slab* previous = fCurrentSlab->previous;
|
||||
free(fCurrentSlab);
|
||||
fCurrentSlab = previous;
|
||||
}
|
||||
if (_pointer == NULL)
|
||||
return;
|
||||
|
||||
Allocation* allocation = (((Allocation*)_pointer) - 1);
|
||||
|
||||
// This needs to be the last thing allocated.
|
||||
uint8* last = fCurrentSlab->data + fCurrentSlab->remaining;
|
||||
if ((uint8*)allocation != last) {
|
||||
debugger("BumpAllocator: out-of-order free");
|
||||
return;
|
||||
}
|
||||
|
||||
fCurrentSlab->remaining += allocation->size;
|
||||
}
|
||||
|
||||
private:
|
||||
#if __cplusplus >= 201103L
|
||||
# define FLA_SIZE
|
||||
#else
|
||||
# define FLA_SIZE 0
|
||||
#endif
|
||||
struct Slab {
|
||||
Slab* previous;
|
||||
uint32 total;
|
||||
uint32 remaining;
|
||||
uint8 data[FLA_SIZE];
|
||||
};
|
||||
struct Allocation {
|
||||
uint32 size; /*!< includes sizeof(Allocation) */
|
||||
uint32 _pad;
|
||||
uint8 data[FLA_SIZE];
|
||||
#undef FLA_SIZE
|
||||
};
|
||||
Slab* fCurrentSlab;
|
||||
uint8 fInlineData[InlineDataSize - sizeof(Slab*)];
|
||||
};
|
||||
|
||||
#endif /* _BUMP_ALLOCATOR_H */
|
||||
@@ -1,681 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005-2009, Ingo Weinhold, [email protected].
|
||||
* Copyright 2006-2009, Axel Dörfler, [email protected].
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef KERNEL_UTIL_DOUBLY_LINKED_LIST_H
|
||||
#define KERNEL_UTIL_DOUBLY_LINKED_LIST_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
# include <debug.h>
|
||||
# include <util/kernel_cpp.h>
|
||||
|
||||
# if !defined(_BOOT_MODE) && KDEBUG
|
||||
# define DEBUG_DOUBLY_LINKED_LIST KDEBUG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// DoublyLinkedListLink
|
||||
template<typename Element>
|
||||
class DoublyLinkedListLink {
|
||||
public:
|
||||
Element* next;
|
||||
Element* previous;
|
||||
};
|
||||
|
||||
// DoublyLinkedListLinkImpl
|
||||
template<typename Element>
|
||||
class DoublyLinkedListLinkImpl {
|
||||
private:
|
||||
typedef DoublyLinkedListLink<Element> DLL_Link;
|
||||
|
||||
public:
|
||||
DLL_Link* GetDoublyLinkedListLink()
|
||||
{ return &fDoublyLinkedListLink; }
|
||||
const DLL_Link* GetDoublyLinkedListLink() const
|
||||
{ return &fDoublyLinkedListLink; }
|
||||
|
||||
private:
|
||||
DLL_Link fDoublyLinkedListLink;
|
||||
};
|
||||
|
||||
// DoublyLinkedListStandardGetLink
|
||||
template<typename Element>
|
||||
class DoublyLinkedListStandardGetLink {
|
||||
private:
|
||||
typedef DoublyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
inline Link* operator()(Element* element) const
|
||||
{
|
||||
return element->GetDoublyLinkedListLink();
|
||||
}
|
||||
|
||||
inline const Link* operator()(const Element* element) const
|
||||
{
|
||||
return element->GetDoublyLinkedListLink();
|
||||
}
|
||||
};
|
||||
|
||||
// DoublyLinkedListMemberGetLink
|
||||
template<typename Element,
|
||||
DoublyLinkedListLink<Element> Element::* LinkMember = &Element::fLink>
|
||||
class DoublyLinkedListMemberGetLink {
|
||||
private:
|
||||
typedef DoublyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
inline Link* operator()(Element* element) const
|
||||
{
|
||||
return &(element->*LinkMember);
|
||||
}
|
||||
|
||||
inline const Link* operator()(const Element* element) const
|
||||
{
|
||||
return &(element->*LinkMember);
|
||||
}
|
||||
};
|
||||
|
||||
// DoublyLinkedListCLink - interface to struct list
|
||||
template<typename Element>
|
||||
class DoublyLinkedListCLink {
|
||||
private:
|
||||
typedef DoublyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
inline Link* operator()(Element* element) const
|
||||
{
|
||||
return (Link*)&element->link;
|
||||
}
|
||||
|
||||
inline const Link* operator()(const Element* element) const
|
||||
{
|
||||
return (const Link*)&element->link;
|
||||
}
|
||||
};
|
||||
|
||||
// for convenience
|
||||
#define DOUBLY_LINKED_LIST_TEMPLATE_LIST \
|
||||
template<typename Element, typename GetLink>
|
||||
#define DOUBLY_LINKED_LIST_CLASS_NAME DoublyLinkedList<Element, GetLink>
|
||||
|
||||
// DoublyLinkedList
|
||||
template<typename Element,
|
||||
typename GetLink = DoublyLinkedListStandardGetLink<Element> >
|
||||
class DoublyLinkedList {
|
||||
private:
|
||||
typedef DoublyLinkedList<Element, GetLink> List;
|
||||
typedef DoublyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(List* list)
|
||||
:
|
||||
fList(list)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Iterator()
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(const Iterator &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element* Next()
|
||||
{
|
||||
fCurrent = fNext;
|
||||
if (fNext)
|
||||
fNext = fList->GetNext(fNext);
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Element* Current()
|
||||
{
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Element* Remove()
|
||||
{
|
||||
Element* element = fCurrent;
|
||||
if (fCurrent) {
|
||||
fList->Remove(fCurrent);
|
||||
fCurrent = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
Iterator &operator=(const Iterator& other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fCurrent = other.fCurrent;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fCurrent = NULL;
|
||||
fNext = fList->First();
|
||||
}
|
||||
|
||||
private:
|
||||
List* fList;
|
||||
Element* fCurrent;
|
||||
Element* fNext;
|
||||
};
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator(const List* list)
|
||||
:
|
||||
fList(list)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
ConstIterator(const ConstIterator& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element* Next()
|
||||
{
|
||||
Element* element = fNext;
|
||||
if (fNext)
|
||||
fNext = fList->GetNext(fNext);
|
||||
return element;
|
||||
}
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fNext = fList->First();
|
||||
}
|
||||
|
||||
private:
|
||||
const List* fList;
|
||||
Element* fNext;
|
||||
};
|
||||
|
||||
class ReverseIterator {
|
||||
public:
|
||||
ReverseIterator(List* list)
|
||||
:
|
||||
fList(list)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
ReverseIterator(const ReverseIterator& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element* Next()
|
||||
{
|
||||
fCurrent = fNext;
|
||||
if (fNext)
|
||||
fNext = fList->GetPrevious(fNext);
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Element* Remove()
|
||||
{
|
||||
Element* element = fCurrent;
|
||||
if (fCurrent) {
|
||||
fList->Remove(fCurrent);
|
||||
fCurrent = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
ReverseIterator &operator=(const ReverseIterator& other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fCurrent = other.fCurrent;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fCurrent = NULL;
|
||||
fNext = fList->Last();
|
||||
}
|
||||
|
||||
private:
|
||||
List* fList;
|
||||
Element* fCurrent;
|
||||
Element* fNext;
|
||||
};
|
||||
|
||||
class ConstReverseIterator {
|
||||
public:
|
||||
ConstReverseIterator(const List* list)
|
||||
:
|
||||
fList(list)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
ConstReverseIterator(const ConstReverseIterator& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element* Next()
|
||||
{
|
||||
Element* element = fNext;
|
||||
if (fNext)
|
||||
fNext = fList->GetPrevious(fNext);
|
||||
return element;
|
||||
}
|
||||
|
||||
ConstReverseIterator& operator=(const ConstReverseIterator& other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fNext = fList->Last();
|
||||
}
|
||||
|
||||
private:
|
||||
const List* fList;
|
||||
Element* fNext;
|
||||
};
|
||||
|
||||
public:
|
||||
DoublyLinkedList() : fFirst(NULL), fLast(NULL) {}
|
||||
~DoublyLinkedList() {}
|
||||
|
||||
inline bool IsEmpty() const { return (fFirst == NULL); }
|
||||
|
||||
inline void InsertBefore(Element* insertBefore, Element* element);
|
||||
inline void InsertAfter(Element* insertAfter, Element* element);
|
||||
inline void Insert(Element* element, bool back = true);
|
||||
inline void Add(Element* element, bool back = true);
|
||||
inline void Remove(Element* element);
|
||||
|
||||
inline void Swap(Element* a, Element* b);
|
||||
|
||||
inline void TakeFrom(DOUBLY_LINKED_LIST_CLASS_NAME* fromList);
|
||||
|
||||
inline void RemoveAll();
|
||||
inline void MakeEmpty() { RemoveAll(); }
|
||||
|
||||
inline Element* First() const { return fFirst; }
|
||||
inline Element* Last() const { return fLast; }
|
||||
|
||||
inline Element* Head() const { return fFirst; }
|
||||
inline Element* Tail() const { return fLast; }
|
||||
|
||||
inline Element* RemoveHead();
|
||||
inline Element* RemoveTail();
|
||||
|
||||
static inline Element* GetPrevious(Element* element);
|
||||
static inline Element* GetNext(Element* element);
|
||||
|
||||
inline bool Contains(Element* element) const;
|
||||
// O(n)!
|
||||
|
||||
inline int32 Count() const;
|
||||
// O(n)!
|
||||
|
||||
template<typename Less>
|
||||
void Sort(const Less& less);
|
||||
// O(n^2)
|
||||
|
||||
inline Iterator GetIterator() { return Iterator(this); }
|
||||
inline ConstIterator GetIterator() const { return ConstIterator(this); }
|
||||
|
||||
inline ReverseIterator GetReverseIterator()
|
||||
{ return ReverseIterator(this); }
|
||||
inline ConstReverseIterator GetReverseIterator() const
|
||||
{ return ConstReverseIterator(this); }
|
||||
|
||||
private:
|
||||
inline void Insert(Element* before, Element* element);
|
||||
// TODO: Obsolete! Use InsertBefore() instead!
|
||||
|
||||
private:
|
||||
Element* fFirst;
|
||||
Element* fLast;
|
||||
|
||||
static GetLink sGetLink;
|
||||
};
|
||||
|
||||
|
||||
// inline methods
|
||||
|
||||
// Insert
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Insert(Element* element, bool back)
|
||||
{
|
||||
if (element) {
|
||||
#if DEBUG_DOUBLY_LINKED_LIST
|
||||
ASSERT_PRINT(fFirst == NULL ? fLast == NULL : fLast != NULL,
|
||||
"list: %p\n", this);
|
||||
#endif
|
||||
|
||||
Link* elLink = sGetLink(element);
|
||||
if (back) {
|
||||
// append
|
||||
elLink->previous = fLast;
|
||||
elLink->next = NULL;
|
||||
if (fLast)
|
||||
sGetLink(fLast)->next = element;
|
||||
else
|
||||
fFirst = element;
|
||||
fLast = element;
|
||||
} else {
|
||||
// prepend
|
||||
elLink->previous = NULL;
|
||||
elLink->next = fFirst;
|
||||
if (fFirst)
|
||||
sGetLink(fFirst)->previous = element;
|
||||
else
|
||||
fLast = element;
|
||||
fFirst = element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::InsertBefore(Element* before, Element* element)
|
||||
{
|
||||
ASSERT(element != NULL);
|
||||
|
||||
if (before == NULL) {
|
||||
Insert(element);
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_DOUBLY_LINKED_LIST
|
||||
ASSERT_PRINT(fFirst == NULL ? fLast == NULL : fLast != NULL,
|
||||
"list: %p\n", this);
|
||||
#endif
|
||||
|
||||
Link* beforeLink = sGetLink(before);
|
||||
Link* link = sGetLink(element);
|
||||
|
||||
link->next = before;
|
||||
link->previous = beforeLink->previous;
|
||||
beforeLink->previous = element;
|
||||
|
||||
if (link->previous != NULL)
|
||||
sGetLink(link->previous)->next = element;
|
||||
else
|
||||
fFirst = element;
|
||||
}
|
||||
|
||||
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::InsertAfter(Element* after, Element* element)
|
||||
{
|
||||
ASSERT(element != NULL);
|
||||
|
||||
if (after == NULL) {
|
||||
Insert(element, false);
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_DOUBLY_LINKED_LIST
|
||||
ASSERT_PRINT(fFirst == NULL ? fLast == NULL : fLast != NULL,
|
||||
"list: %p\n", this);
|
||||
#endif
|
||||
|
||||
Link* afterLink = sGetLink(after);
|
||||
Link* link = sGetLink(element);
|
||||
|
||||
link->previous = after;
|
||||
link->next = afterLink->next;
|
||||
afterLink->next = element;
|
||||
|
||||
if (link->next != NULL)
|
||||
sGetLink(link->next)->previous = element;
|
||||
else
|
||||
fLast = element;
|
||||
}
|
||||
|
||||
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Insert(Element* before, Element* element)
|
||||
{
|
||||
InsertBefore(before, element);
|
||||
}
|
||||
|
||||
|
||||
// Add
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Add(Element* element, bool back)
|
||||
{
|
||||
Insert(element, back);
|
||||
}
|
||||
|
||||
// Remove
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Remove(Element* element)
|
||||
{
|
||||
if (element == NULL)
|
||||
return;
|
||||
|
||||
#if DEBUG_DOUBLY_LINKED_LIST
|
||||
ASSERT_PRINT(fFirst != NULL && fLast != NULL
|
||||
&& (fFirst != fLast || element == fFirst),
|
||||
"list: %p, element: %p\n", this, element);
|
||||
#endif
|
||||
|
||||
Link* elLink = sGetLink(element);
|
||||
|
||||
if (element == fFirst)
|
||||
fFirst = elLink->next;
|
||||
else
|
||||
sGetLink(elLink->previous)->next = elLink->next;
|
||||
|
||||
if (element == fLast)
|
||||
fLast = elLink->previous;
|
||||
else
|
||||
sGetLink(elLink->next)->previous = elLink->previous;
|
||||
|
||||
elLink->next = elLink->previous = NULL;
|
||||
}
|
||||
|
||||
// Swap
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Swap(Element* a, Element* b)
|
||||
{
|
||||
if (a && b && a != b) {
|
||||
Element* aNext = sGetLink(a)->next;
|
||||
Element* bNext = sGetLink(b)->next;
|
||||
if (a == bNext) {
|
||||
Remove(a);
|
||||
Insert(b, a);
|
||||
} else if (b == aNext) {
|
||||
Remove(b);
|
||||
Insert(a, b);
|
||||
} else {
|
||||
Remove(a);
|
||||
Remove(b);
|
||||
Insert(aNext, b);
|
||||
Insert(bNext, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TakeFrom
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::TakeFrom(DOUBLY_LINKED_LIST_CLASS_NAME* fromList)
|
||||
{
|
||||
if (fromList && fromList->fFirst) {
|
||||
if (fFirst) {
|
||||
sGetLink(fLast)->next = fromList->fFirst;
|
||||
sGetLink(fromList->fFirst)->previous = fLast;
|
||||
fLast = fromList->fLast;
|
||||
} else {
|
||||
fFirst = fromList->fFirst;
|
||||
fLast = fromList->fLast;
|
||||
}
|
||||
fromList->fFirst = NULL;
|
||||
fromList->fLast = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveAll
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::RemoveAll()
|
||||
{
|
||||
fFirst = NULL;
|
||||
fLast = NULL;
|
||||
}
|
||||
|
||||
// RemoveHead
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element*
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::RemoveHead()
|
||||
{
|
||||
Element* element = Head();
|
||||
Remove(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
// RemoveTail
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element*
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::RemoveTail()
|
||||
{
|
||||
Element* element = Tail();
|
||||
Remove(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
// GetPrevious
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element*
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::GetPrevious(Element* element)
|
||||
{
|
||||
Element* result = NULL;
|
||||
if (element)
|
||||
result = sGetLink(element)->previous;
|
||||
return result;
|
||||
}
|
||||
|
||||
// GetNext
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element*
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::GetNext(Element* element)
|
||||
{
|
||||
Element* result = NULL;
|
||||
if (element)
|
||||
result = sGetLink(element)->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
bool
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Contains(Element* _element) const
|
||||
{
|
||||
for (Element* element = First(); element; element = GetNext(element)) {
|
||||
if (element == _element)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Count
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
int32
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Count() const
|
||||
{
|
||||
int32 count = 0;
|
||||
for (Element* element = First(); element; element = GetNext(element))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
template<typename Less>
|
||||
void
|
||||
DOUBLY_LINKED_LIST_CLASS_NAME::Sort(const Less& less)
|
||||
{
|
||||
// selection sort
|
||||
Element* tail = Head();
|
||||
while (tail != NULL) {
|
||||
Element* leastElement = tail;
|
||||
Element* element = tail;
|
||||
while ((element = GetNext(element)) != NULL) {
|
||||
if (less(element, leastElement))
|
||||
leastElement = element;
|
||||
}
|
||||
|
||||
if (leastElement != tail) {
|
||||
Remove(leastElement);
|
||||
InsertBefore(tail, leastElement);
|
||||
} else
|
||||
tail = GetNext(tail);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sGetLink
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
GetLink DOUBLY_LINKED_LIST_CLASS_NAME::sGetLink;
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // _KERNEL_UTIL_DOUBLY_LINKED_LIST_H
|
||||
@@ -1,368 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Copyright 2005-2006, Ingo Weinhold, [email protected]. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef KERNEL_UTIL_DOUBLY_LINKED_QUEUE_H
|
||||
#define KERNEL_UTIL_DOUBLY_LINKED_QUEUE_H
|
||||
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
/*!
|
||||
A doubly linked queue is like a doubly linked list, but only has a pointer
|
||||
to the head of the list, none to its tail.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// for convenience
|
||||
#define DOUBLY_LINKED_QUEUE_CLASS_NAME DoublyLinkedQueue<Element, GetLink>
|
||||
|
||||
|
||||
template<typename Element,
|
||||
typename GetLink = DoublyLinkedListStandardGetLink<Element> >
|
||||
class DoublyLinkedQueue {
|
||||
private:
|
||||
typedef DoublyLinkedQueue<Element, GetLink> Queue;
|
||||
typedef DoublyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(Queue *queue)
|
||||
:
|
||||
fQueue(queue)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Iterator(const Iterator &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element *Next()
|
||||
{
|
||||
fCurrent = fNext;
|
||||
if (fNext)
|
||||
fNext = fQueue->GetNext(fNext);
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Element *Remove()
|
||||
{
|
||||
Element *element = fCurrent;
|
||||
if (fCurrent) {
|
||||
fQueue->Remove(fCurrent);
|
||||
fCurrent = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
Iterator &operator=(const Iterator &other)
|
||||
{
|
||||
fQueue = other.fQueue;
|
||||
fCurrent = other.fCurrent;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fCurrent = NULL;
|
||||
fNext = fQueue->First();
|
||||
}
|
||||
|
||||
private:
|
||||
Queue *fQueue;
|
||||
Element *fCurrent;
|
||||
Element *fNext;
|
||||
};
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator(const Queue *queue)
|
||||
:
|
||||
fQueue(queue)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
ConstIterator(const ConstIterator &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element *Next()
|
||||
{
|
||||
Element *element = fNext;
|
||||
if (fNext)
|
||||
fNext = fQueue->GetNext(fNext);
|
||||
return element;
|
||||
}
|
||||
|
||||
ConstIterator &operator=(const ConstIterator &other)
|
||||
{
|
||||
fQueue = other.fQueue;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fNext = fQueue->First();
|
||||
}
|
||||
|
||||
private:
|
||||
const Queue *fQueue;
|
||||
Element *fNext;
|
||||
};
|
||||
|
||||
public:
|
||||
DoublyLinkedQueue() : fFirst(NULL) {}
|
||||
~DoublyLinkedQueue() {}
|
||||
|
||||
inline bool IsEmpty() const { return (fFirst == NULL); }
|
||||
|
||||
inline void Insert(Element *element);
|
||||
inline void InsertBefore(Element *before, Element *element);
|
||||
inline void Add(Element *element);
|
||||
inline void Remove(Element *element);
|
||||
|
||||
inline void Swap(Element *a, Element *b);
|
||||
|
||||
inline void TakeFrom(DOUBLY_LINKED_QUEUE_CLASS_NAME *fromList);
|
||||
|
||||
inline void RemoveAll();
|
||||
inline void MakeEmpty() { RemoveAll(); }
|
||||
|
||||
inline Element *First() const { return fFirst; }
|
||||
inline Element *Head() const { return fFirst; }
|
||||
|
||||
inline Element *RemoveHead();
|
||||
|
||||
inline Element *GetPrevious(Element *element) const;
|
||||
inline Element *GetNext(Element *element) const;
|
||||
|
||||
inline int32 Size() const;
|
||||
// O(n)!
|
||||
|
||||
inline Iterator GetIterator() { return Iterator(this); }
|
||||
inline ConstIterator GetIterator() const { return ConstIterator(this); }
|
||||
|
||||
private:
|
||||
Element *fFirst;
|
||||
|
||||
static GetLink sGetLink;
|
||||
};
|
||||
|
||||
|
||||
// inline methods
|
||||
|
||||
// Insert
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::Insert(Element *element)
|
||||
{
|
||||
if (element) {
|
||||
Link *elLink = sGetLink(element);
|
||||
elLink->previous = NULL;
|
||||
elLink->next = fFirst;
|
||||
if (fFirst)
|
||||
sGetLink(fFirst)->previous = element;
|
||||
fFirst = element;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::InsertBefore(Element *before, Element *element)
|
||||
{
|
||||
if (before == NULL) {
|
||||
Insert(element);
|
||||
return;
|
||||
}
|
||||
if (element == NULL)
|
||||
return;
|
||||
|
||||
Link *beforeLink = sGetLink(before);
|
||||
Link *link = sGetLink(element);
|
||||
|
||||
link->next = before;
|
||||
link->previous = beforeLink->previous;
|
||||
if (link->previous != NULL)
|
||||
sGetLink(link->previous)->next = element;
|
||||
beforeLink->previous = element;
|
||||
|
||||
if (fFirst == before)
|
||||
fFirst = element;
|
||||
}
|
||||
|
||||
// Add
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::Add(Element *element)
|
||||
{
|
||||
Insert(element);
|
||||
}
|
||||
|
||||
// Remove
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::Remove(Element *element)
|
||||
{
|
||||
if (element == NULL)
|
||||
return;
|
||||
|
||||
#if DEBUG_DOUBLY_LINKED_LIST
|
||||
ASSERT_PRINT(fFirst != NULL,
|
||||
"queue: %p, element: %p\n", this, element);
|
||||
#endif
|
||||
|
||||
Link *elLink = sGetLink(element);
|
||||
if (element == fFirst)
|
||||
fFirst = elLink->next;
|
||||
else
|
||||
sGetLink(elLink->previous)->next = elLink->next;
|
||||
|
||||
if (elLink->next)
|
||||
sGetLink(elLink->next)->previous = elLink->previous;
|
||||
|
||||
elLink->next = elLink->previous = NULL;
|
||||
}
|
||||
|
||||
// Swap
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::Swap(Element *a, Element *b)
|
||||
{
|
||||
if (a && b && a != b) {
|
||||
Link *aLink = sGetLink(a);
|
||||
Link *bLink = sGetLink(b);
|
||||
Element *aPrev = aLink->previous;
|
||||
Element *bPrev = bLink->previous;
|
||||
Element *aNext = aLink->next;
|
||||
Element *bNext = bLink->next;
|
||||
// place a
|
||||
if (bPrev)
|
||||
sGetLink(bPrev)->next = a;
|
||||
else
|
||||
fFirst = a;
|
||||
if (bNext)
|
||||
sGetLink(bNext)->previous = a;
|
||||
|
||||
aLink->previous = bPrev;
|
||||
aLink->next = bNext;
|
||||
// place b
|
||||
if (aPrev)
|
||||
sGetLink(aPrev)->next = b;
|
||||
else
|
||||
fFirst = b;
|
||||
if (aNext)
|
||||
sGetLink(aNext)->previous = b;
|
||||
|
||||
bLink->previous = aPrev;
|
||||
bLink->next = aNext;
|
||||
}
|
||||
}
|
||||
|
||||
// TakeFrom
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::TakeFrom(DOUBLY_LINKED_QUEUE_CLASS_NAME *fromList)
|
||||
{
|
||||
if (fromList && fromList->fFirst) {
|
||||
if (fFirst) {
|
||||
Element *element = fFirst;
|
||||
Link *elLink;
|
||||
while ((elLink = sGetLink(element))->next) {
|
||||
element = elLink->next;
|
||||
}
|
||||
elLink->next = fromList->fFirst;
|
||||
} else {
|
||||
fFirst = fromList->fFirst;
|
||||
}
|
||||
fromList->fFirst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveAll
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::RemoveAll()
|
||||
{
|
||||
Element *element = fFirst;
|
||||
while (element) {
|
||||
Link *elLink = sGetLink(element);
|
||||
element = elLink->next;
|
||||
elLink->previous = NULL;
|
||||
elLink->next = NULL;
|
||||
}
|
||||
fFirst = NULL;
|
||||
}
|
||||
|
||||
// RemoveHead
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element *
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::RemoveHead()
|
||||
{
|
||||
Element *element = Head();
|
||||
Remove(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
// GetPrevious
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element *
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::GetPrevious(Element *element) const
|
||||
{
|
||||
Element *result = NULL;
|
||||
if (element)
|
||||
result = sGetLink(element)->previous;
|
||||
return result;
|
||||
}
|
||||
|
||||
// GetNext
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element *
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::GetNext(Element *element) const
|
||||
{
|
||||
Element *result = NULL;
|
||||
if (element)
|
||||
result = sGetLink(element)->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Size
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
int32
|
||||
DOUBLY_LINKED_QUEUE_CLASS_NAME::Size() const
|
||||
{
|
||||
int32 count = 0;
|
||||
for (Element* element = First(); element; element = GetNext(element))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// sGetLink
|
||||
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
||||
GetLink DOUBLY_LINKED_QUEUE_CLASS_NAME::sGetLink;
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // _KERNEL_UTIL_DOUBLY_LINKED_QUEUE_H
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Hugo Santos, [email protected]
|
||||
*/
|
||||
#ifndef _KERNEL_UTIL_MULTI_HASH_TABLE_H
|
||||
#define _KERNEL_UTIL_MULTI_HASH_TABLE_H
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
|
||||
// MultiHashTable is a container which acts a bit like multimap<>
|
||||
// but with hash table semantics.
|
||||
|
||||
// refer to OpenHashTable.h for how to use this container.
|
||||
|
||||
template<typename Definition, bool AutoExpand = true,
|
||||
bool CheckDuplicates = false>
|
||||
class MultiHashTable : private BOpenHashTable<Definition,
|
||||
AutoExpand, CheckDuplicates> {
|
||||
public:
|
||||
typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
|
||||
typedef MultiHashTable<Definition, AutoExpand, CheckDuplicates> MultiTable;
|
||||
|
||||
typedef typename HashTable::Iterator Iterator;
|
||||
typedef typename Definition::KeyType KeyType;
|
||||
typedef typename Definition::ValueType ValueType;
|
||||
|
||||
MultiHashTable()
|
||||
: HashTable() {}
|
||||
|
||||
MultiHashTable(const Definition& definition)
|
||||
: HashTable(definition) {}
|
||||
|
||||
status_t Init(size_t initialSize = HashTable::kMinimumSize)
|
||||
{
|
||||
return HashTable::Init(initialSize);
|
||||
}
|
||||
|
||||
void Insert(ValueType *value)
|
||||
{
|
||||
if (AutoExpand
|
||||
&& HashTable::fItemCount >= (HashTable::fTableSize * 200 / 256))
|
||||
_Resize(HashTable::fTableSize * 2);
|
||||
|
||||
InsertUnchecked(value);
|
||||
}
|
||||
|
||||
void InsertUnchecked(ValueType *value)
|
||||
{
|
||||
_Insert(HashTable::fTable, HashTable::fTableSize, value);
|
||||
HashTable::fItemCount++;
|
||||
}
|
||||
|
||||
bool Remove(ValueType *value)
|
||||
{
|
||||
if (!HashTable::RemoveUnchecked(value))
|
||||
return false;
|
||||
|
||||
if (AutoExpand && HashTable::fTableSize > HashTable::kMinimumSize
|
||||
&& HashTable::fItemCount < (HashTable::fTableSize * 50 / 256))
|
||||
_Resize(HashTable::fTableSize / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Iterator GetIterator() const { return HashTable::GetIterator(); }
|
||||
|
||||
class ValueIterator : protected Iterator {
|
||||
public:
|
||||
ValueIterator(const HashTable *table, size_t index, ValueType *value)
|
||||
: fOriginalIndex(index), fOriginalValue(value)
|
||||
{
|
||||
Iterator::fTable = table;
|
||||
Rewind();
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
if (Iterator::fNext == NULL)
|
||||
return false;
|
||||
if (Iterator::fNext == fOriginalValue)
|
||||
return true;
|
||||
return ((const MultiTable *)Iterator::fTable)->_Definition().CompareValues(
|
||||
fOriginalValue, Iterator::fNext);
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
Iterator::fIndex = fOriginalIndex + 1;
|
||||
Iterator::fNext = fOriginalValue;
|
||||
}
|
||||
|
||||
ValueType *Next() { return Iterator::Next(); }
|
||||
|
||||
private:
|
||||
size_t fOriginalIndex;
|
||||
ValueType *fOriginalValue;
|
||||
};
|
||||
|
||||
ValueIterator Lookup(const KeyType &key) const
|
||||
{
|
||||
size_t index = 0;
|
||||
ValueType *slot = NULL;
|
||||
if (HashTable::fTableSize > 0) {
|
||||
index = HashTable::fDefinition.HashKey(key)
|
||||
& (HashTable::fTableSize - 1);
|
||||
slot = HashTable::fTable[index];
|
||||
}
|
||||
|
||||
while (slot) {
|
||||
if (HashTable::fDefinition.Compare(key, slot))
|
||||
break;
|
||||
slot = HashTable::_Link(slot);
|
||||
}
|
||||
|
||||
if (slot == NULL)
|
||||
return ValueIterator(this, HashTable::fTableSize, NULL);
|
||||
|
||||
return ValueIterator(this, index, slot);
|
||||
}
|
||||
|
||||
private:
|
||||
// for g++ 2.95
|
||||
friend class ValueIterator;
|
||||
|
||||
const Definition &_Definition() const { return HashTable::fDefinition; }
|
||||
|
||||
void _Insert(ValueType **table, size_t tableSize, ValueType *value)
|
||||
{
|
||||
size_t index = HashTable::fDefinition.Hash(value) & (tableSize - 1);
|
||||
|
||||
ValueType *previous;
|
||||
|
||||
// group values with the same key
|
||||
for (previous = table[index]; previous
|
||||
&& !HashTable::fDefinition.CompareValues(previous, value);
|
||||
previous = HashTable::_Link(previous));
|
||||
|
||||
if (previous) {
|
||||
HashTable::_Link(value) = HashTable::_Link(previous);
|
||||
HashTable::_Link(previous) = value;
|
||||
} else {
|
||||
HashTable::_Link(value) = table[index];
|
||||
table[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use BOpenHashTable's _Resize
|
||||
bool _Resize(size_t newSize)
|
||||
{
|
||||
ValueType **newTable = new ValueType *[newSize];
|
||||
if (newTable == NULL)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < newSize; i++)
|
||||
newTable[i] = NULL;
|
||||
|
||||
if (HashTable::fTable) {
|
||||
for (size_t i = 0; i < HashTable::fTableSize; i++) {
|
||||
ValueType *bucket = HashTable::fTable[i];
|
||||
while (bucket) {
|
||||
ValueType *next = HashTable::_Link(bucket);
|
||||
_Insert(newTable, newSize, bucket);
|
||||
bucket = next;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] HashTable::fTable;
|
||||
}
|
||||
|
||||
HashTable::fTableSize = newSize;
|
||||
HashTable::fTable = newTable;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _KERNEL_UTIL_MULTI_HASH_TABLE_H
|
||||
@@ -1,497 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_UTIL_OPEN_HASH_TABLE_H
|
||||
#define _KERNEL_UTIL_OPEN_HASH_TABLE_H
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
# include <KernelExport.h>
|
||||
# include <util/kernel_cpp.h>
|
||||
# include <util/TypeOperation.h>
|
||||
#else
|
||||
# include <new>
|
||||
# include <TypeOperation.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
The Definition template must have four methods: `HashKey', `Hash',
|
||||
`Compare' and `GetLink;. It must also define several types as shown in the
|
||||
following example:
|
||||
|
||||
struct Foo {
|
||||
int bar;
|
||||
|
||||
Foo* fNext;
|
||||
};
|
||||
|
||||
struct HashTableDefinition {
|
||||
typedef int KeyType;
|
||||
typedef Foo ValueType;
|
||||
|
||||
size_t HashKey(KeyType key) const
|
||||
{
|
||||
return key >> 1;
|
||||
}
|
||||
|
||||
size_t Hash(ValueType* value) const
|
||||
{
|
||||
return HashKey(value->bar);
|
||||
}
|
||||
|
||||
bool Compare(KeyType key, ValueType* value) const
|
||||
{
|
||||
return value->bar == key;
|
||||
}
|
||||
|
||||
ValueType*& GetLink(ValueType* value) const
|
||||
{
|
||||
return value->fNext;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
struct MallocAllocator {
|
||||
void* Allocate(size_t size) const
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void Free(void* memory) const
|
||||
{
|
||||
free(memory);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Implements an hash table with open hashing, that is, colliding entries are
|
||||
* stored in a linked list. The table may be made to adjust its number of slots
|
||||
* depending on the load factor (this should be enabled unless the object is to
|
||||
* be used at times where memory allocations aren't possible, such as code
|
||||
* called by the memory allocator).
|
||||
*
|
||||
* The link between entries is part of the ValueType stored items, which makes
|
||||
* sure the table can always accept new items and will never fail because it is
|
||||
* out of memory (except at Init time).
|
||||
*/
|
||||
template<typename Definition, bool AutoExpand = true,
|
||||
bool CheckDuplicates = false, typename Allocator = MallocAllocator>
|
||||
class BOpenHashTable {
|
||||
public:
|
||||
typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
|
||||
typedef typename Definition::KeyType KeyType;
|
||||
typedef typename Definition::ValueType ValueType;
|
||||
|
||||
static const size_t kMinimumSize = 8;
|
||||
|
||||
// All allocations are of power of 2 lengths.
|
||||
|
||||
// regrowth factor: 200 / 256 = 78.125%
|
||||
// 50 / 256 = 19.53125%
|
||||
|
||||
BOpenHashTable()
|
||||
:
|
||||
fTableSize(0),
|
||||
fItemCount(0),
|
||||
fTable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BOpenHashTable(const Definition& definition)
|
||||
:
|
||||
fDefinition(definition),
|
||||
fTableSize(0),
|
||||
fItemCount(0),
|
||||
fTable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BOpenHashTable(const Definition& definition, const Allocator& allocator)
|
||||
:
|
||||
fDefinition(definition),
|
||||
fAllocator(allocator),
|
||||
fTableSize(0),
|
||||
fItemCount(0),
|
||||
fTable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~BOpenHashTable()
|
||||
{
|
||||
fAllocator.Free(fTable);
|
||||
}
|
||||
|
||||
status_t Init(size_t initialSize = kMinimumSize)
|
||||
{
|
||||
if (initialSize > 0 && !_Resize(initialSize))
|
||||
return B_NO_MEMORY;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
size_t TableSize() const
|
||||
{
|
||||
return fTableSize;
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return fItemCount == 0;
|
||||
}
|
||||
|
||||
size_t CountElements() const
|
||||
{
|
||||
return fItemCount;
|
||||
}
|
||||
|
||||
ValueType* Lookup(typename TypeOperation<KeyType>::ConstRefT key) const
|
||||
{
|
||||
if (fTableSize == 0)
|
||||
return NULL;
|
||||
|
||||
size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
|
||||
ValueType* slot = fTable[index];
|
||||
|
||||
while (slot) {
|
||||
if (fDefinition.Compare(key, slot))
|
||||
break;
|
||||
slot = _Link(slot);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
status_t Insert(ValueType* value)
|
||||
{
|
||||
if (fTableSize == 0) {
|
||||
if (!_Resize(kMinimumSize))
|
||||
return B_NO_MEMORY;
|
||||
} else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256))
|
||||
_Resize(fTableSize * 2);
|
||||
|
||||
InsertUnchecked(value);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*! \brief Inserts a value without resizing the table.
|
||||
|
||||
Use this method if you need to insert a value into the table while
|
||||
iterating it, as regular insertion can invalidate iterators.
|
||||
*/
|
||||
void InsertUnchecked(ValueType* value)
|
||||
{
|
||||
if (CheckDuplicates && _ExhaustiveSearch(value)) {
|
||||
#ifdef _KERNEL_MODE
|
||||
panic("Hash Table: value already in table.");
|
||||
#else
|
||||
debugger("Hash Table: value already in table.");
|
||||
#endif
|
||||
}
|
||||
|
||||
_Insert(fTable, fTableSize, value);
|
||||
fItemCount++;
|
||||
}
|
||||
|
||||
// TODO: a ValueType* Remove(const KeyType& key) method is missing
|
||||
|
||||
bool Remove(ValueType* value)
|
||||
{
|
||||
if (!RemoveUnchecked(value))
|
||||
return false;
|
||||
|
||||
if (AutoExpand && fTableSize > kMinimumSize
|
||||
&& fItemCount < (fTableSize * 50 / 256))
|
||||
_Resize(fTableSize / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Removes a value without resizing the table.
|
||||
|
||||
Use this method if you need to remove a value from the table while
|
||||
iterating it, as Remove can invalidate iterators.
|
||||
|
||||
Also use this method if you know you are going to reinsert the item soon
|
||||
(possibly with a different hash) to avoid shrinking then growing the
|
||||
table again.
|
||||
*/
|
||||
bool RemoveUnchecked(ValueType* value)
|
||||
{
|
||||
size_t index = fDefinition.Hash(value) & (fTableSize - 1);
|
||||
ValueType* previous = NULL;
|
||||
ValueType* slot = fTable[index];
|
||||
|
||||
while (slot) {
|
||||
ValueType* next = _Link(slot);
|
||||
|
||||
if (value == slot) {
|
||||
if (previous)
|
||||
_Link(previous) = next;
|
||||
else
|
||||
fTable[index] = next;
|
||||
break;
|
||||
}
|
||||
|
||||
previous = slot;
|
||||
slot = next;
|
||||
}
|
||||
|
||||
if (slot == NULL)
|
||||
return false;
|
||||
|
||||
if (CheckDuplicates && _ExhaustiveSearch(value)) {
|
||||
#ifdef _KERNEL_MODE
|
||||
panic("Hash Table: duplicate detected.");
|
||||
#else
|
||||
debugger("Hash Table: duplicate detected.");
|
||||
#endif
|
||||
}
|
||||
|
||||
fItemCount--;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Removes all elements from the hash table.
|
||||
|
||||
No resizing happens. The elements are not deleted. If \a returnElements
|
||||
is \c true, the method returns all elements chained via their hash table
|
||||
link.
|
||||
*/
|
||||
ValueType* Clear(bool returnElements = false)
|
||||
{
|
||||
if (fItemCount == 0)
|
||||
return NULL;
|
||||
|
||||
ValueType* result = NULL;
|
||||
|
||||
if (returnElements) {
|
||||
ValueType** nextPointer = &result;
|
||||
|
||||
// iterate through all buckets
|
||||
for (size_t i = 0; i < fTableSize; i++) {
|
||||
ValueType* element = fTable[i];
|
||||
if (element != NULL) {
|
||||
// add the bucket to the list
|
||||
*nextPointer = element;
|
||||
|
||||
// update nextPointer to point to the fNext of the last
|
||||
// element in the bucket
|
||||
while (element != NULL) {
|
||||
nextPointer = &_Link(element);
|
||||
element = *nextPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize);
|
||||
fItemCount = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*! If the table needs resizing, the number of bytes for the required
|
||||
allocation is returned. If no resizing is needed, 0 is returned.
|
||||
*/
|
||||
size_t ResizeNeeded() const
|
||||
{
|
||||
size_t size = fTableSize;
|
||||
if (size == 0 || fItemCount >= (size * 200 / 256)) {
|
||||
// grow table
|
||||
if (size == 0)
|
||||
size = kMinimumSize;
|
||||
while (fItemCount >= size * 200 / 256)
|
||||
size <<= 1;
|
||||
} else if (size > kMinimumSize && fItemCount < size * 50 / 256) {
|
||||
// shrink table
|
||||
while (fItemCount < size * 50 / 256)
|
||||
size >>= 1;
|
||||
if (size < kMinimumSize)
|
||||
size = kMinimumSize;
|
||||
}
|
||||
|
||||
if (size == fTableSize)
|
||||
return 0;
|
||||
|
||||
return size * sizeof(ValueType*);
|
||||
}
|
||||
|
||||
/*! Resizes the table using the given allocation. The allocation must not
|
||||
be \c NULL. It must be of size \a size, which must be a value returned
|
||||
earlier by ResizeNeeded(). If the size requirements have changed in the
|
||||
meantime, the method free()s the given allocation and returns \c false,
|
||||
unless \a force is \c true, in which case the supplied allocation is
|
||||
used in any event.
|
||||
Otherwise \c true is returned.
|
||||
If \a oldTable is non-null and resizing is successful, the old table
|
||||
will not be freed, but will be returned via this parameter instead.
|
||||
*/
|
||||
bool Resize(void* allocation, size_t size, bool force = false,
|
||||
void** oldTable = NULL)
|
||||
{
|
||||
if (!force && size != ResizeNeeded()) {
|
||||
fAllocator.Free(allocation);
|
||||
return false;
|
||||
}
|
||||
|
||||
_Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Iterator for BOpenHashTable
|
||||
|
||||
The iterator is not invalidated when removing the current element from
|
||||
the table, unless the removal triggers a resize.
|
||||
*/
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const HashTable* table)
|
||||
: fTable(table)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Iterator(const HashTable* table, size_t index, ValueType* value)
|
||||
: fTable(table), fIndex(index), fNext(value) {}
|
||||
|
||||
bool HasNext() const { return fNext != NULL; }
|
||||
|
||||
ValueType* Next()
|
||||
{
|
||||
ValueType* current = fNext;
|
||||
_GetNext();
|
||||
return current;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
// get the first one
|
||||
fIndex = 0;
|
||||
fNext = NULL;
|
||||
_GetNext();
|
||||
}
|
||||
|
||||
protected:
|
||||
Iterator() {}
|
||||
|
||||
void _GetNext()
|
||||
{
|
||||
if (fNext)
|
||||
fNext = fTable->_Link(fNext);
|
||||
|
||||
while (fNext == NULL && fIndex < fTable->fTableSize)
|
||||
fNext = fTable->fTable[fIndex++];
|
||||
}
|
||||
|
||||
const HashTable* fTable;
|
||||
size_t fIndex;
|
||||
ValueType* fNext;
|
||||
};
|
||||
|
||||
Iterator GetIterator() const
|
||||
{
|
||||
return Iterator(this);
|
||||
}
|
||||
|
||||
Iterator GetIterator(typename TypeOperation<KeyType>::ConstRefT key) const
|
||||
{
|
||||
if (fTableSize == 0)
|
||||
return Iterator(this, fTableSize, NULL);
|
||||
|
||||
size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
|
||||
ValueType* slot = fTable[index];
|
||||
|
||||
while (slot) {
|
||||
if (fDefinition.Compare(key, slot))
|
||||
break;
|
||||
slot = _Link(slot);
|
||||
}
|
||||
|
||||
if (slot == NULL)
|
||||
return Iterator(this, fTableSize, NULL);
|
||||
|
||||
return Iterator(this, index + 1, slot);
|
||||
}
|
||||
|
||||
protected:
|
||||
// for g++ 2.95
|
||||
friend class Iterator;
|
||||
|
||||
void _Insert(ValueType** table, size_t tableSize, ValueType* value)
|
||||
{
|
||||
size_t index = fDefinition.Hash(value) & (tableSize - 1);
|
||||
|
||||
_Link(value) = table[index];
|
||||
table[index] = value;
|
||||
}
|
||||
|
||||
bool _Resize(size_t newSize)
|
||||
{
|
||||
ValueType** newTable
|
||||
= (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize);
|
||||
if (newTable == NULL)
|
||||
return false;
|
||||
|
||||
_Resize(newTable, newSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL)
|
||||
{
|
||||
for (size_t i = 0; i < newSize; i++)
|
||||
newTable[i] = NULL;
|
||||
|
||||
if (fTable) {
|
||||
for (size_t i = 0; i < fTableSize; i++) {
|
||||
ValueType* bucket = fTable[i];
|
||||
while (bucket) {
|
||||
ValueType* next = _Link(bucket);
|
||||
_Insert(newTable, newSize, bucket);
|
||||
bucket = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (_oldTable != NULL)
|
||||
*_oldTable = fTable;
|
||||
else
|
||||
fAllocator.Free(fTable);
|
||||
} else if (_oldTable != NULL)
|
||||
*_oldTable = NULL;
|
||||
|
||||
fTableSize = newSize;
|
||||
fTable = newTable;
|
||||
}
|
||||
|
||||
ValueType*& _Link(ValueType* bucket) const
|
||||
{
|
||||
return fDefinition.GetLink(bucket);
|
||||
}
|
||||
|
||||
bool _ExhaustiveSearch(ValueType* value) const
|
||||
{
|
||||
for (size_t i = 0; i < fTableSize; i++) {
|
||||
ValueType* bucket = fTable[i];
|
||||
while (bucket) {
|
||||
if (bucket == value)
|
||||
return true;
|
||||
bucket = _Link(bucket);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Definition fDefinition;
|
||||
Allocator fAllocator;
|
||||
size_t fTableSize;
|
||||
size_t fItemCount;
|
||||
ValueType** fTable;
|
||||
};
|
||||
|
||||
#endif // _KERNEL_UTIL_OPEN_HASH_TABLE_H
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2013, Axel Dörfler, [email protected].
|
||||
* Copyright 2005-2013, Ingo Weinhold, [email protected].
|
||||
* Copyright 2025, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SIMPLE_ALLOCATOR_H
|
||||
#define _SIMPLE_ALLOCATOR_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <util/SplayTree.h>
|
||||
|
||||
|
||||
/*! This is a very simple malloc()/free() implementation - it only
|
||||
manages a free list using a splay tree.
|
||||
|
||||
After heap_init() is called, all free memory is contained in one
|
||||
big chunk, the only entry in the free chunk tree.
|
||||
|
||||
When memory is allocated, the smallest free chunk that contains
|
||||
the requested size is split (or taken as a whole if it can't be
|
||||
splitted anymore), and its lower half will be removed from the
|
||||
free list.
|
||||
|
||||
The free list is ordered by size, starting with the smallest
|
||||
free chunk available. When a chunk is freed, it will be joined
|
||||
with its predecessor or successor, if possible.
|
||||
*/
|
||||
|
||||
template<uint32 Alignment = 8>
|
||||
class SimpleAllocator {
|
||||
class Chunk {
|
||||
public:
|
||||
size_t CompleteSize() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
protected:
|
||||
union {
|
||||
uint32 fSize;
|
||||
char fAlignment[Alignment];
|
||||
};
|
||||
};
|
||||
|
||||
class FreeChunk;
|
||||
|
||||
struct FreeChunkData : SplayTreeLink<FreeChunk> {
|
||||
|
||||
FreeChunk* Next() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
FreeChunk** NextLink()
|
||||
{
|
||||
return &fNext;
|
||||
}
|
||||
|
||||
protected:
|
||||
FreeChunk* fNext;
|
||||
};
|
||||
|
||||
class FreeChunk : public Chunk, public FreeChunkData {
|
||||
public:
|
||||
void SetTo(size_t size)
|
||||
{
|
||||
Chunk::fSize = size;
|
||||
FreeChunkData::fNext = NULL;
|
||||
}
|
||||
|
||||
/*! Returns the amount of bytes that can be allocated
|
||||
in this chunk.
|
||||
*/
|
||||
size_t Size() const
|
||||
{
|
||||
return (addr_t)this + Chunk::fSize - (addr_t)AllocatedAddress();
|
||||
}
|
||||
|
||||
/*! Splits the upper half at the requested location and returns it. This chunk
|
||||
will no longer be a valid FreeChunk object; only its fSize will be valid.
|
||||
*/
|
||||
FreeChunk* Split(size_t splitSize)
|
||||
{
|
||||
splitSize = Align(splitSize);
|
||||
|
||||
FreeChunk* chunk = (FreeChunk*)((addr_t)AllocatedAddress() + splitSize);
|
||||
size_t newSize = (addr_t)chunk - (addr_t)this;
|
||||
chunk->fSize = Chunk::fSize - newSize;
|
||||
chunk->fNext = NULL;
|
||||
|
||||
Chunk::fSize = newSize;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/*! Checks if the specified chunk touches this chunk, so
|
||||
that they could be joined.
|
||||
*/
|
||||
bool IsTouching(FreeChunk* chunk)
|
||||
{
|
||||
return chunk
|
||||
&& (((uint8*)this + Chunk::fSize == (uint8*)chunk)
|
||||
|| (uint8*)chunk + chunk->fSize == (uint8*)this);
|
||||
}
|
||||
|
||||
/*! Joins the chunk to this chunk and returns the pointer
|
||||
to the new chunk - which will either be one of the
|
||||
two chunks.
|
||||
Note, the chunks must be joinable, or else this method
|
||||
doesn't work correctly. Use FreeChunk::IsTouching()
|
||||
to check if this method can be applied.
|
||||
*/
|
||||
FreeChunk* Join(FreeChunk* chunk)
|
||||
{
|
||||
if (chunk < this) {
|
||||
chunk->fSize += Chunk::fSize;
|
||||
chunk->fNext = FreeChunkData::fNext;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
Chunk::fSize += chunk->fSize;
|
||||
FreeChunkData::fNext = chunk->fNext;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void* AllocatedAddress() const
|
||||
{
|
||||
return (void*)static_cast<const FreeChunkData*>(this);
|
||||
}
|
||||
|
||||
static FreeChunk* SetToAllocated(void* allocated)
|
||||
{
|
||||
return static_cast<FreeChunk*>((FreeChunkData*)allocated);
|
||||
}
|
||||
};
|
||||
|
||||
struct FreeChunkKey {
|
||||
FreeChunkKey(size_t size)
|
||||
:
|
||||
fSize(size),
|
||||
fChunk(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
FreeChunkKey(const FreeChunk* chunk)
|
||||
:
|
||||
fSize(chunk->Size()),
|
||||
fChunk(chunk)
|
||||
{
|
||||
}
|
||||
|
||||
int Compare(const FreeChunk* chunk) const
|
||||
{
|
||||
size_t chunkSize = chunk->Size();
|
||||
if (chunkSize != fSize)
|
||||
return fSize < chunkSize ? -1 : 1;
|
||||
|
||||
if (fChunk == chunk)
|
||||
return 0;
|
||||
return fChunk < chunk ? -1 : 1;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t fSize;
|
||||
const FreeChunk* fChunk;
|
||||
};
|
||||
|
||||
struct FreeChunkTreeDefinition {
|
||||
typedef FreeChunkKey KeyType;
|
||||
typedef FreeChunk NodeType;
|
||||
|
||||
static FreeChunkKey GetKey(const FreeChunk* node)
|
||||
{
|
||||
return FreeChunkKey(node);
|
||||
}
|
||||
|
||||
static SplayTreeLink<FreeChunk>* GetLink(FreeChunk* node)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
static int Compare(const FreeChunkKey& key, const FreeChunk* node)
|
||||
{
|
||||
return key.Compare(node);
|
||||
}
|
||||
|
||||
static FreeChunk** GetListLink(FreeChunk* node)
|
||||
{
|
||||
return node->NextLink();
|
||||
}
|
||||
};
|
||||
typedef IteratableSplayTree<FreeChunkTreeDefinition> FreeChunkTree;
|
||||
|
||||
public:
|
||||
static inline size_t Align(size_t size, size_t alignment = Alignment)
|
||||
{
|
||||
return (size + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
public:
|
||||
SimpleAllocator()
|
||||
:
|
||||
fAvailable(0)
|
||||
{
|
||||
#ifdef DEBUG_MAX_HEAP_USAGE
|
||||
fMaxHeapSize = fMaxHeapUsage = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
~SimpleAllocator()
|
||||
{
|
||||
// Releasing memory is the caller's responsibility.
|
||||
}
|
||||
|
||||
void AddChunk(void* base, uint32 size)
|
||||
{
|
||||
FreeChunk* chunk = (FreeChunk*)base;
|
||||
chunk->SetTo(size);
|
||||
#ifdef DEBUG_MAX_HEAP_USAGE
|
||||
fMaxHeapSize += chunk->Size();
|
||||
#endif
|
||||
_InsertChunk(chunk);
|
||||
}
|
||||
|
||||
uint32 Available() const { return fAvailable; }
|
||||
|
||||
void* Allocate(uint32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
// align the size requirement to an Alignment bytes boundary
|
||||
if (size < sizeof(FreeChunkData))
|
||||
size = sizeof(FreeChunkData);
|
||||
size = Align(size);
|
||||
|
||||
if (size > fAvailable)
|
||||
return NULL;
|
||||
|
||||
FreeChunk* chunk = fFreeChunkTree.FindClosest(FreeChunkKey(size), true, true);
|
||||
if (chunk == NULL) {
|
||||
// could not find a free chunk as large as needed
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fFreeChunkTree.Remove(chunk);
|
||||
fAvailable -= chunk->Size();
|
||||
|
||||
void* allocated = chunk->AllocatedAddress();
|
||||
|
||||
// If this chunk is bigger than the requested size and there's enough space
|
||||
// left over for a new chunk, we split it.
|
||||
if (chunk->Size() >= (size + Align(sizeof(FreeChunk)))) {
|
||||
FreeChunk* freeChunk = chunk->Split(size);
|
||||
fFreeChunkTree.Insert(freeChunk);
|
||||
fAvailable += freeChunk->Size();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MAX_HEAP_USAGE
|
||||
fMaxHeapUsage = std::max(fMaxHeapUsage, fMaxHeapSize - fAvailable);
|
||||
#endif
|
||||
#ifdef DEBUG_ALLOCATIONS
|
||||
memset(allocated, 0xcc, chunk->Size());
|
||||
#endif
|
||||
|
||||
return allocated;
|
||||
}
|
||||
|
||||
uint32 UsableSize(void* allocated)
|
||||
{
|
||||
FreeChunk* chunk = FreeChunk::SetToAllocated(allocated);
|
||||
return chunk->Size();
|
||||
}
|
||||
|
||||
void* Reallocate(void* oldBuffer, uint32 newSize)
|
||||
{
|
||||
size_t oldSize = 0;
|
||||
if (oldBuffer != NULL) {
|
||||
oldSize = UsableSize(oldBuffer);
|
||||
|
||||
// Check if the old buffer still fits, and if it makes sense to keep it.
|
||||
if (oldSize >= newSize && (oldSize < 128 || newSize > (oldSize / 3)))
|
||||
return oldBuffer;
|
||||
}
|
||||
|
||||
void* newBuffer = Allocate(newSize);
|
||||
if (newBuffer == NULL)
|
||||
return NULL;
|
||||
|
||||
if (oldBuffer != NULL) {
|
||||
memcpy(newBuffer, oldBuffer, (oldSize < newSize) ? oldSize : newSize);
|
||||
Free(oldBuffer);
|
||||
}
|
||||
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
void Free(void* allocated)
|
||||
{
|
||||
if (allocated == NULL)
|
||||
return;
|
||||
|
||||
FreeChunk* freedChunk = FreeChunk::SetToAllocated(allocated);
|
||||
|
||||
#ifdef DEBUG_VALIDATE_HEAP_ON_FREE
|
||||
if (freedChunk->Size() > (fMaxHeapSize - fAvailable)) {
|
||||
panic("freed chunk %p clobbered (%#zx)!\n", freedChunk,
|
||||
freedChunk->Size());
|
||||
}
|
||||
{
|
||||
FreeChunk* chunk = fFreeChunkTree.FindMin();
|
||||
while (chunk) {
|
||||
if (chunk->Size() > fAvailable || freedChunk == chunk)
|
||||
panic("invalid chunk in free list (%p (%zu)), or double free\n",
|
||||
chunk, chunk->Size());
|
||||
chunk = chunk->Next();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG_ALLOCATIONS
|
||||
for (uint32 i = 0; i < (freedChunk->Size() / 4); i++)
|
||||
((uint32*)allocated)[i] = 0xdeadbeef;
|
||||
#endif
|
||||
|
||||
_InsertChunk(freedChunk);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MAX_HEAP_USAGE
|
||||
uint32 MaxHeapSize() const { return fMaxHeapSize; }
|
||||
uint32 MaxHeapUsage() const { return fMaxHeapUsage; }
|
||||
#endif
|
||||
|
||||
void DumpChunks()
|
||||
{
|
||||
FreeChunk* chunk = fFreeChunkTree.FindMin();
|
||||
while (chunk != NULL) {
|
||||
printf("\t%p: chunk size = %ld, end = %p, next = %p\n", chunk,
|
||||
chunk->Size(), (uint8*)chunk + chunk->CompleteSize(),
|
||||
chunk->Next());
|
||||
chunk = chunk->Next();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void _InsertChunk(FreeChunk* freedChunk)
|
||||
{
|
||||
// try to join the new free chunk with an existing one
|
||||
// it may be joined with up to two chunks
|
||||
|
||||
FreeChunk* chunk = fFreeChunkTree.FindMin();
|
||||
int32 joinCount = 0;
|
||||
|
||||
while (chunk != NULL) {
|
||||
FreeChunk* nextChunk = chunk->Next();
|
||||
|
||||
if (chunk->IsTouching(freedChunk)) {
|
||||
fFreeChunkTree.Remove(chunk);
|
||||
fAvailable -= chunk->Size();
|
||||
|
||||
freedChunk = chunk->Join(freedChunk);
|
||||
|
||||
if (++joinCount == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
chunk = nextChunk;
|
||||
}
|
||||
|
||||
fFreeChunkTree.Insert(freedChunk);
|
||||
fAvailable += freedChunk->Size();
|
||||
#ifdef DEBUG_MAX_HEAP_USAGE
|
||||
fMaxHeapUsage = std::max(fMaxHeapUsage, fMaxHeapSize - fAvailable);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
FreeChunkTree fFreeChunkTree;
|
||||
uint32 fAvailable;
|
||||
#ifdef DEBUG_MAX_HEAP_USAGE
|
||||
uint32 fMaxHeapSize, fMaxHeapUsage;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif /* _SIMPLE_ALLOCATOR_H */
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Copyright 2005-2010, Ingo Weinhold, [email protected].
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef KERNEL_UTIL_SINGLY_LINKED_LIST_H
|
||||
#define KERNEL_UTIL_SINGLY_LINKED_LIST_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// SinglyLinkedListLink
|
||||
template<typename Element>
|
||||
class SinglyLinkedListLink {
|
||||
public:
|
||||
SinglyLinkedListLink() : next(NULL) {}
|
||||
~SinglyLinkedListLink() {}
|
||||
|
||||
Element* next;
|
||||
};
|
||||
|
||||
// SinglyLinkedListLinkImpl
|
||||
template<typename Element>
|
||||
class SinglyLinkedListLinkImpl {
|
||||
private:
|
||||
typedef SinglyLinkedListLink<Element> SLL_Link;
|
||||
|
||||
public:
|
||||
SinglyLinkedListLinkImpl() : fSinglyLinkedListLink() {}
|
||||
~SinglyLinkedListLinkImpl() {}
|
||||
|
||||
SLL_Link* GetSinglyLinkedListLink()
|
||||
{ return &fSinglyLinkedListLink; }
|
||||
const SLL_Link* GetSinglyLinkedListLink() const
|
||||
{ return &fSinglyLinkedListLink; }
|
||||
|
||||
private:
|
||||
SLL_Link fSinglyLinkedListLink;
|
||||
};
|
||||
|
||||
// SinglyLinkedListStandardGetLink
|
||||
template<typename Element>
|
||||
class SinglyLinkedListStandardGetLink {
|
||||
private:
|
||||
typedef SinglyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
inline Link* operator()(Element* element) const
|
||||
{
|
||||
return element->GetSinglyLinkedListLink();
|
||||
}
|
||||
|
||||
inline const Link* operator()(const Element* element) const
|
||||
{
|
||||
return element->GetSinglyLinkedListLink();
|
||||
}
|
||||
};
|
||||
|
||||
// SinglyLinkedListMemberGetLink
|
||||
template<typename Element,
|
||||
SinglyLinkedListLink<Element> Element::* LinkMember = &Element::fLink>
|
||||
class SinglyLinkedListMemberGetLink {
|
||||
private:
|
||||
typedef SinglyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
inline Link* operator()(Element* element) const
|
||||
{
|
||||
return &(element->*LinkMember);
|
||||
}
|
||||
|
||||
inline const Link* operator()(const Element* element) const
|
||||
{
|
||||
return &(element->*LinkMember);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// for convenience
|
||||
#define SINGLY_LINKED_LIST_TEMPLATE_LIST \
|
||||
template<typename Element, typename GetLink>
|
||||
#define SINGLY_LINKED_LIST_CLASS_NAME SinglyLinkedList<Element, GetLink>
|
||||
|
||||
|
||||
template<typename Element,
|
||||
typename GetLink = SinglyLinkedListStandardGetLink<Element> >
|
||||
class SinglyLinkedList {
|
||||
private:
|
||||
typedef SinglyLinkedList<Element, GetLink> List;
|
||||
typedef SinglyLinkedListLink<Element> Link;
|
||||
|
||||
public:
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator(const List* list)
|
||||
:
|
||||
fList(list)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
ConstIterator(const ConstIterator& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext;
|
||||
}
|
||||
|
||||
Element* Next()
|
||||
{
|
||||
Element* element = fNext;
|
||||
if (fNext)
|
||||
fNext = fList->GetNext(fNext);
|
||||
return element;
|
||||
}
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& other)
|
||||
{
|
||||
fList = other.fList;
|
||||
fNext = other.fNext;
|
||||
return* this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fNext = fList->First();
|
||||
}
|
||||
|
||||
private:
|
||||
const List* fList;
|
||||
Element* fNext;
|
||||
};
|
||||
|
||||
public:
|
||||
SinglyLinkedList() : fFirst(NULL) {}
|
||||
~SinglyLinkedList() {}
|
||||
|
||||
inline bool IsEmpty() const { return (fFirst == NULL); }
|
||||
|
||||
inline void Add(Element* element);
|
||||
inline bool Remove(Element* element);
|
||||
inline void Remove(Element* previous, Element* element);
|
||||
|
||||
inline void TakeFrom(SINGLY_LINKED_LIST_CLASS_NAME* fromList);
|
||||
// O(1) if either list is empty, otherwise O(n).
|
||||
|
||||
inline void RemoveAll();
|
||||
inline void MakeEmpty() { RemoveAll(); }
|
||||
|
||||
inline Element* First() const { return fFirst; }
|
||||
inline Element* Head() const { return fFirst; }
|
||||
|
||||
inline Element* RemoveHead();
|
||||
|
||||
inline Element* GetNext(Element* element) const;
|
||||
|
||||
inline int32 Count() const;
|
||||
// O(n)!
|
||||
|
||||
inline ConstIterator GetIterator() const { return ConstIterator(this); }
|
||||
|
||||
private:
|
||||
Element *fFirst;
|
||||
|
||||
static GetLink sGetLink;
|
||||
};
|
||||
|
||||
|
||||
// inline methods
|
||||
|
||||
// Add
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::Add(Element* element)
|
||||
{
|
||||
if (element != NULL) {
|
||||
sGetLink(element)->next = fFirst;
|
||||
fFirst = element;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Removes \a element from the list.
|
||||
It is safe to call the list with a \c NULL element or an element that isn't
|
||||
in the list.
|
||||
\param element The element to be removed.
|
||||
\return \c true, if the element was in the list and has been removed,
|
||||
\c false otherwise.
|
||||
*/
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
bool
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::Remove(Element* element)
|
||||
{
|
||||
if (element == NULL)
|
||||
return false;
|
||||
|
||||
Element* next = fFirst;
|
||||
Element* last = NULL;
|
||||
while (element != next) {
|
||||
if (next == NULL)
|
||||
return false;
|
||||
last = next;
|
||||
next = sGetLink(next)->next;
|
||||
}
|
||||
|
||||
Link* elementLink = sGetLink(element);
|
||||
if (last == NULL)
|
||||
fFirst = elementLink->next;
|
||||
else
|
||||
sGetLink(last)->next = elementLink->next;
|
||||
|
||||
elementLink->next = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::Remove(Element* previous, Element* element)
|
||||
{
|
||||
// ASSERT(previous == NULL
|
||||
// ? fFirst == element : sGetLink(previous)->next == element);
|
||||
|
||||
Link* elementLink = sGetLink(element);
|
||||
if (previous == NULL)
|
||||
fFirst = elementLink->next;
|
||||
else
|
||||
sGetLink(previous)->next = elementLink->next;
|
||||
|
||||
elementLink->next = NULL;
|
||||
}
|
||||
|
||||
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::TakeFrom(SINGLY_LINKED_LIST_CLASS_NAME* fromList)
|
||||
{
|
||||
if (fromList->fFirst == NULL)
|
||||
return;
|
||||
|
||||
if (fFirst == NULL) {
|
||||
// This list is empty -- just transfer the head.
|
||||
fFirst = fromList->fFirst;
|
||||
fromList->fFirst = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Neither list is empty -- find the tail of this list.
|
||||
Element* tail = fFirst;
|
||||
while (Element* next = sGetLink(tail)->next)
|
||||
tail = next;
|
||||
|
||||
sGetLink(tail)->next = fromList->fFirst;
|
||||
fromList->fFirst = NULL;
|
||||
}
|
||||
|
||||
|
||||
// RemoveAll
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::RemoveAll()
|
||||
{
|
||||
Element* element = fFirst;
|
||||
while (element) {
|
||||
Link* elLink = sGetLink(element);
|
||||
element = elLink->next;
|
||||
elLink->next = NULL;
|
||||
}
|
||||
fFirst = NULL;
|
||||
}
|
||||
|
||||
// RemoveHead
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element*
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::RemoveHead()
|
||||
{
|
||||
Element* element = Head();
|
||||
Remove(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
// GetNext
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
Element*
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::GetNext(Element* element) const
|
||||
{
|
||||
Element* result = NULL;
|
||||
if (element)
|
||||
result = sGetLink(element)->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Size
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
int32
|
||||
SINGLY_LINKED_LIST_CLASS_NAME::Count() const
|
||||
{
|
||||
int32 count = 0;
|
||||
for (Element* element = First(); element; element = GetNext(element))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// sGetLink
|
||||
SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
GetLink SINGLY_LINKED_LIST_CLASS_NAME::sGetLink;
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // _KERNEL_UTIL_SINGLY_LINKED_LIST_H
|
||||
@@ -1,623 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008-2009, Ingo Weinhold <[email protected]>.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Original Java implementation:
|
||||
* Available at http://www.link.cs.cmu.edu/splay/
|
||||
* Author: Danny Sleator <[email protected]>
|
||||
* This code is in the public domain.
|
||||
*/
|
||||
#ifndef KERNEL_UTIL_SPLAY_TREE_H
|
||||
#define KERNEL_UTIL_SPLAY_TREE_H
|
||||
|
||||
/*! Implements two classes:
|
||||
|
||||
SplayTree: A top-down splay tree.
|
||||
|
||||
IteratableSplayTree: Extends SplayTree by a singly-linked list to make it
|
||||
cheaply iteratable (requires another pointer per node).
|
||||
|
||||
Both classes are templatized over a definition parameter with the following
|
||||
(or a compatible) interface:
|
||||
|
||||
struct SplayTreeDefinition {
|
||||
typedef xxx KeyType;
|
||||
typedef yyy NodeType;
|
||||
|
||||
static const KeyType& GetKey(const NodeType* node);
|
||||
static SplayTreeLink<NodeType>* GetLink(NodeType* node);
|
||||
|
||||
static int Compare(const KeyType& key, const NodeType* node);
|
||||
|
||||
// for IteratableSplayTree only
|
||||
static NodeType** GetListLink(NodeType* node);
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
template<typename Node>
|
||||
struct SplayTreeLink {
|
||||
Node* left;
|
||||
Node* right;
|
||||
};
|
||||
|
||||
|
||||
template<typename Definition>
|
||||
class SplayTree {
|
||||
protected:
|
||||
typedef typename Definition::KeyType Key;
|
||||
typedef typename Definition::NodeType Node;
|
||||
typedef SplayTreeLink<Node> Link;
|
||||
|
||||
public:
|
||||
SplayTree()
|
||||
:
|
||||
fRoot(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Insert into the tree.
|
||||
\param node the item to insert.
|
||||
*/
|
||||
bool Insert(Node* node)
|
||||
{
|
||||
Link* nodeLink = Definition::GetLink(node);
|
||||
|
||||
if (fRoot == NULL) {
|
||||
fRoot = node;
|
||||
nodeLink->left = NULL;
|
||||
nodeLink->right = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Key key = Definition::GetKey(node);
|
||||
_Splay(key);
|
||||
|
||||
int c = Definition::Compare(key, fRoot);
|
||||
if (c == 0)
|
||||
return false;
|
||||
|
||||
Link* rootLink = Definition::GetLink(fRoot);
|
||||
|
||||
if (c < 0) {
|
||||
nodeLink->left = rootLink->left;
|
||||
nodeLink->right = fRoot;
|
||||
rootLink->left = NULL;
|
||||
} else {
|
||||
nodeLink->right = rootLink->right;
|
||||
nodeLink->left = fRoot;
|
||||
rootLink->right = NULL;
|
||||
}
|
||||
|
||||
fRoot = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
Node* Remove(const Key& key)
|
||||
{
|
||||
if (fRoot == NULL)
|
||||
return NULL;
|
||||
|
||||
_Splay(key);
|
||||
|
||||
if (Definition::Compare(key, fRoot) != 0)
|
||||
return NULL;
|
||||
|
||||
// Now delete the root
|
||||
Node* node = fRoot;
|
||||
Link* rootLink = Definition::GetLink(fRoot);
|
||||
if (rootLink->left == NULL) {
|
||||
fRoot = rootLink->right;
|
||||
} else {
|
||||
Node* temp = rootLink->right;
|
||||
fRoot = rootLink->left;
|
||||
_Splay(key);
|
||||
Definition::GetLink(fRoot)->right = temp;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*!
|
||||
Remove from the tree.
|
||||
\param node the item to remove.
|
||||
*/
|
||||
bool Remove(Node* node)
|
||||
{
|
||||
Key key = Definition::GetKey(node);
|
||||
_Splay(key);
|
||||
|
||||
if (node != fRoot)
|
||||
return false;
|
||||
|
||||
// Now delete the root
|
||||
Link* rootLink = Definition::GetLink(fRoot);
|
||||
if (rootLink->left == NULL) {
|
||||
fRoot = rootLink->right;
|
||||
} else {
|
||||
Node* temp = rootLink->right;
|
||||
fRoot = rootLink->left;
|
||||
_Splay(key);
|
||||
Definition::GetLink(fRoot)->right = temp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the smallest item in the tree.
|
||||
*/
|
||||
Node* FindMin()
|
||||
{
|
||||
if (fRoot == NULL)
|
||||
return NULL;
|
||||
|
||||
Node* node = fRoot;
|
||||
|
||||
while (Node* left = Definition::GetLink(node)->left)
|
||||
node = left;
|
||||
|
||||
_Splay(Definition::GetKey(node));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the largest item in the tree.
|
||||
*/
|
||||
Node* FindMax()
|
||||
{
|
||||
if (fRoot == NULL)
|
||||
return NULL;
|
||||
|
||||
Node* node = fRoot;
|
||||
|
||||
while (Node* right = Definition::GetLink(node)->right)
|
||||
node = right;
|
||||
|
||||
_Splay(Definition::GetKey(node));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find an item in the tree.
|
||||
*/
|
||||
Node* Lookup(const Key& key)
|
||||
{
|
||||
if (fRoot == NULL)
|
||||
return NULL;
|
||||
|
||||
_Splay(key);
|
||||
|
||||
return Definition::Compare(key, fRoot) == 0 ? fRoot : NULL;
|
||||
}
|
||||
|
||||
Node* Root() const
|
||||
{
|
||||
return fRoot;
|
||||
}
|
||||
|
||||
/*!
|
||||
Test if the tree is logically empty.
|
||||
\return true if empty, false otherwise.
|
||||
*/
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return fRoot == NULL;
|
||||
}
|
||||
|
||||
Node* PreviousDontSplay(const Key& key) const
|
||||
{
|
||||
Node* closestNode = NULL;
|
||||
Node* node = fRoot;
|
||||
while (node != NULL) {
|
||||
if (Definition::Compare(key, node) > 0) {
|
||||
closestNode = node;
|
||||
node = Definition::GetLink(node)->right;
|
||||
} else
|
||||
node = Definition::GetLink(node)->left;
|
||||
}
|
||||
|
||||
return closestNode;
|
||||
}
|
||||
|
||||
Node* FindClosest(const Key& key, bool greater, bool orEqual)
|
||||
{
|
||||
if (fRoot == NULL)
|
||||
return NULL;
|
||||
|
||||
_Splay(key);
|
||||
|
||||
Node* closestNode = NULL;
|
||||
Node* node = fRoot;
|
||||
while (node != NULL) {
|
||||
int compare = Definition::Compare(key, node);
|
||||
if (compare == 0 && orEqual)
|
||||
return node;
|
||||
|
||||
if (greater) {
|
||||
if (compare < 0) {
|
||||
closestNode = node;
|
||||
node = Definition::GetLink(node)->left;
|
||||
} else
|
||||
node = Definition::GetLink(node)->right;
|
||||
} else {
|
||||
if (compare > 0) {
|
||||
closestNode = node;
|
||||
node = Definition::GetLink(node)->right;
|
||||
} else
|
||||
node = Definition::GetLink(node)->left;
|
||||
}
|
||||
}
|
||||
|
||||
return closestNode;
|
||||
}
|
||||
|
||||
SplayTree& operator=(const SplayTree& other)
|
||||
{
|
||||
fRoot = other.fRoot;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
Internal method to perform a top-down splay.
|
||||
|
||||
_Splay(key) does the splay operation on the given key.
|
||||
If key is in the tree, then the node containing
|
||||
that key becomes the root. If key is not in the tree,
|
||||
then after the splay, key.root is either the greatest key
|
||||
< key in the tree, or the least key > key in the tree.
|
||||
|
||||
This means, among other things, that if you splay with
|
||||
a key that's larger than any in the tree, the rightmost
|
||||
node of the tree becomes the root. This property is used
|
||||
in the Remove() method.
|
||||
*/
|
||||
void _Splay(const Key& key) {
|
||||
Link headerLink;
|
||||
headerLink.left = headerLink.right = NULL;
|
||||
|
||||
Link* lLink = &headerLink;
|
||||
Link* rLink = &headerLink;
|
||||
|
||||
Node* l = NULL;
|
||||
Node* r = NULL;
|
||||
Node* t = fRoot;
|
||||
|
||||
for (;;) {
|
||||
int c = Definition::Compare(key, t);
|
||||
if (c < 0) {
|
||||
Node*& left = Definition::GetLink(t)->left;
|
||||
if (left == NULL)
|
||||
break;
|
||||
|
||||
if (Definition::Compare(key, left) < 0) {
|
||||
// rotate right
|
||||
Node* y = left;
|
||||
Link* yLink = Definition::GetLink(y);
|
||||
left = yLink->right;
|
||||
yLink->right = t;
|
||||
t = y;
|
||||
if (yLink->left == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
// link right
|
||||
rLink->left = t;
|
||||
r = t;
|
||||
rLink = Definition::GetLink(r);
|
||||
t = rLink->left;
|
||||
} else if (c > 0) {
|
||||
Node*& right = Definition::GetLink(t)->right;
|
||||
if (right == NULL)
|
||||
break;
|
||||
|
||||
if (Definition::Compare(key, right) > 0) {
|
||||
// rotate left
|
||||
Node* y = right;
|
||||
Link* yLink = Definition::GetLink(y);
|
||||
right = yLink->left;
|
||||
yLink->left = t;
|
||||
t = y;
|
||||
if (yLink->right == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
// link left
|
||||
lLink->right = t;
|
||||
l = t;
|
||||
lLink = Definition::GetLink(l);
|
||||
t = lLink->right;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// assemble
|
||||
Link* tLink = Definition::GetLink(t);
|
||||
lLink->right = tLink->left;
|
||||
rLink->left = tLink->right;
|
||||
tLink->left = headerLink.right;
|
||||
tLink->right = headerLink.left;
|
||||
fRoot = t;
|
||||
}
|
||||
|
||||
protected:
|
||||
Node* fRoot;
|
||||
};
|
||||
|
||||
|
||||
template<typename Definition>
|
||||
class IteratableSplayTree {
|
||||
protected:
|
||||
typedef typename Definition::KeyType Key;
|
||||
typedef typename Definition::NodeType Node;
|
||||
typedef SplayTreeLink<Node> Link;
|
||||
typedef IteratableSplayTree<Definition> Tree;
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator()
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(const Iterator& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Iterator(Tree* tree)
|
||||
:
|
||||
fTree(tree)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Iterator(Tree* tree, Node* next)
|
||||
:
|
||||
fTree(tree),
|
||||
fCurrent(NULL),
|
||||
fNext(next)
|
||||
{
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext != NULL;
|
||||
}
|
||||
|
||||
Node* Next()
|
||||
{
|
||||
fCurrent = fNext;
|
||||
if (fNext != NULL)
|
||||
fNext = *Definition::GetListLink(fNext);
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Node* Current()
|
||||
{
|
||||
return fCurrent;
|
||||
}
|
||||
|
||||
Node* Remove()
|
||||
{
|
||||
Node* element = fCurrent;
|
||||
if (fCurrent) {
|
||||
fTree->Remove(fCurrent);
|
||||
fCurrent = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
Iterator &operator=(const Iterator &other)
|
||||
{
|
||||
fTree = other.fTree;
|
||||
fCurrent = other.fCurrent;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fCurrent = NULL;
|
||||
fNext = fTree->fFirst;
|
||||
}
|
||||
|
||||
private:
|
||||
Tree* fTree;
|
||||
Node* fCurrent;
|
||||
Node* fNext;
|
||||
};
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
ConstIterator()
|
||||
{
|
||||
}
|
||||
|
||||
ConstIterator(const ConstIterator& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
ConstIterator(const Tree* tree)
|
||||
:
|
||||
fTree(tree)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
ConstIterator(const Tree* tree, Node* next)
|
||||
:
|
||||
fTree(tree),
|
||||
fNext(next)
|
||||
{
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return fNext != NULL;
|
||||
}
|
||||
|
||||
Node* Next()
|
||||
{
|
||||
Node* node = fNext;
|
||||
if (fNext != NULL)
|
||||
fNext = *Definition::GetListLink(fNext);
|
||||
return node;
|
||||
}
|
||||
|
||||
ConstIterator &operator=(const ConstIterator &other)
|
||||
{
|
||||
fTree = other.fTree;
|
||||
fNext = other.fNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fNext = fTree->fFirst;
|
||||
}
|
||||
|
||||
private:
|
||||
const Tree* fTree;
|
||||
Node* fNext;
|
||||
};
|
||||
|
||||
IteratableSplayTree()
|
||||
:
|
||||
fTree(),
|
||||
fFirst(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
bool Insert(Node* node)
|
||||
{
|
||||
if (!fTree.Insert(node))
|
||||
return false;
|
||||
|
||||
Node** previousNext;
|
||||
if (Node* previous = fTree.PreviousDontSplay(Definition::GetKey(node)))
|
||||
previousNext = Definition::GetListLink(previous);
|
||||
else
|
||||
previousNext = &fFirst;
|
||||
|
||||
*Definition::GetListLink(node) = *previousNext;
|
||||
*previousNext = node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Node* Remove(const Key& key)
|
||||
{
|
||||
Node* node = fTree.Remove(key);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
Node** previousNext;
|
||||
if (Node* previous = fTree.PreviousDontSplay(key))
|
||||
previousNext = Definition::GetListLink(previous);
|
||||
else
|
||||
previousNext = &fFirst;
|
||||
|
||||
*previousNext = *Definition::GetListLink(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool Remove(Node* node)
|
||||
{
|
||||
if (!fTree.Remove(node))
|
||||
return false;
|
||||
|
||||
Node** previousNext;
|
||||
if (Node* previous = fTree.PreviousDontSplay(Definition::GetKey(node)))
|
||||
previousNext = Definition::GetListLink(previous);
|
||||
else
|
||||
previousNext = &fFirst;
|
||||
|
||||
*previousNext = *Definition::GetListLink(node);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Node* Lookup(const Key& key)
|
||||
{
|
||||
return fTree.Lookup(key);
|
||||
}
|
||||
|
||||
Node* Root() const
|
||||
{
|
||||
return fTree.Root();
|
||||
}
|
||||
|
||||
/*!
|
||||
Test if the tree is logically empty.
|
||||
\return true if empty, false otherwise.
|
||||
*/
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return fTree.IsEmpty();
|
||||
}
|
||||
|
||||
Node* PreviousDontSplay(const Key& key)
|
||||
{
|
||||
return fTree.PreviousDontSplay(key);
|
||||
}
|
||||
|
||||
Node* FindClosest(const Key& key, bool greater, bool orEqual)
|
||||
{
|
||||
return fTree.FindClosest(key, greater, orEqual);
|
||||
}
|
||||
|
||||
Node* FindMin()
|
||||
{
|
||||
return fTree.FindMin();
|
||||
}
|
||||
|
||||
Node* FindMax()
|
||||
{
|
||||
return fTree.FindMax();
|
||||
}
|
||||
|
||||
Iterator GetIterator()
|
||||
{
|
||||
return Iterator(this);
|
||||
}
|
||||
|
||||
ConstIterator GetIterator() const
|
||||
{
|
||||
return ConstIterator(this);
|
||||
}
|
||||
|
||||
Iterator GetIterator(const Key& key, bool greater, bool orEqual)
|
||||
{
|
||||
return Iterator(this, fTree.FindClosest(key, greater, orEqual));
|
||||
}
|
||||
|
||||
ConstIterator GetIterator(const Key& key, bool greater, bool orEqual) const
|
||||
{
|
||||
return ConstIterator(this, FindClosest(key, greater, orEqual));
|
||||
}
|
||||
|
||||
IteratableSplayTree& operator=(const IteratableSplayTree& other)
|
||||
{
|
||||
fTree = other.fTree;
|
||||
fFirst = other.fFirst;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class Iterator;
|
||||
friend class ConstIterator;
|
||||
// needed for gcc 2.95.3 only
|
||||
|
||||
SplayTree<Definition> fTree;
|
||||
Node* fFirst;
|
||||
};
|
||||
|
||||
|
||||
#endif // KERNEL_UTIL_SPLAY_TREE_H
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001-2008, Axel Dörfler, [email protected].
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef KERNEL_UTIL_STACK_H
|
||||
#define KERNEL_UTIL_STACK_H
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
|
||||
template<class T> class Stack {
|
||||
public:
|
||||
Stack()
|
||||
:
|
||||
fArray(NULL),
|
||||
fUsed(0),
|
||||
fMax(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Stack()
|
||||
{
|
||||
free(fArray);
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return fUsed == 0;
|
||||
}
|
||||
|
||||
void MakeEmpty()
|
||||
{
|
||||
// could also free the memory
|
||||
fUsed = 0;
|
||||
}
|
||||
|
||||
status_t Push(T value)
|
||||
{
|
||||
if (fUsed >= fMax) {
|
||||
fMax += 16;
|
||||
T *newArray = (T *)realloc(fArray, fMax * sizeof(T));
|
||||
if (newArray == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fArray = newArray;
|
||||
}
|
||||
fArray[fUsed++] = value;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
bool Pop(T *value)
|
||||
{
|
||||
if (fUsed == 0)
|
||||
return false;
|
||||
|
||||
*value = fArray[--fUsed];
|
||||
return true;
|
||||
}
|
||||
|
||||
T *Array()
|
||||
{
|
||||
return fArray;
|
||||
}
|
||||
|
||||
int32 CountItems() const
|
||||
{
|
||||
return fUsed;
|
||||
}
|
||||
|
||||
private:
|
||||
T *fArray;
|
||||
int32 fUsed;
|
||||
int32 fMax;
|
||||
};
|
||||
|
||||
|
||||
template<typename T> class StackDelete {
|
||||
public:
|
||||
inline void operator()(Stack<T>* stack)
|
||||
{
|
||||
if (stack == NULL)
|
||||
return;
|
||||
|
||||
T item;
|
||||
while (stack->Pop(&item)) {
|
||||
delete item;
|
||||
}
|
||||
|
||||
delete stack;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class StackDeleter
|
||||
: public BPrivate::AutoDeleter<Stack<T>, StackDelete<T> > {
|
||||
public:
|
||||
StackDeleter()
|
||||
{
|
||||
}
|
||||
|
||||
StackDeleter(Stack<T>* stack)
|
||||
: BPrivate::AutoDeleter<Stack<T>, StackDelete<T> >(stack)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* KERNEL_UTIL_STACK_H */
|
||||
Reference in New Issue
Block a user