1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Morgan Deters, Andrew Reynolds, Christopher L. Conway |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* A manager for Nodes. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
/* circular dependency; force node.h first */ |
19 |
|
//#include "expr/attribute.h" |
20 |
|
#include "expr/node.h" |
21 |
|
#include "expr/type_node.h" |
22 |
|
|
23 |
|
#ifndef CVC5__NODE_MANAGER_H |
24 |
|
#define CVC5__NODE_MANAGER_H |
25 |
|
|
26 |
|
#include <string> |
27 |
|
#include <unordered_set> |
28 |
|
#include <vector> |
29 |
|
|
30 |
|
#include "base/check.h" |
31 |
|
#include "expr/kind.h" |
32 |
|
#include "expr/metakind.h" |
33 |
|
#include "expr/node_value.h" |
34 |
|
#include "util/floatingpoint_size.h" |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
|
38 |
|
using Record = std::vector<std::pair<std::string, TypeNode>>; |
39 |
|
|
40 |
|
namespace api { |
41 |
|
class Solver; |
42 |
|
} |
43 |
|
|
44 |
|
class ResourceManager; |
45 |
|
class SkolemManager; |
46 |
|
class BoundVarManager; |
47 |
|
|
48 |
|
class DType; |
49 |
|
|
50 |
|
namespace expr { |
51 |
|
namespace attr { |
52 |
|
class AttributeUniqueId; |
53 |
|
class AttributeManager; |
54 |
|
} // namespace attr |
55 |
|
|
56 |
|
class TypeChecker; |
57 |
|
} // namespace expr |
58 |
|
|
59 |
|
class NodeManager |
60 |
|
{ |
61 |
|
friend class api::Solver; |
62 |
|
friend class expr::NodeValue; |
63 |
|
friend class expr::TypeChecker; |
64 |
|
friend class SkolemManager; |
65 |
|
|
66 |
|
friend class NodeBuilder; |
67 |
|
|
68 |
|
public: |
69 |
|
/** |
70 |
|
* Return true if given kind is n-ary. The test is based on n-ary kinds |
71 |
|
* having their maximal arity as the maximal possible number of children |
72 |
|
* of a node. |
73 |
|
*/ |
74 |
|
static bool isNAryKind(Kind k); |
75 |
|
|
76 |
|
private: |
77 |
|
/** |
78 |
|
* Instead of creating an instance using the constructor, |
79 |
|
* `NodeManager::currentNM()` should be used to retrieve an instance of |
80 |
|
* `NodeManager`. |
81 |
|
*/ |
82 |
|
explicit NodeManager(); |
83 |
|
~NodeManager(); |
84 |
|
|
85 |
|
/** Predicate for use with STL algorithms */ |
86 |
|
struct NodeValueReferenceCountNonZero { |
87 |
33735057 |
bool operator()(expr::NodeValue* nv) { return nv->d_rc > 0; } |
88 |
|
}; |
89 |
|
|
90 |
|
typedef std::unordered_set<expr::NodeValue*, |
91 |
|
expr::NodeValuePoolHashFunction, |
92 |
|
expr::NodeValuePoolEq> NodeValuePool; |
93 |
|
typedef std::unordered_set<expr::NodeValue*, |
94 |
|
expr::NodeValueIDHashFunction, |
95 |
|
expr::NodeValueIDEquality> NodeValueIDSet; |
96 |
|
|
97 |
|
/** The skolem manager */ |
98 |
|
std::unique_ptr<SkolemManager> d_skManager; |
99 |
|
/** The bound variable manager */ |
100 |
|
std::unique_ptr<BoundVarManager> d_bvManager; |
101 |
|
|
102 |
|
NodeValuePool d_nodeValuePool; |
103 |
|
|
104 |
|
bool d_initialized; |
105 |
|
|
106 |
|
size_t next_id; |
107 |
|
|
108 |
|
expr::attr::AttributeManager* d_attrManager; |
109 |
|
|
110 |
|
/** |
111 |
|
* The node value we're currently freeing. This unique node value |
112 |
|
* is permitted to have outstanding TNodes to it (in "soft" |
113 |
|
* contexts, like as a key in attribute tables), even though |
114 |
|
* normally it's an error to have a TNode to a node value with a |
115 |
|
* reference count of 0. Being "under deletion" also enables |
116 |
|
* assertions that inc() is not called on it. |
117 |
|
*/ |
118 |
|
expr::NodeValue* d_nodeUnderDeletion; |
119 |
|
|
120 |
|
/** |
121 |
|
* True iff we are in reclaimZombies(). This avoids unnecessary |
122 |
|
* recursion; a NodeValue being deleted might zombify other |
123 |
|
* NodeValues, but these shouldn't trigger a (recursive) call to |
124 |
|
* reclaimZombies(). |
125 |
|
*/ |
126 |
|
bool d_inReclaimZombies; |
127 |
|
|
128 |
|
/** |
129 |
|
* The set of zombie nodes. We may want to revisit this design, as |
130 |
|
* we might like to delete nodes in least-recently-used order. But |
131 |
|
* we also need to avoid processing a zombie twice. |
132 |
|
*/ |
133 |
|
NodeValueIDSet d_zombies; |
134 |
|
|
135 |
|
/** |
136 |
|
* NodeValues with maxed out reference counts. These live as long as the |
137 |
|
* NodeManager. They have a custom deallocation procedure at the very end. |
138 |
|
*/ |
139 |
|
std::vector<expr::NodeValue*> d_maxedOut; |
140 |
|
|
141 |
|
/** |
142 |
|
* A set of operator singletons (w.r.t. to this NodeManager |
143 |
|
* instance) for operators. Conceptually, Nodes with kind, say, |
144 |
|
* PLUS, are APPLYs of a PLUS operator to arguments. This array |
145 |
|
* holds the set of operators for these things. A PLUS operator is |
146 |
|
* a Node with kind "BUILTIN", and if you call |
147 |
|
* plusOperator->getConst<cvc5::Kind>(), you get kind::PLUS back. |
148 |
|
*/ |
149 |
|
Node d_operators[kind::LAST_KIND]; |
150 |
|
|
151 |
|
/** unique vars per (Kind,Type) */ |
152 |
|
std::map< Kind, std::map< TypeNode, Node > > d_unique_vars; |
153 |
|
|
154 |
|
/** A list of datatypes owned by this node manager */ |
155 |
|
std::vector<std::unique_ptr<DType> > d_dtypes; |
156 |
|
|
157 |
|
/** |
158 |
|
* A map of tuple and record types to their corresponding datatype. |
159 |
|
*/ |
160 |
22396 |
class TupleTypeCache { |
161 |
|
public: |
162 |
|
std::map< TypeNode, TupleTypeCache > d_children; |
163 |
|
TypeNode d_data; |
164 |
|
TypeNode getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index = 0 ); |
165 |
|
}; |
166 |
20774 |
class RecTypeCache { |
167 |
|
public: |
168 |
|
std::map< TypeNode, std::map< std::string, RecTypeCache > > d_children; |
169 |
|
TypeNode d_data; |
170 |
|
TypeNode getRecordType( NodeManager * nm, const Record& rec, unsigned index = 0 ); |
171 |
|
}; |
172 |
|
TupleTypeCache d_tt_cache; |
173 |
|
RecTypeCache d_rt_cache; |
174 |
|
|
175 |
|
/** |
176 |
|
* Keep a count of all abstract values produced by this NodeManager. |
177 |
|
* Abstract values have a type attribute, so if multiple SolverEngines |
178 |
|
* are attached to this NodeManager, we don't want their abstract |
179 |
|
* values to overlap. |
180 |
|
*/ |
181 |
|
unsigned d_abstractValueCount; |
182 |
|
|
183 |
|
/** |
184 |
|
* Look up a NodeValue in the pool associated to this NodeManager. |
185 |
|
* The NodeValue argument need not be a "completely-constructed" |
186 |
|
* NodeValue. In particular, "non-inlined" constants are permitted |
187 |
|
* (see below). |
188 |
|
* |
189 |
|
* For non-CONSTANT metakinds, nv's d_kind and d_nchildren should be |
190 |
|
* correctly set, and d_children[0..n-1] should be valid (extant) |
191 |
|
* NodeValues for lookup. |
192 |
|
* |
193 |
|
* For CONSTANT metakinds, nv's d_kind should be set correctly. |
194 |
|
* Normally a CONSTANT would have d_nchildren == 0 and the constant |
195 |
|
* value inlined in the d_children space. However, here we permit |
196 |
|
* "non-inlined" NodeValues to avoid unnecessary copying. For |
197 |
|
* these, d_nchildren == 1, and d_nchildren is a pointer to the |
198 |
|
* constant value. |
199 |
|
* |
200 |
|
* The point of this complex design is to permit efficient lookups |
201 |
|
* (without fully constructing a NodeValue). In the case that the |
202 |
|
* argument is not fully constructed, and this function returns |
203 |
|
* NULL, the caller should fully construct an equivalent one before |
204 |
|
* calling poolInsert(). NON-FULLY-CONSTRUCTED NODEVALUES are not |
205 |
|
* permitted in the pool! |
206 |
|
*/ |
207 |
|
inline expr::NodeValue* poolLookup(expr::NodeValue* nv) const; |
208 |
|
|
209 |
|
/** |
210 |
|
* Insert a NodeValue into the NodeManager's pool. |
211 |
|
* |
212 |
|
* It is an error to insert a NodeValue already in the pool. |
213 |
|
* Enquire first with poolLookup(). |
214 |
|
*/ |
215 |
|
inline void poolInsert(expr::NodeValue* nv); |
216 |
|
|
217 |
|
/** |
218 |
|
* Remove a NodeValue from the NodeManager's pool. |
219 |
|
* |
220 |
|
* It is an error to request the removal of a NodeValue from the |
221 |
|
* pool that is not in the pool. |
222 |
|
*/ |
223 |
|
inline void poolRemove(expr::NodeValue* nv); |
224 |
|
|
225 |
|
/** |
226 |
|
* Determine if nv is currently being deleted by the NodeManager. |
227 |
|
*/ |
228 |
17910238733 |
inline bool isCurrentlyDeleting(const expr::NodeValue* nv) const { |
229 |
17910238733 |
return d_nodeUnderDeletion == nv; |
230 |
|
} |
231 |
|
|
232 |
|
/** |
233 |
|
* Register a NodeValue as a zombie. |
234 |
|
*/ |
235 |
52907130 |
inline void markForDeletion(expr::NodeValue* nv) { |
236 |
52907130 |
Assert(nv->d_rc == 0); |
237 |
|
|
238 |
|
// if d_reclaiming is set, make sure we don't call |
239 |
|
// reclaimZombies(), because it's already running. |
240 |
52907130 |
if(Debug.isOn("gc")) { |
241 |
|
Debug("gc") << "zombifying node value " << nv |
242 |
|
<< " [" << nv->d_id << "]: "; |
243 |
|
nv->printAst(Debug("gc")); |
244 |
|
Debug("gc") << (d_inReclaimZombies ? " [CURRENTLY-RECLAIMING]" : "") |
245 |
|
<< std::endl; |
246 |
|
} |
247 |
|
|
248 |
|
// `d_zombies` uses the node id to hash and compare nodes. If `d_zombies` |
249 |
|
// already contains a node value with the same id as `nv`, but the pointers |
250 |
|
// are different, then the wrong `NodeManager` was in scope for one of the |
251 |
|
// two nodes when it reached refcount zero. |
252 |
52907130 |
Assert(d_zombies.find(nv) == d_zombies.end() || *d_zombies.find(nv) == nv); |
253 |
|
|
254 |
52907130 |
d_zombies.insert(nv); |
255 |
|
|
256 |
52907130 |
if(safeToReclaimZombies()) { |
257 |
35692738 |
if(d_zombies.size() > 5000) { |
258 |
2897 |
reclaimZombies(); |
259 |
|
} |
260 |
|
} |
261 |
52907130 |
} |
262 |
|
|
263 |
|
/** |
264 |
|
* Register a NodeValue as having a maxed out reference count. This NodeValue |
265 |
|
* will live as long as its containing NodeManager. |
266 |
|
*/ |
267 |
7 |
inline void markRefCountMaxedOut(expr::NodeValue* nv) { |
268 |
7 |
Assert(nv->HasMaximizedReferenceCount()); |
269 |
7 |
if(Debug.isOn("gc")) { |
270 |
|
Debug("gc") << "marking node value " << nv |
271 |
|
<< " [" << nv->d_id << "]: as maxed out" << std::endl; |
272 |
|
} |
273 |
7 |
d_maxedOut.push_back(nv); |
274 |
7 |
} |
275 |
|
|
276 |
|
/** |
277 |
|
* Reclaim all zombies. |
278 |
|
*/ |
279 |
|
void reclaimZombies(); |
280 |
|
|
281 |
|
/** |
282 |
|
* It is safe to collect zombies. |
283 |
|
*/ |
284 |
|
bool safeToReclaimZombies() const; |
285 |
|
|
286 |
|
/** |
287 |
|
* Returns a reverse topological sort of a list of NodeValues. The NodeValues |
288 |
|
* must be valid and have ids. The NodeValues are not modified (including ref |
289 |
|
* counts). |
290 |
|
*/ |
291 |
|
static std::vector<expr::NodeValue*> TopologicalSort( |
292 |
|
const std::vector<expr::NodeValue*>& roots); |
293 |
|
|
294 |
|
/** |
295 |
|
* This template gives a mechanism to stack-allocate a NodeValue |
296 |
|
* with enough space for N children (where N is a compile-time |
297 |
|
* constant). You use it like this: |
298 |
|
* |
299 |
|
* NVStorage<4> nvStorage; |
300 |
|
* NodeValue& nvStack = reinterpret_cast<NodeValue&>(nvStorage); |
301 |
|
* |
302 |
|
* ...and then you can use nvStack as a NodeValue that you know has |
303 |
|
* room for 4 children. |
304 |
|
*/ |
305 |
|
template <size_t N> |
306 |
244969612 |
struct NVStorage { |
307 |
|
expr::NodeValue nv; |
308 |
|
expr::NodeValue* child[N]; |
309 |
|
};/* struct NodeManager::NVStorage<N> */ |
310 |
|
|
311 |
|
// undefined private copy constructor (disallow copy) |
312 |
|
NodeManager(const NodeManager&) = delete; |
313 |
|
|
314 |
|
NodeManager& operator=(const NodeManager&) = delete; |
315 |
|
|
316 |
|
/** |
317 |
|
* Create a variable with the given name and type. NOTE that no |
318 |
|
* lookup is done on the name. If you mkVar("a", type) and then |
319 |
|
* mkVar("a", type) again, you have two variables. The NodeManager |
320 |
|
* version of this is private to avoid internal uses of mkVar() from |
321 |
|
* within cvc5. Such uses should employ SkolemManager::mkSkolem() instead. |
322 |
|
*/ |
323 |
|
Node mkVar(const std::string& name, const TypeNode& type); |
324 |
|
|
325 |
|
/** Create a variable with the given type. */ |
326 |
|
Node mkVar(const TypeNode& type); |
327 |
|
|
328 |
|
public: |
329 |
|
/** |
330 |
|
* Initialize the node manager by adding a null node to the pool and filling |
331 |
|
* the caches for `operatorOf()`. This method must be called before using the |
332 |
|
* NodeManager. This method may be called multiple times. Subsequent calls to |
333 |
|
* this method have no effect. |
334 |
|
*/ |
335 |
|
void init(); |
336 |
|
|
337 |
|
/** The node manager in the current public-facing cvc5 library context */ |
338 |
|
static NodeManager* currentNM(); |
339 |
|
/** Get this node manager's skolem manager */ |
340 |
238761 |
SkolemManager* getSkolemManager() { return d_skManager.get(); } |
341 |
|
/** Get this node manager's bound variable manager */ |
342 |
840138 |
BoundVarManager* getBoundVarManager() { return d_bvManager.get(); } |
343 |
|
|
344 |
|
/** |
345 |
|
* Return the datatype at the given index owned by this class. Type nodes are |
346 |
|
* associated with datatypes through the DatatypeIndexConstant class. The |
347 |
|
* argument index is intended to be a value taken from that class. |
348 |
|
* |
349 |
|
* Type nodes must access their DTypes through a level of indirection to |
350 |
|
* prevent cycles in the Node AST (as DTypes themselves contain Nodes), which |
351 |
|
* would lead to memory leaks. Thus TypeNode are given a DatatypeIndexConstant |
352 |
|
* which is used as an index to retrieve the DType via this call. |
353 |
|
*/ |
354 |
|
const DType& getDTypeForIndex(size_t index) const; |
355 |
|
|
356 |
|
/** Get a Kind from an operator expression */ |
357 |
|
static inline Kind operatorToKind(TNode n); |
358 |
|
|
359 |
|
/** Get corresponding application kind for function |
360 |
|
* |
361 |
|
* Different functional nodes are applied differently, according to their |
362 |
|
* type. For example, uninterpreted functions (of FUNCTION_TYPE) are applied |
363 |
|
* via APPLY_UF, while constructors (of CONSTRUCTOR_TYPE) via |
364 |
|
* APPLY_CONSTRUCTOR. This method provides the correct application according |
365 |
|
* to which functional type fun has. |
366 |
|
* |
367 |
|
* @param fun The functional node |
368 |
|
* @return the correct application kind for fun. If fun's type is not function |
369 |
|
* like (see TypeNode::isFunctionLike), then UNDEFINED_KIND is returned. |
370 |
|
*/ |
371 |
|
static Kind getKindForFunction(TNode fun); |
372 |
|
|
373 |
|
// general expression-builders |
374 |
|
// |
375 |
|
/** Create a node with no child. */ |
376 |
|
Node mkNode(Kind kind); |
377 |
|
|
378 |
|
/** Create a node with one child. */ |
379 |
|
Node mkNode(Kind kind, TNode child1); |
380 |
|
|
381 |
|
/** Create a node with two children. */ |
382 |
|
Node mkNode(Kind kind, TNode child1, TNode child2); |
383 |
|
|
384 |
|
/** Create a node with three children. */ |
385 |
|
Node mkNode(Kind kind, TNode child1, TNode child2, TNode child3); |
386 |
|
|
387 |
|
/** Create a node with an arbitrary number of children. */ |
388 |
|
template <bool ref_count> |
389 |
|
Node mkNode(Kind kind, const std::vector<NodeTemplate<ref_count> >& children); |
390 |
|
|
391 |
|
/** Create a node using an initializer list. |
392 |
|
* |
393 |
|
* This function serves two purposes: |
394 |
|
* - We can avoid creating a temporary vector in some cases, e.g., when we |
395 |
|
* want to create a node with a fixed, large number of children |
396 |
|
* - It makes sure that calls to `mkNode` that braced-init-lists work as |
397 |
|
* expected, e.g., mkNode(REGEXP_EMPTY, {}) will call this overload instead |
398 |
|
* of creating a node with a null node as a child. |
399 |
|
*/ |
400 |
|
Node mkNode(Kind kind, std::initializer_list<TNode> children); |
401 |
|
|
402 |
|
/** |
403 |
|
* Create an AND node with arbitrary number of children. This returns the |
404 |
|
* true node if children is empty, or the single node in children if |
405 |
|
* it contains only one node. |
406 |
|
* |
407 |
|
* We define construction of AND as a special case here since it is widely |
408 |
|
* used for e.g. constructing explanations. |
409 |
|
*/ |
410 |
|
template <bool ref_count> |
411 |
|
Node mkAnd(const std::vector<NodeTemplate<ref_count> >& children); |
412 |
|
|
413 |
|
/** |
414 |
|
* Create an OR node with arbitrary number of children. This returns the |
415 |
|
* false node if children is empty, or the single node in children if |
416 |
|
* it contains only one node. |
417 |
|
* |
418 |
|
* We define construction of OR as a special case here since it is widely |
419 |
|
* used for e.g. constructing explanations or lemmas. |
420 |
|
*/ |
421 |
|
template <bool ref_count> |
422 |
|
Node mkOr(const std::vector<NodeTemplate<ref_count> >& children); |
423 |
|
|
424 |
|
/** Create a node (with no children) by operator. */ |
425 |
|
Node mkNode(TNode opNode); |
426 |
|
|
427 |
|
/** Create a node with one child by operator. */ |
428 |
|
Node mkNode(TNode opNode, TNode child1); |
429 |
|
|
430 |
|
/** Create a node with two children by operator. */ |
431 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2); |
432 |
|
|
433 |
|
/** Create a node with three children by operator. */ |
434 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2, TNode child3); |
435 |
|
|
436 |
|
/** Create a node by applying an operator to the children. */ |
437 |
|
template <bool ref_count> |
438 |
|
Node mkNode(TNode opNode, const std::vector<NodeTemplate<ref_count> >& children); |
439 |
|
|
440 |
|
/** |
441 |
|
* Create a node by applying an operator to an arbitrary number of children. |
442 |
|
* |
443 |
|
* Analoguous to `mkNode(Kind, std::initializer_list<TNode>)`. |
444 |
|
*/ |
445 |
|
Node mkNode(TNode opNode, std::initializer_list<TNode> children); |
446 |
|
|
447 |
|
Node mkBoundVar(const std::string& name, const TypeNode& type); |
448 |
|
|
449 |
|
Node mkBoundVar(const TypeNode& type); |
450 |
|
|
451 |
|
/** get the canonical bound variable list for function type tn */ |
452 |
|
Node getBoundVarListForFunctionType( TypeNode tn ); |
453 |
|
|
454 |
|
/** |
455 |
|
* Create an Node by applying an associative operator to the children. |
456 |
|
* If <code>children.size()</code> is greater than the max arity for |
457 |
|
* <code>kind</code>, then the expression will be broken up into |
458 |
|
* suitably-sized chunks, taking advantage of the associativity of |
459 |
|
* <code>kind</code>. For example, if kind <code>FOO</code> has max arity |
460 |
|
* 2, then calling <code>mkAssociative(FOO,a,b,c)</code> will return |
461 |
|
* <code>(FOO (FOO a b) c)</code> or <code>(FOO a (FOO b c))</code>. |
462 |
|
* The order of the arguments will be preserved in a left-to-right |
463 |
|
* traversal of the resulting tree. |
464 |
|
*/ |
465 |
|
Node mkAssociative(Kind kind, const std::vector<Node>& children); |
466 |
|
|
467 |
|
/** |
468 |
|
* Create an Node by applying an binary left-associative operator to the |
469 |
|
* children. For example, mkLeftAssociative( f, { a, b, c } ) returns |
470 |
|
* f( f( a, b ), c ). |
471 |
|
*/ |
472 |
|
Node mkLeftAssociative(Kind kind, const std::vector<Node>& children); |
473 |
|
/** |
474 |
|
* Create an Node by applying an binary right-associative operator to the |
475 |
|
* children. For example, mkRightAssociative( f, { a, b, c } ) returns |
476 |
|
* f( a, f( b, c ) ). |
477 |
|
*/ |
478 |
|
Node mkRightAssociative(Kind kind, const std::vector<Node>& children); |
479 |
|
|
480 |
|
/** make chain |
481 |
|
* |
482 |
|
* Given a kind k and arguments t_1, ..., t_n, this returns the |
483 |
|
* conjunction of: |
484 |
|
* (k t_1 t_2) .... (k t_{n-1} t_n) |
485 |
|
* It is expected that k is a kind denoting a predicate, and args is a list |
486 |
|
* of terms of size >= 2 such that the terms above are well-typed. |
487 |
|
*/ |
488 |
|
Node mkChain(Kind kind, const std::vector<Node>& children); |
489 |
|
|
490 |
|
/** Create a instantiation constant with the given type. */ |
491 |
|
Node mkInstConstant(const TypeNode& type); |
492 |
|
|
493 |
|
/** Make a new abstract value with the given type. */ |
494 |
|
Node mkAbstractValue(const TypeNode& type); |
495 |
|
|
496 |
|
/** make unique (per Type,Kind) variable. */ |
497 |
|
Node mkNullaryOperator(const TypeNode& type, Kind k); |
498 |
|
|
499 |
|
/** |
500 |
|
* Create a singleton set from the given element n. |
501 |
|
* @param t the element type of the returned set. |
502 |
|
* Note that the type of n needs to be a subtype of t. |
503 |
|
* @param n the single element in the singleton. |
504 |
|
* @return a singleton set constructed from the element n. |
505 |
|
*/ |
506 |
|
Node mkSingleton(const TypeNode& t, const TNode n); |
507 |
|
|
508 |
|
/** |
509 |
|
* Create a bag from the given element n along with its multiplicity m. |
510 |
|
* @param t the element type of the returned bag. |
511 |
|
* Note that the type of n needs to be a subtype of t. |
512 |
|
* @param n the element that is used to to construct the bag |
513 |
|
* @param m the multiplicity of the element n |
514 |
|
* @return a bag that contains m occurrences of n. |
515 |
|
*/ |
516 |
|
Node mkBag(const TypeNode& t, const TNode n, const TNode m); |
517 |
|
|
518 |
|
/** |
519 |
|
* Create a constant of type T. It will have the appropriate |
520 |
|
* CONST_* kind defined for T. |
521 |
|
*/ |
522 |
|
template <class T> |
523 |
|
Node mkConst(const T&); |
524 |
|
|
525 |
|
template <class T> |
526 |
|
TypeNode mkTypeConst(const T&); |
527 |
|
|
528 |
|
template <class NodeClass, class T> |
529 |
|
NodeClass mkConstInternal(const T&); |
530 |
|
|
531 |
|
/** Create a node with children. */ |
532 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1); |
533 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2); |
534 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2, |
535 |
|
TypeNode child3); |
536 |
|
TypeNode mkTypeNode(Kind kind, const std::vector<TypeNode>& children); |
537 |
|
|
538 |
|
/** |
539 |
|
* Determine whether Nodes of a particular Kind have operators. |
540 |
|
* @returns true if Nodes of Kind k have operators. |
541 |
|
*/ |
542 |
|
static inline bool hasOperator(Kind k); |
543 |
|
|
544 |
|
/** |
545 |
|
* Get the (singleton) operator of an OPERATOR-kinded kind. The |
546 |
|
* returned node n will have kind BUILTIN, and calling |
547 |
|
* n.getConst<cvc5::Kind>() will yield k. |
548 |
|
*/ |
549 |
7349066 |
inline TNode operatorOf(Kind k) { |
550 |
7349066 |
AssertArgument( kind::metaKindOf(k) == kind::metakind::OPERATOR, k, |
551 |
|
"Kind is not an OPERATOR-kinded kind " |
552 |
|
"in NodeManager::operatorOf()" ); |
553 |
7349066 |
return d_operators[k]; |
554 |
|
} |
555 |
|
|
556 |
|
/** |
557 |
|
* Retrieve an attribute for a node. |
558 |
|
* |
559 |
|
* @param nv the node value |
560 |
|
* @param attr an instance of the attribute kind to retrieve. |
561 |
|
* @returns the attribute, if set, or a default-constructed |
562 |
|
* <code>AttrKind::value_type</code> if not. |
563 |
|
*/ |
564 |
|
template <class AttrKind> |
565 |
|
inline typename AttrKind::value_type getAttribute(expr::NodeValue* nv, |
566 |
|
const AttrKind& attr) const; |
567 |
|
|
568 |
|
/** |
569 |
|
* Check whether an attribute is set for a node. |
570 |
|
* |
571 |
|
* @param nv the node value |
572 |
|
* @param attr an instance of the attribute kind to check |
573 |
|
* @returns <code>true</code> iff <code>attr</code> is set for |
574 |
|
* <code>nv</code>. |
575 |
|
*/ |
576 |
|
template <class AttrKind> |
577 |
|
inline bool hasAttribute(expr::NodeValue* nv, |
578 |
|
const AttrKind& attr) const; |
579 |
|
|
580 |
|
/** |
581 |
|
* Check whether an attribute is set for a node, and, if so, |
582 |
|
* retrieve it. |
583 |
|
* |
584 |
|
* @param nv the node value |
585 |
|
* @param attr an instance of the attribute kind to check |
586 |
|
* @param value a reference to an object of the attribute's value type. |
587 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
588 |
|
* set for <code>nv</code>; otherwise, it will be set to the default |
589 |
|
* value of the attribute. |
590 |
|
* @returns <code>true</code> iff <code>attr</code> is set for |
591 |
|
* <code>nv</code>. |
592 |
|
*/ |
593 |
|
template <class AttrKind> |
594 |
|
inline bool getAttribute(expr::NodeValue* nv, |
595 |
|
const AttrKind& attr, |
596 |
|
typename AttrKind::value_type& value) const; |
597 |
|
|
598 |
|
/** |
599 |
|
* Set an attribute for a node. If the node doesn't have the |
600 |
|
* attribute, this function assigns one. If the node has one, this |
601 |
|
* overwrites it. |
602 |
|
* |
603 |
|
* @param nv the node value |
604 |
|
* @param attr an instance of the attribute kind to set |
605 |
|
* @param value the value of <code>attr</code> for <code>nv</code> |
606 |
|
*/ |
607 |
|
template <class AttrKind> |
608 |
|
inline void setAttribute(expr::NodeValue* nv, |
609 |
|
const AttrKind& attr, |
610 |
|
const typename AttrKind::value_type& value); |
611 |
|
|
612 |
|
/** |
613 |
|
* Retrieve an attribute for a TNode. |
614 |
|
* |
615 |
|
* @param n the node |
616 |
|
* @param attr an instance of the attribute kind to retrieve. |
617 |
|
* @returns the attribute, if set, or a default-constructed |
618 |
|
* <code>AttrKind::value_type</code> if not. |
619 |
|
*/ |
620 |
|
template <class AttrKind> |
621 |
|
inline typename AttrKind::value_type |
622 |
|
getAttribute(TNode n, const AttrKind& attr) const; |
623 |
|
|
624 |
|
/** |
625 |
|
* Check whether an attribute is set for a TNode. |
626 |
|
* |
627 |
|
* @param n the node |
628 |
|
* @param attr an instance of the attribute kind to check |
629 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
630 |
|
*/ |
631 |
|
template <class AttrKind> |
632 |
|
inline bool hasAttribute(TNode n, |
633 |
|
const AttrKind& attr) const; |
634 |
|
|
635 |
|
/** |
636 |
|
* Check whether an attribute is set for a TNode and, if so, retieve |
637 |
|
* it. |
638 |
|
* |
639 |
|
* @param n the node |
640 |
|
* @param attr an instance of the attribute kind to check |
641 |
|
* @param value a reference to an object of the attribute's value type. |
642 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
643 |
|
* set for <code>nv</code>; otherwise, it will be set to the default value of |
644 |
|
* the attribute. |
645 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
646 |
|
*/ |
647 |
|
template <class AttrKind> |
648 |
|
inline bool getAttribute(TNode n, |
649 |
|
const AttrKind& attr, |
650 |
|
typename AttrKind::value_type& value) const; |
651 |
|
|
652 |
|
/** |
653 |
|
* Set an attribute for a node. If the node doesn't have the |
654 |
|
* attribute, this function assigns one. If the node has one, this |
655 |
|
* overwrites it. |
656 |
|
* |
657 |
|
* @param n the node |
658 |
|
* @param attr an instance of the attribute kind to set |
659 |
|
* @param value the value of <code>attr</code> for <code>n</code> |
660 |
|
*/ |
661 |
|
template <class AttrKind> |
662 |
|
inline void setAttribute(TNode n, |
663 |
|
const AttrKind& attr, |
664 |
|
const typename AttrKind::value_type& value); |
665 |
|
|
666 |
|
/** |
667 |
|
* Retrieve an attribute for a TypeNode. |
668 |
|
* |
669 |
|
* @param n the type node |
670 |
|
* @param attr an instance of the attribute kind to retrieve. |
671 |
|
* @returns the attribute, if set, or a default-constructed |
672 |
|
* <code>AttrKind::value_type</code> if not. |
673 |
|
*/ |
674 |
|
template <class AttrKind> |
675 |
|
inline typename AttrKind::value_type |
676 |
|
getAttribute(TypeNode n, const AttrKind& attr) const; |
677 |
|
|
678 |
|
/** |
679 |
|
* Check whether an attribute is set for a TypeNode. |
680 |
|
* |
681 |
|
* @param n the type node |
682 |
|
* @param attr an instance of the attribute kind to check |
683 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
684 |
|
*/ |
685 |
|
template <class AttrKind> |
686 |
|
inline bool hasAttribute(TypeNode n, |
687 |
|
const AttrKind& attr) const; |
688 |
|
|
689 |
|
/** |
690 |
|
* Check whether an attribute is set for a TypeNode and, if so, retieve |
691 |
|
* it. |
692 |
|
* |
693 |
|
* @param n the type node |
694 |
|
* @param attr an instance of the attribute kind to check |
695 |
|
* @param value a reference to an object of the attribute's value type. |
696 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
697 |
|
* set for <code>nv</code>; otherwise, it will be set to the default value of |
698 |
|
* the attribute. |
699 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
700 |
|
*/ |
701 |
|
template <class AttrKind> |
702 |
|
inline bool getAttribute(TypeNode n, |
703 |
|
const AttrKind& attr, |
704 |
|
typename AttrKind::value_type& value) const; |
705 |
|
|
706 |
|
/** |
707 |
|
* Set an attribute for a type node. If the node doesn't have the |
708 |
|
* attribute, this function assigns one. If the type node has one, |
709 |
|
* this overwrites it. |
710 |
|
* |
711 |
|
* @param n the type node |
712 |
|
* @param attr an instance of the attribute kind to set |
713 |
|
* @param value the value of <code>attr</code> for <code>n</code> |
714 |
|
*/ |
715 |
|
template <class AttrKind> |
716 |
|
inline void setAttribute(TypeNode n, |
717 |
|
const AttrKind& attr, |
718 |
|
const typename AttrKind::value_type& value); |
719 |
|
|
720 |
|
/** Get the (singleton) type for Booleans. */ |
721 |
|
TypeNode booleanType(); |
722 |
|
|
723 |
|
/** Get the (singleton) type for integers. */ |
724 |
|
TypeNode integerType(); |
725 |
|
|
726 |
|
/** Get the (singleton) type for reals. */ |
727 |
|
TypeNode realType(); |
728 |
|
|
729 |
|
/** Get the (singleton) type for strings. */ |
730 |
|
TypeNode stringType(); |
731 |
|
|
732 |
|
/** Get the (singleton) type for RegExp. */ |
733 |
|
TypeNode regExpType(); |
734 |
|
|
735 |
|
/** Get the (singleton) type for rounding modes. */ |
736 |
|
TypeNode roundingModeType(); |
737 |
|
|
738 |
|
/** Get the bound var list type. */ |
739 |
|
TypeNode boundVarListType(); |
740 |
|
|
741 |
|
/** Get the instantiation pattern type. */ |
742 |
|
TypeNode instPatternType(); |
743 |
|
|
744 |
|
/** Get the instantiation pattern type. */ |
745 |
|
TypeNode instPatternListType(); |
746 |
|
|
747 |
|
/** |
748 |
|
* Get the (singleton) type for builtin operators (that is, the type |
749 |
|
* of the Node returned from Node::getOperator() when the operator |
750 |
|
* is built-in, like EQUAL). */ |
751 |
|
TypeNode builtinOperatorType(); |
752 |
|
|
753 |
|
/** |
754 |
|
* Make a function type from domain to range. |
755 |
|
* |
756 |
|
* @param domain the domain type |
757 |
|
* @param range the range type |
758 |
|
* @returns the functional type domain -> range |
759 |
|
*/ |
760 |
|
TypeNode mkFunctionType(const TypeNode& domain, |
761 |
|
const TypeNode& range); |
762 |
|
|
763 |
|
/** |
764 |
|
* Make a function type with input types from |
765 |
|
* argTypes. <code>argTypes</code> must have at least one element. |
766 |
|
* |
767 |
|
* @param argTypes the domain is a tuple (argTypes[0], ..., argTypes[n]) |
768 |
|
* @param range the range type |
769 |
|
* @returns the functional type (argTypes[0], ..., argTypes[n]) -> range |
770 |
|
*/ |
771 |
|
TypeNode mkFunctionType(const std::vector<TypeNode>& argTypes, |
772 |
|
const TypeNode& range); |
773 |
|
|
774 |
|
/** |
775 |
|
* Make a function type with input types from |
776 |
|
* <code>sorts[0..sorts.size()-2]</code> and result type |
777 |
|
* <code>sorts[sorts.size()-1]</code>. <code>sorts</code> must have |
778 |
|
* at least 2 elements. |
779 |
|
* |
780 |
|
* @param sorts The argument and range sort of the function type, where the |
781 |
|
* range type is the last in this vector. |
782 |
|
* @return the function type |
783 |
|
*/ |
784 |
|
TypeNode mkFunctionType(const std::vector<TypeNode>& sorts); |
785 |
|
|
786 |
|
/** |
787 |
|
* Make a predicate type with input types from |
788 |
|
* <code>sorts</code>. The result with be a function type with range |
789 |
|
* <code>BOOLEAN</code>. <code>sorts</code> must have at least one |
790 |
|
* element. |
791 |
|
*/ |
792 |
|
TypeNode mkPredicateType(const std::vector<TypeNode>& sorts); |
793 |
|
|
794 |
|
/** |
795 |
|
* Make a tuple type with types from |
796 |
|
* <code>types</code>. <code>types</code> must have at least one |
797 |
|
* element. |
798 |
|
* |
799 |
|
* @param types a vector of types |
800 |
|
* @returns the tuple type (types[0], ..., types[n]) |
801 |
|
*/ |
802 |
|
TypeNode mkTupleType(const std::vector<TypeNode>& types); |
803 |
|
|
804 |
|
/** |
805 |
|
* Make a record type with the description from rec. |
806 |
|
* |
807 |
|
* @param rec a description of the record |
808 |
|
* @returns the record type |
809 |
|
*/ |
810 |
|
TypeNode mkRecordType(const Record& rec); |
811 |
|
|
812 |
|
/** |
813 |
|
* @returns the symbolic expression type |
814 |
|
*/ |
815 |
|
TypeNode sExprType(); |
816 |
|
|
817 |
|
/** Make the type of floating-point with <code>exp</code> bit exponent and |
818 |
|
<code>sig</code> bit significand */ |
819 |
|
TypeNode mkFloatingPointType(unsigned exp, unsigned sig); |
820 |
|
TypeNode mkFloatingPointType(FloatingPointSize fs); |
821 |
|
|
822 |
|
/** Make the type of bitvectors of size <code>size</code> */ |
823 |
|
TypeNode mkBitVectorType(unsigned size); |
824 |
|
|
825 |
|
/** Make the type of arrays with the given parameterization */ |
826 |
|
inline TypeNode mkArrayType(TypeNode indexType, TypeNode constituentType); |
827 |
|
|
828 |
|
/** Make the type of set with the given parameterization */ |
829 |
|
inline TypeNode mkSetType(TypeNode elementType); |
830 |
|
|
831 |
|
/** Make the type of bags with the given parameterization */ |
832 |
|
TypeNode mkBagType(TypeNode elementType); |
833 |
|
|
834 |
|
/** Make the type of sequences with the given parameterization */ |
835 |
|
TypeNode mkSequenceType(TypeNode elementType); |
836 |
|
|
837 |
|
/** Bits for use in mkDatatypeType() flags. |
838 |
|
* |
839 |
|
* DATATYPE_FLAG_PLACEHOLDER indicates that the type should not be printed |
840 |
|
* out as a definition, for example, in models or during dumping. |
841 |
|
*/ |
842 |
|
enum |
843 |
|
{ |
844 |
|
DATATYPE_FLAG_NONE = 0, |
845 |
|
DATATYPE_FLAG_PLACEHOLDER = 1 |
846 |
|
}; /* enum */ |
847 |
|
|
848 |
|
/** Make a type representing the given datatype. */ |
849 |
|
TypeNode mkDatatypeType(DType& datatype, uint32_t flags = DATATYPE_FLAG_NONE); |
850 |
|
|
851 |
|
/** |
852 |
|
* Make a set of types representing the given datatypes, which may be |
853 |
|
* mutually recursive. |
854 |
|
*/ |
855 |
|
std::vector<TypeNode> mkMutualDatatypeTypes( |
856 |
|
const std::vector<DType>& datatypes, uint32_t flags = DATATYPE_FLAG_NONE); |
857 |
|
|
858 |
|
/** |
859 |
|
* Make a set of types representing the given datatypes, which may |
860 |
|
* be mutually recursive. unresolvedTypes is a set of SortTypes |
861 |
|
* that were used as placeholders in the Datatypes for the Datatypes |
862 |
|
* of the same name. This is just a more complicated version of the |
863 |
|
* above mkMutualDatatypeTypes() function, but is required to handle |
864 |
|
* complex types. |
865 |
|
* |
866 |
|
* For example, unresolvedTypes might contain the single sort "list" |
867 |
|
* (with that name reported from SortType::getName()). The |
868 |
|
* datatypes list might have the single datatype |
869 |
|
* |
870 |
|
* DATATYPE |
871 |
|
* list = cons(car:ARRAY INT OF list, cdr:list) | nil; |
872 |
|
* END; |
873 |
|
* |
874 |
|
* To represent the Type of the array, the user had to create a |
875 |
|
* placeholder type (an uninterpreted sort) to stand for "list" in |
876 |
|
* the type of "car". It is this placeholder sort that should be |
877 |
|
* passed in unresolvedTypes. If the datatype was of the simpler |
878 |
|
* form: |
879 |
|
* |
880 |
|
* DATATYPE |
881 |
|
* list = cons(car:list, cdr:list) | nil; |
882 |
|
* END; |
883 |
|
* |
884 |
|
* then no complicated Type needs to be created, and the above, |
885 |
|
* simpler form of mkMutualDatatypeTypes() is enough. |
886 |
|
*/ |
887 |
|
std::vector<TypeNode> mkMutualDatatypeTypes( |
888 |
|
const std::vector<DType>& datatypes, |
889 |
|
const std::set<TypeNode>& unresolvedTypes, |
890 |
|
uint32_t flags = DATATYPE_FLAG_NONE); |
891 |
|
|
892 |
|
/** |
893 |
|
* Make a type representing a constructor with the given argument (subfield) |
894 |
|
* types and return type range. |
895 |
|
*/ |
896 |
|
TypeNode mkConstructorType(const std::vector<TypeNode>& args, TypeNode range); |
897 |
|
|
898 |
|
/** Make a type representing a selector with the given parameterization */ |
899 |
|
TypeNode mkSelectorType(TypeNode domain, TypeNode range); |
900 |
|
|
901 |
|
/** Make a type representing a tester with given parameterization */ |
902 |
|
TypeNode mkTesterType(TypeNode domain); |
903 |
|
|
904 |
|
/** Make a type representing an updater with the given parameterization */ |
905 |
|
TypeNode mkDatatypeUpdateType(TypeNode domain, TypeNode range); |
906 |
|
|
907 |
|
/** Bits for use in mkSort() flags. */ |
908 |
|
enum |
909 |
|
{ |
910 |
|
SORT_FLAG_NONE = 0, |
911 |
|
SORT_FLAG_PLACEHOLDER = 1 |
912 |
|
}; /* enum */ |
913 |
|
|
914 |
|
/** Make a new (anonymous) sort of arity 0. */ |
915 |
|
TypeNode mkSort(uint32_t flags = SORT_FLAG_NONE); |
916 |
|
|
917 |
|
/** Make a new sort with the given name of arity 0. */ |
918 |
|
TypeNode mkSort(const std::string& name, uint32_t flags = SORT_FLAG_NONE); |
919 |
|
|
920 |
|
/** Make a new sort by parameterizing the given sort constructor. */ |
921 |
|
TypeNode mkSort(TypeNode constructor, |
922 |
|
const std::vector<TypeNode>& children, |
923 |
|
uint32_t flags = SORT_FLAG_NONE); |
924 |
|
|
925 |
|
/** Make a new sort with the given name and arity. */ |
926 |
|
TypeNode mkSortConstructor(const std::string& name, |
927 |
|
size_t arity, |
928 |
|
uint32_t flags = SORT_FLAG_NONE); |
929 |
|
|
930 |
|
/** |
931 |
|
* Get the type for the given node and optionally do type checking. |
932 |
|
* |
933 |
|
* Initial type computation will be near-constant time if |
934 |
|
* type checking is not requested. Results are memoized, so that |
935 |
|
* subsequent calls to getType() without type checking will be |
936 |
|
* constant time. |
937 |
|
* |
938 |
|
* Initial type checking is linear in the size of the expression. |
939 |
|
* Again, the results are memoized, so that subsequent calls to |
940 |
|
* getType(), with or without type checking, will be constant |
941 |
|
* time. |
942 |
|
* |
943 |
|
* NOTE: A TypeCheckingException can be thrown even when type |
944 |
|
* checking is not requested. getType() will always return a |
945 |
|
* valid and correct type and, thus, an exception will be thrown |
946 |
|
* when no valid or correct type can be computed (e.g., if the |
947 |
|
* arguments to a bit-vector operation aren't bit-vectors). When |
948 |
|
* type checking is not requested, getType() will do the minimum |
949 |
|
* amount of checking required to return a valid result. |
950 |
|
* |
951 |
|
* @param n the Node for which we want a type |
952 |
|
* @param check whether we should check the type as we compute it |
953 |
|
* (default: false) |
954 |
|
*/ |
955 |
|
TypeNode getType(TNode n, bool check = false); |
956 |
|
|
957 |
|
/** Reclaim zombies while there are more than k nodes in the pool (if possible).*/ |
958 |
|
void reclaimZombiesUntil(uint32_t k); |
959 |
|
|
960 |
|
/** Reclaims all zombies (if possible).*/ |
961 |
|
void reclaimAllZombies(); |
962 |
|
|
963 |
|
/** Size of the node pool. */ |
964 |
|
size_t poolSize() const; |
965 |
|
|
966 |
|
/** Deletes a list of attributes from the NM's AttributeManager.*/ |
967 |
|
void deleteAttributes(const std::vector< const expr::attr::AttributeUniqueId* >& ids); |
968 |
|
|
969 |
|
/** |
970 |
|
* This function gives developers a hook into the NodeManager. |
971 |
|
* This can be changed in node_manager.cpp without recompiling most of cvc5. |
972 |
|
* |
973 |
|
* debugHook is a debugging only function, and should not be present in |
974 |
|
* any published code! |
975 |
|
*/ |
976 |
|
void debugHook(int debugFlag); |
977 |
|
}; /* class NodeManager */ |
978 |
|
|
979 |
10002 |
inline TypeNode NodeManager::mkArrayType(TypeNode indexType, |
980 |
|
TypeNode constituentType) { |
981 |
10002 |
CheckArgument(!indexType.isNull(), indexType, |
982 |
|
"unexpected NULL index type"); |
983 |
10002 |
CheckArgument(!constituentType.isNull(), constituentType, |
984 |
|
"unexpected NULL constituent type"); |
985 |
20004 |
Debug("arrays") << "making array type " << indexType << " " |
986 |
10002 |
<< constituentType << std::endl; |
987 |
10002 |
return mkTypeNode(kind::ARRAY_TYPE, indexType, constituentType); |
988 |
|
} |
989 |
|
|
990 |
17632 |
inline TypeNode NodeManager::mkSetType(TypeNode elementType) { |
991 |
17632 |
CheckArgument(!elementType.isNull(), elementType, |
992 |
|
"unexpected NULL element type"); |
993 |
17632 |
Debug("sets") << "making sets type " << elementType << std::endl; |
994 |
17632 |
return mkTypeNode(kind::SET_TYPE, elementType); |
995 |
|
} |
996 |
|
|
997 |
499698903 |
inline expr::NodeValue* NodeManager::poolLookup(expr::NodeValue* nv) const { |
998 |
499698903 |
NodeValuePool::const_iterator find = d_nodeValuePool.find(nv); |
999 |
499698903 |
if(find == d_nodeValuePool.end()) { |
1000 |
31808219 |
return NULL; |
1001 |
|
} else { |
1002 |
467890684 |
return *find; |
1003 |
|
} |
1004 |
|
} |
1005 |
|
|
1006 |
31818444 |
inline void NodeManager::poolInsert(expr::NodeValue* nv) { |
1007 |
31818444 |
Assert(d_nodeValuePool.find(nv) == d_nodeValuePool.end()) |
1008 |
|
<< "NodeValue already in the pool!"; |
1009 |
31818444 |
d_nodeValuePool.insert(nv);// FIXME multithreading |
1010 |
31818444 |
} |
1011 |
|
|
1012 |
31815473 |
inline void NodeManager::poolRemove(expr::NodeValue* nv) { |
1013 |
31815473 |
Assert(d_nodeValuePool.find(nv) != d_nodeValuePool.end()) |
1014 |
|
<< "NodeValue is not in the pool!"; |
1015 |
|
|
1016 |
31815473 |
d_nodeValuePool.erase(nv);// FIXME multithreading |
1017 |
31815473 |
} |
1018 |
|
|
1019 |
|
} // namespace cvc5 |
1020 |
|
|
1021 |
|
#define CVC5__NODE_MANAGER_NEEDS_CONSTANT_MAP |
1022 |
|
#include "expr/metakind.h" |
1023 |
|
#undef CVC5__NODE_MANAGER_NEEDS_CONSTANT_MAP |
1024 |
|
|
1025 |
|
#include "expr/node_builder.h" |
1026 |
|
|
1027 |
|
namespace cvc5 { |
1028 |
|
|
1029 |
|
// general expression-builders |
1030 |
|
|
1031 |
18981371 |
inline bool NodeManager::hasOperator(Kind k) { |
1032 |
18981371 |
switch(kind::MetaKind mk = kind::metaKindOf(k)) { |
1033 |
|
|
1034 |
1974253 |
case kind::metakind::INVALID: |
1035 |
|
case kind::metakind::VARIABLE: |
1036 |
|
case kind::metakind::NULLARY_OPERATOR: |
1037 |
1974253 |
return false; |
1038 |
|
|
1039 |
14923301 |
case kind::metakind::OPERATOR: |
1040 |
|
case kind::metakind::PARAMETERIZED: |
1041 |
14923301 |
return true; |
1042 |
|
|
1043 |
2083817 |
case kind::metakind::CONSTANT: |
1044 |
2083817 |
return false; |
1045 |
|
|
1046 |
|
default: Unhandled() << mk; |
1047 |
|
} |
1048 |
|
} |
1049 |
|
|
1050 |
621547 |
inline Kind NodeManager::operatorToKind(TNode n) { |
1051 |
621547 |
return kind::operatorToKind(n.d_nv); |
1052 |
|
} |
1053 |
|
|
1054 |
15573 |
inline Node NodeManager::mkNode(Kind kind) |
1055 |
|
{ |
1056 |
31146 |
NodeBuilder nb(this, kind); |
1057 |
31146 |
return nb.constructNode(); |
1058 |
|
} |
1059 |
|
|
1060 |
46617607 |
inline Node NodeManager::mkNode(Kind kind, TNode child1) { |
1061 |
93235214 |
NodeBuilder nb(this, kind); |
1062 |
46617607 |
nb << child1; |
1063 |
93235202 |
return nb.constructNode(); |
1064 |
|
} |
1065 |
|
|
1066 |
125834292 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2) { |
1067 |
251668584 |
NodeBuilder nb(this, kind); |
1068 |
125834292 |
nb << child1 << child2; |
1069 |
251668206 |
return nb.constructNode(); |
1070 |
|
} |
1071 |
|
|
1072 |
1176362 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2, |
1073 |
|
TNode child3) { |
1074 |
2352724 |
NodeBuilder nb(this, kind); |
1075 |
1176362 |
nb << child1 << child2 << child3; |
1076 |
2352692 |
return nb.constructNode(); |
1077 |
|
} |
1078 |
|
|
1079 |
|
// N-ary version |
1080 |
|
template <bool ref_count> |
1081 |
16724840 |
inline Node NodeManager::mkNode(Kind kind, |
1082 |
|
const std::vector<NodeTemplate<ref_count> >& |
1083 |
|
children) { |
1084 |
33449680 |
NodeBuilder nb(this, kind); |
1085 |
16724840 |
nb.append(children); |
1086 |
33449650 |
return nb.constructNode(); |
1087 |
|
} |
1088 |
|
|
1089 |
|
template <bool ref_count> |
1090 |
930904 |
Node NodeManager::mkAnd(const std::vector<NodeTemplate<ref_count> >& children) |
1091 |
|
{ |
1092 |
930904 |
if (children.empty()) |
1093 |
|
{ |
1094 |
62190 |
return mkConst(true); |
1095 |
|
} |
1096 |
868714 |
else if (children.size() == 1) |
1097 |
|
{ |
1098 |
640960 |
return children[0]; |
1099 |
|
} |
1100 |
227754 |
return mkNode(kind::AND, children); |
1101 |
|
} |
1102 |
|
|
1103 |
|
template <bool ref_count> |
1104 |
1000454 |
Node NodeManager::mkOr(const std::vector<NodeTemplate<ref_count> >& children) |
1105 |
|
{ |
1106 |
1000454 |
if (children.empty()) |
1107 |
|
{ |
1108 |
4524 |
return mkConst(false); |
1109 |
|
} |
1110 |
995930 |
else if (children.size() == 1) |
1111 |
|
{ |
1112 |
146689 |
return children[0]; |
1113 |
|
} |
1114 |
849241 |
return mkNode(kind::OR, children); |
1115 |
|
} |
1116 |
|
|
1117 |
|
// for operators |
1118 |
|
inline Node NodeManager::mkNode(TNode opNode) { |
1119 |
|
NodeBuilder nb(this, operatorToKind(opNode)); |
1120 |
|
if(opNode.getKind() != kind::BUILTIN) { |
1121 |
|
nb << opNode; |
1122 |
|
} |
1123 |
|
return nb.constructNode(); |
1124 |
|
} |
1125 |
|
|
1126 |
327889 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1) { |
1127 |
655778 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1128 |
327889 |
if(opNode.getKind() != kind::BUILTIN) { |
1129 |
327889 |
nb << opNode; |
1130 |
|
} |
1131 |
327889 |
nb << child1; |
1132 |
655778 |
return nb.constructNode(); |
1133 |
|
} |
1134 |
|
|
1135 |
69 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2) { |
1136 |
138 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1137 |
69 |
if(opNode.getKind() != kind::BUILTIN) { |
1138 |
69 |
nb << opNode; |
1139 |
|
} |
1140 |
69 |
nb << child1 << child2; |
1141 |
138 |
return nb.constructNode(); |
1142 |
|
} |
1143 |
|
|
1144 |
4 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2, |
1145 |
|
TNode child3) { |
1146 |
8 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1147 |
4 |
if(opNode.getKind() != kind::BUILTIN) { |
1148 |
4 |
nb << opNode; |
1149 |
|
} |
1150 |
4 |
nb << child1 << child2 << child3; |
1151 |
8 |
return nb.constructNode(); |
1152 |
|
} |
1153 |
|
|
1154 |
|
// N-ary version for operators |
1155 |
|
template <bool ref_count> |
1156 |
63673 |
inline Node NodeManager::mkNode(TNode opNode, |
1157 |
|
const std::vector<NodeTemplate<ref_count> >& |
1158 |
|
children) { |
1159 |
127346 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1160 |
63673 |
if(opNode.getKind() != kind::BUILTIN) { |
1161 |
866 |
nb << opNode; |
1162 |
|
} |
1163 |
63673 |
nb.append(children); |
1164 |
127346 |
return nb.constructNode(); |
1165 |
|
} |
1166 |
|
|
1167 |
43221 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1) { |
1168 |
43221 |
return (NodeBuilder(this, kind) << child1).constructTypeNode(); |
1169 |
|
} |
1170 |
|
|
1171 |
57578 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1, |
1172 |
|
TypeNode child2) { |
1173 |
57578 |
return (NodeBuilder(this, kind) << child1 << child2).constructTypeNode(); |
1174 |
|
} |
1175 |
|
|
1176 |
|
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1, |
1177 |
|
TypeNode child2, TypeNode child3) { |
1178 |
|
return (NodeBuilder(this, kind) << child1 << child2 << child3) |
1179 |
|
.constructTypeNode(); |
1180 |
|
} |
1181 |
|
|
1182 |
|
// N-ary version for types |
1183 |
85209 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, |
1184 |
|
const std::vector<TypeNode>& children) { |
1185 |
85209 |
return NodeBuilder(this, kind).append(children).constructTypeNode(); |
1186 |
|
} |
1187 |
|
|
1188 |
|
template <class T> |
1189 |
212653434 |
Node NodeManager::mkConst(const T& val) { |
1190 |
212653434 |
return mkConstInternal<Node, T>(val); |
1191 |
|
} |
1192 |
|
|
1193 |
|
template <class T> |
1194 |
32316178 |
TypeNode NodeManager::mkTypeConst(const T& val) { |
1195 |
32316178 |
return mkConstInternal<TypeNode, T>(val); |
1196 |
|
} |
1197 |
|
|
1198 |
|
template <class NodeClass, class T> |
1199 |
244969612 |
NodeClass NodeManager::mkConstInternal(const T& val) { |
1200 |
|
// typedef typename kind::metakind::constantMap<T>::OwningTheory theory_t; |
1201 |
244969612 |
NVStorage<1> nvStorage; |
1202 |
244969612 |
expr::NodeValue& nvStack = reinterpret_cast<expr::NodeValue&>(nvStorage); |
1203 |
|
|
1204 |
244969612 |
nvStack.d_id = 0; |
1205 |
244969612 |
nvStack.d_kind = kind::metakind::ConstantMap<T>::kind; |
1206 |
244969612 |
nvStack.d_rc = 0; |
1207 |
244969612 |
nvStack.d_nchildren = 1; |
1208 |
|
|
1209 |
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) |
1210 |
|
#pragma GCC diagnostic push |
1211 |
|
#pragma GCC diagnostic ignored "-Warray-bounds" |
1212 |
|
#endif |
1213 |
|
|
1214 |
244969612 |
nvStack.d_children[0] = |
1215 |
|
const_cast<expr::NodeValue*>(reinterpret_cast<const expr::NodeValue*>(&val)); |
1216 |
244969612 |
expr::NodeValue* nv = poolLookup(&nvStack); |
1217 |
|
|
1218 |
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) |
1219 |
|
#pragma GCC diagnostic pop |
1220 |
|
#endif |
1221 |
|
|
1222 |
244969612 |
if(nv != NULL) { |
1223 |
241590413 |
return NodeClass(nv); |
1224 |
|
} |
1225 |
|
|
1226 |
3379199 |
nv = (expr::NodeValue*) |
1227 |
3379199 |
std::malloc(sizeof(expr::NodeValue) + sizeof(T)); |
1228 |
3379199 |
if(nv == NULL) { |
1229 |
|
throw std::bad_alloc(); |
1230 |
|
} |
1231 |
|
|
1232 |
3379199 |
nv->d_nchildren = 0; |
1233 |
3379199 |
nv->d_kind = kind::metakind::ConstantMap<T>::kind; |
1234 |
3379199 |
nv->d_id = next_id++;// FIXME multithreading |
1235 |
3379199 |
nv->d_rc = 0; |
1236 |
|
|
1237 |
|
//OwningTheory::mkConst(val); |
1238 |
3379199 |
new (&nv->d_children) T(val); |
1239 |
|
|
1240 |
3379199 |
poolInsert(nv); |
1241 |
3379199 |
if(Debug.isOn("gc")) { |
1242 |
|
Debug("gc") << "creating node value " << nv |
1243 |
|
<< " [" << nv->d_id << "]: "; |
1244 |
|
nv->printAst(Debug("gc")); |
1245 |
|
Debug("gc") << std::endl; |
1246 |
|
} |
1247 |
|
|
1248 |
3379199 |
return NodeClass(nv); |
1249 |
|
} |
1250 |
|
|
1251 |
|
} // namespace cvc5 |
1252 |
|
|
1253 |
|
#endif /* CVC5__NODE_MANAGER_H */ |