From 3cd101561465f99ca0854fb99cd18599178b9167 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 12 Jun 2018 13:56:20 +0200 Subject: [PATCH] Initial import --- Makefile | 12 +++ addition_node.h | 46 +++++++++++ expression_node.h | 22 +++++ expression_reference.h | 38 +++++++++ float_node.h | 41 ++++++++++ test.cpp | 107 +++++++++++++++++++++++++ tree_node.h | 178 +++++++++++++++++++++++++++++++++++++++++ tree_pool.cpp | 52 ++++++++++++ tree_pool.h | 79 ++++++++++++++++++ tree_reference.cpp | 14 ++++ tree_reference.h | 88 ++++++++++++++++++++ 11 files changed, 677 insertions(+) create mode 100644 Makefile create mode 100644 addition_node.h create mode 100644 expression_node.h create mode 100644 expression_reference.h create mode 100644 float_node.h create mode 100644 test.cpp create mode 100644 tree_node.h create mode 100644 tree_pool.cpp create mode 100644 tree_pool.h create mode 100644 tree_reference.cpp create mode 100644 tree_reference.h diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..992202f4f --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +OBJS = tree_pool.o tree_reference.o test.o +CXXFLAGS = -std=c++11 -g -O0 + +test: $(OBJS) + clang++ $(CXXFLAGS) $^ -o $@ + +clean: + rm -f $(OBJS) + +%.o: %.cpp + clang++ $(CXXFLAGS) -c $< -o $@ + diff --git a/addition_node.h b/addition_node.h new file mode 100644 index 000000000..b7c427f9e --- /dev/null +++ b/addition_node.h @@ -0,0 +1,46 @@ +#ifndef ADDITION_NODE_H +#define ADDITION_NODE_H + +#include "expression_reference.h" +#include "expression_node.h" + +class AdditionNode : public ExpressionNode { +public: + AdditionNode(int identifier) : ExpressionNode(identifier) { + printf("Create Addition\n"); + } +#if TREE_LOGGING + const char * description() const override { + return "Addition"; + } +#endif + float approximate() override { + float result = 0.0f; + for (int i=0; iapproximate(); + } + return result; + } +/* + Expression simplify() override { + // Scan operands, merge constants + Addition a = wrapped(this); + if (operand(0)->type() == Integer && operand(1)->type() == Integer) { + } + } + */ +}; + +class Addition : public ExpressionReference { +public: + Addition(Expression e1, Expression e2) : + ExpressionReference() + { + // Ok, here I want to take e1 and e2 as operands + } +}; + + +//typedef ExpressionReference Addition; + +#endif diff --git a/expression_node.h b/expression_node.h new file mode 100644 index 000000000..eeeb6c439 --- /dev/null +++ b/expression_node.h @@ -0,0 +1,22 @@ +#ifndef EXPRESSION_NODE_H +#define EXPRESSION_NODE_H + +#include "tree_node.h" + +class TreePool; + +class ExpressionNode : public TreeNode { +public: + ExpressionNode(int identifier) : TreeNode(identifier) {} + + static TreePool * Pool() { + static TreePool pool; + return &pool; + } + + virtual float approximate() = 0; + int numberOfOperands() { return numberOfChildren(); } + ExpressionNode * operand(int i) { return static_cast(childAtIndex(i)); } +}; + +#endif diff --git a/expression_reference.h b/expression_reference.h new file mode 100644 index 000000000..b851a67d4 --- /dev/null +++ b/expression_reference.h @@ -0,0 +1,38 @@ +#ifndef EXPRESSION_REFERENCE_H +#define EXPRESSION_REFERENCE_H + +#include "tree_reference.h" +#include "expression_node.h" + +#include + +template +class ExpressionReference : public TreeReference { +public: + ExpressionReference() : TreeReference(ExpressionNode::Pool()) { } + + /*ExpressionReference(const ExpressionReference & er) { + }*/ + + // Allow every ExpressionReference to be transformed into an ExpressionReference, i.e. Expression + operator ExpressionReference() const { + printf("ExpressionReference cast\n"); + // TODO: make sure this is kosher + // static_assert(sizeof(ExpressionReference) == sizeof(ExpressionReference), "All ExpressionReference are supposed to have the same size"); + return *(reinterpret_cast *>(this)); + } + + float approximate() const { + return this->node()->approximate(); + } + + /* + ExpressionReference simplify() { + return node()->simplify(); + } + */ +}; + +typedef ExpressionReference Expression; + +#endif diff --git a/float_node.h b/float_node.h new file mode 100644 index 000000000..6aae43a7f --- /dev/null +++ b/float_node.h @@ -0,0 +1,41 @@ +#ifndef FLOAT_NODE_H +#define FLOAT_NODE_H + +#include "expression_reference.h" +#include "expression_node.h" + +class FloatNode : public ExpressionNode { +public: + FloatNode(int identifier) : ExpressionNode(identifier) { + printf("Create float\n"); + } + size_t size() const override { + return sizeof(FloatNode); + } + float approximate() override { + return m_value; + } +#if TREE_LOGGING + const char * description() const override { + if (m_value > 1) { + return "BigFloat"; + } else { + return "SmallFloat"; + } + } +#endif + void setFloat(float f) { m_value = f; } +private: + float m_value; +}; + +class Float : public ExpressionReference { +public: + Float(float f) : ExpressionReference() { + this->node()->setFloat(f); + } +}; + +//typedef ExpressionReference Float; + +#endif diff --git a/test.cpp b/test.cpp new file mode 100644 index 000000000..23ebf14f3 --- /dev/null +++ b/test.cpp @@ -0,0 +1,107 @@ +#include "float_node.h" +#include "addition_node.h" +#include + + +int main() { + printf("Hello\n"); + + 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"); + Expression j = e; + 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(source); + uint32_t * dst = reinterpret_cast(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 diff --git a/tree_node.h b/tree_node.h new file mode 100644 index 000000000..7f9e50ef6 --- /dev/null +++ b/tree_node.h @@ -0,0 +1,178 @@ +#ifndef TREE_NODE_H +#define TREE_NODE_H + +#include +#include +#include + +#define TREE_LOGGING 1 + +#include + +class TreeNode { + //friend class TreeReference; + // friend class TreePool; +public: + virtual ~TreeNode() { + } + + + // Iterators + + class Iterator { + public: + Iterator(TreeNode * node) : m_node(node) {} + TreeNode * operator*() { return m_node; } + bool operator!=(const Iterator& it) const { return (m_node != it.m_node); } + protected: + TreeNode * m_node; + }; + + class DepthFirst { + public: + DepthFirst(TreeNode * node) : m_node(node) {} + class Iterator : public TreeNode::Iterator { + 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()); + m_node = m_node->next(); + return *this; + } + }; + Iterator begin() const { return Iterator(m_node); } + Iterator end() const { return Iterator(m_node->nextSibling()); } + private: + TreeNode * m_node; + }; + + DepthFirst depthFirstChildren() { return DepthFirst(this); } + + + int identifier() const { return m_identifier; } + +#if TREE_LOGGING + virtual const char * description() const { + return "UNKNOWN"; + } +#endif + + virtual size_t size() const { + return sizeof(TreeNode); + } + + void retain() { + m_referenceCounter++; + } + void release() { + m_referenceCounter--; + } + + int retainCount() { + return m_referenceCounter; + } + + virtual bool hasVariableNumberOfChildren() const { + return false; + } + + int numberOfChildren() const { + if (hasVariableNumberOfChildren()) { + int numberOfChildren = 0; + TreeNode * child = next(); + while (!child->isEndMarker()) { + child = child->nextSibling(); + numberOfChildren++; + } + return numberOfChildren; + } else { + // TODO: Make this function virtual + return 0; + } + } + + TreeNode * childAtIndex(int i) const { + assert(i >= 0); + assert(i < numberOfChildren()); + TreeNode * child = next(); + while (i>0) { + child = child->nextSibling(); + assert(child != nullptr); + assert(!child->isEndMarker()); + i--; + } + return child; + } + + /* + void addChild(TreeNode * node) { + // This will move node in the pool so that it becomes + // a children of this + pool->move(node, this + size()); + } + */ + +//private: + + // FIXME: Make this private + TreeNode(int identifier) : + m_identifier(identifier), + m_referenceCounter(1) + { + } + + constexpr static int EmptyIdentifier = 0; + constexpr static int EndMarkerIdentifier = 1; + + bool isEndMarker() const { + return (m_identifier == EndMarkerIdentifier); + } + + bool isEmpty() const { + return (m_identifier == EmptyIdentifier); + } + + void markAsEmpty() { + m_identifier = EmptyIdentifier; + } + + TreeNode * next() const { + // Simple version would be "return this + 1;", with pointer arithmetics taken care of by the compiler. + // Unfortunately, we want TreeNode to have a VARIABLE size + return reinterpret_cast(reinterpret_cast(const_cast(this)) + size()); + } + + TreeNode * nextSibling() const { + TreeNode * n = const_cast(this); + int depth = 0; + do { + if (n->hasVariableNumberOfChildren()) { + depth++; + } + /* + if (n->isEndMarker()) { + depth--; + } + */ + n = n->next(); + // TODO: Return nullptr if n overflows the pool! + assert(depth >= 0); + } while(depth != 0); + return n; + } + + size_t deepSize() const { + // TODO: Error handling + return + reinterpret_cast(nextSibling()) + - + reinterpret_cast(this); + ; + } + +//private: + int m_identifier; + int m_referenceCounter; +}; + +#endif diff --git a/tree_pool.cpp b/tree_pool.cpp new file mode 100644 index 000000000..af69c5494 --- /dev/null +++ b/tree_pool.cpp @@ -0,0 +1,52 @@ +#include "tree_pool.h" +#include +#include "tree_node.h" + +void * TreePool::alloc(size_t size) { + void * result = m_cursor; + m_cursor += size; + return result; +} + +void TreePool::dealloc(void * ptr, size_t size) { + // Step 1 - Compact the pool + memmove( + ptr, + static_cast(ptr) - size, + m_cursor - static_cast(ptr) + ); + m_cursor -= size; +} + +TreeNode * TreePool::node(int identifier) const { + for (TreeNode * node : *this) { + if (node->identifier() == identifier) { + return node; + } + } + /* + TreeNode * node = const_cast(reinterpret_cast(m_buffer)); + TreeNode * endOfPool = reinterpret_cast(m_cursor); + while (node < endOfPool) { + if (node->identifier() == identifier) { + return node; + } + node = node->next(); + } + */ + return nullptr; +} + +#if TREE_LOGGING +#include + +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("|\n"); +} +#endif + diff --git a/tree_pool.h b/tree_pool.h new file mode 100644 index 000000000..196b861bf --- /dev/null +++ b/tree_pool.h @@ -0,0 +1,79 @@ +#ifndef TREE_POOL_H +#define TREE_POOL_H + +#include + +#include "tree_node.h" + +class TreePool { +public: + TreePool() : m_lastIdentifier(0), m_cursor(m_buffer) {} + + int generateIdentifier() { + assert(node(m_lastIdentifier) == nullptr); + return m_lastIdentifier++; + } + void reclaimIdentifier(int identifier) { + } + + void * alloc(size_t size); + void dealloc(void * ptr, size_t size); + + TreeNode * node(int identifier) const; +#if TREE_LOGGING + void log(); +#endif + +private: + + TreeNode::DepthFirst::Iterator begin() const { return TreeNode::DepthFirst::Iterator(reinterpret_cast(const_cast(m_buffer))); } + TreeNode::DepthFirst::Iterator end() const { return TreeNode::DepthFirst::Iterator(reinterpret_cast(const_cast(m_cursor))); } + + 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 diff --git a/tree_reference.cpp b/tree_reference.cpp new file mode 100644 index 000000000..e42312dad --- /dev/null +++ b/tree_reference.cpp @@ -0,0 +1,14 @@ +#include "tree_reference.h" + +#if 0 +void TreeReference::addOperand(TreeReference t) { + // At this point, e has been copied. + // We can therefore pilfer its node! + Node * n = node(); + pool->move( + t->node(), + t->next() + ); + node->stealAsOperand(t->node()); +} +#endif diff --git a/tree_reference.h b/tree_reference.h new file mode 100644 index 000000000..a2c13f0c5 --- /dev/null +++ b/tree_reference.h @@ -0,0 +1,88 @@ +#ifndef TREE_REFERENCE_H +#define TREE_REFERENCE_H + +#include "tree_pool.h" +#include + +#include + +template +class TreeReference { +public: + TreeReference(const TreeReference & tr) : + m_pool(tr.m_pool), + m_identifier(tr.m_identifier) + { + printf("TreeReference copy\n"); + node()->retain(); + } + + ~TreeReference() { + TreeNode * node = this->node(); + node->release(); + if (node->retainCount() == 0) { + 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 + // Here, if needed, call reclaimIdentifier + for (TreeNode * child : node->depthFirstChildren()) { + m_pool->reclaimIdentifier(child->identifier()); + } + m_pool->reclaimIdentifier(node->identifier()); +#endif + static_cast(node)->~T(); + m_pool->dealloc(node, deepNodeSize); + } + } + + int numberOfChildren() const { + return node()->numberOfChildren(); + } + + TreeReference childAtIndex(int i) const { + return TreeReference(node()->childAtIndex(i)); + } + + void addOperand(TreeReference t) { + assert(t.m_pool == m_pool); + /* + m_pool->move( + t->node(), + t->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; + } + + T * node() const { + // TODO: Here, assert that the node type is indeed T + return static_cast(m_pool->node(m_identifier)); + } +private: + TreeReference(TreePool * pool, TreeNode * node) : + m_pool(pool), + m_identifier(node->identifier()) + //m_cachedNode(node) + { + node->retain(); + } + + + TreePool * m_pool; + int m_identifier; + //TreeNode * m_cachedNode; +}; + +#endif