GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/node_builder.cpp Lines: 278 366 76.0 %
Date: 2021-09-09 Branches: 201 1174 17.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andres Noetzli, Morgan Deters, Mathias Preiner
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 builder interface for Nodes.
14
 */
15
16
#include "expr/node_builder.h"
17
18
#include <memory>
19
20
namespace cvc5 {
21
22
40680530
NodeBuilder::NodeBuilder()
23
40680530
    : d_nv(&d_inlineNv),
24
40680530
      d_nm(NodeManager::currentNM()),
25
122041590
      d_nvMaxChildren(default_nchild_thresh)
26
{
27
40680530
  d_inlineNv.d_id = 0;
28
40680530
  d_inlineNv.d_rc = 0;
29
40680530
  d_inlineNv.d_kind = expr::NodeValue::kindToDKind(kind::UNDEFINED_KIND);
30
40680530
  d_inlineNv.d_nchildren = 0;
31
40680530
}
32
33
33782459
NodeBuilder::NodeBuilder(Kind k)
34
33782459
    : d_nv(&d_inlineNv),
35
33782459
      d_nm(NodeManager::currentNM()),
36
101347377
      d_nvMaxChildren(default_nchild_thresh)
37
{
38
33782459
  Assert(k != kind::NULL_EXPR && k != kind::UNDEFINED_KIND)
39
      << "illegal Node-building kind";
40
41
33782459
  d_inlineNv.d_id = 1;  // have a kind already
42
33782459
  d_inlineNv.d_rc = 0;
43
33782459
  d_inlineNv.d_kind = expr::NodeValue::kindToDKind(k);
44
33782459
  d_inlineNv.d_nchildren = 0;
45
33782459
}
46
47
2
NodeBuilder::NodeBuilder(NodeManager* nm)
48
2
    : d_nv(&d_inlineNv), d_nm(nm), d_nvMaxChildren(default_nchild_thresh)
49
{
50
2
  d_inlineNv.d_id = 0;
51
2
  d_inlineNv.d_rc = 0;
52
2
  d_inlineNv.d_kind = expr::NodeValue::kindToDKind(kind::UNDEFINED_KIND);
53
2
  d_inlineNv.d_nchildren = 0;
54
2
}
55
56
183953462
NodeBuilder::NodeBuilder(NodeManager* nm, Kind k)
57
183953462
    : d_nv(&d_inlineNv), d_nm(nm), d_nvMaxChildren(default_nchild_thresh)
58
{
59
183953462
  Assert(k != kind::NULL_EXPR && k != kind::UNDEFINED_KIND)
60
      << "illegal Node-building kind";
61
62
183953462
  d_inlineNv.d_id = 1;  // have a kind already
63
183953462
  d_inlineNv.d_rc = 0;
64
183953462
  d_inlineNv.d_kind = expr::NodeValue::kindToDKind(k);
65
183953462
  d_inlineNv.d_nchildren = 0;
66
183953462
}
67
68
46994723
NodeBuilder::NodeBuilder(const NodeBuilder& nb)
69
46994723
    : d_nv(&d_inlineNv), d_nm(nb.d_nm), d_nvMaxChildren(default_nchild_thresh)
70
{
71
46994723
  d_inlineNv.d_id = nb.d_nv->d_id;
72
46994723
  d_inlineNv.d_rc = 0;
73
46994723
  d_inlineNv.d_kind = nb.d_nv->d_kind;
74
46994723
  d_inlineNv.d_nchildren = 0;
75
76
46994723
  internalCopy(nb);
77
46994723
}
78
79
610822346
NodeBuilder::~NodeBuilder()
80
{
81
305411173
  if (CVC5_PREDICT_FALSE(nvIsAllocated()))
82
  {
83
7833
    dealloc();
84
  }
85
305403340
  else if (CVC5_PREDICT_FALSE(!isUsed()))
86
  {
87
78896776
    decrRefCounts();
88
  }
89
305411173
}
90
91
1834783843
Kind NodeBuilder::getKind() const
92
{
93
1834783843
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
94
                       "attempt to access it after conversion";
95
1834783843
  return d_nv->getKind();
96
}
97
98
677269572
kind::MetaKind NodeBuilder::getMetaKind() const
99
{
100
677269572
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
101
                       "attempt to access it after conversion";
102
677269572
  Assert(getKind() != kind::UNDEFINED_KIND)
103
      << "The metakind of a NodeBuilder is undefined "
104
         "until a Kind is set";
105
677269572
  return d_nv->getMetaKind();
106
}
107
108
454263181
unsigned NodeBuilder::getNumChildren() const
109
{
110
454263181
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
111
                       "attempt to access it after conversion";
112
454263181
  Assert(getKind() != kind::UNDEFINED_KIND)
113
      << "The number of children of a NodeBuilder is undefined "
114
         "until a Kind is set";
115
454263181
  return d_nv->getNumChildren();
116
}
117
118
Node NodeBuilder::getOperator() const
119
{
120
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
121
                       "attempt to access it after conversion";
122
  Assert(getKind() != kind::UNDEFINED_KIND)
123
      << "NodeBuilder operator access is not permitted "
124
         "until a Kind is set";
125
  Assert(getMetaKind() == kind::metakind::PARAMETERIZED)
126
      << "NodeBuilder operator access is only permitted "
127
         "on parameterized kinds, not `"
128
      << getKind() << "'";
129
  return Node(d_nv->getOperator());
130
}
131
132
2716557
Node NodeBuilder::getChild(int i) const
133
{
134
2716557
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
135
                       "attempt to access it after conversion";
136
2716557
  Assert(getKind() != kind::UNDEFINED_KIND)
137
      << "NodeBuilder child access is not permitted "
138
         "until a Kind is set";
139
2716557
  Assert(i >= 0 && unsigned(i) < d_nv->getNumChildren())
140
      << "index out of range for NodeBuilder::getChild()";
141
2716557
  return Node(d_nv->getChild(i));
142
}
143
144
2709116
Node NodeBuilder::operator[](int i) const { return getChild(i); }
145
146
105107
void NodeBuilder::clear(Kind k)
147
{
148
105107
  Assert(k != kind::NULL_EXPR) << "illegal Node-building clear kind";
149
150
105107
  if (CVC5_PREDICT_FALSE(nvIsAllocated()))
151
  {
152
6
    dealloc();
153
  }
154
105101
  else if (CVC5_PREDICT_FALSE(!isUsed()))
155
  {
156
105095
    decrRefCounts();
157
  }
158
  else
159
  {
160
6
    setUnused();
161
  }
162
163
105107
  d_inlineNv.d_kind = expr::NodeValue::kindToDKind(k);
164
105107
  for (expr::NodeValue::nv_iterator i = d_inlineNv.nv_begin();
165
105107
       i != d_inlineNv.nv_end();
166
       ++i)
167
  {
168
    (*i)->dec();
169
  }
170
105107
  d_inlineNv.d_nchildren = 0;
171
  // keep track of whether or not we hvae a kind already
172
105107
  d_inlineNv.d_id = (k == kind::UNDEFINED_KIND) ? 0 : 1;
173
105107
}
174
175
11608122
NodeBuilder& NodeBuilder::operator<<(const Kind& k)
176
{
177
11608122
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
178
                       "attempt to access it after conversion";
179
11608122
  Assert(getKind() == kind::UNDEFINED_KIND || d_nv->d_id == 0)
180
      << "can't redefine the Kind of a NodeBuilder";
181
11608122
  Assert(d_nv->d_id == 0)
182
      << "internal inconsistency with NodeBuilder: d_id != 0";
183
11608122
  AssertArgument(
184
      k != kind::UNDEFINED_KIND && k != kind::NULL_EXPR && k < kind::LAST_KIND,
185
      k,
186
      "illegal node-building kind");
187
  // This test means: we didn't have a Kind at the beginning (on
188
  // NodeBuilder construction or at the last clear()), but we do
189
  // now.  That means we appended a Kind with operator<<(Kind),
190
  // which now (lazily) we'll collapse.
191
11608122
  if (CVC5_PREDICT_FALSE(d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND))
192
  {
193
    Node n2 = operator Node();
194
    clear();
195
    append(n2);
196
  }
197
11608122
  else if (d_nv->d_nchildren == 0)
198
  {
199
11608094
    d_nv->d_id = 1;  // remember that we had a kind from the start
200
  }
201
11608122
  d_nv->d_kind = expr::NodeValue::kindToDKind(k);
202
11608122
  return *this;
203
}
204
205
414639498
NodeBuilder& NodeBuilder::operator<<(TNode n)
206
{
207
414639498
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
208
                       "attempt to access it after conversion";
209
  // This test means: we didn't have a Kind at the beginning (on
210
  // NodeBuilder construction or at the last clear()), but we do
211
  // now.  That means we appended a Kind with operator<<(Kind),
212
  // which now (lazily) we'll collapse.
213
414639498
  if (CVC5_PREDICT_FALSE(d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND))
214
  {
215
12
    Node n2 = operator Node();
216
6
    clear();
217
6
    append(n2);
218
  }
219
414639498
  return append(n);
220
}
221
222
132556
NodeBuilder& NodeBuilder::operator<<(TypeNode n)
223
{
224
132556
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
225
                       "attempt to access it after conversion";
226
  // This test means: we didn't have a Kind at the beginning (on
227
  // NodeBuilder construction or at the last clear()), but we do
228
  // now.  That means we appended a Kind with operator<<(Kind),
229
  // which now (lazily) we'll collapse.
230
132556
  if (CVC5_PREDICT_FALSE(d_nv->d_id == 0 && getKind() != kind::UNDEFINED_KIND))
231
  {
232
    Node n2 = operator Node();
233
    clear();
234
    append(n2);
235
  }
236
132556
  return append(n);
237
}
238
239
73531
NodeBuilder& NodeBuilder::append(const std::vector<TypeNode>& children)
240
{
241
73531
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
242
                       "attempt to access it after conversion";
243
73531
  return append(children.begin(), children.end());
244
}
245
246
487441712
NodeBuilder& NodeBuilder::append(TNode n)
247
{
248
487441712
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
249
                       "attempt to access it after conversion";
250
487441712
  Assert(!n.isNull()) << "Cannot use NULL Node as a child of a Node";
251
487441712
  if (n.getKind() == kind::BUILTIN)
252
  {
253
    return *this << NodeManager::operatorToKind(n);
254
  }
255
487441712
  allocateNvIfNecessaryForAppend();
256
487441712
  expr::NodeValue* nv = n.d_nv;
257
487441712
  nv->inc();
258
487441712
  d_nv->d_children[d_nv->d_nchildren++] = nv;
259
487441712
  Assert(d_nv->d_nchildren <= d_nvMaxChildren);
260
487441712
  return *this;
261
}
262
263
372396
NodeBuilder& NodeBuilder::append(const TypeNode& typeNode)
264
{
265
372396
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
266
                       "attempt to access it after conversion";
267
372396
  Assert(!typeNode.isNull()) << "Cannot use NULL Node as a child of a Node";
268
372396
  allocateNvIfNecessaryForAppend();
269
372396
  expr::NodeValue* nv = typeNode.d_nv;
270
372396
  nv->inc();
271
372396
  d_nv->d_children[d_nv->d_nchildren++] = nv;
272
372396
  Assert(d_nv->d_nchildren <= d_nvMaxChildren);
273
372396
  return *this;
274
}
275
276
2668901
void NodeBuilder::realloc(size_t toSize)
277
{
278
2668901
  AlwaysAssert(toSize > d_nvMaxChildren)
279
      << "attempt to realloc() a NodeBuilder to a smaller/equal size!";
280
2668901
  Assert(toSize < (static_cast<size_t>(1) << expr::NodeValue::NBITS_NCHILDREN))
281
      << "attempt to realloc() a NodeBuilder to size " << toSize
282
      << " (beyond hard limit of " << expr::NodeValue::MAX_CHILDREN << ")";
283
284
2668901
  if (CVC5_PREDICT_FALSE(nvIsAllocated()))
285
  {
286
    // Ensure d_nv is not modified on allocation failure
287
1032711
    expr::NodeValue* newBlock = (expr::NodeValue*)std::realloc(
288
1032711
        d_nv, sizeof(expr::NodeValue) + (sizeof(expr::NodeValue*) * toSize));
289
1032711
    if (newBlock == nullptr)
290
    {
291
      // In this case, d_nv was NOT freed.  If we throw, the
292
      // deallocation should occur on destruction of the NodeBuilder.
293
      throw std::bad_alloc();
294
    }
295
1032711
    d_nvMaxChildren = toSize;
296
1032711
    Assert(d_nvMaxChildren == toSize);  // overflow check
297
    // Here, the copy (between two heap-allocated buffers) has already
298
    // been done for us by the std::realloc().
299
1032711
    d_nv = newBlock;
300
  }
301
  else
302
  {
303
    // Ensure d_nv is not modified on allocation failure
304
1636190
    expr::NodeValue* newBlock = (expr::NodeValue*)std::malloc(
305
1636190
        sizeof(expr::NodeValue) + (sizeof(expr::NodeValue*) * toSize));
306
1636190
    if (newBlock == nullptr)
307
    {
308
      throw std::bad_alloc();
309
    }
310
1636190
    d_nvMaxChildren = toSize;
311
1636190
    Assert(d_nvMaxChildren == toSize);  // overflow check
312
313
1636190
    d_nv = newBlock;
314
1636190
    d_nv->d_id = d_inlineNv.d_id;
315
1636190
    d_nv->d_rc = 0;
316
1636190
    d_nv->d_kind = d_inlineNv.d_kind;
317
1636190
    d_nv->d_nchildren = d_inlineNv.d_nchildren;
318
319
3272380
    std::copy(d_inlineNv.d_children,
320
1636190
              d_inlineNv.d_children + d_inlineNv.d_nchildren,
321
1636190
              d_nv->d_children);
322
323
    // ensure "inline" children don't get decremented in dtor
324
1636190
    d_inlineNv.d_nchildren = 0;
325
  }
326
2668901
}
327
328
1104914
void NodeBuilder::dealloc()
329
{
330
1104914
  Assert(nvIsAllocated())
331
      << "Internal error: NodeBuilder: dealloc() called without a "
332
         "private NodeBuilder-allocated buffer";
333
334
42160767
  for (expr::NodeValue::nv_iterator i = d_nv->nv_begin(); i != d_nv->nv_end();
335
       ++i)
336
  {
337
41055853
    (*i)->dec();
338
  }
339
340
1104914
  free(d_nv);
341
1104914
  d_nv = &d_inlineNv;
342
1104914
  d_nvMaxChildren = default_nchild_thresh;
343
1104914
}
344
345
276590700
void NodeBuilder::decrRefCounts()
346
{
347
276590700
  Assert(!nvIsAllocated())
348
      << "Internal error: NodeBuilder: decrRefCounts() called with a "
349
         "private NodeBuilder-allocated buffer";
350
351
646987372
  for (expr::NodeValue::nv_iterator i = d_inlineNv.nv_begin();
352
646987372
       i != d_inlineNv.nv_end();
353
       ++i)
354
  {
355
370396672
    (*i)->dec();
356
  }
357
358
276590700
  d_inlineNv.d_nchildren = 0;
359
276590700
}
360
361
161011
TypeNode NodeBuilder::constructTypeNode() { return TypeNode(constructNV()); }
362
363
226345559
Node NodeBuilder::constructNode()
364
{
365
226345559
  Node n(constructNV());
366
226346017
  maybeCheckType(n);
367
226345101
  return n;
368
}
369
370
Node* NodeBuilder::constructNodePtr()
371
{
372
  std::unique_ptr<Node> np(new Node(constructNV()));
373
  maybeCheckType(*np.get());
374
  return np.release();
375
}
376
377
43388559
NodeBuilder::operator Node() { return constructNode(); }
378
379
NodeBuilder::operator TypeNode() { return constructTypeNode(); }
380
381
226506570
expr::NodeValue* NodeBuilder::constructNV()
382
{
383
226506570
  Assert(!isUsed()) << "NodeBuilder is one-shot only; "
384
                       "attempt to access it after conversion";
385
226506570
  Assert(getKind() != kind::UNDEFINED_KIND)
386
      << "Can't make an expression of an undefined kind!";
387
388
  // NOTE: The comments in this function refer to the cases in the
389
  // file comments at the top of this file.
390
391
  // Case 0: If a VARIABLE
392
453013140
  if (getMetaKind() == kind::metakind::VARIABLE
393
226506570
      || getMetaKind() == kind::metakind::NULLARY_OPERATOR)
394
  {
395
    /* 0. If a VARIABLE, treat similarly to 1(b), except that we know
396
     * there are no children (no reference counts to reason about),
397
     * and we don't keep VARIABLE-kinded Nodes in the NodeManager
398
     * pool. */
399
400
1127639
    Assert(!nvIsAllocated())
401
        << "internal NodeBuilder error: "
402
           "VARIABLE-kinded NodeBuilder is heap-allocated !?";
403
1127639
    Assert(d_inlineNv.d_nchildren == 0)
404
        << "improperly-formed VARIABLE-kinded NodeBuilder: "
405
           "no children permitted";
406
407
    // we have to copy the inline NodeValue out
408
    expr::NodeValue* nv =
409
1127639
        (expr::NodeValue*)std::malloc(sizeof(expr::NodeValue));
410
1127639
    if (nv == nullptr)
411
    {
412
      throw std::bad_alloc();
413
    }
414
    // there are no children, so we don't have to worry about
415
    // reference counts in this case.
416
1127639
    nv->d_nchildren = 0;
417
1127639
    nv->d_kind = d_nv->d_kind;
418
1127639
    nv->d_id = d_nm->next_id++;  // FIXME multithreading
419
1127639
    nv->d_rc = 0;
420
1127639
    setUsed();
421
1127639
    if (Debug.isOn("gc"))
422
    {
423
      Debug("gc") << "creating node value " << nv << " [" << nv->d_id << "]: ";
424
      nv->printAst(Debug("gc"));
425
      Debug("gc") << std::endl;
426
    }
427
1127639
    return nv;
428
  }
429
430
  // check that there are the right # of children for this kind
431
225378931
  Assert(getMetaKind() != kind::metakind::CONSTANT)
432
      << "Cannot make Nodes with NodeBuilder that have CONSTANT-kinded kinds";
433
225378931
  Assert(getNumChildren() >= kind::metakind::getMinArityForKind(getKind()))
434
      << "Nodes with kind " << getKind() << " must have at least "
435
      << kind::metakind::getMinArityForKind(getKind())
436
      << " children (the one under "
437
         "construction has "
438
      << getNumChildren() << ")";
439
225378931
  Assert(getNumChildren() <= kind::metakind::getMaxArityForKind(getKind()))
440
      << "Nodes with kind " << getKind() << " must have at most "
441
      << kind::metakind::getMaxArityForKind(getKind())
442
      << " children (the one under "
443
         "construction has "
444
      << getNumChildren() << ")";
445
446
  // Implementation differs depending on whether the NodeValue was
447
  // malloc'ed or not and whether or not it's in the already-been-seen
448
  // NodeManager pool of Nodes.  See implementation notes at the top
449
  // of this file.
450
451
225378931
  if (CVC5_PREDICT_TRUE(!nvIsAllocated()))
452
  {
453
    /** Case 1.  d_nv points to d_inlineNv: it is the backing store
454
     ** allocated "inline" in this NodeBuilder. **/
455
456
    // Lookup the expression value in the pool we already have
457
223750580
    expr::NodeValue* poolNv = d_nm->poolLookup(&d_inlineNv);
458
    // If something else is there, we reuse it
459
223750580
    if (poolNv != nullptr)
460
    {
461
      /* Subcase (a): The Node under construction already exists in
462
       * the NodeManager's pool. */
463
464
      /* 1(a). Reference-counts for all children in d_inlineNv must be
465
       * decremented, and the NodeBuilder must be marked as "used" and
466
       * the number of children set to zero so that we don't decrement
467
       * them again on destruction.  The existing NodeManager pool
468
       * entry is returned.
469
       */
470
197588829
      decrRefCounts();
471
197588829
      d_inlineNv.d_nchildren = 0;
472
197588829
      setUsed();
473
197588829
      return poolNv;
474
    }
475
    else
476
    {
477
      /* Subcase (b): The Node under construction is NOT already in
478
       * the NodeManager's pool. */
479
480
      /* 1(b). A new heap-allocated NodeValue must be constructed and
481
       * all settings and children from d_inlineNv copied into it.
482
       * This new NodeValue is put into the NodeManager's pool.  The
483
       * NodeBuilder is marked as "used" and the number of children in
484
       * d_inlineNv set to zero so that we don't decrement child
485
       * reference counts on destruction (the child reference counts
486
       * have been "taken over" by the new NodeValue).  We return a
487
       * Node wrapper for this new NodeValue, which increments its
488
       * reference count. */
489
490
      // create the canonical expression value for this node
491
26161751
      expr::NodeValue* nv = (expr::NodeValue*)std::malloc(
492
          sizeof(expr::NodeValue)
493
52323502
          + (sizeof(expr::NodeValue*) * d_inlineNv.d_nchildren));
494
26161751
      if (nv == nullptr)
495
      {
496
        throw std::bad_alloc();
497
      }
498
26161751
      nv->d_nchildren = d_inlineNv.d_nchildren;
499
26161751
      nv->d_kind = d_inlineNv.d_kind;
500
26161751
      nv->d_id = d_nm->next_id++;  // FIXME multithreading
501
26161751
      nv->d_rc = 0;
502
503
52323502
      std::copy(d_inlineNv.d_children,
504
26161751
                d_inlineNv.d_children + d_inlineNv.d_nchildren,
505
26161751
                nv->d_children);
506
507
26161751
      d_inlineNv.d_nchildren = 0;
508
26161751
      setUsed();
509
510
      // poolNv = nv;
511
26161751
      d_nm->poolInsert(nv);
512
26161751
      if (Debug.isOn("gc"))
513
      {
514
        Debug("gc") << "creating node value " << nv << " [" << nv->d_id
515
                    << "]: ";
516
        nv->printAst(Debug("gc"));
517
        Debug("gc") << std::endl;
518
      }
519
26161751
      return nv;
520
    }
521
  }
522
  else
523
  {
524
    /** Case 2. d_nv does NOT point to d_inlineNv: it is a new, larger
525
     ** buffer that was heap-allocated by this NodeBuilder. **/
526
527
    // Lookup the expression value in the pool we already have (with insert)
528
1628351
    expr::NodeValue* poolNv = d_nm->poolLookup(d_nv);
529
    // If something else is there, we reuse it
530
1628351
    if (poolNv != nullptr)
531
    {
532
      /* Subcase (a): The Node under construction already exists in
533
       * the NodeManager's pool. */
534
535
      /* 2(a). Reference-counts for all children in d_nv must be
536
       * decremented.  The NodeBuilder is marked as "used" and the
537
       * heap-allocated d_nv deleted.  d_nv is repointed to d_inlineNv
538
       * so that destruction of the NodeBuilder doesn't cause any
539
       * problems.  The existing NodeManager pool entry is
540
       * returned. */
541
542
1097075
      dealloc();
543
1097075
      setUsed();
544
1097075
      return poolNv;
545
    }
546
    else
547
    {
548
      /* Subcase (b) The Node under construction is NOT already in the
549
       * NodeManager's pool. */
550
551
      /* 2(b). The heap-allocated d_nv is "cropped" to the correct
552
       * size (based on the number of children it _actually_ has).
553
       * d_nv is repointed to d_inlineNv so that destruction of the
554
       * NodeBuilder doesn't cause any problems, and the (old) value
555
       * it had is placed into the NodeManager's pool and returned in
556
       * a Node wrapper. */
557
558
531276
      crop();
559
531276
      expr::NodeValue* nv = d_nv;
560
531276
      nv->d_id = d_nm->next_id++;  // FIXME multithreading
561
531276
      d_nv = &d_inlineNv;
562
531276
      d_nvMaxChildren = default_nchild_thresh;
563
531276
      setUsed();
564
565
      // poolNv = nv;
566
531276
      d_nm->poolInsert(nv);
567
1062552
      Debug("gc") << "creating node value " << nv << " [" << nv->d_id
568
531276
                  << "]: " << *nv << "\n";
569
531276
      return nv;
570
    }
571
  }
572
}
573
574
46994723
void NodeBuilder::internalCopy(const NodeBuilder& nb)
575
{
576
46994723
  if (nb.isUsed())
577
  {
578
    setUsed();
579
    return;
580
  }
581
582
46994723
  bool realloced CVC5_UNUSED = false;
583
46994723
  if (nb.d_nvMaxChildren > d_nvMaxChildren)
584
  {
585
7827
    realloced = true;
586
7827
    realloc(nb.d_nvMaxChildren);
587
  }
588
589
46994723
  Assert(nb.d_nvMaxChildren <= d_nvMaxChildren);
590
46994723
  Assert(nb.d_nv->nv_end() >= nb.d_nv->nv_begin());
591
46994723
  Assert((size_t)(nb.d_nv->nv_end() - nb.d_nv->nv_begin()) <= d_nvMaxChildren)
592
      << "realloced:" << (realloced ? "true" : "false")
593
      << ", d_nvMax:" << d_nvMaxChildren
594
      << ", size:" << nb.d_nv->nv_end() - nb.d_nv->nv_begin()
595
      << ", nc:" << nb.d_nv->getNumChildren();
596
46994723
  std::copy(nb.d_nv->nv_begin(), nb.d_nv->nv_end(), d_nv->nv_begin());
597
598
46994723
  d_nv->d_nchildren = nb.d_nv->d_nchildren;
599
600
49203840
  for (expr::NodeValue::nv_iterator i = d_nv->nv_begin(); i != d_nv->nv_end();
601
       ++i)
602
  {
603
2209117
    (*i)->inc();
604
  }
605
}
606
607
#ifdef CVC5_DEBUG
608
226345559
inline void NodeBuilder::maybeCheckType(const TNode n) const
609
{
610
  /* force an immediate type check, if early type checking is
611
     enabled and the current node isn't a variable or constant */
612
226345559
  kind::MetaKind mk = n.getMetaKind();
613
226345559
  if (mk != kind::metakind::VARIABLE && mk != kind::metakind::NULLARY_OPERATOR
614
225217920
      && mk != kind::metakind::CONSTANT)
615
  {
616
225218378
    d_nm->getType(n, true);
617
  }
618
226345101
}
619
#endif /* CVC5_DEBUG */
620
621
4720332063
bool NodeBuilder::isUsed() const { return CVC5_PREDICT_FALSE(d_nv == nullptr); }
622
623
226506570
void NodeBuilder::setUsed()
624
{
625
226506570
  Assert(!isUsed()) << "Internal error: bad `used' state in NodeBuilder!";
626
226506570
  Assert(d_inlineNv.d_nchildren == 0
627
         && d_nvMaxChildren == default_nchild_thresh)
628
      << "Internal error: bad `inline' state in NodeBuilder!";
629
226506570
  d_nv = nullptr;
630
226506570
}
631
632
6
void NodeBuilder::setUnused()
633
{
634
6
  Assert(isUsed()) << "Internal error: bad `used' state in NodeBuilder!";
635
6
  Assert(d_inlineNv.d_nchildren == 0
636
         && d_nvMaxChildren == default_nchild_thresh)
637
      << "Internal error: bad `inline' state in NodeBuilder!";
638
6
  d_nv = &d_inlineNv;
639
6
}
640
641
812918641
bool NodeBuilder::nvIsAllocated() const
642
{
643
812918641
  return CVC5_PREDICT_FALSE(d_nv != &d_inlineNv)
644
812918641
         && CVC5_PREDICT_TRUE(d_nv != nullptr);
645
}
646
647
487814108
bool NodeBuilder::nvNeedsToBeAllocated() const
648
{
649
487814108
  return CVC5_PREDICT_FALSE(d_nv->d_nchildren == d_nvMaxChildren);
650
}
651
652
2661054
void NodeBuilder::realloc()
653
{
654
2661054
  size_t newSize = 2 * size_t(d_nvMaxChildren);
655
2661054
  size_t hardLimit = expr::NodeValue::MAX_CHILDREN;
656
2661054
  realloc(CVC5_PREDICT_FALSE(newSize > hardLimit) ? hardLimit : newSize);
657
2661054
}
658
659
487814108
void NodeBuilder::allocateNvIfNecessaryForAppend()
660
{
661
487814108
  if (CVC5_PREDICT_FALSE(nvNeedsToBeAllocated()))
662
  {
663
2661054
    realloc();
664
  }
665
487814108
}
666
667
531276
void NodeBuilder::crop()
668
{
669
1062552
  if (CVC5_PREDICT_FALSE(nvIsAllocated())
670
531276
      && CVC5_PREDICT_TRUE(d_nvMaxChildren > d_nv->d_nchildren))
671
  {
672
    // Ensure d_nv is not modified on allocation failure
673
515207
    expr::NodeValue* newBlock = (expr::NodeValue*)std::realloc(
674
515207
        d_nv,
675
        sizeof(expr::NodeValue)
676
1030414
            + (sizeof(expr::NodeValue*) * d_nv->d_nchildren));
677
515207
    if (newBlock == nullptr)
678
    {
679
      // In this case, d_nv was NOT freed.  If we throw, the
680
      // deallocation should occur on destruction of the
681
      // NodeBuilder.
682
      throw std::bad_alloc();
683
    }
684
515207
    d_nv = newBlock;
685
515207
    d_nvMaxChildren = d_nv->d_nchildren;
686
  }
687
531276
}
688
689
NodeBuilder& NodeBuilder::collapseTo(Kind k)
690
{
691
  AssertArgument(
692
      k != kind::UNDEFINED_KIND && k != kind::NULL_EXPR && k < kind::LAST_KIND,
693
      k,
694
      "illegal collapsing kind");
695
696
  if (getKind() != k)
697
  {
698
    Node n = operator Node();
699
    clear();
700
    d_nv->d_kind = expr::NodeValue::kindToDKind(k);
701
    d_nv->d_id = 1;  // have a kind already
702
    return append(n);
703
  }
704
  return *this;
705
}
706
707
std::ostream& operator<<(std::ostream& out, const NodeBuilder& nb)
708
{
709
  return out << *nb.d_nv;
710
}
711
712
29505
}  // namespace cvc5