Use operator new/delete directly on ExpressionNode

This commit is contained in:
Romain Goyet
2018-06-12 16:50:49 +02:00
parent 3cd1015614
commit 68f663d47e
12 changed files with 234 additions and 164 deletions

View File

@@ -1,4 +1,4 @@
OBJS = tree_pool.o tree_reference.o test.o
OBJS = tree_pool.o tree_node.o tree_reference.o test.o
CXXFLAGS = -std=c++11 -g -O0
test: $(OBJS)

View File

@@ -6,7 +6,7 @@
class AdditionNode : public ExpressionNode {
public:
AdditionNode(int identifier) : ExpressionNode(identifier) {
AdditionNode() : ExpressionNode() {
printf("Create Addition\n");
}
#if TREE_LOGGING
@@ -31,12 +31,17 @@ public:
*/
};
#include "end_node.h"
class Addition : public ExpressionReference<AdditionNode> {
public:
Addition(Expression e1, Expression e2) :
ExpressionReference<AdditionNode>()
{
// Ok, here I want to take e1 and e2 as operands
ExpressionReference<EndNode> end;
ExpressionNode::Pool()->log();
addOperand(end);
ExpressionNode::Pool()->log();
}
};

25
end_node.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef END_NODE_H
#define END_NODE_H
#include "expression_reference.h"
#include "expression_node.h"
class EndNode : public ExpressionNode {
public:
EndNode() : ExpressionNode() {
printf("Create end node\n");
}
float approximate() override {
assert(false);
return 0.0f;
}
#if TREE_LOGGING
const char * description() const override {
return "End";
}
#endif
};
//typedef ExpressionReference<EndNode> End;
#endif

View File

@@ -2,12 +2,23 @@
#define EXPRESSION_NODE_H
#include "tree_node.h"
class TreePool;
#include "tree_pool.h"
class ExpressionNode : public TreeNode {
public:
ExpressionNode(int identifier) : TreeNode(identifier) {}
ExpressionNode() : TreeNode(Pool()->generateIdentifier()) {}
// TODO: operator new and delte
// this behavior is the same for every TreeNode
// Find a way to define it on the TreeNode
void * operator new(size_t count) {
return Pool()->alloc(count);
}
void operator delete(void * ptr) {
Pool()->dealloc(ptr);
}
static TreePool * Pool() {
static TreePool pool;
@@ -20,3 +31,9 @@ public:
};
#endif
/* Code I want to write:
*
* ExpressionNode * n = new AdditionNode();
* delete n;
*/

View File

@@ -22,6 +22,10 @@ public:
return *(reinterpret_cast<const ExpressionReference<ExpressionNode> *>(this));
}
void addOperand(ExpressionReference<ExpressionNode> e) {
TreeReference<T>::addChild(e);
}
float approximate() const {
return this->node()->approximate();
}

View File

@@ -6,7 +6,7 @@
class FloatNode : public ExpressionNode {
public:
FloatNode(int identifier) : ExpressionNode(identifier) {
FloatNode() : ExpressionNode() {
printf("Create float\n");
}
size_t size() const override {

119
test.cpp
View File

@@ -2,31 +2,43 @@
#include "addition_node.h"
#include <stdio.h>
void poolTest() {
ExpressionNode::Pool()->log();
FloatNode * f = new FloatNode();
f->setFloat(0.1f);
FloatNode * g = new FloatNode();
g->setFloat(1.1f);
AdditionNode * h = new AdditionNode();
EndNode * i = new EndNode();
ExpressionNode::Pool()->log();
delete g;
ExpressionNode::Pool()->log();
}
Expression buildAddition() {
Float smallFloat(0.2f);
Float bigFloat(3.4f);
ExpressionNode::Pool()->log();
Addition a(smallFloat, bigFloat);
ExpressionNode::Pool()->log();
return a;
}
int main() {
printf("Hello\n");
buildAddition();
ExpressionNode::Pool()->log();
Float e(0.2f);
ExpressionNode::Pool()->log();
if (true) {
Expression j = e;
ExpressionNode::Pool()->log();
Float m(3.4f);
ExpressionNode::Pool()->log();
}
ExpressionNode::Pool()->log();
Addition a(e, e);
ExpressionNode::Pool()->log();
/*
Expression e = Parse("1+1");
@@ -34,74 +46,7 @@ int main() {
Expression f = Addition(e, Parse("5"));
f.removeChildAtIndex(0);
*/
#if 0
TreeNodePool pool;
TreeNodePool * p = &pool;
pool.log();
TreeNode * t1 = new (pool) AdditionNode();
TreeNode * t1 = TreeNode::Create(p, 11);
TreeNode * t2 = TreeNode::Create(p, 12);
TreeNode * t3 = TreeNode::Create(p, 13);
TreeNode * t4 = AddNode::Create(t1, t3);
//TreeNode * t4 = new(p) IntNode(4);
//
t4->createChild(Addition()
pool.log();
pool.move(t1, t3);
pool.log();
#endif
return 0;
}
#if 0
static inline swap(uint32_t * a, uint32_t * b) {
uint32_t tmp = *a;
*a = *b;
*b = tmp;
}
void insert(char * source, char * destination, size_t length) {
assert(length % 4 == 0);
assert(source % 4 == 0);
assert(destination % 4 == 0);
uint32_t * src = reinterpret_cast<uint32_t *>(source);
uint32_t * dst = reinterpret_cast<uint32_t *>(destination);
size_t len = length/4;
if (dst < src) {
if (src - dst <= len) {
uint32_t * srcPointer = src;
uint32_t * dstPointer = dst;
while (dstPointer != src) {
swap(srcPointer, dstPointer);
srcPointer++;
dstPointer++;
if (srcPointer == src + len) {
srcPointer = src;
}
}
}
}
}
void TreeNodePool::move(TreeNode * source, TreeNode * destination) {
if (source == destination) {
return;
}
insert(source, destination, source->deepSize());
}
bool TreeNode::hasVariableNumberOfChildren() const {
return false;
}
#endif

16
tree_node.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "tree_node.h"
#include "expression_node.h"
void TreeNode::release() {
m_referenceCounter--;
for (TreeNode * child : directChildren()) {
child->release();
}
if (m_referenceCounter == 0) {
printf("DELETE %d(%p)\n", m_identifier, this);
delete this;
//dealloc();
printf("Will log\n");
ExpressionNode::Pool()->log();
}
}

View File

@@ -16,7 +16,6 @@ public:
virtual ~TreeNode() {
}
// Iterators
class Iterator {
@@ -28,6 +27,25 @@ public:
TreeNode * m_node;
};
class Direct {
public:
Direct(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->next()); }
Iterator end() const { return Iterator(m_node->nextSibling()); }
private:
TreeNode * m_node;
};
Direct directChildren() { return Direct(this); }
class DepthFirst {
public:
DepthFirst(TreeNode * node) : m_node(node) {}
@@ -35,7 +53,7 @@ public:
public:
using TreeNode::Iterator::Iterator;
Iterator & operator++() {
printf(" Iterating from %d(%p) to %d(%p)\n", m_node->m_identifier, m_node, m_node->next()->m_identifier, m_node->next());
// printf(" Iterating from %d(%p) to %d(%p)\n", m_node->m_identifier, m_node, m_node->next()->m_identifier, m_node->next());
m_node = m_node->next();
return *this;
}
@@ -64,8 +82,11 @@ public:
void retain() {
m_referenceCounter++;
}
void release() {
m_referenceCounter--;
void release();
void rename(int identifier) {
m_identifier = identifier;
m_referenceCounter = 1;
}
int retainCount() {

View File

@@ -8,11 +8,15 @@ void * TreePool::alloc(size_t size) {
return result;
}
void TreePool::dealloc(void * ptr, size_t size) {
void TreePool::dealloc(void * ptr) {
assert(ptr >= m_buffer && ptr < m_cursor);
TreeNode * node = reinterpret_cast<TreeNode *>(ptr);
size_t size = node->size();
printf("Dealloc %d(%p) of size %d\n", node->m_identifier, node, size);
// Step 1 - Compact the pool
memmove(
ptr,
static_cast<char *>(ptr) - size,
static_cast<char *>(ptr) + size,
m_cursor - static_cast<char *>(ptr)
);
m_cursor -= size;
@@ -37,14 +41,50 @@ TreeNode * TreePool::node(int identifier) const {
return nullptr;
}
static inline void swap(uint32_t * a, uint32_t * b) {
uint32_t tmp = *a;
*a = *b;
*b = tmp;
}
static inline void insert(char * source, char * destination, size_t length) {
assert(length % 4 == 0);
assert((long)source % 4 == 0);
assert((long)destination % 4 == 0);
uint32_t * src = reinterpret_cast<uint32_t *>(source);
uint32_t * dst = reinterpret_cast<uint32_t *>(destination);
size_t len = length/4;
if (dst < src) {
if (src - dst <= len) {
uint32_t * srcPointer = src;
uint32_t * dstPointer = dst;
while (dstPointer != src) {
swap(srcPointer, dstPointer);
srcPointer++;
dstPointer++;
if (srcPointer == src + len) {
srcPointer = src;
}
}
}
}
}
void TreePool::move(TreeNode * source, TreeNode * destination) {
if (source == destination) {
return;
}
insert(reinterpret_cast<char *>(source), reinterpret_cast<char *>(destination), source->deepSize());
}
#if TREE_LOGGING
#include <stdio.h>
void TreePool::log() {
printf("POOL:");
for (TreeNode * node : *this) {
printf("|%d", node->m_identifier);
//printf("|(%03d|%s|%03d)", node->m_identifier, node->description(), node->retainCount());
printf("|(%03d|%s|%03d|%p)", node->m_identifier, node->description(), node->retainCount(), node);
}
printf("|\n");
}

View File

@@ -10,70 +10,46 @@ public:
TreePool() : m_lastIdentifier(0), m_cursor(m_buffer) {}
int generateIdentifier() {
assert(node(m_lastIdentifier) == nullptr);
/* For now we're not bothering with making sure the identifiers are indeed
* unique. We're just assuming we'll never overflow... */
//assert(node(m_lastIdentifier) == nullptr);
return m_lastIdentifier++;
}
void reclaimIdentifier(int identifier) {
}
void * alloc(size_t size);
void dealloc(void * ptr, size_t size);
void dealloc(void * ptr);
TreeNode * node(int identifier) const;
void move(TreeNode * source, TreeNode * destination);
TreeNode * first() const { return reinterpret_cast<TreeNode *>(const_cast<char *>(m_buffer)); }
TreeNode * last() const { return reinterpret_cast<TreeNode *>(const_cast<char *>(m_cursor)); }
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);
copy->rename(generateIdentifier());
for (TreeNode * child : copy->depthFirstChildren()) {
child->rename(generateIdentifier());
}
return copy;
}
#if TREE_LOGGING
void log();
#endif
private:
TreeNode::DepthFirst::Iterator begin() const { return TreeNode::DepthFirst::Iterator(reinterpret_cast<TreeNode *>(const_cast<char *>(m_buffer))); }
TreeNode::DepthFirst::Iterator end() const { return TreeNode::DepthFirst::Iterator(reinterpret_cast<TreeNode *>(const_cast<char *>(m_cursor))); }
TreeNode::DepthFirst::Iterator begin() const { return TreeNode::DepthFirst::Iterator(first()); }
TreeNode::DepthFirst::Iterator end() const { return TreeNode::DepthFirst::Iterator(last()); }
int m_lastIdentifier;
char * m_cursor;
char m_buffer[256];
};
#if 0
class TreePool {
public:
TreePool() :
m_identifier(0),
m_cursor(m_data)
{
}
class Slot {
public:
Slot(int identifier, void * area) :
m_identifier(identifier), m_area(area) {}
int identifier() const { return m_identifier; }
void * area() const { return m_area; }
private:
int m_identifier;
void * m_area;
int m_size;
};
Slot alloc(size_t size);
void dealloc(Slot s, size_t size);
//TreeNode * node(int identifier) const;
TreeNode * alloc(size_t size) {
}
void dealloc(TreeNode * node);
void move(TreeNode * source, TreeNode * destination);
//#define TREE_LOGGING 1
#if TREE_LOGGING
void log();
#endif
private:
int m_identifier;
char * m_cursor;
char m_data[200];
};
#endif
#endif

View File

@@ -20,8 +20,17 @@ public:
~TreeReference() {
TreeNode * node = this->node();
node->release();
#if 0
if (node->retainCount() == 0) {
// Here we deal with removing a node.
// It's not as easy as one may think.
// -> When a node is not needed anymore
printf("Discarding node %d(%p)\n", node->identifier(), node);
// Here the static_cast should fail if T is not a subclass of TreeNode
size_t deepNodeSize = node->deepSize();
#if 0
@@ -34,6 +43,13 @@ public:
static_cast<T*>(node)->~T();
m_pool->dealloc(node, deepNodeSize);
}
#endif
}
operator TreeReference<TreeNode>() const {
// TODO: make sure this is kosher
// static_assert(sizeof(ExpressionReference<T>) == sizeof(ExpressionReference<ExpressionNode>), "All ExpressionReference are supposed to have the same size");
return *(reinterpret_cast<const TreeReference<TreeNode> *>(this));
}
int numberOfChildren() const {
@@ -44,32 +60,37 @@ public:
return TreeReference(node()->childAtIndex(i));
}
void addOperand(TreeReference<TreeNode> t) {
assert(t.m_pool == m_pool);
/*
void addChild(TreeReference<TreeNode> t) {
//assert(t.m_pool == m_pool);
//t.node()->retain();
TreeNode * deepCopy = m_pool->deepCopy(t.node());
m_pool->move(
t->node(),
t->next()
deepCopy,
node()->next()
);
*/
}
protected:
TreeReference(TreePool * pool) :
m_pool(pool)
{
int identifier = pool->generateIdentifier();
void * area = pool->alloc(sizeof(T));
TreeNode * n = new (area) T(identifier);
m_identifier = n->identifier();
assert(m_identifier == identifier);
//m_cachedNode = n;
void removeChild(TreeReference<TreeNode> t) {
m_pool->move(
t.node(),
m_pool->last()
);
t.node()->release();
}
T * node() const {
// TODO: Here, assert that the node type is indeed T
return static_cast<T*>(m_pool->node(m_identifier));
}
protected:
TreeReference(TreePool * pool) :
m_pool(pool)
{
TreeNode * node = new T();
m_identifier = node->identifier();
}
private:
TreeReference(TreePool * pool, TreeNode * node) :
m_pool(pool),