neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
queue.hpp
Go to the documentation of this file.
1// queue.hpp - v1.4
2/*
3 * Copyright (c) 2007 Leigh Johnston.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * * Neither the name of Leigh Johnston nor the names of any
19 * other contributors to this software may be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*/
35
36#pragma once
37
38#include <neolib/neolib.hpp>
39#include <list>
40#include <vector>
41#include <neolib/core/interlockable.hpp>
42#include <neolib/core/event.hpp>
43
44namespace neolib
45{
46 template <typename QueueItem>
47 class queue : public interlockable
48 {
49 // types
50 public:
51 typedef QueueItem value_type;
52 class sink
53 {
54 public:
55 virtual void from_queue(queue& aQueue, QueueItem& aItem) = 0;
56 };
57 struct no_sink : std::logic_error { no_sink() : std::logic_error("neolib::queue::no_sink") {} };
58 private:
59 class entry
60 {
61 // types
62 public:
63 enum type_e { Send, Post };
64 // construction
65 public:
66 entry(const QueueItem& aItem, type_e aType) : iItem(aItem), iType(aType), iEvent(nullptr), iFrom(nullptr) {}
67 entry(const QueueItem& aItem, type_e aType, const event& aEvent) : iItem(aItem), iType(aType), iEvent(&aEvent), iFrom(nullptr) {}
68 entry(const QueueItem& aItem, type_e aType, const interlockable& aFrom) : iItem(aItem), iType(aType), iEvent(nullptr), iFrom(&aFrom) {}
69 entry(const QueueItem& aItem, type_e aType, const event& aEvent, const interlockable& aFrom) : iItem(aItem), iType(aType), iEvent(&aEvent), iFrom(&aFrom) {}
70 // operations
71 public:
72 const QueueItem& item() const { return iItem; }
73 QueueItem& item() { return iItem; }
74 type_e type() const { return iType; }
75 const interlockable* from() const { return iFrom; }
76 void signal() const { if (iEvent != nullptr) iEvent->signal_one(); }
77 // attributes
78 private:
79 QueueItem iItem;
80 type_e iType;
81 const event* iEvent;
82 const interlockable* iFrom;
83 };
84 typedef std::list<entry> std_type;
85 typedef typename std_type::const_iterator const_iterator;
86 typedef typename std_type::iterator iterator;
87 typedef std::vector<iterator> working_list;
88 // construction
89 public:
90 queue() : iSink(nullptr) {}
91 queue(sink& aSink) : iSink(&aSink) {}
92 // operations
93 public:
94 void wait()
95 {
96 return iNewItemEvent.wait();
97 }
98 bool wait(uint32_t aTimeout_ms)
99 {
100 return iNewItemEvent.wait(aTimeout_ms);
101 }
102 void loop(bool (*aYieldProc)() = nullptr)
103 {
104 if (iSink == nullptr)
105 throw std::logic_error("neolib::queue::loop");
106 while (!aYieldProc || !aYieldProc())
107 {
108 wait();
109 process_queue();
110 }
111 }
112 void loop(uint32_t aTimeout_ms, bool (*aYieldProc)() = nullptr)
113 {
114 if (iSink == nullptr)
115 throw std::logic_error("neolib::queue::loop");
116 while ((!aYieldProc || !aYieldProc()) && wait(aTimeout_ms))
117 process_queue();
118 }
119 void send(const QueueItem& aItem)
120 {
121 send(iProcessedItemEvent, aItem);
122 }
123 bool send(const QueueItem& aItem, uint32_t aTimeout_ms)
124 {
125 return send(iProcessedItemEvent, aItem, aTimeout_ms);
126 }
127 void send(const event& aEvent, const QueueItem& aItem)
128 {
129 lock();
130 iItems.push_back(entry(aItem, entry::Send, aEvent));
131 unlock();
132 iNewItemEvent.signal();
133 return aEvent.wait();
134 }
135 bool send(const event& aEvent, const QueueItem& aItem, uint32_t aTimeout_ms)
136 {
137 lock();
138 iItems.push_back(entry(aItem, entry::Send, aEvent));
139 unlock();
140 iNewItemEvent.signal();
141 return aEvent.timed_wait(aTimeout_ms);
142 }
143 void interlocked_send(const interlockable& aOther, const QueueItem& aItem)
144 {
145 interlocked_send(aOther, iProcessedItemEvent, aItem);
146 }
147 bool interlocked_send(const interlockable& aOther, const QueueItem& aItem, uint32_t aTimeout_ms)
148 {
149 return interlocked_send(aOther, iProcessedItemEvent, aItem, aTimeout_ms);
150 }
151 void interlocked_send(const interlockable& aOther, const event& aEvent, const QueueItem& aItem)
152 {
153 interlock_acquire(aOther);
154 lock();
155 iItems.push_back(entry(aItem, entry::Send, aEvent, aOther));
156 unlock();
157 iNewItemEvent.signal_one();
158 interlock_release(aOther);
159 aEvent.wait();
160 }
161 bool interlocked_send(const interlockable& aOther, const event& aEvent, const QueueItem& aItem, uint32_t aTimeout_ms)
162 {
163 interlock_acquire(aOther);
164 lock();
165 iItems.push_back(entry(aItem, entry::Send, aEvent, aOther));
166 unlock();
167 iNewItemEvent.signal_one();
168 interlock_release(aOther);
169 return aEvent.wait(aTimeout_ms);
170 }
171 void post(const QueueItem& aItem)
172 {
173 lock();
174 iItems.push_back(entry(aItem, entry::Post));
175 unlock();
176 iNewItemEvent.signal_one();
177 }
178 QueueItem& next()
179 {
180 neolib::lock lock(*this);
181 iterator nextEntry = next_available();
182 iWorkingList.push_back(nextEntry);
183 return nextEntry->item();
184 }
185 void pop_next()
186 {
187 neolib::lock lock(*this);
188 iterator nextEntry = iWorkingList.back();
189 iWorkingList.pop_back();
190 if (nextEntry->type() == entry::Send)
191 nextEntry->signal();
192 iItems.erase(nextEntry);
193 }
194 bool any() const
195 {
196 neolib::lock lock(*this);
197 return next_available() != iItems.end();
198 }
199 void clear()
200 {
201 neolib::lock lock(*this);
202 iItems.clear();
203 }
204 // implementation
205 private:
206 const_iterator next_available() const
207 {
208 const_iterator nextAvailable;
209 if (iWorkingList.empty())
210 nextAvailable = iItems.begin();
211 else
212 {
213 nextAvailable = iWorkingList.back();
214 ++nextAvailable;
215 }
216 return nextAvailable;
217 }
218 iterator next_available()
219 {
220 iterator nextAvailable;
221 if (iWorkingList.empty())
222 nextAvailable = iItems.begin();
223 else
224 {
225 nextAvailable = iWorkingList.back();
226 ++nextAvailable;
227 }
228 return nextAvailable;
229 }
230 void process_queue()
231 {
232 if (iSink == nullptr)
233 throw no_sink();
234 while (any())
235 {
236 QueueItem& nextItem = next();
237 iSink->from_queue(*this, nextItem);
238 pop_next();
239 }
240 }
241 // from interlockable
242 virtual bool purge(const interlockable& aOther)
243 {
244 if (iSink == nullptr)
245 throw std::logic_error("neolib::queue::purge");
246 neolib::lock lock(*this);
247 for (working_list::const_iterator i = iWorkingList.begin(); i != iWorkingList.end(); ++i)
248 {
249 entry& theEntry = **i;
250 if (theEntry.type() == entry::Send && theEntry.from() == &aOther)
251 return false;
252 }
253 if (wait(event::ShortTimeout_ms))
254 process_queue();
255 return true;
256 }
257 // attributes
258 private:
259 std_type iItems;
260 working_list iWorkingList;
261 event iNewItemEvent;
262 event iProcessedItemEvent;
263 sink* iSink;
264 };
265}
virtual void from_queue(queue &aQueue, QueueItem &aItem)=0
void interlocked_send(const interlockable &aOther, const QueueItem &aItem)
Definition queue.hpp:143
bool send(const QueueItem &aItem, uint32_t aTimeout_ms)
Definition queue.hpp:123
QueueItem value_type
Definition queue.hpp:51
QueueItem & next()
Definition queue.hpp:178
void loop(bool(*aYieldProc)()=nullptr)
Definition queue.hpp:102
void send(const event &aEvent, const QueueItem &aItem)
Definition queue.hpp:127
void send(const QueueItem &aItem)
Definition queue.hpp:119
void pop_next()
Definition queue.hpp:185
bool wait(uint32_t aTimeout_ms)
Definition queue.hpp:98
bool send(const event &aEvent, const QueueItem &aItem, uint32_t aTimeout_ms)
Definition queue.hpp:135
void loop(uint32_t aTimeout_ms, bool(*aYieldProc)()=nullptr)
Definition queue.hpp:112
void wait()
Definition queue.hpp:94
bool interlocked_send(const interlockable &aOther, const QueueItem &aItem, uint32_t aTimeout_ms)
Definition queue.hpp:147
void clear()
Definition queue.hpp:199
bool interlocked_send(const interlockable &aOther, const event &aEvent, const QueueItem &aItem, uint32_t aTimeout_ms)
Definition queue.hpp:161
void post(const QueueItem &aItem)
Definition queue.hpp:171
void interlocked_send(const interlockable &aOther, const event &aEvent, const QueueItem &aItem)
Definition queue.hpp:151
bool any() const
Definition queue.hpp:194
queue(sink &aSink)
Definition queue.hpp:91