#pragma once
#include "common.hpp"
#include "pool.hpp"
#include "test.hpp"
template <class T> struct queue_node_s {
struct queue_node_s<T>* next;
T data;
};
/** simple FIFO queue with built-in pool support **/
template <class T> class Queue {
private:
TPool<queue_node_s<T> > pool; // TODO: use own pool list? (as we have multiple wrapper pointers atm). Isn't static as it needs to be threadsafe.
queue_node_s<T>* head;
queue_node_s<T>* tail;
size_t len;
public:
Queue();
~Queue();
T* push();
INLINE T* peek();
void pop();
INLINE size_t size() { return len; }
};
/** simple FILO stack with pool and very simple iterators **/
template <class T> class Stack {
private:
TPool<queue_node_s<T> > pool; // TODO: use own pool list? (as we have multiple wrapper pointers atm)
queue_node_s<T>* head;
public:
Stack();
~Stack();
void push(T);
T* push_get();
T pop();
INLINE bool empty() const { return head == NULL; }
INLINE T* iterator() { return head? &head->data: NULL; }
T* iterator_next(T*);
};
/** push/pop (-only) thread-safety **/
template <class T> class StackTS: private Stack<T> {
private:
atomic_t lock;
public:
INLINE StackTS(): lock(0) {};
INLINE void push(T t) { spin_lock(&lock); Stack<T>::push(t); spin_unlock(&lock); } // TODO: use some cmpxchg approach?
INLINE T pop() { spin_lock(&lock); T t = Stack<T>::pop(); spin_unlock(&lock); return t; }
using Stack<T>::empty;
};
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
template <class T> Queue<T>::Queue(): head(NULL), tail(NULL), len(0) {
}
template <class T> Queue<T>::~Queue() { // cleanup will be done by pool
}
template <class T> T* Queue<T>::push() {
queue_node_s<T>* node = pool.pop();
node->next = NULL;
if (!tail) {
head = node;
tail = node;
} else {
tail->next = node;
tail = node;
}
++len;
return &node->data;
}
template <class T> T* Queue<T>::peek() {
return head? &head->data: NULL;
}
template <class T> void Queue<T>::pop() {
assert(head);
queue_node_s<T>* node = head;
head = head->next;
if (!head) {
assert(len == 1);
tail = NULL;
}
pool.push(node);
--len;
}
template <class T> Stack<T>::Stack(): head(NULL) {
}
template <class T> Stack<T>::~Stack() { // cleanup will be done by pool
}
template <class T> void Stack<T>::push(T t) {
queue_node_s<T>* node = pool.pop();
node->data = t;
node->next = head;
head = node;
}
template <class T> T* Stack<T>::push_get() {
queue_node_s<T>* node = pool.pop();
node->next = head;
head = node;
return &node->data;
}
template <class T> T Stack<T>::pop() {
assert(head);
queue_node_s<T>* node = head;
head = head->next;
T t = node->data;
pool.push(node);
return t;
}
template <class T> T* Stack<T>::iterator_next(T* t) {
queue_node_s<T>* node = ((queue_node_s<T>*)((char*)t - sizeof(queue_node_s<T>*)))->next;
return node? &node->data: NULL;
}