diff options
author | Morgan Deters <mdeters@gmail.com> | 2010-04-14 06:21:26 +0000 |
---|---|---|
committer | Morgan Deters <mdeters@gmail.com> | 2010-04-14 06:21:26 +0000 |
commit | 7c83d004874a46efe36d58717f7a4d72553b3693 (patch) | |
tree | 40fdb91a99c0ea0a9e4ce884126c0f572959a003 /src/expr/node_builder.h | |
parent | 12a8a7f9a90e45e8313f26af527a52e6dda943d3 (diff) |
* Better dependency tracking for unit test building and linking, and
auto-generated headers (metakind.h etc.), so they don't have to be
recompiled every time. This drastically improves build time when
only small updates are made.
* Added "memory.h" unit test header for checking out-of-memory
conditions. cdlist_black uses it.
* Added helpful output when you "make lcov" in a non-coverage-enabled
build.
* Removed strict aliasing warning when compiling metakind.h header
with optimization on.
* Removed const version of NodeBuilder::operator Node()---it was
poorly performing, better to not permit it---and fixed the
convenience builders to use the non-const version
(re: code review #63)
* Color-coded test output on capable terminals.
* Fixed some warnings in unit tests.
Diffstat (limited to 'src/expr/node_builder.h')
-rw-r--r-- | src/expr/node_builder.h | 288 |
1 files changed, 37 insertions, 251 deletions
diff --git a/src/expr/node_builder.h b/src/expr/node_builder.h index 5c0cfb987..c854b6b80 100644 --- a/src/expr/node_builder.h +++ b/src/expr/node_builder.h @@ -58,12 +58,11 @@ ** (b) The Node under construction is NOT already in the ** NodeManager's pool. ** - ** When a Node is extracted (see the non-const version of - ** NodeBuilderBase<>::operator Node()), we convert the NodeBuilder to - ** a Node and make sure the reference counts are properly maintained. - ** That means we must ensure there are no reference-counting errors - ** among the node's children, that the children aren't re-decremented - ** on clear() or NodeBuilder destruction, and that the returned Node + ** When a Node is extracted, we convert the NodeBuilder to a Node and + ** make sure the reference counts are properly maintained. That + ** means we must ensure there are no reference-counting errors among + ** the node's children, that the children aren't re-decremented on + ** clear() or NodeBuilder destruction, and that the returned Node ** wraps a NodeValue with a reference count of 1. ** ** 0. If a VARIABLE, treat similarly to 1(b), except that we @@ -109,37 +108,6 @@ ** decremented, which makes it eligible for collection before the ** builder has even returned it! So this is a no-no. ** - ** For the _const_ version of NodeBuilderBase<>::operator Node(), no - ** reference-count modifications or anything else can take place! - ** Therefore, we have a slightly more expensive version: - ** - ** 0. If a VARIABLE, treat similarly to 1(b), except that we - ** know there are no children, and we don't keep - ** VARIABLE-kinded Nodes in the NodeManager pool. - ** - ** 1(a). The existing NodeManager pool entry is returned; we leave - ** child reference counts alone and get them at NodeBuilder - ** destruction time. - ** - ** 1(b). A new heap-allocated NodeValue must be constructed and all - ** settings and children from d_inlineNv copied into it. - ** This new NodeValue is put into the NodeManager's pool. - ** The NodeBuilder cannot be marked as "used", so we - ** increment all child reference counts (which will be - ** decremented to match on destruction of the NodeBuilder). - ** We return a Node wrapper for this new NodeValue, which - ** increments its reference count. - ** - ** 2(a). The existing NodeManager pool entry is returned; we leave - ** child reference counts alone and get them at NodeBuilder - ** destruction time. - ** - ** 2(b). The heap-allocated d_nv cannot be "cropped" to the correct - ** size; we create a copy, increment child reference counts, - ** place this copy into the NodeManager pool, and return a - ** Node wrapper around it. The child reference counts will - ** be decremented to match at NodeBuilder destruction time. - ** ** There are also two cases when the NodeBuilder is clear()'ed: ** ** 1. d_nv == &d_inlineNv (NodeBuilder using the user-supplied @@ -285,9 +253,8 @@ protected: /** * Returns whether or not this NodeBuilder has been "used"---i.e., - * whether a Node has been extracted with [the non-const version of] - * operator Node(). Internally, this state is represented by d_nv - * pointing to NULL. + * whether a Node has been extracted with operator Node(). + * Internally, this state is represented by d_nv pointing to NULL. */ inline bool isUsed() const { return EXPECT_FALSE( d_nv == NULL ); @@ -570,10 +537,7 @@ public: return static_cast<Builder&>(*this); } - // two versions, so we can support extraction from (const) - // NodeBuilders which are temporaries appearing as rvalues operator Node(); - operator Node() const; inline void toStream(std::ostream& out, int depth = -1) const { Assert(!isUsed(), "NodeBuilder is one-shot only; " @@ -890,19 +854,19 @@ inline OrNodeBuilder AndNodeBuilder::operator||(const NodeTemplate<rc>& n) { inline AndNodeBuilder& operator&&(AndNodeBuilder& a, const AndNodeBuilder& b) { - return a && Node(b.d_eb); + return a && Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline AndNodeBuilder& operator&&(AndNodeBuilder& a, const OrNodeBuilder& b) { - return a && Node(b.d_eb); + return a && Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline OrNodeBuilder operator||(AndNodeBuilder& a, const AndNodeBuilder& b) { - return a || Node(b.d_eb); + return a || Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline OrNodeBuilder operator||(AndNodeBuilder& a, const OrNodeBuilder& b) { - return a || Node(b.d_eb); + return a || Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> @@ -918,19 +882,19 @@ inline OrNodeBuilder& OrNodeBuilder::operator||(const NodeTemplate<rc>& n) { inline AndNodeBuilder operator&&(OrNodeBuilder& a, const AndNodeBuilder& b) { - return a && Node(b.d_eb); + return a && Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline AndNodeBuilder operator&&(OrNodeBuilder& a, const OrNodeBuilder& b) { - return a && Node(b.d_eb); + return a && Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline OrNodeBuilder& operator||(OrNodeBuilder& a, const AndNodeBuilder& b) { - return a || Node(b.d_eb); + return a || Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline OrNodeBuilder& operator||(OrNodeBuilder& a, const OrNodeBuilder& b) { - return a || Node(b.d_eb); + return a || Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> @@ -952,27 +916,27 @@ inline MultNodeBuilder PlusNodeBuilder::operator*(const NodeTemplate<rc>& n) { inline PlusNodeBuilder& operator+(PlusNodeBuilder& a, const PlusNodeBuilder& b) { - return a + Node(b.d_eb); + return a + Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline PlusNodeBuilder& operator+(PlusNodeBuilder& a, const MultNodeBuilder& b) { - return a + Node(b.d_eb); + return a + Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline PlusNodeBuilder& operator-(PlusNodeBuilder&a, const PlusNodeBuilder& b) { - return a - Node(b.d_eb); + return a - Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline PlusNodeBuilder& operator-(PlusNodeBuilder& a, const MultNodeBuilder& b) { - return a - Node(b.d_eb); + return a - Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline MultNodeBuilder operator*(PlusNodeBuilder& a, const PlusNodeBuilder& b) { - return a * Node(b.d_eb); + return a * Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline MultNodeBuilder operator*(PlusNodeBuilder& a, const MultNodeBuilder& b) { - return a * Node(b.d_eb); + return a * Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> @@ -994,27 +958,27 @@ inline MultNodeBuilder& MultNodeBuilder::operator*(const NodeTemplate<rc>& n) { inline PlusNodeBuilder operator+(MultNodeBuilder& a, const PlusNodeBuilder& b) { - return a + Node(b.d_eb); + return a + Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline PlusNodeBuilder operator+(MultNodeBuilder& a, const MultNodeBuilder& b) { - return a + Node(b.d_eb); + return a + Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline PlusNodeBuilder operator-(MultNodeBuilder& a, const PlusNodeBuilder& b) { - return a - Node(b.d_eb); + return a - Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline PlusNodeBuilder operator-(MultNodeBuilder& a, const MultNodeBuilder& b) { - return a - Node(b.d_eb); + return a - Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline MultNodeBuilder& operator*(MultNodeBuilder& a, const PlusNodeBuilder& b) { - return a * Node(b.d_eb); + return a * Node(const_cast<NodeBuilder<>&>(b.d_eb)); } inline MultNodeBuilder& operator*(MultNodeBuilder& a, const MultNodeBuilder& b) { - return a * Node(b.d_eb); + return a * Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc1, bool rc2> @@ -1050,61 +1014,61 @@ inline MultNodeBuilder operator*(const NodeTemplate<rc1>& a, template <bool rc> inline AndNodeBuilder operator&&(const NodeTemplate<rc>& a, const AndNodeBuilder& b) { - return a && Node(b.d_eb); + return a && Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline AndNodeBuilder operator&&(const NodeTemplate<rc>& a, const OrNodeBuilder& b) { - return a && Node(b.d_eb); + return a && Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline OrNodeBuilder operator||(const NodeTemplate<rc>& a, const AndNodeBuilder& b) { - return a || Node(b.d_eb); + return a || Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline OrNodeBuilder operator||(const NodeTemplate<rc>& a, const OrNodeBuilder& b) { - return a || Node(b.d_eb); + return a || Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline PlusNodeBuilder operator+(const NodeTemplate<rc>& a, const PlusNodeBuilder& b) { - return a + Node(b.d_eb); + return a + Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline PlusNodeBuilder operator+(const NodeTemplate<rc>& a, const MultNodeBuilder& b) { - return a + Node(b.d_eb); + return a + Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline PlusNodeBuilder operator-(const NodeTemplate<rc>& a, const PlusNodeBuilder& b) { - return a - Node(b.d_eb); + return a - Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline PlusNodeBuilder operator-(const NodeTemplate<rc>& a, const MultNodeBuilder& b) { - return a - Node(b.d_eb); + return a - Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline MultNodeBuilder operator*(const NodeTemplate<rc>& a, const PlusNodeBuilder& b) { - return a * Node(b.d_eb); + return a * Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> inline MultNodeBuilder operator*(const NodeTemplate<rc>& a, const MultNodeBuilder& b) { - return a * Node(b.d_eb); + return a * Node(const_cast<NodeBuilder<>&>(b.d_eb)); } template <bool rc> @@ -1262,7 +1226,6 @@ void NodeBuilderBase<Builder>::decrRefCounts() { d_inlineNv.d_nchildren = 0; } -// NON-CONST VERSION OF NODE EXTRACTOR template <class Builder> NodeBuilderBase<Builder>::operator Node() { Assert(!isUsed(), "NodeBuilder is one-shot only; " @@ -1434,183 +1397,6 @@ NodeBuilderBase<Builder>::operator Node() { } } -// CONST VERSION OF NODE EXTRACTOR -template <class Builder> -NodeBuilderBase<Builder>::operator Node() const { - Assert(!isUsed(), "NodeBuilder is one-shot only; " - "attempt to access it after conversion"); - Assert(getKind() != kind::UNDEFINED_KIND, - "Can't make an expression of an undefined kind!"); - - // NOTE: The comments in this function refer to the cases in the - // file comments at the top of this file. - - // Case 0: If a VARIABLE - if(getMetaKind() == kind::metakind::VARIABLE) { - /* 0. If a VARIABLE, treat similarly to 1(b), except that we know - * there are no children (no reference counts to reason about), - * and we don't keep VARIABLE-kinded Nodes in the NodeManager - * pool. */ - - Assert( ! nvIsAllocated(), - "internal NodeBuilder error: " - "VARIABLE-kinded NodeBuilder is heap-allocated !?" ); - Assert( d_inlineNv.d_nchildren == 0, - "improperly-formed VARIABLE-kinded NodeBuilder: " - "no children permitted" ); - - // we have to copy the inline NodeValue out - expr::NodeValue* nv = (expr::NodeValue*) - std::malloc(sizeof(expr::NodeValue)); - if(nv == NULL) { - throw std::bad_alloc(); - } - // there are no children, so we don't have to worry about - // reference counts in this case. - nv->d_nchildren = 0; - nv->d_kind = d_nv->d_kind; - nv->d_id = expr::NodeValue::next_id++;// FIXME multithreading - nv->d_rc = 0; - Debug("gc") << "creating node value " << nv - << " [" << nv->d_id << "]: " << *nv << "\n"; - return Node(nv); - } - - // check that there are the right # of children for this kind - Assert(getMetaKind() != kind::metakind::CONSTANT, - "Cannot make Nodes with NodeBuilder that have CONSTANT-kinded kinds"); - Assert(d_nv->d_nchildren >= kind::metakind::getLowerBoundForKind(getKind()), - "Nodes with kind %s must have at least %u children (the one under " - "construction has %u)", - kind::kindToString(getKind()).c_str(), - kind::metakind::getLowerBoundForKind(getKind()), - getNumChildren()); - Assert(d_nv->d_nchildren <= kind::metakind::getUpperBoundForKind(getKind()), - "Nodes with kind %s must have at most %u children (the one under " - "construction has %u)", - kind::kindToString(getKind()).c_str(), - kind::metakind::getUpperBoundForKind(getKind()), - getNumChildren()); - - // Implementation differs depending on whether the NodeValue was - // malloc'ed or not and whether or not it's in the already-been-seen - // NodeManager pool of Nodes. See implementation notes at the top - // of this file. - - if(EXPECT_TRUE( ! nvIsAllocated() )) { - /** Case 1. d_nv points to d_inlineNv: it is the backing store - ** supplied by the user (or derived class) **/ - - // Lookup the expression value in the pool we already have - expr::NodeValue* poolNv = d_nm->poolLookup(&d_inlineNv); - // If something else is there, we reuse it - if(poolNv != NULL) { - /* Subcase (a): The Node under construction already exists in - * the NodeManager's pool. */ - - /* 1(a). The existing NodeManager pool entry is returned; we - * leave child reference counts alone and get them at - * NodeBuilder destruction time. */ - - return Node(poolNv); - } else { - /* Subcase (b): The Node under construction is NOT already in - * the NodeManager's pool. */ - - /* 1(b). A new heap-allocated NodeValue must be constructed and - * all settings and children from d_inlineNv copied into it. - * This new NodeValue is put into the NodeManager's pool. The - * NodeBuilder cannot be marked as "used", so we increment all - * child reference counts (which will be decremented to match on - * destruction of the NodeBuilder). We return a Node wrapper - * for this new NodeValue, which increments its reference - * count. */ - - // create the canonical expression value for this node - expr::NodeValue* nv = (expr::NodeValue*) - std::malloc(sizeof(expr::NodeValue) + - ( sizeof(expr::NodeValue*) * d_inlineNv.d_nchildren )); - if(nv == NULL) { - throw std::bad_alloc(); - } - nv->d_nchildren = d_inlineNv.d_nchildren; - nv->d_kind = d_inlineNv.d_kind; - nv->d_id = expr::NodeValue::next_id++;// FIXME multithreading - nv->d_rc = 0; - - std::copy(d_inlineNv.d_children, - d_inlineNv.d_children + d_inlineNv.d_nchildren, - nv->d_children); - - for(expr::NodeValue::nv_iterator i = nv->nv_begin(); - i != nv->nv_end(); - ++i) { - (*i)->inc(); - } - - //poolNv = nv; - d_nm->poolInsert(nv); - Debug("gc") << "creating node value " << nv - << " [" << nv->d_id << "]: " << *nv << "\n"; - return Node(nv); - } - } else { - /** Case 2. d_nv does NOT point to d_inlineNv: it is a new, larger - ** buffer that was heap-allocated by this NodeBuilder. **/ - - // Lookup the expression value in the pool we already have (with insert) - expr::NodeValue* poolNv = d_nm->poolLookup(d_nv); - // If something else is there, we reuse it - if(poolNv != NULL) { - /* Subcase (a): The Node under construction already exists in - * the NodeManager's pool. */ - - /* 2(a). The existing NodeManager pool entry is returned; we - * leave child reference counts alone and get them at - * NodeBuilder destruction time. */ - - return Node(poolNv); - } else { - /* Subcase (b) The Node under construction is NOT already in the - * NodeManager's pool. */ - - /* 2(b). The heap-allocated d_nv cannot be "cropped" to the - * correct size; we create a copy, increment child reference - * counts, place this copy into the NodeManager pool, and return - * a Node wrapper around it. The child reference counts will be - * decremented to match at NodeBuilder destruction time. */ - - // create the canonical expression value for this node - expr::NodeValue* nv = (expr::NodeValue*) - std::malloc(sizeof(expr::NodeValue) + - ( sizeof(expr::NodeValue*) * d_nv->d_nchildren )); - if(nv == NULL) { - throw std::bad_alloc(); - } - nv->d_nchildren = d_nv->d_nchildren; - nv->d_kind = d_nv->d_kind; - nv->d_id = expr::NodeValue::next_id++;// FIXME multithreading - nv->d_rc = 0; - - std::copy(d_nv->d_children, - d_nv->d_children + d_nv->d_nchildren, - nv->d_children); - - for(expr::NodeValue::nv_iterator i = nv->nv_begin(); - i != nv->nv_end(); - ++i) { - (*i)->inc(); - } - - //poolNv = nv; - d_nm->poolInsert(nv); - Debug("gc") << "creating node value " << nv - << " [" << nv->d_id << "]: " << *nv << "\n"; - return Node(nv); - } - } -} - template <unsigned nchild_thresh> template <unsigned N> void NodeBuilder<nchild_thresh>::internalCopy(const NodeBuilder<N>& nb) { |