From 46d56ade21e5e4acbca58ec514cc8a3ea066e076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 28 Jun 2018 14:50:45 +0200 Subject: [PATCH] Allocation failure fix and test --- addition_node.h | 15 ++++--- allocation_failed_expression_node.h | 3 ++ allocation_failed_layout_node.h | 21 ++++++++++ expression_node.cpp | 8 ++++ expression_node.h | 1 + expression_reference.cpp | 8 ++++ expression_reference.h | 8 +++- float_node.h | 3 +- horizontal_layout_node.h | 10 +++-- layout_node.cpp | 5 +++ layout_node.h | 2 + layout_reference.cpp | 7 ++++ layout_reference.h | 2 + test.cpp | 63 ++++++++++++++++++++++++----- tree_node.h | 3 ++ tree_pool.h | 8 ++-- tree_reference.h | 12 +++++- 17 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 allocation_failed_layout_node.h create mode 100644 expression_node.cpp create mode 100644 expression_reference.cpp diff --git a/addition_node.h b/addition_node.h index 4476a7374..d6fe1efed 100644 --- a/addition_node.h +++ b/addition_node.h @@ -6,11 +6,9 @@ class AdditionNode : public ExpressionNode { public: -#if TREE_LOGGING const char * description() const override { return "Addition"; } -#endif size_t size() const override { return sizeof(AdditionNode); @@ -23,8 +21,11 @@ public: return result; } - int numberOfChildren() const override { - return 2; + int numberOfChildren() const override { return m_numberOfChildren; } + void incrementNumberOfChildren() override { m_numberOfChildren++; } + void decrementNumberOfChildren() override { + assert(m_numberOfChildren > 0); + m_numberOfChildren--; } /* Expression simplify() override { @@ -34,6 +35,8 @@ public: } } */ +private: + int m_numberOfChildren; }; class AdditionRef : public ExpressionReference { @@ -41,8 +44,8 @@ public: AdditionRef(ExpressionRef e1, ExpressionRef e2) : ExpressionReference() { - addOperand(e2); - addOperand(e1); + addChild(e2); + addChild(e1); } }; diff --git a/allocation_failed_expression_node.h b/allocation_failed_expression_node.h index 4e33c71d1..fae6873a0 100644 --- a/allocation_failed_expression_node.h +++ b/allocation_failed_expression_node.h @@ -2,6 +2,8 @@ #define ALLOCATION_FAILED_EXPRESSION_NODE_H #include "expression_node.h" +#include "expression_reference.h" +#include class AllocationFailedExpressionNode : public ExpressionNode { public: @@ -12,6 +14,7 @@ public: size_t size() const override { return sizeof(AllocationFailedExpressionNode); } const char * description() const override { return "Allocation Failed"; } int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } }; class AllocationFailedExpressionRef : public ExpressionReference { diff --git a/allocation_failed_layout_node.h b/allocation_failed_layout_node.h new file mode 100644 index 000000000..d41c329ed --- /dev/null +++ b/allocation_failed_layout_node.h @@ -0,0 +1,21 @@ +#ifndef ALLOCATION_FAILED_LAYOUT_NODE_H +#define ALLOCATION_FAILED_LAYOUT_NODE_H + +#include "layout_node.h" +#include "layout_reference.h" + +class AllocationFailedLayoutNode : public LayoutNode { +public: + // TreeNode + size_t size() const override { return sizeof(AllocationFailedLayoutNode); } + const char * description() const override { return "Allocation Failed"; } + int numberOfChildren() const override { return 0; } + bool isAllocationFailure() const override { return true; } +}; + +class AllocationFailedLayoutRef : public LayoutReference { +public: + AllocationFailedLayoutRef() : LayoutReference() {} +}; + +#endif diff --git a/expression_node.cpp b/expression_node.cpp new file mode 100644 index 000000000..a112c302b --- /dev/null +++ b/expression_node.cpp @@ -0,0 +1,8 @@ +#include "expression_node.h" +#include "expression_reference.h" + +TreeNode * ExpressionNode::failedAllocationNode() { + return ExpressionRef::failedAllocationNode(); +} + + diff --git a/expression_node.h b/expression_node.h index 6512d864c..9c1fd6c25 100644 --- a/expression_node.h +++ b/expression_node.h @@ -5,6 +5,7 @@ class ExpressionNode : public TreeNode { public: + static TreeNode * failedAllocationNode(); virtual float approximate() = 0; ExpressionNode * child(int i) { return static_cast(childTreeAtIndex(i)); } }; diff --git a/expression_reference.cpp b/expression_reference.cpp new file mode 100644 index 000000000..b1ef3e524 --- /dev/null +++ b/expression_reference.cpp @@ -0,0 +1,8 @@ +#include "expression_reference.h" +#include "allocation_failed_expression_node.h" + +template<> +TreeNode * ExpressionRef::failedAllocationNode() { + static AllocationFailedExpressionRef FailureRef; + return FailureRef.node(); +} diff --git a/expression_reference.h b/expression_reference.h index efd6291ba..78e3f1338 100644 --- a/expression_reference.h +++ b/expression_reference.h @@ -16,8 +16,12 @@ public: return ExpressionReference(this->node()); } - void addOperand(ExpressionReference e) { - TreeReference::addChild(e); + static TreeNode * failedAllocationNode(); + + void addChild(ExpressionReference e) { + if (!this->node()->isAllocationFailure()) { + TreeReference::addTreeChild(e); + } } ExpressionReference childAtIndex(int i) { diff --git a/float_node.h b/float_node.h index 0942c4f3b..555e714a9 100644 --- a/float_node.h +++ b/float_node.h @@ -14,6 +14,7 @@ public: return m_value > 1 ? "BigFloat" : "SmallFloat"; } void setFloat(float f) { m_value = f; } + void init(float f) override { m_value = f; } private: float m_value; }; @@ -21,7 +22,7 @@ private: class FloatRef : public ExpressionReference { public: FloatRef(float f) : ExpressionReference() { - this->node()->setFloat(f); + this->uncastedNode()->init(f); } }; diff --git a/horizontal_layout_node.h b/horizontal_layout_node.h index eeafa600c..6fff30feb 100644 --- a/horizontal_layout_node.h +++ b/horizontal_layout_node.h @@ -18,6 +18,10 @@ public: int numberOfChildren() const override { return m_numberOfChildren; } void incrementNumberOfChildren() override { m_numberOfChildren++; } + void decrementNumberOfChildren() override { + assert(m_numberOfChildren > 0); + m_numberOfChildren--; + } void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override { if (this == cursor->layoutReference().node()) { @@ -78,12 +82,12 @@ class HorizontalLayoutRef : public LayoutReference { public: HorizontalLayoutRef() : LayoutReference() {} HorizontalLayoutRef(LayoutRef l) : LayoutReference() { - addChild(l); + addTreeChild(l); } HorizontalLayoutRef(LayoutRef l1, LayoutRef l2) : LayoutReference() { - addChild(l2); - addChild(l1); + addTreeChild(l2); + addTreeChild(l1); } }; diff --git a/layout_node.cpp b/layout_node.cpp index 17a11e301..fcc02d983 100644 --- a/layout_node.cpp +++ b/layout_node.cpp @@ -1,4 +1,9 @@ #include "layout_node.h" +#include "layout_reference.h" + +TreeNode * LayoutNode::failedAllocationNode() { + return LayoutRef::failedAllocationNode(); +} void LayoutNode::draw() { for (LayoutNode * child : children()) { diff --git a/layout_node.h b/layout_node.h index 4fbafe641..5f4ab2881 100644 --- a/layout_node.h +++ b/layout_node.h @@ -7,6 +7,8 @@ class LayoutCursor; class LayoutNode : public TreeNode { public: + static TreeNode * failedAllocationNode(); + /* Hierarchy */ LayoutNode * parent() const { return static_cast(parentTree()); } diff --git a/layout_reference.cpp b/layout_reference.cpp index 52ffecc96..35de1075f 100644 --- a/layout_reference.cpp +++ b/layout_reference.cpp @@ -1,8 +1,15 @@ #include "layout_reference.h" #include "layout_cursor.h" +#include "allocation_failed_layout_node.h" #include "layout_node.h" #include "char_layout_node.h" +template<> +TreeNode * LayoutRef::failedAllocationNode() { + static AllocationFailedLayoutRef FailureRef; + return FailureRef.node(); +} + template LayoutCursor LayoutReference::cursor() const { return LayoutCursor(this->node()); diff --git a/layout_reference.h b/layout_reference.h index 31760fcfb..0e347cfa0 100644 --- a/layout_reference.h +++ b/layout_reference.h @@ -18,6 +18,8 @@ public: return LayoutReference(this->node()); } + static TreeNode * failedAllocationNode(); + LayoutCursor cursor() const; LayoutReference childAtIndex(int i) { diff --git a/test.cpp b/test.cpp index 0d472e05a..16a05fd63 100644 --- a/test.cpp +++ b/test.cpp @@ -94,25 +94,66 @@ void testCursorMoveLeft() { assert(aChar.nodeRetainCount() == 3); } -void testPoolAllocationFail() { - printf("Pool allocation fail test\n"); +void testPoolExpressionAllocationFail() { + printf("Pool expression allocation fail test\n"); - // Fill the pool for size 256 - - // Allocation fail - assert(TreePool::sharedPool()->numberOfNodes() == 0); - AllocationFailedExpressionRef a; + ExpressionRef::failedAllocationNode(); assert(TreePool::sharedPool()->numberOfNodes() == 1); + // Fill the pool for size 256 + FloatRef f1(0.0f); + FloatRef f2(1.0f); + AdditionRef a1(f1, f2); + float result1 = a1.approximate(); + assert(result1 == 1); + + FloatRef f3(2.0f); + FloatRef f4(3.0f); + FloatRef f5(4.0f); + FloatRef f6(5.0f); + FloatRef f7(6.0f); + FloatRef f8(7.0f); + FloatRef f9(8.0f); + + // Allocation fail + FloatRef f11(10.0f); + AdditionRef a(f11, f3); + float result = a.approximate(); + assert(result == -1); + assert(ExpressionRef::failedAllocationNode()->retainCount() == 3); + + f1.replaceWith(f11); + float result2 = a1.approximate(); + assert(result2 == 0); + TreePool::sharedPool()->log(); +} + +void testPoolLayoutAllocationFail() { + printf("Pool layout allocation fail test\n"); + + // Fill the pool for size 256 + CharLayoutRef char1('a'); + LayoutRef::failedAllocationNode(); + CharLayoutRef char2('b'); + CharLayoutRef char3('a'); + CharLayoutRef char4('b'); + CharLayoutRef char5('a'); + CharLayoutRef char6('b'); + CharLayoutRef char7('a'); + CharLayoutRef char8('b'); + CharLayoutRef char9('a'); + CharLayoutRef char10('b'); + + // Allocation fail + CharLayoutRef char11('a'); /*Expression e = ; - e.simplify*/ + e.simplify*/ } typedef void (test)(); void runTest(test t) { - assert(TreePool::sharedPool()->numberOfNodes() == 0); + // TODO add aserts on the pool size once we decide to create allocationFailureNodesFromTheStart t(); - assert(TreePool::sharedPool()->numberOfNodes() == 0); } int main() { @@ -121,7 +162,7 @@ int main() { runTest(testPoolEmpties); runTest(testCursorCreateAndRetain); runTest(testCursorMoveLeft); - runTest(testPoolAllocationFail); + runTest(testPoolExpressionAllocationFail); printf("\n*******************\nEnd of tests\n*******************\n\n"); return 0; } diff --git a/tree_node.h b/tree_node.h index 5cddb5fa4..a56e63f06 100644 --- a/tree_node.h +++ b/tree_node.h @@ -25,8 +25,10 @@ public: virtual const char * description() const { return "UNKNOWN"; } + virtual bool isAllocationFailure() const { return false; } // Node operations + virtual void init(float f) {} void retain() { m_referenceCounter++; } void release(); void rename(int identifier) { @@ -39,6 +41,7 @@ public: TreeNode * editableRootTree(); virtual int numberOfChildren() const = 0; virtual void incrementNumberOfChildren() {} //TODO Put an assert false + virtual void decrementNumberOfChildren() {} //TODO Put an assert false //TODO what if somebody i stealing a unary tree's only child ? int numberOfDescendants(bool includeSelf) const; TreeNode * childTreeAtIndex(int i) const; int indexOfChildByIdentifier(int childID) const; diff --git a/tree_pool.h b/tree_pool.h index 41b9770d8..002eecbc3 100644 --- a/tree_pool.h +++ b/tree_pool.h @@ -15,14 +15,16 @@ public: TreeNode * last() const { return reinterpret_cast(const_cast(m_cursor)); } template - T * createTreeNode() { + TreeNode * createTreeNode() { int nodeIdentifier = generateIdentifier(); if (nodeIdentifier == -1) { - return nullptr; // TODO return static node "failedAllocation" + T::failedAllocationNode()->retain(); + return T::failedAllocationNode(); // TODO return static node "failedAllocation" } void * ptr = alloc(sizeof(T)); if (ptr == nullptr) { - return nullptr; + T::failedAllocationNode()->retain(); + return T::failedAllocationNode(); } T * node = new(ptr) T(); node->rename(nodeIdentifier); diff --git a/tree_reference.h b/tree_reference.h index cbe4631d4..4afe8e386 100644 --- a/tree_reference.h +++ b/tree_reference.h @@ -58,9 +58,15 @@ public: T * node() const { // TODO: Here, assert that the node type is indeed T + // ?? Might be allocation failure, not T return static_cast(TreePool::sharedPool()->node(m_identifier)); } + TreeNode * uncastedNode() const { + return TreePool::sharedPool()->node(m_identifier); + } + + int identifier() const { return m_identifier; } // Hierarchy @@ -78,7 +84,7 @@ public: // Hierarchy operations - void addChild(TreeReference t) { + void addTreeChild(TreeReference t) { t.node()->retain(); TreePool::sharedPool()->move(t.node(), node()->next()); node()->incrementNumberOfChildren(); @@ -90,10 +96,12 @@ public: } void replaceWith(TreeReference t) { - parent().replaceChild(node()->indexOfChild(t.node()), t); + TreeReference p = parent(); + p.replaceChildAtIndex(p.node()->indexOfChildByIdentifier(identifier()), t); } void replaceChildAtIndex(int oldChildIndex, TreeReference newChild) { + // TODO decrement the children count of the new child parent assert(oldChildIndex >= 0 && oldChildIndex < numberOfChildren()); TreeReference oldChild = treeChildAtIndex(oldChildIndex); TreePool::sharedPool()->move(newChild.node(), oldChild.node()->next());