diff --git a/addition_node.h b/addition_node.h index d6fe1efed..f68cce382 100644 --- a/addition_node.h +++ b/addition_node.h @@ -16,7 +16,11 @@ public: float approximate() override { float result = 0.0f; for (int i=0; iapproximate(); + float approximateI = child(i)->approximate(); + if (approximateI == -1) { + return -1; + } + result += approximateI; } return result; } diff --git a/expression_node.cpp b/expression_node.cpp index a112c302b..f759167c6 100644 --- a/expression_node.cpp +++ b/expression_node.cpp @@ -1,8 +1,7 @@ #include "expression_node.h" +#include "allocation_failed_expression_node.h" #include "expression_reference.h" -TreeNode * ExpressionNode::failedAllocationNode() { - return ExpressionRef::failedAllocationNode(); +TreeNode * ExpressionNode::staticFailedAllocationStaticNode() { + return ExpressionRef::staticFailedAllocationStaticNode(); } - - diff --git a/expression_node.h b/expression_node.h index 9c1fd6c25..3e2ef389c 100644 --- a/expression_node.h +++ b/expression_node.h @@ -5,7 +5,8 @@ class ExpressionNode : public TreeNode { public: - static TreeNode * failedAllocationNode(); + static TreeNode * staticFailedAllocationStaticNode(); + TreeNode * failedAllocationStaticNode() override { return staticFailedAllocationStaticNode(); } virtual float approximate() = 0; ExpressionNode * child(int i) { return static_cast(childTreeAtIndex(i)); } }; diff --git a/expression_reference.cpp b/expression_reference.cpp index 9c7c29d64..d404f3155 100644 --- a/expression_reference.cpp +++ b/expression_reference.cpp @@ -2,12 +2,12 @@ #include "allocation_failed_expression_node.h" template<> -TreeNode * ExpressionRef::failedAllocationNode() { +TreeNode * ExpressionRef::staticFailedAllocationStaticNode() { static AllocationFailedExpressionRef FailureRef; return FailureRef.node(); } template<> -ExpressionReference ExpressionRef::failedAllocationRef() { - return ExpressionReference(failedAllocationNode()); +ExpressionReference ExpressionRef::staticFailedAllocationStaticRef() { + return ExpressionReference(staticFailedAllocationStaticNode()); } diff --git a/expression_reference.h b/expression_reference.h index 390ab704a..9143432fe 100644 --- a/expression_reference.h +++ b/expression_reference.h @@ -12,12 +12,12 @@ public: using TreeReference::TreeReference; // Allow every ExpressionReference to be transformed into an ExpressionReference, i.e. Expression - operator ExpressionReference() { + operator ExpressionReference() const { return ExpressionReference(this->node()); } - static ExpressionReference failedAllocationRef(); - static TreeNode * failedAllocationNode(); + static ExpressionReference staticFailedAllocationStaticRef(); + static TreeNode * staticFailedAllocationStaticNode(); void addChild(ExpressionReference e) { if (!this->node()->isAllocationFailure()) { @@ -25,6 +25,12 @@ public: } } + void addChildAtIndex(ExpressionReference e, int index) { + if (!this->node()->isAllocationFailure()) { + TreeReference::addTreeChildAtIndex(e, index); + } + } + ExpressionReference childAtIndex(int i) { return ExpressionReference(TreeReference::treeChildAtIndex(i).node()); } @@ -33,7 +39,7 @@ public: TreeReference::replaceChildAtIndex(oldChildIndex, newChild); } - float approximate() { + float approximate() const { return this->castedNode()->approximate(); } diff --git a/layout_cursor.h b/layout_cursor.h index 1281b1479..9d7eaa6f8 100644 --- a/layout_cursor.h +++ b/layout_cursor.h @@ -25,7 +25,7 @@ public: printf("\n"); } - bool isDefined() { return m_layoutRef.isDefined(); } + bool isDefined() const { return m_layoutRef.isDefined(); } /* Getters and setters */ diff --git a/layout_node.cpp b/layout_node.cpp index fcc02d983..092d3ea2a 100644 --- a/layout_node.cpp +++ b/layout_node.cpp @@ -1,8 +1,9 @@ #include "layout_node.h" +#include "allocation_failed_layout_node.h" #include "layout_reference.h" -TreeNode * LayoutNode::failedAllocationNode() { - return LayoutRef::failedAllocationNode(); +TreeNode * LayoutNode::staticFailedAllocationStaticNode() { + return LayoutRef::staticFailedAllocationStaticNode(); } void LayoutNode::draw() { diff --git a/layout_node.h b/layout_node.h index 5f4ab2881..f81211f57 100644 --- a/layout_node.h +++ b/layout_node.h @@ -7,7 +7,8 @@ class LayoutCursor; class LayoutNode : public TreeNode { public: - static TreeNode * failedAllocationNode(); + static TreeNode * staticFailedAllocationStaticNode(); + TreeNode * failedAllocationStaticNode() override { return staticFailedAllocationStaticNode(); } /* Hierarchy */ LayoutNode * parent() const { return static_cast(parentTree()); } diff --git a/layout_reference.cpp b/layout_reference.cpp index 505ae3f57..2c4c93726 100644 --- a/layout_reference.cpp +++ b/layout_reference.cpp @@ -5,15 +5,15 @@ #include "char_layout_node.h" template<> -TreeNode * LayoutRef::failedAllocationNode() { +TreeNode * LayoutRef::staticFailedAllocationStaticNode() { static AllocationFailedLayoutRef FailureRef; return FailureRef.node(); } template -LayoutCursor LayoutReference::cursor() { +LayoutCursor LayoutReference::cursor() const { return LayoutCursor(this->castedNode()); } -template LayoutCursor LayoutReference::cursor(); -template LayoutCursor LayoutReference::cursor(); +template LayoutCursor LayoutReference::cursor() const; +template LayoutCursor LayoutReference::cursor() const; diff --git a/layout_reference.h b/layout_reference.h index 606e8f037..495c33801 100644 --- a/layout_reference.h +++ b/layout_reference.h @@ -14,13 +14,13 @@ public: /* Allow every LayoutReference to be transformed into a * LayoutReference, i.e. Layout */ - operator LayoutReference() { + operator LayoutReference() const { return LayoutReference(this->node()); } - static TreeNode * failedAllocationNode(); + static TreeNode * staticFailedAllocationStaticNode(); - LayoutCursor cursor(); + LayoutCursor cursor() const; LayoutReference childAtIndex(int i) { TreeReference treeRefChild = TreeReference::treeChildAtIndex(i); diff --git a/test.cpp b/test.cpp index 80f6df654..866ed9ebc 100644 --- a/test.cpp +++ b/test.cpp @@ -122,7 +122,7 @@ void testPoolExpressionAllocationFail() { AdditionRef a(f11, f3); float result = a.approximate(); assert(result == -1); - assert(ExpressionRef::failedAllocationNode()->retainCount() == 3); + assert(ExpressionRef::staticFailedAllocationStaticNode()->retainCount() == 3); f1.replaceWith(f11); float result2 = a1.approximate(); @@ -130,7 +130,7 @@ void testPoolExpressionAllocationFail() { } void testPoolExpressionAllocationFail2() { - printf("Pool expression allocation fail second test\n"); + printf("Pool expression allocation multiple fail test\n"); // Fill the pool for size 256 FloatRef f1(0.0f); @@ -153,33 +153,54 @@ void testPoolExpressionAllocationFail2() { FloatRef f9(8.0f); FloatRef f10(8.0f); - printf("\n"); - TreePool::sharedPool()->log(); - printf("\n"); f1.replaceWith(f9); result1 = a1.approximate(); assert(result1 == -1); - TreePool::sharedPool()->log(); - printf("\n"); f3.replaceWith(f10); result2 = a2.approximate(); assert(result2 == -1); - printf("\n"); - TreePool::sharedPool()->log(); result1 = a1.approximate(); - printf("a1 number children %d\n", a1.numberOfChildren()); - printf("a1 %f\n", result1); assert(result1 == -1); } +void testPoolExpressionAllocationFailOnImbricatedAdditions() { + printf("Pool expression allocation fail second test\n"); + + // 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); + AdditionRef a2(a1, f3); + float result2 = a2.approximate(); + assert(result2 == 3); + + FloatRef f4(3.0f); + FloatRef f5(4.0f); + FloatRef f6(5.0f); + FloatRef f7(6.0f); + FloatRef f8(7.0f); + // Allocation fail + FloatRef f9(7.0f); + f1.replaceWith(f9); + result2 = a2.approximate(); + assert(result2 == -1); + a2.removeChild(a1); + result2 = a2.approximate(); + assert(result2 == 2); +} + void testPoolLayoutAllocationFail() { printf("Pool layout allocation fail test\n"); // Fill the pool for size 256 CharLayoutRef char1('a'); - LayoutRef::failedAllocationNode(); + LayoutRef::staticFailedAllocationStaticNode(); CharLayoutRef char2('b'); CharLayoutRef char3('a'); CharLayoutRef char4('b'); @@ -205,7 +226,7 @@ void runTest(test t) { int main() { printf("\n*******************\nStart running tests\n*******************\n\n"); - ExpressionRef::failedAllocationNode(); + ExpressionRef::staticFailedAllocationStaticNode(); assert(TreePool::sharedPool()->numberOfNodes() == 1); runTest(testAddition); runTest(testPoolEmpties); @@ -213,6 +234,7 @@ int main() { runTest(testCursorMoveLeft); runTest(testPoolExpressionAllocationFail); runTest(testPoolExpressionAllocationFail2); + runTest(testPoolExpressionAllocationFailOnImbricatedAdditions); printf("\n*******************\nEnd of tests\n*******************\n\n"); return 0; } diff --git a/tree_node.cpp b/tree_node.cpp index 6a2d4e612..a26d57b96 100644 --- a/tree_node.cpp +++ b/tree_node.cpp @@ -127,6 +127,14 @@ int TreeNode::indexOfChild(const TreeNode * child) const { return indexOfChildByIdentifier(child->identifier()); } +int TreeNode::indexInParent() const { + TreeNode * p = parentTree(); + if (p == nullptr) { + return -1; + } + return p->indexOfChildByIdentifier(m_identifier); +} + bool TreeNode::hasChild(const TreeNode * child) const { if (child == nullptr) { return false; diff --git a/tree_node.h b/tree_node.h index b662d3f5c..7abdc8251 100644 --- a/tree_node.h +++ b/tree_node.h @@ -22,10 +22,15 @@ public: virtual size_t size() const = 0; int identifier() const { return m_identifier; } int retainCount() const { return m_referenceCounter; } + void setReferenceCounter(int refCount) { m_referenceCounter = refCount; } //TODO make this method privte with only friends that can access it virtual const char * description() const { return "UNKNOWN"; } virtual bool isAllocationFailure() const { return false; } + virtual TreeNode * failedAllocationStaticNode() { + assert(false); + return nullptr; + } // Node operations virtual void init(float f) {} @@ -48,6 +53,7 @@ public: TreeNode * childTreeAtIndex(int i) const; int indexOfChildByIdentifier(int childID) const; int indexOfChild(const TreeNode * child) const; + int indexInParent() const; bool hasChild(const TreeNode * child) const; bool hasAncestor(const TreeNode * node, bool includeSelf) const; bool hasSibling(const TreeNode * e) const; @@ -104,16 +110,6 @@ public: return reinterpret_cast(reinterpret_cast(const_cast(this)) + size()); } - // Hierarchy operations - void moveAndReleaseAllChildren(); - -protected: - TreeNode() : - m_identifier(-1), - m_referenceCounter(1) - { - } - TreeNode * nextSibling() const { int remainingNodesToVisit = numberOfChildren(); TreeNode * node = const_cast(this)->next(); @@ -125,6 +121,16 @@ protected: return node; } + // Hierarchy operations + void moveAndReleaseAllChildren(); + +protected: + TreeNode() : + m_identifier(-1), + m_referenceCounter(1) + { + } + /*TreeNode * lastDescendant() const { TreeNode * node = const_cast(this); int remainingNodesToVisit = node->numberOfChildren(); diff --git a/tree_pool.h b/tree_pool.h index 96a6edd1e..bfe382b65 100644 --- a/tree_pool.h +++ b/tree_pool.h @@ -19,13 +19,13 @@ public: TreeNode * createTreeNode() { int nodeIdentifier = generateIdentifier(); if (nodeIdentifier == -1) { - T::failedAllocationNode()->retain(); - return T::failedAllocationNode(); + T::staticFailedAllocationStaticNode()->retain(); + return T::staticFailedAllocationStaticNode(); } void * ptr = alloc(sizeof(T)); if (ptr == nullptr) { - T::failedAllocationNode()->retain(); - return T::failedAllocationNode(); + T::staticFailedAllocationStaticNode()->retain(); + return T::staticFailedAllocationStaticNode(); } T * node = new(ptr) T(); node->rename(nodeIdentifier); diff --git a/tree_reference.h b/tree_reference.h index 9c456cbce..a99cf2c1f 100644 --- a/tree_reference.h +++ b/tree_reference.h @@ -36,7 +36,7 @@ public: setIdentifierAndRetain(tr.identifier()); } - TreeReference clone() { + TreeReference clone() const { TreeNode * myNode = node(); if (myNode->isAllocationFailure()) { return TreeReference(TreePool::sharedPool()->node(TreePool::AllocationFailureIdentifier)); @@ -53,69 +53,70 @@ public: } } - bool isDefined() { return m_identifier >= 0 && node() != nullptr; } - bool isAllocationFailure() { return node()->isAllocationFailure(); } + bool isDefined() const { return m_identifier >= 0 && node() != nullptr; } + bool isAllocationFailure() const { return node()->isAllocationFailure(); } - int nodeRetainCount() { return node()->retainCount(); } + int nodeRetainCount() const { return node()->retainCount(); } void incrementNumberOfChildren() { return node()->incrementNumberOfChildren(); } void decrementNumberOfChildren() { return node()->decrementNumberOfChildren(); } - operator TreeReference() { + operator TreeReference() const { return TreeReference(this->node()); } - T * castedNode() { + T * castedNode() const { // TODO: Here, assert that the node type is indeed T // ?? Might be allocation failure, not T - updateIdentifier(); return static_cast(TreePool::sharedPool()->node(m_identifier)); } - TreeNode * node() { - updateIdentifier(); + TreeNode * node() const { return TreePool::sharedPool()->node(m_identifier); } - void updateIdentifier() { - /* If the node was replaced with an allocation failure, change the - * identifier */ - if (TreePool::sharedPool()->nodeWasReplacedWithAllocationFailure(m_identifier)) { - TreePool::sharedPool()->releaseAllocationFailure(m_identifier); - setIdentifierAndRetain(TreePool::AllocationFailureIdentifier); - } - } - int identifier() const { return m_identifier; } // Hierarchy - int numberOfChildren() { + int numberOfChildren() const { return node()->numberOfChildren(); } - TreeReference parent() { + TreeReference parent() const { return TreeReference(node()->parentTree()); } - TreeReference treeChildAtIndex(int i) { + TreeReference treeChildAtIndex(int i) const { return TreeReference(node()->childTreeAtIndex(i)); } // Hierarchy operations void addTreeChild(TreeReference t) { + return addTreeChildAtIndex(t, 0); + } + + void addTreeChildAtIndex(TreeReference t, int index) { + assert(index >= 0 && index <= numberOfChildren()); t.node()->retain(); - TreePool::sharedPool()->move(t.node(), node()->next()); + TreeNode * newChildPosition = node()->next(); + for (int i = 0; i < index; i++) { + newChildPosition = newChildPosition->nextSibling(); + } + TreePool::sharedPool()->move(t.node(), newChildPosition); node()->incrementNumberOfChildren(); } void removeChild(TreeReference t) { TreePool::sharedPool()->move(t.node(), TreePool::sharedPool()->last()); t.node()->release(); + node()->decrementNumberOfChildren(); } void replaceWith(TreeReference t) { TreeReference p = parent(); - p.replaceChildAtIndex(p.node()->indexOfChildByIdentifier(identifier()), t); + if (p.isDefined()) { + p.replaceChildAtIndex(p.node()->indexOfChildByIdentifier(identifier()), t); + } } void replaceChildAtIndex(int oldChildIndex, TreeReference newChild) { @@ -137,7 +138,9 @@ public: void replaceWithAllocationFailure() { TreeReference p = parent(); + int indexInParentNode = node()->indexInParent(); int currentRetainCount = node()->retainCount(); + TreeNode * staticAllocFailNode = castedNode()->failedAllocationStaticNode(); // Move the node to the end of the pool and decrease children count of parent TreePool::sharedPool()->move(node(), TreePool::sharedPool()->last()); @@ -148,16 +151,21 @@ public: // Release all children and delete the node in the pool node()->releaseChildrenAndDestroy(); - /* In case another ref is pointing to the node, register the identifier as - * AllocationFailure. If the retainCount is 1 (this reference is the only - * one pointing to the node), the pool will register the identifier as - * free. */ - TreePool::sharedPool()->registerIdentiferAsAllocationFailure(m_identifier, currentRetainCount - 1); - setIdentifierAndRetain(TreePool::AllocationFailureIdentifier); - - // Replace parent with AllocationFailure + /* Create an allocation failure node with the previous node id. We know + * there is room in the pool as we deleted the previous node and an + * AllocationFailure nodes size is smaller or equal to any other node size.*/ + //TODO static assert that the size is smaller + TreeNode * newAllocationFailureNode = TreePool::sharedPool()->deepCopy(staticAllocFailNode); + newAllocationFailureNode->rename(m_identifier); if (p.isDefined()) { - p.replaceWithAllocationFailure(); + assert(indexInParentNode >= 0); + /* Set the refCount to previousRefCount-1 because the previous parent is + * no longer retaining the node. When we add this node to the parent, it + * will retain it and increment the retain count. */ + newAllocationFailureNode->setReferenceCounter(currentRetainCount - 1); + p.addTreeChildAtIndex(newAllocationFailureNode, indexInParentNode); + } else { + newAllocationFailureNode->setReferenceCounter(currentRetainCount); } }