Beginnings of the kernel utils library.
Templated singly linked list class (not quite complete). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3621 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
34259581cf
commit
e9ebb4a961
483
headers/private/kernel/util/SinglyLinkedList.h
Normal file
483
headers/private/kernel/util/SinglyLinkedList.h
Normal file
@ -0,0 +1,483 @@
|
||||
#ifndef _SINGLY_LINKED_LIST_H_
|
||||
#define _SINGLY_LINKED_LIST_H_
|
||||
|
||||
#include "MallocFreeAllocator.h"
|
||||
#include "SupportDefs.h"
|
||||
|
||||
namespace Strategy {
|
||||
namespace SinglyLinkedList {
|
||||
//! Automatic node strategy (works like STL containers do)
|
||||
template <typename Value, template <class> class Allocator = MallocFreeAllocator>
|
||||
class Auto;
|
||||
|
||||
//! User managed node strategy (user is responsible for node allocation/deallocation)
|
||||
template <class Node, Node* Node::* NextMember = &Node::next>
|
||||
class User;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Value, class Reference, class Pointer, class Parent>
|
||||
class SinglyLinkedListIterator;
|
||||
|
||||
template <class NodeStrategy>
|
||||
class SinglyLinkedList
|
||||
{
|
||||
public:
|
||||
typedef SinglyLinkedList<NodeStrategy> Type;
|
||||
|
||||
typedef typename NodeStrategy::NodeType NodeType;
|
||||
typedef typename NodeStrategy::ValueType ValueType;
|
||||
|
||||
typedef NodeType* NodeType::* NodePointerMember;
|
||||
|
||||
typedef SinglyLinkedListIterator<ValueType, ValueType&, ValueType*, Type> Iterator;
|
||||
typedef SinglyLinkedListIterator<ValueType, const ValueType&, const ValueType*, const Type> ConstIterator;
|
||||
|
||||
SinglyLinkedList()
|
||||
: fFirst(NULL)
|
||||
, fLast(NULL)
|
||||
, fCount(0)
|
||||
{
|
||||
}
|
||||
~SinglyLinkedList();
|
||||
|
||||
ssize_t Count() const;
|
||||
bool IsEmpty() const;
|
||||
void MakeEmpty();
|
||||
|
||||
status_t PushFront(const ValueType &data);
|
||||
status_t PushBack(const ValueType &data);
|
||||
|
||||
void PopFront();
|
||||
|
||||
Iterator Begin();
|
||||
ConstIterator Begin() const;
|
||||
Iterator End();
|
||||
ConstIterator End() const;
|
||||
Iterator Null();
|
||||
ConstIterator Null() const;
|
||||
|
||||
ssize_t Remove(const ValueType &value);
|
||||
Iterator Erase(Iterator &pos);
|
||||
|
||||
protected:
|
||||
friend class Iterator;
|
||||
friend class ConstIterator;
|
||||
|
||||
inline NodeType *Allocate(const ValueType &data) { return fStrategy.Allocate(data); }
|
||||
inline void Free(NodeType *node) { fStrategy.Free(node); }
|
||||
inline ValueType& GetValue(NodeType *node) const { return fStrategy.GetValue(node); }
|
||||
inline NodeType* GetNext(NodeType *node) const { return fStrategy.GetNext(node); }
|
||||
inline NodeType* SetNext(NodeType *node, NodeType* next) const { return fStrategy.SetNext(node, next); }
|
||||
|
||||
NodeStrategy fStrategy;
|
||||
|
||||
NodeType *fFirst;
|
||||
NodeType *fLast;
|
||||
|
||||
ssize_t fCount;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// SinglyLinkedListIterator
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Value, class Reference, class Pointer, class Parent>
|
||||
class SinglyLinkedListIterator {
|
||||
public:
|
||||
typedef SinglyLinkedListIterator<Value, Reference, Pointer, Parent> IteratorType;
|
||||
typedef typename Parent::NodeType NodeType;
|
||||
|
||||
SinglyLinkedListIterator(Parent *parent, NodeType *node, NodeType *previous);
|
||||
|
||||
bool operator==(const IteratorType &ref);
|
||||
bool operator!=(const IteratorType &ref);
|
||||
inline Reference operator*();
|
||||
inline Pointer operator->();
|
||||
IteratorType operator++();
|
||||
IteratorType operator++(int);
|
||||
|
||||
private:
|
||||
Parent *fParent;
|
||||
NodeType *fNode;
|
||||
NodeType *fPrevious;
|
||||
};
|
||||
|
||||
#define _ITERATOR_TEMPLATE_LIST template <class Value, class Reference, class Pointer, class Parent>
|
||||
#define _ITERATOR SinglyLinkedListIterator<Value, Reference, Pointer, Parent>
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
_ITERATOR::SinglyLinkedListIterator(Parent *parent, NodeType *node, NodeType *previous)
|
||||
: fParent(parent)
|
||||
, fNode(node)
|
||||
, fPrevious(previous)
|
||||
{
|
||||
}
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
bool
|
||||
_ITERATOR::operator==(const _ITERATOR &ref) {
|
||||
return fParent == ref.fParent && fNode == ref.fNode && fPrevious == ref.fPrevious;
|
||||
}
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
bool
|
||||
_ITERATOR::operator!=(const _ITERATOR &ref)
|
||||
{
|
||||
return !operator==(ref);
|
||||
}
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
inline
|
||||
Reference
|
||||
_ITERATOR::operator*() {
|
||||
return fParent->GetValue(fNode);
|
||||
}
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
Pointer
|
||||
_ITERATOR::operator->() {
|
||||
return &(operator*());
|
||||
}
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
_ITERATOR
|
||||
_ITERATOR::operator++() {
|
||||
if (fNode) {
|
||||
fPrevious = fNode;
|
||||
fNode = fParent->GetNext(fNode);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_ITERATOR_TEMPLATE_LIST
|
||||
_ITERATOR
|
||||
_ITERATOR::operator++(int) {
|
||||
IteratorType old = *this;
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// SinglyLinkedList implementation
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#define _SINGLY_LINKED_LIST_TEMPLATE_LIST template <class NodeStrategy>
|
||||
#define _SINGLY_LINKED_LIST SinglyLinkedList<NodeStrategy>
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::~SinglyLinkedList()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
ssize_t
|
||||
_SINGLY_LINKED_LIST::Count() const
|
||||
{
|
||||
return fCount;
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
bool
|
||||
_SINGLY_LINKED_LIST::IsEmpty() const
|
||||
{
|
||||
return Count() == 0;
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
_SINGLY_LINKED_LIST::MakeEmpty()
|
||||
{
|
||||
for (NodeType *node = fFirst; node; ) {
|
||||
NodeType* next = GetNext(node);
|
||||
Free(node);
|
||||
node = next;
|
||||
}
|
||||
fFirst = fLast = NULL;
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
status_t
|
||||
_SINGLY_LINKED_LIST::PushFront(const ValueType &data)
|
||||
{
|
||||
status_t err = B_OK;
|
||||
|
||||
if (!fFirst) {
|
||||
fFirst = fLast = Allocate(data);
|
||||
if (fFirst)
|
||||
SetNext(fFirst, NULL);
|
||||
else
|
||||
err = B_NO_MEMORY;
|
||||
} else {
|
||||
NodeType* node = Allocate(data);
|
||||
if (node) {
|
||||
SetNext(node, fFirst);
|
||||
fFirst = node;
|
||||
} else
|
||||
err = B_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
++fCount;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
status_t
|
||||
_SINGLY_LINKED_LIST::PushBack(const ValueType &data)
|
||||
{
|
||||
status_t err = B_OK;
|
||||
|
||||
if (!fLast) {
|
||||
fFirst = fLast = Allocate(data);
|
||||
if (fFirst)
|
||||
SetNext(fFirst, NULL);
|
||||
else
|
||||
err = B_NO_MEMORY;
|
||||
} else {
|
||||
NodeType* node = Allocate(data);
|
||||
if (node) {
|
||||
SetNext(fLast, node);
|
||||
SetNext(node, NULL);
|
||||
fLast = node;
|
||||
} else
|
||||
err = B_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
++fCount;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
void
|
||||
_SINGLY_LINKED_LIST::PopFront()
|
||||
{
|
||||
if (fFirst) {
|
||||
if (fFirst == fLast)
|
||||
fLast = NULL;
|
||||
NodeType* temp = fFirst;
|
||||
fFirst = GetNext(fFirst);
|
||||
Free(temp);
|
||||
--fCount;
|
||||
}
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::Iterator
|
||||
_SINGLY_LINKED_LIST::Begin()
|
||||
{
|
||||
return Iterator(this, fFirst, NULL);
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::ConstIterator
|
||||
_SINGLY_LINKED_LIST::Begin() const
|
||||
{
|
||||
return ConstIterator(this, fFirst, NULL);
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::Iterator
|
||||
_SINGLY_LINKED_LIST::End()
|
||||
{
|
||||
return Iterator(this, NULL, fLast);
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::ConstIterator
|
||||
_SINGLY_LINKED_LIST::End() const
|
||||
{
|
||||
return ConstIterator(this, NULL, fLast);
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::Iterator
|
||||
_SINGLY_LINKED_LIST::Null()
|
||||
{
|
||||
return Iterator(this, NULL, NULL);
|
||||
}
|
||||
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::ConstIterator
|
||||
_SINGLY_LINKED_LIST::Null() const
|
||||
{
|
||||
return ConstIterator(this, NULL, NULL);
|
||||
}
|
||||
|
||||
/*! \brief Removes all elements in the list whose value
|
||||
matches \c value.
|
||||
|
||||
\return The number of elements removed.
|
||||
*/
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
ssize_t
|
||||
_SINGLY_LINKED_LIST::Remove(const ValueType &value)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
for (Iterator i = Begin(); i != End(); ) {
|
||||
if (*i == value) {
|
||||
i = Erase(i);
|
||||
++count;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*! \brief Removes the specified item from the list, returning
|
||||
the item that previously followed \c pos.
|
||||
|
||||
Note that this operation invalidates any previously valid
|
||||
iterators for the given container.
|
||||
|
||||
\return An iterator pointing to the item following \c pos
|
||||
before the removal, or End() if pos is an invalid argument.
|
||||
*/
|
||||
_SINGLY_LINKED_LIST_TEMPLATE_LIST
|
||||
_SINGLY_LINKED_LIST::Iterator
|
||||
_SINGLY_LINKED_LIST::Erase(Iterator &pos)
|
||||
{
|
||||
if (pos.fNode) {
|
||||
if (pos.fNode == fStart) {
|
||||
if (pos.fNode != fLast) {
|
||||
// Strictly first node in the list
|
||||
fFirst = GetNext(pos.fNode);
|
||||
Free(pos.fNode);
|
||||
--fCount;
|
||||
return Begin();
|
||||
} else {
|
||||
// Only node in the list
|
||||
fFist = fLast = NULL;
|
||||
Free(pos.fNode);
|
||||
--fCount;
|
||||
return End();
|
||||
}
|
||||
} else if (pos.fNode == fLast) {
|
||||
// Strictly last node in the list
|
||||
fLast = pos.fPrevious;
|
||||
SetNext(fLast, NULL);
|
||||
Free(pos.fNode);
|
||||
--fCount;
|
||||
return End();
|
||||
} else if (pos.fPrevious) {
|
||||
// Neither first nor last, but at least valid
|
||||
NodeType *next = GetNext(pos.fNode);
|
||||
SetNext(pos.fPrevious, next); // fPrev->next = fNode->next
|
||||
Free(pos.fNode);
|
||||
--fCount;
|
||||
return Iterator(this, next, pos.fPrevious);
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid position for erasing
|
||||
return End(); // Better to return Null()?
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Strategies
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Strategy {
|
||||
namespace SinglyLinkedList {
|
||||
|
||||
namespace Private {
|
||||
template <class Value>
|
||||
class ListNode
|
||||
{
|
||||
public:
|
||||
typedef Value ValueType;
|
||||
|
||||
ListNode(const ValueType &data)
|
||||
: data(data)
|
||||
, next(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ValueType data;
|
||||
ListNode<Value> *next;
|
||||
};
|
||||
} // namespace Private
|
||||
|
||||
template <typename Value, template <class> class Allocator>
|
||||
class Auto
|
||||
{
|
||||
public:
|
||||
typedef Private::ListNode<Value> NodeType;
|
||||
typedef Value ValueType;
|
||||
|
||||
inline NodeType *Allocate(const ValueType &data)
|
||||
{
|
||||
NodeType* result = fAllocator.Allocate();
|
||||
fAllocator.Construct(result, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void Free(NodeType *node)
|
||||
{
|
||||
fAllocator.Destruct(node);
|
||||
fAllocator.Deallocate(node);
|
||||
}
|
||||
|
||||
inline ValueType& GetValue(NodeType *node) const {
|
||||
return node->data;
|
||||
}
|
||||
|
||||
inline NodeType* GetNext(NodeType *node) const {
|
||||
return node->next;
|
||||
}
|
||||
|
||||
inline NodeType* SetNext(NodeType *node, NodeType* next) const {
|
||||
return node->next = next;
|
||||
}
|
||||
|
||||
inline NodeType* GetPrevious(NodeType *node) const {
|
||||
return node->previous;
|
||||
}
|
||||
|
||||
inline NodeType* SetPrevious(NodeType *node, NodeType* previous) const {
|
||||
return node->previous = previous;
|
||||
}
|
||||
|
||||
protected:
|
||||
Allocator<NodeType> fAllocator;
|
||||
};
|
||||
|
||||
template <class Node, Node* Node::* NextMember>
|
||||
class User
|
||||
{
|
||||
public:
|
||||
typedef Node NodeType;
|
||||
typedef Node ValueType;
|
||||
|
||||
inline NodeType *Allocate(const ValueType &data)
|
||||
{
|
||||
return (NodeType*)&data;
|
||||
}
|
||||
|
||||
inline void Free(NodeType *node)
|
||||
{
|
||||
}
|
||||
|
||||
inline ValueType& GetValue(NodeType *node) const {
|
||||
return *node;
|
||||
}
|
||||
|
||||
inline NodeType* GetNext(NodeType *node) const {
|
||||
return node->*NextMember;
|
||||
}
|
||||
|
||||
inline NodeType* SetNext(NodeType *node, NodeType* next) const {
|
||||
return node->*NextMember = next;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SinglyLinkedList
|
||||
} // namespace Strategy
|
||||
|
||||
#endif // #ifndef _SINGLY_LINKED_LIST_H_
|
Loading…
x
Reference in New Issue
Block a user