/*
 * Copyright 2013 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Paweł Dziepak, pdziepak@quarnos.org
 */
#ifndef RUN_QUEUE_H
#define RUN_QUEUE_H
 
 
#include <util/Heap.h>
 
#include "scheduler_profiler.h"
 
 
template<typename Element>
struct RunQueueLink {
					RunQueueLink();
 
	unsigned int	fPriority;
	Element*		fPrevious;
	Element*		fNext;
};
 
template<typename Element>
class RunQueueLinkImpl {
public:
	inline	RunQueueLink<Element>*	GetRunQueueLink();
 
private:
			RunQueueLink<Element>	fRunQueueLink;
};
 
template<typename Element>
class RunQueueStandardGetLink {
private:
	typedef RunQueueLink<Element> Link;
 
public:
	inline	Link*		operator()(Element* element) const;
};
 
template<typename Element, RunQueueLink<Element> Element::*LinkMember>
class RunQueueMemberGetLink {
private:
	typedef RunQueueLink<Element> Link;
 
public:
	inline	Link*		operator()(Element* element) const;
};
 
#define RUN_QUEUE_TEMPLATE_LIST	\
	template<typename Element, unsigned int MaxPriority, typename GetLink>
#define RUN_QUEUE_CLASS_NAME	RunQueue<Element, MaxPriority, GetLink>
 
template<typename Element, unsigned int MaxPriority,
	typename GetLink = RunQueueStandardGetLink<Element> >
class RunQueue {
public:
	class ConstIterator {
	public:
								ConstIterator();
								ConstIterator(const RunQueue<Element,
										MaxPriority, GetLink>* list);
 
		inline	ConstIterator&	operator=(const ConstIterator& other);
 
				bool			HasNext() const;
				Element*		Next();
 
				void			Rewind();
 
	private:
		inline	void			_FindNextPriority();
 
				const RUN_QUEUE_CLASS_NAME*	fList;
				unsigned int	fPriority;
				Element*		fNext;
 
		static	GetLink			sGetLink;
	};
 
						RunQueue();
 
	inline	status_t	GetInitStatus();
 
	inline	Element*	PeekMaximum() const;
 
	inline	void		PushFront(Element* element, unsigned int priority);
	inline	void		PushBack(Element* elementt, unsigned int priority);
 
	inline	void		Remove(Element* element);
 
	inline	Element*	GetHead(unsigned int priority) const;
 
	inline	ConstIterator	GetConstIterator() const;
 
private:
	struct PriorityEntry : public HeapLinkImpl<PriorityEntry, unsigned int>
	{
	};
 
	typedef Heap<PriorityEntry, unsigned int, HeapGreaterCompare<unsigned int> >
		PriorityHeap;
 
			status_t	fInitStatus;
 
			PriorityEntry	fPriorityEntries[MaxPriority + 1];
			PriorityHeap	fPriorityHeap;
 
			Element*	fHeads[MaxPriority + 1];
			Element*	fTails[MaxPriority + 1];
 
	static	GetLink		sGetLink;
};
 
 
template<typename Element>
RunQueueLink<Element>::RunQueueLink()
	:
	fPrevious(NULL),
	fNext(NULL)
{
}
 
 
template<typename Element>
RunQueueLink<Element>*
RunQueueLinkImpl<Element>::GetRunQueueLink()
{
	return &fRunQueueLink;
}
 
 
template<typename Element>
RunQueueLink<Element>*
RunQueueStandardGetLink<Element>::operator()(Element* element) const
{
	return element->GetRunQueueLink();
}
 
 
template<typename Element, RunQueueLink<Element> Element::*LinkMember>
RunQueueLink<Element>*
RunQueueMemberGetLink<Element, LinkMember>::operator()(Element* element) const
{
	return &(element->*LinkMember);
}
 
 
RUN_QUEUE_TEMPLATE_LIST
RUN_QUEUE_CLASS_NAME::ConstIterator::ConstIterator()
	:
	fList(NULL)
{
}
 
 
RUN_QUEUE_TEMPLATE_LIST
RUN_QUEUE_CLASS_NAME::ConstIterator::ConstIterator(const RunQueue<Element,
		MaxPriority, GetLink>* list)
	:
	fList(list)
{
	Rewind();
}
 
 
RUN_QUEUE_TEMPLATE_LIST
typename RUN_QUEUE_CLASS_NAME::ConstIterator&
RUN_QUEUE_CLASS_NAME::ConstIterator::operator=(const ConstIterator& other)
{
	fList = other.fList;
	fPriority = other.fPriority;
	fNext = other.fNext;
 
	return *this;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
bool
RUN_QUEUE_CLASS_NAME::ConstIterator::HasNext() const
{
	return fNext != NULL;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
Element*
RUN_QUEUE_CLASS_NAME::ConstIterator::Next()
{
	ASSERT(HasNext());
 
	Element* current = fNext;
	RunQueueLink<Element>* link = sGetLink(fNext);
 
	fNext = link->fNext;
	if (fNext == NULL)
		_FindNextPriority();
 
	return current;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
void
RUN_QUEUE_CLASS_NAME::ConstIterator::Rewind()
{
	ASSERT(fList != NULL);
 
	fPriority = MaxPriority;
	fNext = fList->GetHead(fPriority);
	if (fNext == NULL)
		_FindNextPriority();
}
 
 
RUN_QUEUE_TEMPLATE_LIST
void
RUN_QUEUE_CLASS_NAME::ConstIterator::_FindNextPriority()
{
	ASSERT(fList != NULL);
 
	while (fPriority-- > 0) {
		fNext = fList->GetHead(fPriority);
		if (fNext != NULL)
			break;
	}
}
 
 
RUN_QUEUE_TEMPLATE_LIST
RUN_QUEUE_CLASS_NAME::RunQueue()
	:
	fInitStatus(B_OK),
	fPriorityHeap(MaxPriority + 1)
{
	memset(fHeads, 0, sizeof(fHeads));
	memset(fTails, 0, sizeof(fTails));
}
 
 
RUN_QUEUE_TEMPLATE_LIST
status_t
RUN_QUEUE_CLASS_NAME::GetInitStatus()
{
	return fInitStatus;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
Element*
RUN_QUEUE_CLASS_NAME::PeekMaximum() const
{
	SCHEDULER_ENTER_FUNCTION();
 
	PriorityEntry* maxPriority = fPriorityHeap.PeekRoot();
	if (maxPriority == NULL)
		return NULL;
	unsigned int priority = PriorityHeap::GetKey(maxPriority);
 
	ASSERT(priority <= MaxPriority);
	ASSERT(fHeads[priority] != NULL);
 
	Element* element = fHeads[priority];
 
	ASSERT(sGetLink(element)->fPriority == priority);
	ASSERT(fTails[priority] != NULL);
	ASSERT(sGetLink(element)->fPrevious == NULL);
 
	return element;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
void
RUN_QUEUE_CLASS_NAME::PushFront(Element* element,
	unsigned int priority)
{
	SCHEDULER_ENTER_FUNCTION();
 
	ASSERT(priority <= MaxPriority);
 
	RunQueueLink<Element>* elementLink = sGetLink(element);
 
	ASSERT(elementLink->fPrevious == NULL);
	ASSERT(elementLink->fNext == NULL);
 
	ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL)
		|| (fHeads[priority] != NULL && fTails[priority] != NULL));
 
	elementLink->fPriority = priority;
	elementLink->fNext = fHeads[priority];
	if (fHeads[priority] != NULL)
		sGetLink(fHeads[priority])->fPrevious = element;
	else {
		fTails[priority] = element;
		fPriorityHeap.Insert(&fPriorityEntries[priority], priority);
	}
	fHeads[priority] = element;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
void
RUN_QUEUE_CLASS_NAME::PushBack(Element* element,
	unsigned int priority)
{
	SCHEDULER_ENTER_FUNCTION();
 
	ASSERT(priority <= MaxPriority);
 
	RunQueueLink<Element>* elementLink = sGetLink(element);
 
	ASSERT(elementLink->fPrevious == NULL);
	ASSERT(elementLink->fNext == NULL);
 
	ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL)
		|| (fHeads[priority] != NULL && fTails[priority] != NULL));
 
	elementLink->fPriority = priority;
	elementLink->fPrevious = fTails[priority];
	if (fTails[priority] != NULL)
		sGetLink(fTails[priority])->fNext = element;
	else {
		fHeads[priority] = element;
		fPriorityHeap.Insert(&fPriorityEntries[priority], priority);
	}
	fTails[priority] = element;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
void
RUN_QUEUE_CLASS_NAME::Remove(Element* element)
{
	SCHEDULER_ENTER_FUNCTION();
 
	RunQueueLink<Element>* elementLink = sGetLink(element);
	unsigned int priority = elementLink->fPriority;
 
	ASSERT(elementLink->fPrevious != NULL || fHeads[priority] == element);
	ASSERT(elementLink->fNext != NULL || fTails[priority] == element);
 
	if (elementLink->fPrevious != NULL)
		sGetLink(elementLink->fPrevious)->fNext = elementLink->fNext;
	else
		fHeads[priority] = elementLink->fNext;
	if (elementLink->fNext != NULL)
		sGetLink(elementLink->fNext)->fPrevious = elementLink->fPrevious;
	else
		fTails[priority] = elementLink->fPrevious;
 
	ASSERT((fHeads[priority] == NULL && fTails[priority] == NULL)
		|| (fHeads[priority] != NULL && fTails[priority] != NULL));
 
	if (fHeads[priority] == NULL) {
		fPriorityHeap.ModifyKey(&fPriorityEntries[priority], MaxPriority + 1);
		ASSERT(fPriorityHeap.PeekRoot() == &fPriorityEntries[priority]);
		fPriorityHeap.RemoveRoot();
	}
 
	elementLink->fPrevious = NULL;
	elementLink->fNext = NULL;
}
 
 
RUN_QUEUE_TEMPLATE_LIST
Element*
RUN_QUEUE_CLASS_NAME::GetHead(unsigned int priority) const
{
	SCHEDULER_ENTER_FUNCTION();
 
	ASSERT(priority <= MaxPriority);
	return fHeads[priority];
}
 
 
RUN_QUEUE_TEMPLATE_LIST
typename RUN_QUEUE_CLASS_NAME::ConstIterator
RUN_QUEUE_CLASS_NAME::GetConstIterator() const
{
	return ConstIterator(this);
}
 
 
RUN_QUEUE_TEMPLATE_LIST
GetLink RUN_QUEUE_CLASS_NAME::sGetLink;
 
RUN_QUEUE_TEMPLATE_LIST
GetLink RUN_QUEUE_CLASS_NAME::ConstIterator::sGetLink;
 
 
#endif	// RUN_QUEUE_H
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fPriority.