Fix AllocationFailure when multiple instances

This commit is contained in:
Léa Saviot
2018-06-28 17:59:06 +02:00
parent bd61298374
commit cb77fbe2ff
10 changed files with 133 additions and 39 deletions

View File

@@ -6,3 +6,8 @@ TreeNode * ExpressionRef::failedAllocationNode() {
static AllocationFailedExpressionRef FailureRef;
return FailureRef.node();
}
template<>
ExpressionReference<ExpressionNode> ExpressionRef::failedAllocationRef() {
return ExpressionReference<ExpressionNode>(failedAllocationNode());
}

View File

@@ -12,10 +12,11 @@ public:
using TreeReference<T>::TreeReference;
// Allow every ExpressionReference<T> to be transformed into an ExpressionReference<ExpressionNode>, i.e. Expression
operator ExpressionReference<ExpressionNode>() const {
operator ExpressionReference<ExpressionNode>() {
return ExpressionReference<ExpressionNode>(this->node());
}
static ExpressionReference<ExpressionNode> failedAllocationRef();
static TreeNode * failedAllocationNode();
void addChild(ExpressionReference<ExpressionNode> e) {
@@ -32,7 +33,7 @@ public:
TreeReference<T>::replaceChildAtIndex(oldChildIndex, newChild);
}
float approximate() const {
float approximate() {
return this->castedNode()->approximate();
}

View File

@@ -25,7 +25,7 @@ public:
printf("\n");
}
bool isDefined() const { return m_layoutRef.isDefined(); }
bool isDefined() { return m_layoutRef.isDefined(); }
/* Getters and setters */

View File

@@ -11,9 +11,9 @@ TreeNode * LayoutRef::failedAllocationNode() {
}
template <typename T>
LayoutCursor LayoutReference<T>::cursor() const {
LayoutCursor LayoutReference<T>::cursor() {
return LayoutCursor(this->castedNode());
}
template LayoutCursor LayoutReference<LayoutNode>::cursor() const;
template LayoutCursor LayoutReference<CharLayoutNode>::cursor() const;
template LayoutCursor LayoutReference<LayoutNode>::cursor();
template LayoutCursor LayoutReference<CharLayoutNode>::cursor();

View File

@@ -14,13 +14,13 @@ public:
/* Allow every LayoutReference<T> to be transformed into a
* LayoutReference<LayoutNode>, i.e. Layout */
operator LayoutReference<LayoutNode>() const {
operator LayoutReference<LayoutNode>() {
return LayoutReference<LayoutNode>(this->node());
}
static TreeNode * failedAllocationNode();
LayoutCursor cursor() const;
LayoutCursor cursor();
LayoutReference<LayoutNode> childAtIndex(int i) {
TreeReference<T> treeRefChild = TreeReference<T>::treeChildAtIndex(i);

View File

@@ -126,7 +126,7 @@ void testPoolExpressionAllocationFail() {
f1.replaceWith(f11);
float result2 = a1.approximate();
assert(result2 == 0);
assert(result2 == -1);
}
void testPoolExpressionAllocationFail2() {
@@ -211,7 +211,7 @@ int main() {
runTest(testPoolEmpties);
runTest(testCursorCreateAndRetain);
runTest(testCursorMoveLeft);
//runTest(testPoolExpressionAllocationFail);
runTest(testPoolExpressionAllocationFail);
runTest(testPoolExpressionAllocationFail2);
printf("\n*******************\nEnd of tests\n*******************\n\n");
return 0;

View File

@@ -8,23 +8,31 @@
void TreeNode::release() {
m_referenceCounter--;
if (m_referenceCounter == 0) {
if (numberOfChildren() != 0) {
int lastIdentifier = lastChild()->identifier();
TreeNode * child = next();
bool lastChildReleased = false;
while (!lastChildReleased) {
lastChildReleased = child->identifier() == lastIdentifier;
int nextSiblingIdentifier = lastChildReleased ? -1 : child->nextSibling()->identifier();
child->release();
if (nextSiblingIdentifier != -1) {
child = TreePool::sharedPool()->node(nextSiblingIdentifier);
}
releaseChildrenAndDestroy();
}
}
void TreeNode::releaseChildren() {
if (numberOfChildren() != 0) {
int lastIdentifier = lastChild()->identifier();
TreeNode * child = next();
bool lastChildReleased = false;
while (!lastChildReleased) {
lastChildReleased = child->identifier() == lastIdentifier;
int nextSiblingIdentifier = lastChildReleased ? -1 : child->nextSibling()->identifier();
child->release();
if (nextSiblingIdentifier != -1) {
child = TreePool::sharedPool()->node(nextSiblingIdentifier);
}
}
TreePool::sharedPool()->discardTreeNode(this);
}
}
void TreeNode::releaseChildrenAndDestroy() {
releaseChildren();
TreePool::sharedPool()->discardTreeNode(this);
}
// Hierarchy
TreeNode * TreeNode::parentTree() const {

View File

@@ -31,6 +31,8 @@ public:
virtual void init(float f) {}
void retain() { m_referenceCounter++; }
void release();
void releaseChildren();
void releaseChildrenAndDestroy();
void rename(int identifier) {
m_identifier = identifier;
m_referenceCounter = 1;
@@ -102,6 +104,9 @@ public:
return reinterpret_cast<TreeNode *>(reinterpret_cast<char *>(const_cast<TreeNode *>(this)) + size());
}
// Hierarchy operations
void moveAndReleaseAllChildren();
protected:
TreeNode() :
m_identifier(-1),

View File

@@ -8,6 +8,7 @@
class TreePool {
friend class TreeNode;
public:
static constexpr int AllocationFailureIdentifier = 0;
static TreePool * sharedPool();
// Node
@@ -19,7 +20,7 @@ public:
int nodeIdentifier = generateIdentifier();
if (nodeIdentifier == -1) {
T::failedAllocationNode()->retain();
return T::failedAllocationNode(); // TODO return static node "failedAllocation"
return T::failedAllocationNode();
}
void * ptr = alloc(sizeof(T));
if (ptr == nullptr) {
@@ -46,9 +47,34 @@ public:
return copy;
}
void log();
// Allocation failure handling
bool nodeWasReplacedWithAllocationFailure(int id) {
return m_allocationFailureRetainCount[id] > 0;
}
void releaseAllocationFailure(int id) {
int currrentRetainCount = m_allocationFailureRetainCount[id];
assert(currrentRetainCount > 0);
m_allocationFailureRetainCount[id] = currrentRetainCount - 1;
if (m_allocationFailureRetainCount[id] == 0) {
freeIdentifier(id);
}
}
void registerIdentiferAsAllocationFailure(int id, int retainCount) {
if (retainCount == 0) {
freeIdentifier(id);
} else {
assert(id >= 0 && id < MaxNumberOfNodes);
m_nodeForIdentifier[id] = first(); // TODO for now the first node in the pool is the allocation failure node (WARNING when implementing for Layouts... HAVE 2 POOLS?)
m_allocationFailureRetainCount[id] = retainCount;
}
}
// Debug
void log();
int numberOfNodes() const {
int count = 0;
AllPool nodes = const_cast<TreePool *>(this)->allNodes();
@@ -72,6 +98,7 @@ private:
void registerNode(TreeNode * node) {
m_nodeForIdentifier[node->identifier()] = node;
}
void renameNode(TreeNode * node) {
node->rename(generateIdentifier());
registerNode(node);
@@ -151,6 +178,7 @@ private:
char * m_cursor;
char m_buffer[BufferSize];
TreeNode * m_nodeForIdentifier[MaxNumberOfNodes];
int m_allocationFailureRetainCount[MaxNumberOfNodes];
};
#endif

View File

@@ -33,12 +33,15 @@ public:
inline bool operator==(TreeReference<TreeNode> t) { return m_identifier == t.identifier(); }
void setTo(const TreeReference & tr) {
m_identifier = tr.identifier();
TreePool::sharedPool()->node(m_identifier)->retain();
setIdentifierAndRetain(tr.identifier());
}
TreeReference<T> clone() const {
TreeNode * nodeCopy = TreePool::sharedPool()->deepCopy(node());
TreeReference<T> clone() {
TreeNode * myNode = node();
if (myNode->isAllocationFailure()) {
return TreeReference<T>(TreePool::sharedPool()->node(TreePool::AllocationFailureIdentifier));
}
TreeNode * nodeCopy = TreePool::sharedPool()->deepCopy(myNode);
return TreeReference<T>(nodeCopy);
}
@@ -50,39 +53,50 @@ public:
}
}
bool isDefined() const { return m_identifier >= 0 && TreePool::sharedPool()->node(m_identifier) != nullptr; }
bool isDefined() { return m_identifier >= 0 && node() != nullptr; }
bool isAllocationFailure() { return node()->isAllocationFailure(); }
int nodeRetainCount() const { return node()->retainCount(); }
int nodeRetainCount() { return node()->retainCount(); }
void incrementNumberOfChildren() { return node()->incrementNumberOfChildren(); }
void decrementNumberOfChildren() { return node()->decrementNumberOfChildren(); }
operator TreeReference<TreeNode>() const {
operator TreeReference<TreeNode>() {
return TreeReference<TreeNode>(this->node());
}
T * castedNode() const {
T * castedNode() {
// TODO: Here, assert that the node type is indeed T
// ?? Might be allocation failure, not T
updateIdentifier();
return static_cast<T*>(TreePool::sharedPool()->node(m_identifier));
}
TreeNode * node() const {
TreeNode * node() {
updateIdentifier();
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() const {
int numberOfChildren() {
return node()->numberOfChildren();
}
TreeReference<T> parent() const {
TreeReference<T> parent() {
return TreeReference(node()->parentTree());
}
TreeReference<T> treeChildAtIndex(int i) const {
TreeReference<T> treeChildAtIndex(int i) {
return TreeReference(node()->childTreeAtIndex(i));
}
@@ -105,7 +119,10 @@ public:
}
void replaceChildAtIndex(int oldChildIndex, TreeReference<TreeNode> newChild) {
// TODO decrement the children count of the new child parent
if (newChild.isAllocationFailure()) {
replaceWithAllocationFailure();
return;
}
TreeReference<TreeNode> p = newChild.parent();
if (p.isDefined()) {
p.decrementNumberOfChildren();
@@ -118,6 +135,32 @@ public:
oldChild.node()->release();
}
void replaceWithAllocationFailure() {
TreeReference<TreeNode> p = parent();
int currentRetainCount = node()->retainCount();
// Move the node to the end of the pool and decrease children count of parent
TreePool::sharedPool()->move(node(), TreePool::sharedPool()->last());
if (p.isDefined()) {
p.decrementNumberOfChildren();
}
// 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
if (p.isDefined()) {
p.replaceWithAllocationFailure();
}
}
void swapChildren(int i, int j) {
assert(i >= 0 && i < numberOfChildren());
assert(j >= 0 && j < numberOfChildren());
@@ -143,10 +186,14 @@ protected:
if (node == nullptr) {
m_identifier = -1;
} else {
m_identifier = node->identifier();
node->retain();
setIdentifierAndRetain(node->identifier());
}
}
void setIdentifierAndRetain(int newId) {
m_identifier = newId;
node()->retain();
}
private:
int m_identifier;
};