mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-24 00:00:44 +01:00
Allocation failure fix and test
This commit is contained in:
@@ -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<AdditionNode> {
|
||||
@@ -41,8 +44,8 @@ public:
|
||||
AdditionRef(ExpressionRef e1, ExpressionRef e2) :
|
||||
ExpressionReference<AdditionNode>()
|
||||
{
|
||||
addOperand(e2);
|
||||
addOperand(e1);
|
||||
addChild(e2);
|
||||
addChild(e1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define ALLOCATION_FAILED_EXPRESSION_NODE_H
|
||||
|
||||
#include "expression_node.h"
|
||||
#include "expression_reference.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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<AllocationFailedExpressionNode> {
|
||||
|
||||
21
allocation_failed_layout_node.h
Normal file
21
allocation_failed_layout_node.h
Normal file
@@ -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<AllocationFailedLayoutNode> {
|
||||
public:
|
||||
AllocationFailedLayoutRef() : LayoutReference<AllocationFailedLayoutNode>() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
8
expression_node.cpp
Normal file
8
expression_node.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "expression_node.h"
|
||||
#include "expression_reference.h"
|
||||
|
||||
TreeNode * ExpressionNode::failedAllocationNode() {
|
||||
return ExpressionRef::failedAllocationNode();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
class ExpressionNode : public TreeNode {
|
||||
public:
|
||||
static TreeNode * failedAllocationNode();
|
||||
virtual float approximate() = 0;
|
||||
ExpressionNode * child(int i) { return static_cast<ExpressionNode *>(childTreeAtIndex(i)); }
|
||||
};
|
||||
|
||||
8
expression_reference.cpp
Normal file
8
expression_reference.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "expression_reference.h"
|
||||
#include "allocation_failed_expression_node.h"
|
||||
|
||||
template<>
|
||||
TreeNode * ExpressionRef::failedAllocationNode() {
|
||||
static AllocationFailedExpressionRef FailureRef;
|
||||
return FailureRef.node();
|
||||
}
|
||||
@@ -16,8 +16,12 @@ public:
|
||||
return ExpressionReference<ExpressionNode>(this->node());
|
||||
}
|
||||
|
||||
void addOperand(ExpressionReference<ExpressionNode> e) {
|
||||
TreeReference<T>::addChild(e);
|
||||
static TreeNode * failedAllocationNode();
|
||||
|
||||
void addChild(ExpressionReference<ExpressionNode> e) {
|
||||
if (!this->node()->isAllocationFailure()) {
|
||||
TreeReference<T>::addTreeChild(e);
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionReference<ExpressionNode> childAtIndex(int i) {
|
||||
|
||||
@@ -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<FloatNode> {
|
||||
public:
|
||||
FloatRef(float f) : ExpressionReference<FloatNode>() {
|
||||
this->node()->setFloat(f);
|
||||
this->uncastedNode()->init(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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<HorizontalLayoutNode> {
|
||||
public:
|
||||
HorizontalLayoutRef() : LayoutReference<HorizontalLayoutNode>() {}
|
||||
HorizontalLayoutRef(LayoutRef l) : LayoutReference<HorizontalLayoutNode>() {
|
||||
addChild(l);
|
||||
addTreeChild(l);
|
||||
}
|
||||
|
||||
HorizontalLayoutRef(LayoutRef l1, LayoutRef l2) : LayoutReference<HorizontalLayoutNode>() {
|
||||
addChild(l2);
|
||||
addChild(l1);
|
||||
addTreeChild(l2);
|
||||
addTreeChild(l1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -7,6 +7,8 @@ class LayoutCursor;
|
||||
|
||||
class LayoutNode : public TreeNode {
|
||||
public:
|
||||
static TreeNode * failedAllocationNode();
|
||||
|
||||
/* Hierarchy */
|
||||
LayoutNode * parent() const { return static_cast<LayoutNode *>(parentTree()); }
|
||||
|
||||
|
||||
@@ -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 <typename T>
|
||||
LayoutCursor LayoutReference<T>::cursor() const {
|
||||
return LayoutCursor(this->node());
|
||||
|
||||
@@ -18,6 +18,8 @@ public:
|
||||
return LayoutReference<LayoutNode>(this->node());
|
||||
}
|
||||
|
||||
static TreeNode * failedAllocationNode();
|
||||
|
||||
LayoutCursor cursor() const;
|
||||
|
||||
LayoutReference<LayoutNode> childAtIndex(int i) {
|
||||
|
||||
63
test.cpp
63
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,14 +15,16 @@ public:
|
||||
TreeNode * last() const { return reinterpret_cast<TreeNode *>(const_cast<char *>(m_cursor)); }
|
||||
|
||||
template <typename T>
|
||||
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);
|
||||
|
||||
@@ -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<T*>(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<TreeNode> t) {
|
||||
void addTreeChild(TreeReference<TreeNode> t) {
|
||||
t.node()->retain();
|
||||
TreePool::sharedPool()->move(t.node(), node()->next());
|
||||
node()->incrementNumberOfChildren();
|
||||
@@ -90,10 +96,12 @@ public:
|
||||
}
|
||||
|
||||
void replaceWith(TreeReference<TreeNode> t) {
|
||||
parent().replaceChild(node()->indexOfChild(t.node()), t);
|
||||
TreeReference<T> p = parent();
|
||||
p.replaceChildAtIndex(p.node()->indexOfChildByIdentifier(identifier()), t);
|
||||
}
|
||||
|
||||
void replaceChildAtIndex(int oldChildIndex, TreeReference<TreeNode> newChild) {
|
||||
// TODO decrement the children count of the new child parent
|
||||
assert(oldChildIndex >= 0 && oldChildIndex < numberOfChildren());
|
||||
TreeReference<T> oldChild = treeChildAtIndex(oldChildIndex);
|
||||
TreePool::sharedPool()->move(newChild.node(), oldChild.node()->next());
|
||||
|
||||
Reference in New Issue
Block a user