|
|
|
|
@ -11,39 +11,16 @@
|
|
|
|
|
/*! \brief Templated Queue for arbitrary objects.
|
|
|
|
|
*
|
|
|
|
|
* Queue is implemented by a head-object (Queue<T>) and next-pointers embedded
|
|
|
|
|
* in the queued objects. This Queue supports arrays of next-pointers by passing
|
|
|
|
|
* an index into the constructor identifying the index into the next-pointer
|
|
|
|
|
* array. By passing a different get_link function into the constructor, the
|
|
|
|
|
* member name of the next-pointer array can be changed and objects can be
|
|
|
|
|
* contained in different independent queues.
|
|
|
|
|
* in the queued objects. By passing a different get_link function into the
|
|
|
|
|
* constructor, the member name of the next-pointer can be changed and objects
|
|
|
|
|
* can be contained in different independent queues.
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
class Queue {
|
|
|
|
|
/*! \brief Default get_link implementation returns a pointer to the
|
|
|
|
|
* link_index'th element of the next-pointer array.
|
|
|
|
|
* The function assumes a member named "queue_link" that stores the
|
|
|
|
|
* next-pointer.
|
|
|
|
|
*
|
|
|
|
|
* If your object contains a queue_link member you can just ignore this
|
|
|
|
|
* function and the get_link keyword argument of the constructor.
|
|
|
|
|
*
|
|
|
|
|
* \param[in] obj the object whose link should be accessed.
|
|
|
|
|
* \param[in] link_index the index within the array.
|
|
|
|
|
*
|
|
|
|
|
* \return A pointer to the next-object pointer.
|
|
|
|
|
*/
|
|
|
|
|
static T** default_get_link(T& obj, unsigned link_index) {
|
|
|
|
|
assert(link_index < sizeof(T::queue_link) / sizeof(void*));
|
|
|
|
|
return &obj.queue_link[link_index];
|
|
|
|
|
}
|
|
|
|
|
/// Default get_link implementation returns a pointer to the next-pointer.
|
|
|
|
|
static T** default_get_link(T& obj) { return &obj.queue_link; }
|
|
|
|
|
/// Type definition for the get_link function
|
|
|
|
|
typedef T** (*NextFunc)(T&, unsigned);
|
|
|
|
|
|
|
|
|
|
/// Queue-local index into the next-pointer array
|
|
|
|
|
unsigned link_index;
|
|
|
|
|
|
|
|
|
|
/// Provides the same signature for single- and multi-core Queue
|
|
|
|
|
T** get_link_wrapped(T& obj) { return get_link(obj, link_index); }
|
|
|
|
|
typedef T** (*NextFunc)(T&);
|
|
|
|
|
|
|
|
|
|
/// Function pointer to the get_link function, called whenever the
|
|
|
|
|
/// next pointer array is referenced
|
|
|
|
|
@ -106,18 +83,15 @@ class Queue {
|
|
|
|
|
constexpr Queue(Queue&&) = default;
|
|
|
|
|
|
|
|
|
|
/*! \brief Constructor
|
|
|
|
|
* \param[in] link_index denotes the index into the next-pointer array
|
|
|
|
|
* to be used by this
|
|
|
|
|
*queue-object
|
|
|
|
|
* \param[in] get_link A function pointer to the get_link, i.e. a function
|
|
|
|
|
* which returns a pointer to the
|
|
|
|
|
*next-pointer of an element in the Queue.
|
|
|
|
|
*/
|
|
|
|
|
explicit Queue(unsigned link_index, NextFunc get_link = default_get_link)
|
|
|
|
|
: link_index(link_index),
|
|
|
|
|
get_link(get_link),
|
|
|
|
|
head(nullptr),
|
|
|
|
|
tail(nullptr) {}
|
|
|
|
|
explicit Queue(NextFunc get_link = default_get_link)
|
|
|
|
|
: get_link(get_link), head(nullptr), tail(nullptr) {
|
|
|
|
|
assert(get_link != nullptr &&
|
|
|
|
|
"get_link function pointer must not be nullptr!");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*! \brief Enqueues the provided item at the end of the queue. If the element
|
|
|
|
|
* is already contained in the queue, false will be returned
|
|
|
|
|
@ -126,7 +100,7 @@ class Queue {
|
|
|
|
|
* or not (and it is now enqueued, then true)
|
|
|
|
|
*/
|
|
|
|
|
bool enqueue(T& item) {
|
|
|
|
|
T** nextptr = get_link_wrapped(item);
|
|
|
|
|
T** nextptr = get_link(item);
|
|
|
|
|
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -136,7 +110,7 @@ class Queue {
|
|
|
|
|
head = tail = &item;
|
|
|
|
|
} else {
|
|
|
|
|
assert(tail != nullptr);
|
|
|
|
|
*get_link_wrapped(*tail) = &item;
|
|
|
|
|
*get_link(*tail) = &item;
|
|
|
|
|
tail = &item;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
@ -147,7 +121,7 @@ class Queue {
|
|
|
|
|
* \return true if successful, false if item was already in the queue
|
|
|
|
|
**/
|
|
|
|
|
bool insertFirst(T& item) {
|
|
|
|
|
T** nextptr = get_link_wrapped(item);
|
|
|
|
|
T** nextptr = get_link(item);
|
|
|
|
|
if (*nextptr != nullptr || (head != nullptr && tail == &item)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@ -177,13 +151,13 @@ class Queue {
|
|
|
|
|
if (&after == tail) {
|
|
|
|
|
return enqueue(item);
|
|
|
|
|
}
|
|
|
|
|
T** nextptr = get_link_wrapped(item);
|
|
|
|
|
T** nextptr = get_link(item);
|
|
|
|
|
// if item is already in the list return false
|
|
|
|
|
if (*nextptr != nullptr || tail == &item) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T** pnextptr = get_link_wrapped(after);
|
|
|
|
|
T** pnextptr = get_link(after);
|
|
|
|
|
// if after is NOT in the list, return false
|
|
|
|
|
if (!(pnextptr != nullptr || tail == &after)) {
|
|
|
|
|
return false;
|
|
|
|
|
@ -201,8 +175,7 @@ class Queue {
|
|
|
|
|
*not in this list
|
|
|
|
|
**/
|
|
|
|
|
T* next(T& item) {
|
|
|
|
|
T** nextptr = get_link_wrapped(item);
|
|
|
|
|
// if item is already in the list return nullptr
|
|
|
|
|
T** nextptr = get_link(item);
|
|
|
|
|
if (head == nullptr || (*nextptr == nullptr && tail != &item)) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
@ -222,7 +195,7 @@ class Queue {
|
|
|
|
|
T* dequeue() {
|
|
|
|
|
T* out = head;
|
|
|
|
|
if (head != nullptr) {
|
|
|
|
|
T** nextptr = get_link_wrapped(*head);
|
|
|
|
|
T** nextptr = get_link(*head);
|
|
|
|
|
head = *nextptr;
|
|
|
|
|
*nextptr = nullptr;
|
|
|
|
|
}
|
|
|
|
|
@ -239,21 +212,21 @@ class Queue {
|
|
|
|
|
T** next_link;
|
|
|
|
|
|
|
|
|
|
if (head == that) {
|
|
|
|
|
head = *get_link_wrapped(*head);
|
|
|
|
|
head = *get_link(*head);
|
|
|
|
|
|
|
|
|
|
*get_link_wrapped(*that) = nullptr;
|
|
|
|
|
*get_link(*that) = nullptr;
|
|
|
|
|
return that;
|
|
|
|
|
}
|
|
|
|
|
while (cur) {
|
|
|
|
|
next_link = get_link_wrapped(*cur);
|
|
|
|
|
next_link = get_link(*cur);
|
|
|
|
|
if (*next_link == that) {
|
|
|
|
|
*next_link = *get_link_wrapped(**next_link);
|
|
|
|
|
*next_link = *get_link(**next_link);
|
|
|
|
|
|
|
|
|
|
if (that == tail) {
|
|
|
|
|
tail = cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*get_link_wrapped(*that) = nullptr;
|
|
|
|
|
*get_link(*that) = nullptr;
|
|
|
|
|
return that;
|
|
|
|
|
}
|
|
|
|
|
cur = *next_link;
|
|
|
|
|
|