1//----------------------------------------------------------------------
2//  This software is part of the Haiku distribution and is covered
3//  by the MIT License.
4//---------------------------------------------------------------------
5
6#include <Message.h>
7
8#include "PriorityMessageQueue.h"
9
10// MessageInfo
11class PriorityMessageQueue::MessageInfo {
12public:
13	MessageInfo(BMessage *message, int32 priority)
14		: fMessage(message),
15		  fPriority(priority)
16	{
17	}
18
19	BMessage *Message() const	{ return fMessage; }
20	int32 Priority() const		{ return fPriority; }
21
22private:
23	BMessage	*fMessage;
24	int32		fPriority;
25};
26
27
28// constructor
29PriorityMessageQueue::PriorityMessageQueue()
30	: fLock(),
31	  fMessages(20, true)
32{
33}
34
35// destructor
36PriorityMessageQueue::~PriorityMessageQueue()
37{
38	// delete the messages
39	for (int32 i = 0; MessageInfo *info = fMessages.ItemAt(i); i++)
40		delete info->Message();
41	// the infos are deleted automatically
42}
43
44// Lock
45bool
46PriorityMessageQueue::Lock()
47{
48	return fLock.Lock();
49}
50
51// Unlock
52void
53PriorityMessageQueue::Unlock()
54{
55	fLock.Unlock();
56}
57
58// PushMessage
59bool
60PriorityMessageQueue::PushMessage(BMessage *message, int32 priority)
61{
62	bool result = (message);
63	if (result)
64		result = Lock();
65	if (result) {
66		if (MessageInfo *info = new MessageInfo(message, priority)) {
67			// find the insertion index
68			int32 index = _FindInsertionIndex(priority);
69			if (!fMessages.AddItem(info, index)) {
70				result = false;
71				delete info;
72			}
73		} else	// no memory
74			result = false;
75		Unlock();
76	}
77	return result;
78}
79
80// PopMessage
81BMessage *
82PriorityMessageQueue::PopMessage()
83{
84	BMessage *result = NULL;
85	if (Lock()) {
86		if (MessageInfo *info = fMessages.RemoveItemAt(0)) {
87			result = info->Message();
88			delete info;
89		}
90		Unlock();
91	}
92	return result;
93}
94
95// CountMessages
96int32
97PriorityMessageQueue::CountMessages() const
98{
99	int32 result = 0;
100	if (fLock.Lock()) {
101		result = fMessages.CountItems();
102		fLock.Unlock();
103	}
104	return result;
105}
106
107// IsEmpty
108bool
109PriorityMessageQueue::IsEmpty() const
110{
111	return (CountMessages() == 0);
112}
113
114// _FindInsertionIndex
115int32
116PriorityMessageQueue::_FindInsertionIndex(int32 priority)
117{
118	int32 lower = 0;
119	int32 upper = fMessages.CountItems();
120	while (lower < upper) {
121		int32 mid = (lower + upper) / 2;
122		MessageInfo *info = fMessages.ItemAt(mid);
123		if (info->Priority() >= priority)
124			lower = mid + 1;
125		else
126			upper = mid;
127	}
128	return lower;
129}
130
131