blob: f9527b165d7a3b3e11ff35ba67de8c12d4192a5e [file] [log] [blame]
#ifndef _STACK_H_
#define _STACK_H_
#include "vmkit/allocator.h"
namespace vmkit {
template <class T>
class StackNode {
public:
StackNode<T>* nextFree;
StackNode<T>* nextBusy;
T* top;
T* max;
};
template <class T>
class Stack {
static const uint32_t defaultNodeCapacity = 256;
BumpAllocator* allocator;
StackNode<T>* head;
void createNode(uint32_t capacity=defaultNodeCapacity) {
uint64_t size = capacity * sizeof(T) + sizeof(StackNode<T>);
StackNode<T>* nn = (StackNode<T>*)allocator->allocate(size);
nn->top = (T*)(nn + 1);
nn->max = (T*)((uintptr_t)nn + size);
nn->nextFree = 0;
nn->nextBusy = head;
if(head)
head->nextFree = nn;
head = nn;
}
public:
Stack(BumpAllocator* _allocator) {
allocator = _allocator;
head = 0;
createNode();
}
void ensureCapacity(uint32_t capacity) {
T* reserve = head->top + capacity;
if(reserve > head->max)
createNode(capacity);
}
bool isEmpty() {
return head->top == (T*)(head+1) && !head->nextBusy;
}
T* push() {
T* res = head->top++;
if(res < head->max)
return res;
if(head->nextFree)
head = head->nextFree;
else
createNode();
return push();
}
T* pop() {
T* res = head->top - 1;
if(res < (T*)(head + 1)) {
head = head->nextBusy;
head->top = (T*)(head+1);
} else
head->top = res;
return head->top;
}
T* tell() {
return head->top;
}
void restore(T* ptr) {
while(ptr <= (T*)head || ptr > head->max)
head = head->nextBusy;
head->top = ptr;
}
};
template <class T>
class LockedStack : private Stack<T> {
pthread_mutex_t mutex;
public:
LockedStack(BumpAllocator* _allocator) : Stack<T>(_allocator) {
pthread_mutex_init(&mutex, 0);
}
T* push() {
pthread_mutex_lock(&mutex);
T* res = Stack<T>::push();
pthread_mutex_unlock(&mutex);
return res;
}
};
}
#endif