Files
Upsilon/tree_pool.h
2018-06-28 17:59:06 +02:00

185 lines
4.9 KiB
C++

#ifndef TREE_POOL_H
#define TREE_POOL_H
#include <stddef.h>
#include "tree_node.h"
#include <new>
class TreePool {
friend class TreeNode;
public:
static constexpr int AllocationFailureIdentifier = 0;
static TreePool * sharedPool();
// Node
TreeNode * node(int identifier) const;
TreeNode * last() const { return reinterpret_cast<TreeNode *>(const_cast<char *>(m_cursor)); }
template <typename T>
TreeNode * createTreeNode() {
int nodeIdentifier = generateIdentifier();
if (nodeIdentifier == -1) {
T::failedAllocationNode()->retain();
return T::failedAllocationNode();
}
void * ptr = alloc(sizeof(T));
if (ptr == nullptr) {
T::failedAllocationNode()->retain();
return T::failedAllocationNode();
}
T * node = new(ptr) T();
node->rename(nodeIdentifier);
registerNode(node);
return node;
}
void move(TreeNode * source, TreeNode * destination);
TreeNode * deepCopy(TreeNode * node) {
size_t size = node->deepSize();
void * ptr = alloc(size);
memcpy(ptr, static_cast<void *>(node), size);
TreeNode * copy = reinterpret_cast<TreeNode *>(ptr);
renameNode(copy);
for (TreeNode * child : copy->depthFirstChildren()) {
renameNode(child);
}
return copy;
}
// Allocation failure handling
bool nodeWasReplacedWithAllocationFailure(int id) {
return m_allocationFailureRetainCount[id] > 0;
}
void releaseAllocationFailure(int id) {
int currrentRetainCount = m_allocationFailureRetainCount[id];
assert(currrentRetainCount > 0);
m_allocationFailureRetainCount[id] = currrentRetainCount - 1;
if (m_allocationFailureRetainCount[id] == 0) {
freeIdentifier(id);
}
}
void registerIdentiferAsAllocationFailure(int id, int retainCount) {
if (retainCount == 0) {
freeIdentifier(id);
} else {
assert(id >= 0 && id < MaxNumberOfNodes);
m_nodeForIdentifier[id] = first(); // TODO for now the first node in the pool is the allocation failure node (WARNING when implementing for Layouts... HAVE 2 POOLS?)
m_allocationFailureRetainCount[id] = retainCount;
}
}
// Debug
void log();
int numberOfNodes() const {
int count = 0;
AllPool nodes = const_cast<TreePool *>(this)->allNodes();
for (TreeNode * t : nodes) {
count++;
}
return count;
}
private:
constexpr static int BufferSize = 256;
constexpr static int MaxNumberOfNodes = BufferSize/sizeof(TreeNode);
// TreeNode
void discardTreeNode(TreeNode * node) {
int nodeIdentifier = node->identifier();
node->~TreeNode();
dealloc(node);
freeIdentifier(nodeIdentifier);
}
void registerNode(TreeNode * node) {
m_nodeForIdentifier[node->identifier()] = node;
}
void renameNode(TreeNode * node) {
node->rename(generateIdentifier());
registerNode(node);
}
// Iterators
TreeNode * first() const { return reinterpret_cast<TreeNode *>(const_cast<char *>(m_buffer)); }
class AllPool {
public:
AllPool(TreeNode * node) : m_node(node) {}
class Iterator : public TreeNode::Iterator {
public:
using TreeNode::Iterator::Iterator;
Iterator & operator++() {
m_node = m_node->next();
return *this;
}
};
Iterator begin() const { return Iterator(m_node); }
Iterator end() const { return Iterator(TreePool::sharedPool()->last()); }
private:
TreeNode * m_node;
};
AllPool allNodes() { return AllPool(*(begin())); }
class Roots {
public:
Roots(TreeNode * node) : m_node(node) {}
class Iterator : public TreeNode::Iterator {
public:
using TreeNode::Iterator::Iterator;
Iterator & operator++() {
m_node = m_node->nextSibling();
return *this;
}
};
Iterator begin() const { return Iterator(m_node); }
Iterator end() const { return Iterator(TreePool::sharedPool()->last()); }
private:
TreeNode * m_node;
};
Roots roots() { return Roots(*(begin())); }
TreeNode::DepthFirst::Iterator begin() const { return TreeNode::DepthFirst::Iterator(first()); }
TreeNode::DepthFirst::Iterator end() const { return TreeNode::DepthFirst::Iterator(last()); }
TreePool() : m_cursor(m_buffer) { }
// Pool memory
void * alloc(size_t size);
void dealloc(TreeNode * ptr);
static inline bool insert(char * destination, char * source, size_t length);
// Identifiers
int generateIdentifier() {
int newIdentifier = -1;
for (int i = 0; i < MaxNumberOfNodes; i++) {
if (m_nodeForIdentifier[i] == nullptr) {
newIdentifier = i;
break;
}
}
assert(newIdentifier != -1);
return newIdentifier;
}
void freeIdentifier(int identifier) {
assert(identifier >= 0 && identifier < MaxNumberOfNodes);
m_nodeForIdentifier[identifier] = nullptr;
}
// Debug
void logNodeForIdentifierArray();
char * m_cursor;
char m_buffer[BufferSize];
TreeNode * m_nodeForIdentifier[MaxNumberOfNodes];
int m_allocationFailureRetainCount[MaxNumberOfNodes];
};
#endif