⛏️ index : haiku.git

// SLList.h

#ifndef SL_LIST_H
#define SL_LIST_H

#include <SupportDefs.h>

namespace UserlandFSUtil {

// SLListLink
template<typename Element>
class SLListLink {
public:
	SLListLink() : next(NULL) {}
	~SLListLink() {}

	Element	*next;
};

// SLListLinkImpl
template<typename Element>
class SLListLinkImpl {
private:
	typedef SLListLink<Element> Link;

public:
	SLListLinkImpl() : fSLListLink()	{}
	~SLListLinkImpl()					{}

	Link *GetSLListLink()				{ return &fSLListLink; }
	const Link *GetSLListLink() const	{ return &fSLListLink; }

private:
	Link	fSLListLink;
};

// SLListStandardGetLink
template<typename Element>
class SLListStandardGetLink {
private:
	typedef SLListLink<Element> Link;

public:
	inline Link *operator()(Element *element) const
	{
		return element->GetSLListLink();
	}

	inline const Link *operator()(const Element *element) const
	{
		return element->GetSLListLink();
	}
};

// for convenience
#define SL_LIST_TEMPLATE_LIST template<typename Element, typename GetLink>
#define SL_LIST_CLASS_NAME SLList<Element, GetLink>

// SLList
template<typename Element, typename GetLink = SLListStandardGetLink<Element> >
class SLList {
private:
	typedef SLList<Element, GetLink>	List;
	typedef SLListLink<Element>			Link;

public:
	class Iterator {
	public:
		Iterator(List *list)
			: fList(list),
			  fPrevious(NULL),
			  fCurrent(NULL),
			  fNext(fList->GetFirst())
		{
		}

		Iterator(const Iterator &other)
		{
			*this = other;
		}

		bool HasNext() const
		{
			return fNext;
		}
		
		Element *Next()
		{
			if (fCurrent)
				fPrevious = fCurrent;

			fCurrent = fNext;

			if (fNext)
				fNext = fList->GetNext(fNext);

			return fCurrent;
		}
	
		Element *Remove()
		{
			Element *element = fCurrent;
			if (fCurrent) {
				fList->_Remove(fPrevious, fCurrent);
				fCurrent = NULL;
			}
			return element;
		}

		Iterator &operator=(const Iterator &other)
		{
			fList = other.fList;
			fPrevious = other.fPrevious;
			fCurrent = other.fCurrent;
			fNext = other.fNext;
			return *this;
		}
	
	private:
		List	*fList;
		Element *fPrevious;
		Element	*fCurrent;
		Element	*fNext;
	};

	class ConstIterator {
	public:
		ConstIterator(const List *list)
			: fList(list),
			  fNext(list->GetFirst())
		{
		}

		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;
		}
	
	private:
		const List	*fList;
		Element		*fNext;
	};

public:
	SLList() : fFirst(NULL), fLast(NULL) {}
	SLList(const GetLink &getLink)
		: fFirst(NULL), fLast(NULL), fGetLink(getLink) {}
	~SLList() {}

	inline bool IsEmpty() const			{ return (fFirst == NULL); }

	inline void Insert(Element *element, bool back = true);
	inline void InsertAfter(Element *previous, Element *element);
	inline void Remove(Element *element);
		// O(n)!

	inline void MoveFrom(SL_LIST_CLASS_NAME *fromList);

	inline void RemoveAll();

	inline Element *GetFirst() const	{ return fFirst; }
	inline Element *GetLast() const		{ return fLast; }

	inline Element *GetHead() const		{ return fFirst; }
	inline Element *GetTail() const		{ return fLast; }

	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:
	friend class Iterator;

	inline void _Remove(Element *previous, Element *element);

private:
	Element	*fFirst;
	Element	*fLast;
	GetLink	fGetLink;
};

}	// namespace UserlandFSUtil

using UserlandFSUtil::SLList;
using UserlandFSUtil::SLListLink;
using UserlandFSUtil::SLListLinkImpl;


// inline methods

// Insert
SL_LIST_TEMPLATE_LIST
void
SL_LIST_CLASS_NAME::Insert(Element *element, bool back)
{
	InsertAfter((back ? fLast : NULL), element);
}

// InsertAfter
SL_LIST_TEMPLATE_LIST
void
SL_LIST_CLASS_NAME::InsertAfter(Element *previous, Element *element)
{
	if (element) {
		Link *elLink = fGetLink(element);
		if (previous) {
			// insert after previous element
			Link *prevLink = fGetLink(previous);
			elLink->next = prevLink->next;
			prevLink->next = element;
		} else {
			// no previous element given: prepend
			elLink->next = fFirst;
			fFirst = element;
		}

		// element may be new last element
		if (fLast == previous)
			fLast = element;
	}
}

// Remove
SL_LIST_TEMPLATE_LIST
void
SL_LIST_CLASS_NAME::Remove(Element *element)
{
	if (!element)
		return;

	for (Iterator it = GetIterator(); it.HasNext();) {
		if (element == it.Next()) {
			it.Remove();
			return;
		}
	}
}

// MoveFrom
SL_LIST_TEMPLATE_LIST
void
SL_LIST_CLASS_NAME::MoveFrom(SL_LIST_CLASS_NAME *fromList)
{
	if (fromList && fromList->fFirst) {
		if (fFirst) {
			fGetLink(fLast)->next = fromList->fFirst;
			fLast = fromList->fLast;
		} else {
			fFirst = fromList->fFirst;
			fLast = fromList->fLast;
		}
		fromList->fFirst = NULL;
		fromList->fLast = NULL;
	}
}

// RemoveAll
SL_LIST_TEMPLATE_LIST
void
SL_LIST_CLASS_NAME::RemoveAll()
{
	Element *element = fFirst;
	while (element) {
		Link *elLink = fGetLink(element);
		element = elLink->next;
		elLink->next = NULL;
	}
	fFirst = NULL;
	fLast = NULL;
}

// GetNext
SL_LIST_TEMPLATE_LIST
Element *
SL_LIST_CLASS_NAME::GetNext(Element *element) const
{
	return (element ? fGetLink(element)->next : NULL);
}

// _Remove
SL_LIST_TEMPLATE_LIST
void
SL_LIST_CLASS_NAME::_Remove(Element *previous, Element *element)
{
	Link *elLink = fGetLink(element);
	if (previous)
		fGetLink(previous)->next = elLink->next;
	else
		fFirst = elLink->next;

	if (element == fLast)
		fLast = previous;

	elLink->next = NULL;
}

// Size
SL_LIST_TEMPLATE_LIST
int32
SL_LIST_CLASS_NAME::Size() const
{
	int32 count = 0;
	for (Element* element = GetFirst(); element; element = GetNext(element))
		count++;
	return count;
}

#endif	// SL_LIST_H