LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/expr - node.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 310 327 94.8 %
Date: 2026-05-02 10:46:03 Functions: 535 567 94.4 %
Branches: 104 202 51.5 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Reference-counted encapsulation of a pointer to node information.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "cvc5_private.h"
      14                 :            : 
      15                 :            : #ifndef CVC5__NODE_H
      16                 :            : #define CVC5__NODE_H
      17                 :            : 
      18                 :            : #include <cvc5/cvc5_skolem_id.h>
      19                 :            : 
      20                 :            : #include <iostream>
      21                 :            : #include <map>
      22                 :            : #include <sstream>
      23                 :            : #include <string>
      24                 :            : #include <unordered_map>
      25                 :            : #include <unordered_set>
      26                 :            : #include <utility>
      27                 :            : #include <vector>
      28                 :            : 
      29                 :            : #include "base/check.h"
      30                 :            : #include "base/exception.h"
      31                 :            : #include "base/output.h"
      32                 :            : #include "expr/internal_skolem_id.h"
      33                 :            : #include "expr/kind.h"
      34                 :            : #include "expr/metakind.h"
      35                 :            : #include "expr/node_value.h"
      36                 :            : #include "options/io_utils.h"
      37                 :            : #include "options/language.h"
      38                 :            : #include "util/hash.h"
      39                 :            : #include "util/utility.h"
      40                 :            : 
      41                 :            : namespace cvc5::internal {
      42                 :            : 
      43                 :            : class TypeNode;
      44                 :            : class NodeManager;
      45                 :            : 
      46                 :            : template <bool ref_count>
      47                 :            : class NodeTemplate;
      48                 :            : 
      49                 :            : /**
      50                 :            :  * Exception thrown during the type-checking phase, it can be
      51                 :            :  * thrown by node.getType().
      52                 :            :  */
      53                 :            : class TypeCheckingExceptionPrivate : public Exception
      54                 :            : {
      55                 :            :  private:
      56                 :            :   /** The node responsible for the failure */
      57                 :            :   NodeTemplate<true>* d_node;
      58                 :            : 
      59                 :            :  public:
      60                 :            :   /**
      61                 :            :    * Construct the exception with the problematic node and the message
      62                 :            :    * @param node the problematic node
      63                 :            :    * @param message the message explaining the failure
      64                 :            :    */
      65                 :            :   TypeCheckingExceptionPrivate(NodeTemplate<false> node, std::string message);
      66                 :            : 
      67                 :            :   /** Destructor */
      68                 :            :   ~TypeCheckingExceptionPrivate() override;
      69                 :            : 
      70                 :            :   /**
      71                 :            :    * Get the Node that caused the type-checking to fail.
      72                 :            :    * @return the node
      73                 :            :    */
      74                 :            :   NodeTemplate<true> getNode() const;
      75                 :            : 
      76                 :            :   /**
      77                 :            :    * Returns the message corresponding to the type-checking failure.
      78                 :            :    * We prefer toStream() to toString() because that keeps the expr-depth
      79                 :            :    * and expr-language settings present in the stream.
      80                 :            :    */
      81                 :            :   void toStream(std::ostream& out) const override;
      82                 :            : 
      83                 :            : }; /* class TypeCheckingExceptionPrivate */
      84                 :            : 
      85                 :            : class UnknownTypeException : public TypeCheckingExceptionPrivate
      86                 :            : {
      87                 :            :  public:
      88                 :            :   UnknownTypeException(NodeTemplate<false> node);
      89                 :            : }; /* class UnknownTypeException */
      90                 :            : 
      91                 :            : /**
      92                 :            :  * \typedef NodeTemplate<true> Node;
      93                 :            :  *
      94                 :            :  * The Node class encapsulates the NodeValue with reference counting.
      95                 :            :  *
      96                 :            :  * One should use generally use Nodes to manipulate expressions, to be safe.
      97                 :            :  * Every outstanding Node that references a NodeValue is counted in that
      98                 :            :  * NodeValue's reference count.  Reference counts are maintained correctly
      99                 :            :  * on assignment of the Node object (to point to another NodeValue), and,
     100                 :            :  * upon destruction of the Node object, the NodeValue's reference count is
     101                 :            :  * decremented and, if zero, it becomes eligible for reclamation by the
     102                 :            :  * system.
     103                 :            :  */
     104                 :            : typedef NodeTemplate<true> Node;
     105                 :            : 
     106                 :            : /**
     107                 :            :  * \typedef NodeTemplate<false> TNode;
     108                 :            :  *
     109                 :            :  * The TNode class encapsulates the NodeValue but doesn't count references.
     110                 :            :  *
     111                 :            :  * TNodes are just like Nodes, but they don't update the reference count.
     112                 :            :  * Therefore, there is less overhead (copying a TNode is just the cost of
     113                 :            :  * the underlying pointer copy).  Generally speaking, this is unsafe!
     114                 :            :  * However, there are certain situations where a TNode can be used safely.
     115                 :            :  *
     116                 :            :  * The largest class of uses for TNodes are when you need to use them in a
     117                 :            :  * "temporary," scoped fashion (hence the "T" in "TNode").  In general,
     118                 :            :  * it is safe to use TNode as a function parameter type, since the calling
     119                 :            :  * function (or some other function on the call stack) presumably has a Node
     120                 :            :  * reference to the expression data.  It is generally _not_ safe, however,
     121                 :            :  * to return a TNode _from_ a function.  (Functions that return Nodes often
     122                 :            :  * create the expression they return; such new expressions may not be
     123                 :            :  * referenced on the call stack, and have a reference count of 1 on
     124                 :            :  * creation.  If this is returned as a TNode rather than a Node, the
     125                 :            :  * count drops to zero, marking the expression as eligible for reclamation.)
     126                 :            :  *
     127                 :            :  * More guidelines on when to use TNodes is available in the cvc5
     128                 :            :  * Developer's Guide:
     129                 :            :  * https://github.com/cvc5/cvc5/wiki/Developer-Guide#dealing-with-expressions-nodes-and-tnodes
     130                 :            :  */
     131                 :            : typedef NodeTemplate<false> TNode;
     132                 :            : 
     133                 :            : }  // namespace cvc5::internal
     134                 :            : 
     135                 :            : namespace std {
     136                 :            : 
     137                 :            : template <>
     138                 :            : struct hash<cvc5::internal::Node>
     139                 :            : {
     140                 :            :   size_t operator()(const cvc5::internal::Node& node) const;
     141                 :            : };
     142                 :            : 
     143                 :            : template <>
     144                 :            : struct hash<cvc5::internal::TNode>
     145                 :            : {
     146                 :            :   size_t operator()(const cvc5::internal::TNode& node) const;
     147                 :            : };
     148                 :            : 
     149                 :            : }  // namespace std
     150                 :            : 
     151                 :            : namespace cvc5::internal {
     152                 :            : namespace expr {
     153                 :            : 
     154                 :            : class NodeValue;
     155                 :            : 
     156                 :            : namespace attr {
     157                 :            : class AttributeManager;
     158                 :            : struct SmtAttributes;
     159                 :            : }  // namespace attr
     160                 :            : 
     161                 :            : class ExprSetDepth;
     162                 :            : }  // namespace expr
     163                 :            : 
     164                 :            : /**
     165                 :            :  * Encapsulation of an NodeValue pointer.  The reference count is
     166                 :            :  * maintained in the NodeValue if ref_count is true.
     167                 :            :  * @param ref_count if true reference are counted in the NodeValue
     168                 :            :  */
     169                 :            : template <bool ref_count>
     170                 :            : class NodeTemplate
     171                 :            : {
     172                 :            :   /**
     173                 :            :    * The NodeValue has access to the private constructors, so that the
     174                 :            :    * iterators can can create new nodes.
     175                 :            :    */
     176                 :            :   friend class expr::NodeValue;
     177                 :            : 
     178                 :            :   /** A convenient null-valued encapsulated pointer */
     179                 :            :   static NodeTemplate s_null;
     180                 :            : 
     181                 :            :   /** The referenced NodeValue */
     182                 :            :   expr::NodeValue* d_nv;
     183                 :            : 
     184                 :            :   /**
     185                 :            :    * This constructor is reserved for use by the NodeTemplate package; one
     186                 :            :    * must construct an NodeTemplate using one of the build mechanisms of the
     187                 :            :    * NodeTemplate package.
     188                 :            :    *
     189                 :            :    * FIXME: there's a type-system escape here to cast away the const,
     190                 :            :    * since the refcount needs to be updated.  But conceptually Nodes
     191                 :            :    * don't change their arguments, and it's nice to have
     192                 :            :    * const_iterators over them.
     193                 :            :    *
     194                 :            :    * This really does needs to be explicit to avoid hard to track errors with
     195                 :            :    * Nodes implicitly wrapping NodeValues
     196                 :            :    */
     197                 :            :   explicit NodeTemplate(const expr::NodeValue*);
     198                 :            : 
     199                 :            :   friend class NodeTemplate<true>;
     200                 :            :   friend class NodeTemplate<false>;
     201                 :            :   friend class TypeNode;
     202                 :            :   friend class NodeManager;
     203                 :            : 
     204                 :            :   friend class NodeBuilder;
     205                 :            : 
     206                 :            :   friend class ::cvc5::internal::expr::attr::AttributeManager;
     207                 :            :   friend struct ::cvc5::internal::expr::attr::SmtAttributes;
     208                 :            : 
     209                 :            :   /**
     210                 :            :    * Assigns the expression value and does reference counting. No assumptions
     211                 :            :    * are made on the expression, and should only be used if we know what we
     212                 :            :    * are doing.
     213                 :            :    *
     214                 :            :    * @param ev the expression value to assign
     215                 :            :    */
     216                 :            :   void assignNodeValue(expr::NodeValue* ev);
     217                 :            : 
     218                 :            :   // May throw an AssertionException if the Node is not live, i.e. the ref count
     219                 :            :   // is not positive.
     220                 :81344462524 :   inline void assertTNodeNotExpired() const
     221                 :            :   {
     222                 :            :     if (!ref_count)
     223                 :            :     {
     224 [ -  + ][ -  + ]:42153403184 :       Assert(d_nv->d_rc > 0) << "TNode pointing to an expired NodeValue";
                 [ -  - ]
     225                 :            :     }
     226                 :81344462524 :   }
     227                 :            : 
     228                 :            :  public:
     229                 :            :   /**
     230                 :            :    * Cache-aware, recursive version of substitute() used by the public
     231                 :            :    * member function with a similar signature.
     232                 :            :    */
     233                 :            :   Node substitute(TNode node,
     234                 :            :                   TNode replacement,
     235                 :            :                   std::unordered_map<TNode, TNode>& cache) const;
     236                 :            : 
     237                 :            :   /**
     238                 :            :    * Cache-aware, recursive version of substitute() used by the public
     239                 :            :    * member function with a similar signature.
     240                 :            :    */
     241                 :            :   template <class Iterator1, class Iterator2>
     242                 :            :   Node substitute(Iterator1 nodesBegin,
     243                 :            :                   Iterator1 nodesEnd,
     244                 :            :                   Iterator2 replacementsBegin,
     245                 :            :                   Iterator2 replacementsEnd,
     246                 :            :                   std::unordered_map<TNode, TNode>& cache) const;
     247                 :            : 
     248                 :            :   /**
     249                 :            :    * Cache-aware, recursive version of substitute() used by the public
     250                 :            :    * member function with a similar signature.
     251                 :            :    */
     252                 :            :   template <class Iterator>
     253                 :            :   Node substitute(Iterator substitutionsBegin,
     254                 :            :                   Iterator substitutionsEnd,
     255                 :            :                   std::unordered_map<TNode, TNode>& cache) const;
     256                 :            : 
     257                 :            :   /** Default constructor, makes a null expression.
     258                 :            :    *
     259                 :            :    * This constructor is `explicit` to avoid accidentially creating a null node
     260                 :            :    * from an empty braced-init-list.
     261                 :            :    */
     262                 : 2868937744 :   explicit NodeTemplate() : d_nv(&expr::NodeValue::null()) {}
     263                 :            : 
     264                 :            :   /**
     265                 :            :    * Conversion between nodes that are reference-counted and those that are
     266                 :            :    * not.
     267                 :            :    * @param node the node to make copy of
     268                 :            :    */
     269                 :            :   NodeTemplate(const NodeTemplate<!ref_count>& node);
     270                 :            : 
     271                 :            :   /**
     272                 :            :    * Copy constructor.  Note that GCC does NOT recognize an instantiation of
     273                 :            :    * the above template as a copy constructor and problems ensue.  So we
     274                 :            :    * provide an explicit one here.
     275                 :            :    * @param node the node to make copy of
     276                 :            :    */
     277                 :            :   NodeTemplate(const NodeTemplate& node);
     278                 :            : 
     279                 :            :   /**
     280                 :            :    * Assignment operator for nodes, copies the relevant information from node
     281                 :            :    * to this node.
     282                 :            :    * @param node the node to copy
     283                 :            :    * @return reference to this node
     284                 :            :    */
     285                 :            :   NodeTemplate& operator=(const NodeTemplate& node);
     286                 :            : 
     287                 :            :   /**
     288                 :            :    * Assignment operator for nodes, copies the relevant information from node
     289                 :            :    * to this node.
     290                 :            :    * @param node the node to copy
     291                 :            :    * @return reference to this node
     292                 :            :    */
     293                 :            :   NodeTemplate& operator=(const NodeTemplate<!ref_count>& node);
     294                 :            : 
     295                 :            :   /**
     296                 :            :    * Destructor. If ref_count is true it will decrement the reference count
     297                 :            :    * and, if zero, collect the NodeValue.
     298                 :            :    */
     299                 :            :   ~NodeTemplate();
     300                 :            : 
     301                 :            :   /**
     302                 :            :    * Return the null node.
     303                 :            :    * @return the null node
     304                 :            :    */
     305                 : 1157691574 :   static NodeTemplate null() { return s_null; }
     306                 :            : 
     307                 :            :   /**
     308                 :            :    * Returns true if this expression is a null expression.
     309                 :            :    * @return true if null
     310                 :            :    */
     311                 : 8107235372 :   bool isNull() const
     312                 :            :   {
     313                 : 8107235372 :     assertTNodeNotExpired();
     314                 : 8107235372 :     return d_nv == &expr::NodeValue::null();
     315                 :            :   }
     316                 :            : 
     317                 :            :   /**
     318                 :            :    * Structural comparison operator for expressions.
     319                 :            :    * @param node the node to compare to
     320                 :            :    * @return true if expressions are equal, false otherwise
     321                 :            :    */
     322                 :            :   template <bool ref_count_1>
     323                 : 9818917118 :   bool operator==(const NodeTemplate<ref_count_1>& node) const
     324                 :            :   {
     325                 : 9818917118 :     assertTNodeNotExpired();
     326                 : 9818917118 :     node.assertTNodeNotExpired();
     327                 : 9818917118 :     return d_nv == node.d_nv;
     328                 :            :   }
     329                 :            : 
     330                 :            :   /**
     331                 :            :    * Structural comparison operator for expressions.
     332                 :            :    * @param node the node to compare to
     333                 :            :    * @return false if expressions are equal, true otherwise
     334                 :            :    */
     335                 :            :   template <bool ref_count_1>
     336                 :  508366456 :   bool operator!=(const NodeTemplate<ref_count_1>& node) const
     337                 :            :   {
     338                 :  508366456 :     assertTNodeNotExpired();
     339                 :  508366456 :     node.assertTNodeNotExpired();
     340                 :  508366456 :     return d_nv != node.d_nv;
     341                 :            :   }
     342                 :            : 
     343                 :            :   /**
     344                 :            :    * We compare by expression ids so, keeping things deterministic and having
     345                 :            :    * that subexpressions have to be smaller than the enclosing expressions.
     346                 :            :    * @param node the node to compare to
     347                 :            :    * @return true if this expression is smaller
     348                 :            :    */
     349                 :            :   template <bool ref_count_1>
     350                 : 6648701941 :   inline bool operator<(const NodeTemplate<ref_count_1>& node) const
     351                 :            :   {
     352                 : 6648701941 :     assertTNodeNotExpired();
     353                 : 6648701941 :     node.assertTNodeNotExpired();
     354                 : 6648701941 :     return d_nv->d_id < node.d_nv->d_id;
     355                 :            :   }
     356                 :            : 
     357                 :            :   /**
     358                 :            :    * We compare by expression ids so, keeping things deterministic and having
     359                 :            :    * that subexpressions have to be smaller than the enclosing expressions.
     360                 :            :    * @param node the node to compare to
     361                 :            :    * @return true if this expression is greater
     362                 :            :    */
     363                 :            :   template <bool ref_count_1>
     364                 :   16843239 :   inline bool operator>(const NodeTemplate<ref_count_1>& node) const
     365                 :            :   {
     366                 :   16843239 :     assertTNodeNotExpired();
     367                 :   16843239 :     node.assertTNodeNotExpired();
     368                 :   16843239 :     return d_nv->d_id > node.d_nv->d_id;
     369                 :            :   }
     370                 :            : 
     371                 :            :   /**
     372                 :            :    * We compare by expression ids so, keeping things deterministic and having
     373                 :            :    * that subexpressions have to be smaller than the enclosing expressions.
     374                 :            :    * @param node the node to compare to
     375                 :            :    * @return true if this expression is smaller than or equal to
     376                 :            :    */
     377                 :            :   template <bool ref_count_1>
     378                 :      14373 :   inline bool operator<=(const NodeTemplate<ref_count_1>& node) const
     379                 :            :   {
     380                 :      14373 :     assertTNodeNotExpired();
     381                 :      14373 :     node.assertTNodeNotExpired();
     382                 :      14373 :     return d_nv->d_id <= node.d_nv->d_id;
     383                 :            :   }
     384                 :            : 
     385                 :            :   /**
     386                 :            :    * We compare by expression ids so, keeping things deterministic and having
     387                 :            :    * that subexpressions have to be smaller than the enclosing expressions.
     388                 :            :    * @param node the node to compare to
     389                 :            :    * @return true if this expression is greater than or equal to
     390                 :            :    */
     391                 :            :   template <bool ref_count_1>
     392                 :    8070240 :   inline bool operator>=(const NodeTemplate<ref_count_1>& node) const
     393                 :            :   {
     394                 :    8070240 :     assertTNodeNotExpired();
     395                 :    8070240 :     node.assertTNodeNotExpired();
     396                 :    8070240 :     return d_nv->d_id >= node.d_nv->d_id;
     397                 :            :   }
     398                 :            : 
     399                 :            :   /**
     400                 :            :    * Returns the i-th child of this node.
     401                 :            :    * @param i the index of the child
     402                 :            :    * @return the node representing the i-th child
     403                 :            :    */
     404                 : 2817525285 :   NodeTemplate operator[](int i) const
     405                 :            :   {
     406                 : 2817525285 :     assertTNodeNotExpired();
     407                 : 2817525285 :     return NodeTemplate(d_nv->getChild(i));
     408                 :            :   }
     409                 :            : 
     410                 :            :   /**
     411                 :            :    * Returns true if this node represents a constant
     412                 :            :    * @return true if const
     413                 :            :    */
     414                 :            :   bool isConst() const;
     415                 :            : 
     416                 :            :   /**
     417                 :            :    * Returns true if this node represents a variable
     418                 :            :    * @return true if variable
     419                 :            :    */
     420                 :  681570318 :   inline bool isVar() const
     421                 :            :   {
     422                 :  681570318 :     assertTNodeNotExpired();
     423                 :  681570318 :     return getMetaKind() == kind::metakind::VARIABLE;
     424                 :            :   }
     425                 :            : 
     426                 :            :   /**
     427                 :            :    * Returns true if this node represents a nullary operator
     428                 :            :    */
     429                 :            :   inline bool isNullaryOp() const
     430                 :            :   {
     431                 :            :     assertTNodeNotExpired();
     432                 :            :     return getMetaKind() == kind::metakind::NULLARY_OPERATOR;
     433                 :            :   }
     434                 :            : 
     435                 :            :   /**
     436                 :            :    * Returns true if this node represents a closure, that is an expression
     437                 :            :    * that binds variables.
     438                 :            :    */
     439                 :  192497938 :   inline bool isClosure() const
     440                 :            :   {
     441                 :  192497938 :     assertTNodeNotExpired();
     442                 :  192497938 :     return isClosureKind(getKind());
     443                 :            :   }
     444                 :            : 
     445                 :            :   /**
     446                 :            :    * Returns the unique id of this node
     447                 :            :    * @return the ud
     448                 :            :    */
     449                 : 7872927307 :   uint64_t getId() const
     450                 :            :   {
     451                 : 7872927307 :     assertTNodeNotExpired();
     452                 : 7872927307 :     return d_nv->getId();
     453                 :            :   }
     454                 :            : 
     455                 :            :   /**
     456                 :            :    * Returns the associated node manager
     457                 :            :    */
     458                 : 4338854328 :   NodeManager* getNodeManager() const
     459                 :            :   {
     460                 : 4338854328 :     assertTNodeNotExpired();
     461                 : 4338854328 :     return d_nv->getNodeManager();
     462                 :            :   }
     463                 :            : 
     464                 :            :   /**
     465                 :            :    * Returns a node representing the operator of this expression.
     466                 :            :    * If this is an APPLY_UF, then the operator will be a functional term.
     467                 :            :    * Otherwise, it will be a node with kind BUILTIN.
     468                 :            :    */
     469                 :            :   NodeTemplate<true> getOperator() const;
     470                 :            : 
     471                 :            :   /**
     472                 :            :    * Returns true if the node has an operator (i.e., it's not a
     473                 :            :    * variable or a constant).
     474                 :            :    */
     475                 :            :   inline bool hasOperator() const;
     476                 :            : 
     477                 :            :   /**
     478                 :            :    * Get the type for the node and optionally do type checking.
     479                 :            :    *
     480                 :            :    * Initial type computation will be near-constant time if
     481                 :            :    * type checking is not requested. Results are memoized, so that
     482                 :            :    * subsequent calls to getType() without type checking will be
     483                 :            :    * constant time.
     484                 :            :    *
     485                 :            :    * Initial type checking is linear in the size of the expression.
     486                 :            :    * Again, the results are memoized, so that subsequent calls to
     487                 :            :    * getType(), with or without type checking, will be constant
     488                 :            :    * time.
     489                 :            :    *
     490                 :            :    * NOTE: A TypeCheckingException can be thrown even when type
     491                 :            :    * checking is not requested. getType() will always return a
     492                 :            :    * valid and correct type and, thus, an exception will be thrown
     493                 :            :    * when no valid or correct type can be computed (e.g., if the
     494                 :            :    * arguments to a bit-vector operation aren't bit-vectors). When
     495                 :            :    * type checking is not requested, getType() will do the minimum
     496                 :            :    * amount of checking required to return a valid result.
     497                 :            :    *
     498                 :            :    * @param check whether we should check the type as we compute it
     499                 :            :    * (default: false)
     500                 :            :    */
     501                 :            :   TypeNode getType(bool check = false) const;
     502                 :            :   /**
     503                 :            :    * Same as getType, but does not throw a type exception if this term is
     504                 :            :    * not well-typed. Instead, this method will return the null type.
     505                 :            :    */
     506                 :            :   TypeNode getTypeOrNull(bool check = false) const;
     507                 :            : 
     508                 :            :   /**
     509                 :            :    * Has name? Return true if this node has an associated variable
     510                 :            :    * name (via the attribute expr::VarNameAttr). This is true typically for
     511                 :            :    * user-created variables.
     512                 :            :    */
     513                 :            :   bool hasName() const;
     514                 :            :   /**
     515                 :            :    * Get the name. Returns the string value of the expr::VarNameAttr attribute
     516                 :            :    * for this node.
     517                 :            :    */
     518                 :            :   std::string getName() const;
     519                 :            : 
     520                 :            :   /**
     521                 :            :    * Substitution of Nodes.
     522                 :            :    */
     523                 :            :   Node substitute(TNode node, TNode replacement) const;
     524                 :            : 
     525                 :            :   /**
     526                 :            :    * Simultaneous substitution of Nodes.  Elements in the Iterator1
     527                 :            :    * range will be replaced by their corresponding element in the
     528                 :            :    * Iterator2 range.  Both ranges should have the same size.
     529                 :            :    */
     530                 :            :   template <class Iterator1, class Iterator2>
     531                 :            :   Node substitute(Iterator1 nodesBegin,
     532                 :            :                   Iterator1 nodesEnd,
     533                 :            :                   Iterator2 replacementsBegin,
     534                 :            :                   Iterator2 replacementsEnd) const;
     535                 :            : 
     536                 :            :   /**
     537                 :            :    * Simultaneous substitution of Nodes.  Iterators should be over
     538                 :            :    * pairs (x,y) for the rewrites [x->y].
     539                 :            :    */
     540                 :            :   template <class Iterator>
     541                 :            :   Node substitute(Iterator substitutionsBegin, Iterator substitutionsEnd) const;
     542                 :            : 
     543                 :            :   /**
     544                 :            :    * Simultaneous substitution of Nodes in cache.
     545                 :            :    */
     546                 :            :   Node substitute(std::unordered_map<TNode, TNode>& cache) const;
     547                 :            : 
     548                 :            :   /**
     549                 :            :    * Returns the kind of this node.
     550                 :            :    * @return the kind
     551                 :            :    */
     552                 :11179890327 :   inline Kind getKind() const
     553                 :            :   {
     554                 :11179890327 :     assertTNodeNotExpired();
     555                 :11179890327 :     return Kind(d_nv->d_kind);
     556                 :            :   }
     557                 :            : 
     558                 :            :   /**
     559                 :            :    * Returns the metakind of this node.
     560                 :            :    * @return the metakind
     561                 :            :    */
     562                 : 2629073819 :   inline kind::MetaKind getMetaKind() const
     563                 :            :   {
     564                 : 2629073819 :     assertTNodeNotExpired();
     565                 : 2629073819 :     return kind::metaKindOf(getKind());
     566                 :            :   }
     567                 :            : 
     568                 :            :   /**
     569                 :            :    * Returns the number of children this node has.
     570                 :            :    * @return the number of children
     571                 :            :    */
     572                 :            :   inline size_t getNumChildren() const;
     573                 :            : 
     574                 :            :   /**
     575                 :            :    * If this is a CONST_* Node, extract the constant from it.
     576                 :            :    */
     577                 :            :   template <class T>
     578                 :            :   CVC5_NO_DANGLING inline const T& getConst() const;
     579                 :            : 
     580                 :            :   /**
     581                 :            :    * @return true if this is a skolem function.
     582                 :            :    */
     583                 :            :   bool isSkolem() const;
     584                 :            : 
     585                 :            :   /**
     586                 :            :    * @return the skolem identifier of this node.
     587                 :            :    */
     588                 :            :   SkolemId getSkolemId() const;
     589                 :            : 
     590                 :            :   /**
     591                 :            :    * @return the skolem indices of this node.
     592                 :            :    */
     593                 :            :   std::vector<Node> getSkolemIndices() const;
     594                 :            : 
     595                 :            :   /**
     596                 :            :    * @return the internal skolem function id, for skolems whose id is
     597                 :            :    * SkolemId::INTERNAL.
     598                 :            :    */
     599                 :            :   InternalSkolemId getInternalSkolemId() const;
     600                 :            : 
     601                 :            :   /**
     602                 :            :    * Returns the reference count of this node.
     603                 :            :    * @return the refcount
     604                 :            :    */
     605                 :            :   unsigned getRefCount() const { return d_nv->getRefCount(); }
     606                 :            : 
     607                 :            :   /**
     608                 :            :    * Returns the value of the given attribute that this has been attached.
     609                 :            :    * @param attKind the kind of the attribute
     610                 :            :    * @return the value of the attribute
     611                 :            :    */
     612                 :            :   template <class AttrKind>
     613                 :            :   inline typename AttrKind::value_type getAttribute(
     614                 :            :       const AttrKind& attKind) const;
     615                 :            : 
     616                 :            :   // Note that there are two, distinct hasAttribute() declarations for
     617                 :            :   // a reason (rather than using a pointer-valued argument with a
     618                 :            :   // default value): they permit more optimized code in the underlying
     619                 :            :   // hasAttribute() implementations.
     620                 :            : 
     621                 :            :   /**
     622                 :            :    * Returns true if this node has been associated an attribute of given kind.
     623                 :            :    * Additionaly, if a pointer to the value_kind is give, and the attribute
     624                 :            :    * value has been set for this node, it will be returned.
     625                 :            :    * @param attKind the kind of the attribute
     626                 :            :    * @return true if this node has the requested attribute
     627                 :            :    */
     628                 :            :   template <class AttrKind>
     629                 :            :   inline bool hasAttribute(const AttrKind& attKind) const;
     630                 :            : 
     631                 :            :   /**
     632                 :            :    * Returns true if this node has been associated an attribute of given kind.
     633                 :            :    * Additionaly, if a pointer to the value_kind is give, and the attribute
     634                 :            :    * value has been set for this node, it will be returned.
     635                 :            :    * @param attKind the kind of the attribute
     636                 :            :    * @param value where to store the value if it exists
     637                 :            :    * @return true if this node has the requested attribute
     638                 :            :    */
     639                 :            :   template <class AttrKind>
     640                 :            :   inline bool getAttribute(const AttrKind& attKind,
     641                 :            :                            typename AttrKind::value_type& value) const;
     642                 :            : 
     643                 :            :   /**
     644                 :            :    * Sets the given attribute of this node to the given value.
     645                 :            :    * @param attKind the kind of the atribute
     646                 :            :    * @param value the value to set the attribute to
     647                 :            :    */
     648                 :            :   template <class AttrKind>
     649                 :            :   inline void setAttribute(const AttrKind& attKind,
     650                 :            :                            const typename AttrKind::value_type& value);
     651                 :            : 
     652                 :            :   /** Iterator allowing for scanning through the children. */
     653                 :            :   typedef typename expr::NodeValue::iterator<NodeTemplate<ref_count>> iterator;
     654                 :            :   /** Constant iterator allowing for scanning through the children. */
     655                 :            :   using const_iterator =
     656                 :            :       typename expr::NodeValue::iterator<NodeTemplate<ref_count>>;
     657                 :            :   /**
     658                 :            :    * Reverse constant iterator allowing for scanning through the children in
     659                 :            :    * reverse order.
     660                 :            :    */
     661                 :            :   using const_reverse_iterator = std::reverse_iterator<
     662                 :            :       typename expr::NodeValue::iterator<NodeTemplate<ref_count>>>;
     663                 :            : 
     664                 :            :   class kinded_iterator
     665                 :            :   {
     666                 :            :     friend class NodeTemplate<ref_count>;
     667                 :            : 
     668                 :            :     NodeTemplate<ref_count> d_node;
     669                 :            :     ssize_t d_child;
     670                 :            : 
     671                 :          4 :     kinded_iterator(TNode node, ssize_t child) : d_node(node), d_child(child) {}
     672                 :            : 
     673                 :            :     // These are factories to serve as clients to Node::begin<K>() and
     674                 :            :     // Node::end<K>().
     675                 :          2 :     static kinded_iterator begin(TNode n, Kind k)
     676                 :            :     {
     677         [ +  + ]:          2 :       return kinded_iterator(n, n.getKind() == k ? 0 : -2);
     678                 :            :     }
     679                 :          2 :     static kinded_iterator end(TNode n, Kind k)
     680                 :            :     {
     681         [ +  + ]:          2 :       return kinded_iterator(n, n.getKind() == k ? n.getNumChildren() : -1);
     682                 :            :     }
     683                 :            : 
     684                 :            :    public:
     685                 :            :     typedef NodeTemplate<ref_count> value_type;
     686                 :            :     typedef std::ptrdiff_t difference_type;
     687                 :            :     typedef NodeTemplate<ref_count>* pointer;
     688                 :            :     typedef NodeTemplate<ref_count>& reference;
     689                 :            : 
     690                 :            :     kinded_iterator() : d_node(NodeTemplate<ref_count>::null()), d_child(-2) {}
     691                 :            : 
     692                 :          4 :     NodeTemplate<ref_count> operator*()
     693                 :            :     {
     694         [ +  + ]:          4 :       return d_child < 0 ? d_node : d_node[d_child];
     695                 :            :     }
     696                 :            : 
     697                 :          2 :     bool operator==(const kinded_iterator& i)
     698                 :            :     {
     699 [ +  - ][ +  - ]:          2 :       return d_node == i.d_node && d_child == i.d_child;
     700                 :            :     }
     701                 :            : 
     702                 :          0 :     bool operator!=(const kinded_iterator& i) { return !(*this == i); }
     703                 :            : 
     704                 :          4 :     kinded_iterator& operator++()
     705                 :            :     {
     706         [ +  - ]:          4 :       if (d_child != -1)
     707                 :            :       {
     708                 :          4 :         ++d_child;
     709                 :            :       }
     710                 :          4 :       return *this;
     711                 :            :     }
     712                 :            : 
     713                 :          4 :     kinded_iterator operator++(int)
     714                 :            :     {
     715                 :          4 :       kinded_iterator i = *this;
     716                 :          4 :       ++*this;
     717                 :          4 :       return i;
     718                 :            :     }
     719                 :            :   }; /* class NodeTemplate<ref_count>::kinded_iterator */
     720                 :            : 
     721                 :            :   typedef kinded_iterator const_kinded_iterator;
     722                 :            : 
     723                 :            :   /**
     724                 :            :    * Returns the iterator pointing to the first child.
     725                 :            :    * @return the iterator
     726                 :            :    */
     727                 :  845686292 :   inline iterator begin()
     728                 :            :   {
     729                 :  845686292 :     assertTNodeNotExpired();
     730                 :  845686292 :     return d_nv->begin<NodeTemplate<ref_count>>();
     731                 :            :   }
     732                 :            : 
     733                 :            :   /**
     734                 :            :    * Returns the iterator pointing to the end of the children (one beyond the
     735                 :            :    * last one).
     736                 :            :    * @return the end of the children iterator.
     737                 :            :    */
     738                 : 1446496222 :   inline iterator end()
     739                 :            :   {
     740                 : 1446496222 :     assertTNodeNotExpired();
     741                 : 1446496222 :     return d_nv->end<NodeTemplate<ref_count>>();
     742                 :            :   }
     743                 :            : 
     744                 :            :   /**
     745                 :            :    * Returns the iterator pointing to the first child, if the node's
     746                 :            :    * kind is the same as the parameter, otherwise returns the iterator
     747                 :            :    * pointing to the node itself.  This is useful if you want to
     748                 :            :    * pretend to iterate over a "unary" ADD, for instance, since unary
     749                 :            :    * PLUSes don't exist---begin(ADD) will give an iterator over the
     750                 :            :    * children if the node's an ADD node, otherwise give an iterator
     751                 :            :    * over the node itself, as if it were a unary ADD.
     752                 :            :    * @param kind the kind to match
     753                 :            :    * @return the kinded_iterator iterating over this Node (if its kind
     754                 :            :    * is not the passed kind) or its children
     755                 :            :    */
     756                 :          2 :   inline kinded_iterator begin(Kind kind)
     757                 :            :   {
     758                 :          2 :     assertTNodeNotExpired();
     759                 :          2 :     return kinded_iterator::begin(*this, kind);
     760                 :            :   }
     761                 :            : 
     762                 :            :   /**
     763                 :            :    * Returns the iterator pointing to the end of the children (one
     764                 :            :    * beyond the last one), if the node's kind is the same as the
     765                 :            :    * parameter, otherwise returns the iterator pointing to the
     766                 :            :    * one-of-the-node-itself.  This is useful if you want to pretend to
     767                 :            :    * iterate over a "unary" ADD, for instance, since unary PLUSes
     768                 :            :    * don't exist---begin(ADD) will give an iterator over the children
     769                 :            :    * if the node's an ADD node, otherwise give an iterator over the
     770                 :            :    * node itself, as if it were a unary ADD.
     771                 :            :    * @param kind the kind to match
     772                 :            :    * @return the kinded_iterator pointing off-the-end of this Node (if
     773                 :            :    * its kind is not the passed kind) or off-the-end of its children
     774                 :            :    */
     775                 :          2 :   inline kinded_iterator end(Kind kind)
     776                 :            :   {
     777                 :          2 :     assertTNodeNotExpired();
     778                 :          2 :     return kinded_iterator::end(*this, kind);
     779                 :            :   }
     780                 :            : 
     781                 :            :   /**
     782                 :            :    * Returns the const_iterator pointing to the first child.
     783                 :            :    * @return the const_iterator
     784                 :            :    */
     785                 :  127068426 :   const_iterator begin() const
     786                 :            :   {
     787                 :  127068426 :     assertTNodeNotExpired();
     788                 :  127068426 :     return d_nv->begin<NodeTemplate<ref_count>>();
     789                 :            :   }
     790                 :            : 
     791                 :            :   /**
     792                 :            :    * Returns the const_iterator pointing to the end of the children (one
     793                 :            :    * beyond the last one.
     794                 :            :    * @return the end of the children const_iterator.
     795                 :            :    */
     796                 :  117494993 :   const_iterator end() const
     797                 :            :   {
     798                 :  117494993 :     assertTNodeNotExpired();
     799                 :  117494993 :     return d_nv->end<NodeTemplate<ref_count>>();
     800                 :            :   }
     801                 :            : 
     802                 :            :   /**
     803                 :            :    * Returns the const_reverse_iterator pointing to the last child.
     804                 :            :    * @return the const_reverse_iterator
     805                 :            :    */
     806                 :   11395268 :   const_reverse_iterator rbegin() const
     807                 :            :   {
     808                 :   11395268 :     assertTNodeNotExpired();
     809                 :   11395268 :     return std::make_reverse_iterator(d_nv->end<NodeTemplate<ref_count>>());
     810                 :            :   }
     811                 :            : 
     812                 :            :   /**
     813                 :            :    * Returns the const_reverse_iterator pointing to one before the first child.
     814                 :            :    * @return the end of the const_reverse_iterator.
     815                 :            :    */
     816                 :   11395268 :   const_reverse_iterator rend() const
     817                 :            :   {
     818                 :   11395268 :     assertTNodeNotExpired();
     819                 :   11395268 :     return std::make_reverse_iterator(d_nv->begin<NodeTemplate<ref_count>>());
     820                 :            :   }
     821                 :            : 
     822                 :            :   /**
     823                 :            :    * Returns the iterator pointing to the first child, if the node's
     824                 :            :    * kind is the same as the parameter, otherwise returns the iterator
     825                 :            :    * pointing to the node itself.  This is useful if you want to
     826                 :            :    * pretend to iterate over a "unary" ADD, for instance, since unary
     827                 :            :    * PLUSes don't exist---begin(ADD) will give an iterator over the
     828                 :            :    * children if the node's an ADD node, otherwise give an iterator
     829                 :            :    * over the node itself, as if it were a unary ADD.
     830                 :            :    * @param kind the kind to match
     831                 :            :    * @return the kinded_iterator iterating over this Node (if its kind
     832                 :            :    * is not the passed kind) or its children
     833                 :            :    */
     834                 :            :   inline const_kinded_iterator begin(Kind kind) const
     835                 :            :   {
     836                 :            :     assertTNodeNotExpired();
     837                 :            :     return const_kinded_iterator::begin(*this, kind);
     838                 :            :   }
     839                 :            : 
     840                 :            :   /**
     841                 :            :    * Returns the iterator pointing to the end of the children (one
     842                 :            :    * beyond the last one), if the node's kind is the same as the
     843                 :            :    * parameter, otherwise returns the iterator pointing to the
     844                 :            :    * one-of-the-node-itself.  This is useful if you want to pretend to
     845                 :            :    * iterate over a "unary" ADD, for instance, since unary PLUSes
     846                 :            :    * don't exist---begin(ADD) will give an iterator over the children
     847                 :            :    * if the node's an ADD node, otherwise give an iterator over the
     848                 :            :    * node itself, as if it were a unary ADD.
     849                 :            :    * @param kind the kind to match
     850                 :            :    * @return the kinded_iterator pointing off-the-end of this Node (if
     851                 :            :    * its kind is not the passed kind) or off-the-end of its children
     852                 :            :    */
     853                 :            :   inline const_kinded_iterator end(Kind kind) const
     854                 :            :   {
     855                 :            :     assertTNodeNotExpired();
     856                 :            :     return const_kinded_iterator::end(*this, kind);
     857                 :            :   }
     858                 :            : 
     859                 :            :   /**
     860                 :            :    * Converts this node into a string representation.
     861                 :            :    * @return the string representation of this node.
     862                 :            :    */
     863                 :      68057 :   inline std::string toString() const
     864                 :            :   {
     865                 :      68057 :     assertTNodeNotExpired();
     866                 :      68057 :     return d_nv->toString();
     867                 :            :   }
     868                 :            : 
     869                 :            :   /**
     870                 :            :    * Converts this node into a string representation and sends it to the
     871                 :            :    * given stream
     872                 :            :    *
     873                 :            :    * @param out the stream to serialize this node to
     874                 :            :    */
     875                 :    8379954 :   inline void toStream(std::ostream& out) const
     876                 :            :   {
     877                 :    8379954 :     assertTNodeNotExpired();
     878                 :    8379954 :     d_nv->toStream(out);
     879                 :    8379954 :   }
     880                 :            : 
     881                 :        542 :   void constToStream(std::ostream& out) const
     882                 :            :   {
     883                 :        542 :     kind::metakind::nodeValueConstantToStream(out, d_nv);
     884                 :        542 :   }
     885                 :            : 
     886                 :            :   /**
     887                 :            :    * Very basic pretty printer for Node.
     888                 :            :    * @param out output stream to print to.
     889                 :            :    * @param indent number of spaces to indent the formula by.
     890                 :            :    */
     891                 :            :   inline void printAst(std::ostream& out, int indent = 0) const;
     892                 :            : 
     893                 :            :   template <bool ref_count2>
     894                 :            :   NodeTemplate<true> eqNode(const NodeTemplate<ref_count2>& right) const;
     895                 :            : 
     896                 :            :   NodeTemplate<true> notNode() const;
     897                 :            :   NodeTemplate<true> negate() const;
     898                 :            :   template <bool ref_count2>
     899                 :            :   NodeTemplate<true> andNode(const NodeTemplate<ref_count2>& right) const;
     900                 :            :   template <bool ref_count2>
     901                 :            :   NodeTemplate<true> orNode(const NodeTemplate<ref_count2>& right) const;
     902                 :            :   template <bool ref_count2, bool ref_count3>
     903                 :            :   NodeTemplate<true> iteNode(const NodeTemplate<ref_count2>& thenpart,
     904                 :            :                              const NodeTemplate<ref_count3>& elsepart) const;
     905                 :            :   NodeTemplate<true> iteNode(const TNode (&args)[2]) const;
     906                 :            :   template <bool ref_count2>
     907                 :            :   NodeTemplate<true> impNode(const NodeTemplate<ref_count2>& right) const;
     908                 :            :   template <bool ref_count2>
     909                 :            :   NodeTemplate<true> xorNode(const NodeTemplate<ref_count2>& right) const;
     910                 :            : 
     911                 :            : }; /* class NodeTemplate<ref_count> */
     912                 :            : 
     913                 :            : /**
     914                 :            :  * Serializes a given node to the given stream.
     915                 :            :  *
     916                 :            :  * @param out the output stream to use
     917                 :            :  * @param n the node to output to the stream
     918                 :            :  * @return the stream
     919                 :            :  */
     920                 :    3141653 : inline std::ostream& operator<<(std::ostream& out, TNode n)
     921                 :            : {
     922                 :    3141653 :   n.toStream(out);
     923                 :    3141653 :   return out;
     924                 :            : }
     925                 :            : 
     926                 :            : /**
     927                 :            :  * Serialize a vector of nodes to given stream.
     928                 :            :  *
     929                 :            :  * @param out the output stream to use
     930                 :            :  * @param container the vector of nodes to output to the stream
     931                 :            :  * @return the stream
     932                 :            :  */
     933                 :            : template <bool RC>
     934                 :          0 : std::ostream& operator<<(std::ostream& out,
     935                 :            :                          const std::vector<NodeTemplate<RC>>& container)
     936                 :            : {
     937                 :          0 :   container_to_stream(out, container);
     938                 :          0 :   return out;
     939                 :            : }
     940                 :            : 
     941                 :            : /**
     942                 :            :  * Serialize a set of nodes to the given stream.
     943                 :            :  *
     944                 :            :  * @param out the output stream to use
     945                 :            :  * @param container the set of nodes to output to the stream
     946                 :            :  * @return the stream
     947                 :            :  */
     948                 :            : template <bool RC>
     949                 :          0 : std::ostream& operator<<(std::ostream& out,
     950                 :            :                          const std::set<NodeTemplate<RC>>& container)
     951                 :            : {
     952                 :          0 :   container_to_stream(out, container);
     953                 :          0 :   return out;
     954                 :            : }
     955                 :            : 
     956                 :            : /**
     957                 :            :  * Serialize an unordered_set of nodes to the given stream.
     958                 :            :  *
     959                 :            :  * @param out the output stream to use
     960                 :            :  * @param container the unordered_set of nodes to output to the stream
     961                 :            :  * @return the stream
     962                 :            :  */
     963                 :            : template <bool RC, typename hash_function>
     964                 :          0 : std::ostream& operator<<(
     965                 :            :     std::ostream& out,
     966                 :            :     const std::unordered_set<NodeTemplate<RC>, hash_function>& container)
     967                 :            : {
     968                 :          0 :   container_to_stream(out, container);
     969                 :          0 :   return out;
     970                 :            : }
     971                 :            : 
     972                 :            : /**
     973                 :            :  * Serialize a map of nodes to the given stream.
     974                 :            :  *
     975                 :            :  * @param out the output stream to use
     976                 :            :  * @param container the map of nodes to output to the stream
     977                 :            :  * @return the stream
     978                 :            :  */
     979                 :            : template <bool RC, typename V>
     980                 :          0 : std::ostream& operator<<(std::ostream& out,
     981                 :            :                          const std::map<NodeTemplate<RC>, V>& container)
     982                 :            : {
     983                 :          0 :   container_to_stream(out, container);
     984                 :          0 :   return out;
     985                 :            : }
     986                 :            : 
     987                 :            : /**
     988                 :            :  * Serialize an unordered_map of nodes to the given stream.
     989                 :            :  *
     990                 :            :  * @param out the output stream to use
     991                 :            :  * @param container the unordered_map of nodes to output to the stream
     992                 :            :  * @return the stream
     993                 :            :  */
     994                 :            : template <bool RC, typename V, typename HF>
     995                 :            : std::ostream& operator<<(
     996                 :            :     std::ostream& out,
     997                 :            :     const std::unordered_map<NodeTemplate<RC>, V, HF>& container)
     998                 :            : {
     999                 :            :   container_to_stream(out, container);
    1000                 :            :   return out;
    1001                 :            : }
    1002                 :            : 
    1003                 :            : }  // namespace cvc5::internal
    1004                 :            : 
    1005                 :            : // #include "expr/attribute.h"
    1006                 :            : #include "expr/node_manager.h"
    1007                 :            : 
    1008                 :            : namespace cvc5::internal {
    1009                 :            : 
    1010                 :            : using TNodePairHashFunction =
    1011                 :            :     PairHashFunction<TNode, TNode, std::hash<TNode>, std::hash<TNode>>;
    1012                 :            : 
    1013                 :            : template <bool ref_count>
    1014                 : 1473805739 : inline size_t NodeTemplate<ref_count>::getNumChildren() const
    1015                 :            : {
    1016                 : 1473805739 :   assertTNodeNotExpired();
    1017                 : 1473805739 :   return d_nv->getNumChildren();
    1018                 :            : }
    1019                 :            : 
    1020                 :            : template <bool ref_count>
    1021                 :            : template <class T>
    1022                 :  789366493 : inline const T& NodeTemplate<ref_count>::getConst() const
    1023                 :            : {
    1024                 :  789366493 :   assertTNodeNotExpired();
    1025                 :  789366493 :   return d_nv->getConst<T>();
    1026                 :            : }
    1027                 :            : 
    1028                 :            : template <bool ref_count>
    1029                 :            : template <class AttrKind>
    1030                 : 1187555355 : inline typename AttrKind::value_type NodeTemplate<ref_count>::getAttribute(
    1031                 :            :     const AttrKind&) const
    1032                 :            : {
    1033                 : 1187555355 :   assertTNodeNotExpired();
    1034                 :            : 
    1035                 : 1187555355 :   return d_nv->getNodeManager()->getAttribute(*this, AttrKind());
    1036                 :            : }
    1037                 :            : 
    1038                 :            : template <bool ref_count>
    1039                 :            : template <class AttrKind>
    1040                 :  372444877 : inline bool NodeTemplate<ref_count>::hasAttribute(const AttrKind&) const
    1041                 :            : {
    1042                 :  372444877 :   assertTNodeNotExpired();
    1043                 :            : 
    1044                 :  372444877 :   return d_nv->getNodeManager()->hasAttribute(*this, AttrKind());
    1045                 :            : }
    1046                 :            : 
    1047                 :            : template <bool ref_count>
    1048                 :            : template <class AttrKind>
    1049                 :  159825424 : inline bool NodeTemplate<ref_count>::getAttribute(
    1050                 :            :     const AttrKind&, typename AttrKind::value_type& ret) const
    1051                 :            : {
    1052                 :  159825424 :   assertTNodeNotExpired();
    1053                 :            : 
    1054                 :  159825424 :   return d_nv->getNodeManager()->getAttribute(*this, AttrKind(), ret);
    1055                 :            : }
    1056                 :            : 
    1057                 :            : template <bool ref_count>
    1058                 :            : template <class AttrKind>
    1059                 :  238987587 : inline void NodeTemplate<ref_count>::setAttribute(
    1060                 :            :     const AttrKind&, const typename AttrKind::value_type& value)
    1061                 :            : {
    1062                 :  238987587 :   assertTNodeNotExpired();
    1063                 :            : 
    1064                 :  238987587 :   d_nv->getNodeManager()->setAttribute(*this, AttrKind(), value);
    1065                 :  238987587 : }
    1066                 :            : 
    1067                 :            : template <bool ref_count>
    1068                 :            : NodeTemplate<ref_count> NodeTemplate<ref_count>::s_null(
    1069                 :            :     &expr::NodeValue::null());
    1070                 :            : 
    1071                 :            : // FIXME: escape from type system convenient but is there a better
    1072                 :            : // way?  Nodes conceptually don't change their expr values but of
    1073                 :            : // course they do modify the refcount.  But it's nice to be able to
    1074                 :            : // support node_iterators over const NodeValue*.  So.... hm.
    1075                 :            : template <bool ref_count>
    1076                 : 6348174269 : NodeTemplate<ref_count>::NodeTemplate(const expr::NodeValue* ev)
    1077                 : 6348174269 :     : d_nv(const_cast<expr::NodeValue*>(ev))
    1078                 :            : {
    1079 [ -  + ][ -  + ]: 6348174269 :   Assert(d_nv != nullptr) << "Expecting a non-NULL expression value!";
                 [ -  - ]
    1080                 :            :   if (ref_count)
    1081                 :            :   {
    1082                 : 2900719808 :     d_nv->inc();
    1083                 :            :   }
    1084                 :            :   else
    1085                 :            :   {
    1086 [ -  + ][ -  - ]: 3447454461 :     Assert(d_nv->d_rc > 0 || d_nv == &expr::NodeValue::null())
         [ -  + ][ -  + ]
                 [ -  - ]
    1087                 :          0 :         << "TNode constructed from NodeValue with rc == 0";
    1088                 :            :   }
    1089                 : 6348174269 : }
    1090                 :            : 
    1091                 :            : // the code for these two following constructors ("conversion/copy
    1092                 :            : // constructors") is identical, but we need both.  see comment in the
    1093                 :            : // class.
    1094                 :            : 
    1095                 :            : template <bool ref_count>
    1096                 :12215859433 : NodeTemplate<ref_count>::NodeTemplate(const NodeTemplate<!ref_count>& e)
    1097                 :            : {
    1098 [ -  + ][ -  + ]:12215859433 :   Assert(e.d_nv != nullptr) << "Expecting a non-NULL expression value!";
                 [ -  - ]
    1099                 :12215859433 :   d_nv = e.d_nv;
    1100                 :            :   if (ref_count)
    1101                 :            :   {
    1102 [ -  + ][ -  + ]: 4439145779 :     Assert(d_nv->d_rc > 0) << "Node constructed from TNode with rc == 0";
                 [ -  - ]
    1103                 : 4439145779 :     d_nv->inc();
    1104                 :            :   }
    1105                 :            :   else
    1106                 :            :   {
    1107                 :            :     // shouldn't ever fail
    1108 [ -  + ][ -  + ]: 7776713654 :     Assert(d_nv->d_rc > 0) << "TNode constructed from Node with rc == 0";
                 [ -  - ]
    1109                 :            :   }
    1110                 :12215859433 : }
    1111                 :            : 
    1112                 :            : template <bool ref_count>
    1113                 :41792199104 : NodeTemplate<ref_count>::NodeTemplate(const NodeTemplate& e)
    1114                 :            : {
    1115 [ -  + ][ -  + ]:41792199104 :   Assert(e.d_nv != nullptr) << "Expecting a non-NULL expression value!";
                 [ -  - ]
    1116                 :41792199104 :   d_nv = e.d_nv;
    1117                 :            :   if (ref_count)
    1118                 :            :   {
    1119                 :            :     // shouldn't ever fail
    1120 [ -  + ][ -  + ]:18949774963 :     Assert(d_nv->d_rc > 0) << "Node constructed from Node with rc == 0";
                 [ -  - ]
    1121                 :18949774963 :     d_nv->inc();
    1122                 :            :   }
    1123                 :            :   else
    1124                 :            :   {
    1125 [ -  + ][ -  + ]:22842424141 :     Assert(d_nv->d_rc > 0) << "TNode constructed from TNode with rc == 0";
                 [ -  - ]
    1126                 :            :   }
    1127                 :41792199104 : }
    1128                 :            : 
    1129                 :            : template <bool ref_count>
    1130                 :63222667244 : NodeTemplate<ref_count>::~NodeTemplate()
    1131                 :            : {
    1132 [ -  + ][ -  + ]:63222667244 :   Assert(d_nv != nullptr) << "Expecting a non-NULL expression value!";
    1133                 :            :   if (ref_count)
    1134                 :            :   {
    1135                 :            :     // shouldn't ever fail
    1136 [ -  + ][ -  + ]:28321340330 :     Assert(d_nv->d_rc > 0) << "Node reference count would be negative";
    1137                 :28321340330 :     d_nv->dec();
    1138                 :            :   }
    1139                 :63222667244 : }
    1140                 :            : 
    1141                 :            : template <bool ref_count>
    1142                 :            : void NodeTemplate<ref_count>::assignNodeValue(expr::NodeValue* ev)
    1143                 :            : {
    1144                 :            :   d_nv = ev;
    1145                 :            :   if (ref_count)
    1146                 :            :   {
    1147                 :            :     d_nv->inc();
    1148                 :            :   }
    1149                 :            :   else
    1150                 :            :   {
    1151                 :            :     Assert(d_nv->d_rc > 0) << "TNode assigned to NodeValue with rc == 0";
    1152                 :            :   }
    1153                 :            : }
    1154                 :            : 
    1155                 :            : template <bool ref_count>
    1156                 : 5142195594 : NodeTemplate<ref_count>& NodeTemplate<ref_count>::operator=(
    1157                 :            :     const NodeTemplate& e)
    1158                 :            : {
    1159 [ -  + ][ -  + ]: 5142195594 :   Assert(d_nv != nullptr) << "Expecting a non-NULL expression value!";
                 [ -  - ]
    1160 [ -  + ][ -  + ]: 5142195594 :   Assert(e.d_nv != nullptr) << "Expecting a non-NULL expression value on RHS!";
                 [ -  - ]
    1161         [ +  + ]: 5142195594 :   if (__builtin_expect((d_nv != e.d_nv), true))
    1162                 :            :   {
    1163                 :            :     if (ref_count)
    1164                 :            :     {
    1165                 :            :       // shouldn't ever fail
    1166 [ -  + ][ -  + ]: 2027598672 :       Assert(d_nv->d_rc > 0) << "Node reference count would be negative";
                 [ -  - ]
    1167                 : 2027598672 :       d_nv->dec();
    1168                 :            :     }
    1169                 : 4005797246 :     d_nv = e.d_nv;
    1170                 :            :     if (ref_count)
    1171                 :            :     {
    1172                 :            :       // shouldn't ever fail
    1173 [ -  + ][ -  + ]: 2027598672 :       Assert(d_nv->d_rc > 0) << "Node assigned from Node with rc == 0";
                 [ -  - ]
    1174                 : 2027598672 :       d_nv->inc();
    1175                 :            :     }
    1176                 :            :     else
    1177                 :            :     {
    1178 [ -  + ][ -  + ]: 1978198574 :       Assert(d_nv->d_rc > 0) << "TNode assigned from TNode with rc == 0";
                 [ -  - ]
    1179                 :            :     }
    1180                 :            :   }
    1181                 : 5142195594 :   return *this;
    1182                 :            : }
    1183                 :            : 
    1184                 :            : template <bool ref_count>
    1185                 :  439527894 : NodeTemplate<ref_count>& NodeTemplate<ref_count>::operator=(
    1186                 :            :     const NodeTemplate<!ref_count>& e)
    1187                 :            : {
    1188 [ -  + ][ -  + ]:  439527894 :   Assert(d_nv != nullptr) << "Expecting a non-NULL expression value!";
                 [ -  - ]
    1189 [ -  + ][ -  + ]:  439527894 :   Assert(e.d_nv != nullptr) << "Expecting a non-NULL expression value on RHS!";
                 [ -  - ]
    1190         [ +  + ]:  439527894 :   if (__builtin_expect((d_nv != e.d_nv), true))
    1191                 :            :   {
    1192                 :            :     if (ref_count)
    1193                 :            :     {
    1194                 :            :       // shouldn't ever fail
    1195 [ -  + ][ -  + ]:  122673333 :       Assert(d_nv->d_rc > 0) << "Node reference count would be negative";
                 [ -  - ]
    1196                 :  122673333 :       d_nv->dec();
    1197                 :            :     }
    1198                 :  354967165 :     d_nv = e.d_nv;
    1199                 :            :     if (ref_count)
    1200                 :            :     {
    1201 [ -  + ][ -  + ]:  122673333 :       Assert(d_nv->d_rc > 0) << "Node assigned from TNode with rc == 0";
                 [ -  - ]
    1202                 :  122673333 :       d_nv->inc();
    1203                 :            :     }
    1204                 :            :     else
    1205                 :            :     {
    1206                 :            :       // shouldn't ever happen
    1207 [ -  + ][ -  + ]:  232293832 :       Assert(d_nv->d_rc > 0) << "TNode assigned from Node with rc == 0";
                 [ -  - ]
    1208                 :            :     }
    1209                 :            :   }
    1210                 :  439527894 :   return *this;
    1211                 :            : }
    1212                 :            : 
    1213                 :            : template <bool ref_count>
    1214                 :            : template <bool ref_count2>
    1215                 :  124143159 : NodeTemplate<true> NodeTemplate<ref_count>::eqNode(
    1216                 :            :     const NodeTemplate<ref_count2>& right) const
    1217                 :            : {
    1218                 :  124143159 :   assertTNodeNotExpired();
    1219                 :  124143159 :   return d_nv->getNodeManager()->mkNode(Kind::EQUAL, *this, right);
    1220                 :            : }
    1221                 :            : 
    1222                 :            : template <bool ref_count>
    1223                 :   62157629 : NodeTemplate<true> NodeTemplate<ref_count>::notNode() const
    1224                 :            : {
    1225                 :   62157629 :   assertTNodeNotExpired();
    1226                 :   62157629 :   return d_nv->getNodeManager()->mkNode(Kind::NOT, *this);
    1227                 :            : }
    1228                 :            : 
    1229                 :            : template <bool ref_count>
    1230                 :   16383177 : NodeTemplate<true> NodeTemplate<ref_count>::negate() const
    1231                 :            : {
    1232                 :   16383177 :   assertTNodeNotExpired();
    1233                 :   16383177 :   return (getKind() == Kind::NOT)
    1234                 :    1463729 :              ? NodeTemplate<true>(d_nv->getChild(0))
    1235                 :   17846906 :              : d_nv->getNodeManager()->mkNode(Kind::NOT, *this);
    1236                 :            : }
    1237                 :            : 
    1238                 :            : template <bool ref_count>
    1239                 :            : template <bool ref_count2>
    1240                 :     230371 : NodeTemplate<true> NodeTemplate<ref_count>::andNode(
    1241                 :            :     const NodeTemplate<ref_count2>& right) const
    1242                 :            : {
    1243                 :     230371 :   assertTNodeNotExpired();
    1244                 :     230371 :   return d_nv->getNodeManager()->mkNode(Kind::AND, *this, right);
    1245                 :            : }
    1246                 :            : 
    1247                 :            : template <bool ref_count>
    1248                 :            : template <bool ref_count2>
    1249                 :     256234 : NodeTemplate<true> NodeTemplate<ref_count>::orNode(
    1250                 :            :     const NodeTemplate<ref_count2>& right) const
    1251                 :            : {
    1252                 :     256234 :   assertTNodeNotExpired();
    1253                 :     256234 :   return d_nv->getNodeManager()->mkNode(Kind::OR, *this, right);
    1254                 :            : }
    1255                 :            : 
    1256                 :            : template <bool ref_count>
    1257                 :            : template <bool ref_count2, bool ref_count3>
    1258                 :      60833 : NodeTemplate<true> NodeTemplate<ref_count>::iteNode(
    1259                 :            :     const NodeTemplate<ref_count2>& thenpart,
    1260                 :            :     const NodeTemplate<ref_count3>& elsepart) const
    1261                 :            : {
    1262                 :      60833 :   assertTNodeNotExpired();
    1263                 :      60833 :   return d_nv->getNodeManager()->mkNode(Kind::ITE, *this, thenpart, elsepart);
    1264                 :            : }
    1265                 :            : 
    1266                 :            : template <bool ref_count>
    1267                 :     767042 : NodeTemplate<true> NodeTemplate<ref_count>::iteNode(
    1268                 :            :     const TNode (&args)[2]) const
    1269                 :            : {
    1270                 :     767042 :   assertTNodeNotExpired();
    1271                 :     767042 :   return d_nv->getNodeManager()->mkNode(Kind::ITE, *this, args[0], args[1]);
    1272                 :            : }
    1273                 :            : 
    1274                 :            : template <bool ref_count>
    1275                 :            : template <bool ref_count2>
    1276                 :     177427 : NodeTemplate<true> NodeTemplate<ref_count>::impNode(
    1277                 :            :     const NodeTemplate<ref_count2>& right) const
    1278                 :            : {
    1279                 :     177427 :   assertTNodeNotExpired();
    1280                 :     177427 :   return d_nv->getNodeManager()->mkNode(Kind::IMPLIES, *this, right);
    1281                 :            : }
    1282                 :            : 
    1283                 :            : template <bool ref_count>
    1284                 :            : template <bool ref_count2>
    1285                 :         49 : NodeTemplate<true> NodeTemplate<ref_count>::xorNode(
    1286                 :            :     const NodeTemplate<ref_count2>& right) const
    1287                 :            : {
    1288                 :         49 :   assertTNodeNotExpired();
    1289                 :         49 :   return d_nv->getNodeManager()->mkNode(Kind::XOR, *this, right);
    1290                 :            : }
    1291                 :            : 
    1292                 :            : template <bool ref_count>
    1293                 :            : inline void NodeTemplate<ref_count>::printAst(std::ostream& out,
    1294                 :            :                                               int indent) const
    1295                 :            : {
    1296                 :            :   assertTNodeNotExpired();
    1297                 :            :   d_nv->printAst(out, indent);
    1298                 :            : }
    1299                 :            : 
    1300                 :            : /**
    1301                 :            :  * Returns a node representing the operator of this expression.
    1302                 :            :  * If this is an APPLY_UF, then the operator will be a functional term.
    1303                 :            :  * Otherwise, it will be a node with kind BUILTIN.
    1304                 :            :  */
    1305                 :            : template <bool ref_count>
    1306                 :  260569325 : NodeTemplate<true> NodeTemplate<ref_count>::getOperator() const
    1307                 :            : {
    1308                 :  260569325 :   assertTNodeNotExpired();
    1309                 :            : 
    1310                 :  260569325 :   kind::MetaKind mk = getMetaKind();
    1311         [ +  + ]:  260569325 :   if (mk == kind::metakind::OPERATOR)
    1312                 :            :   {
    1313                 :            :     /* Returns a BUILTIN node. */
    1314                 :  112271215 :     return d_nv->getNodeManager()->operatorOf(getKind());
    1315                 :            :   }
    1316 [ -  + ][ -  + ]:  148298110 :   Assert(mk == kind::metakind::PARAMETERIZED);
                 [ -  - ]
    1317                 :            :   /* The operator is the first child. */
    1318                 :  148298110 :   return Node(d_nv->d_children[0]);
    1319                 :            : }
    1320                 :            : 
    1321                 :            : /**
    1322                 :            :  * Returns true if the node has an operator (i.e., it's not a variable
    1323                 :            :  * or a constant).
    1324                 :            :  */
    1325                 :            : template <bool ref_count>
    1326                 :  159428675 : inline bool NodeTemplate<ref_count>::hasOperator() const
    1327                 :            : {
    1328                 :  159428675 :   assertTNodeNotExpired();
    1329                 :  159428675 :   return NodeManager::hasOperator(getKind());
    1330                 :            : }
    1331                 :            : 
    1332                 :            : template <bool ref_count>
    1333                 : 1173267930 : TypeNode NodeTemplate<ref_count>::getType(bool check) const
    1334                 :            : {
    1335                 : 1173267930 :   assertTNodeNotExpired();
    1336                 : 1173267930 :   TypeNode tn = d_nv->getNodeManager()->getType(*this, check);
    1337         [ +  + ]: 1173267930 :   if (tn.isNull())
    1338                 :            :   {
    1339                 :            :     // recompute with an error stream and throw a type exception
    1340                 :        244 :     std::stringstream errOutTmp;
    1341                 :        244 :     tn = d_nv->getNodeManager()->getType(*this, check, &errOutTmp);
    1342                 :        244 :     throw TypeCheckingExceptionPrivate(*this, errOutTmp.str());
    1343                 :        244 :   }
    1344                 : 1173267686 :   return tn;
    1345                 :        244 : }
    1346                 :            : 
    1347                 :            : template <bool ref_count>
    1348                 :  288245014 : TypeNode NodeTemplate<ref_count>::getTypeOrNull(bool check) const
    1349                 :            : {
    1350                 :  288245014 :   assertTNodeNotExpired();
    1351                 :  288245014 :   return d_nv->getNodeManager()->getType(*this, check);
    1352                 :            : }
    1353                 :            : 
    1354                 :            : template <bool ref_count>
    1355                 :     570921 : inline Node NodeTemplate<ref_count>::substitute(TNode node,
    1356                 :            :                                                 TNode replacement) const
    1357                 :            : {
    1358         [ +  + ]:     570921 :   if (node == *this)
    1359                 :            :   {
    1360                 :     100887 :     return replacement;
    1361                 :            :   }
    1362                 :     470034 :   std::unordered_map<TNode, TNode> cache;
    1363                 :     470034 :   return substitute(node, replacement, cache);
    1364                 :     470034 : }
    1365                 :            : 
    1366                 :            : template <bool ref_count>
    1367                 :   27778139 : Node NodeTemplate<ref_count>::substitute(
    1368                 :            :     TNode node,
    1369                 :            :     TNode replacement,
    1370                 :            :     std::unordered_map<TNode, TNode>& cache) const
    1371                 :            : {
    1372 [ -  + ][ -  + ]:   27778139 :   Assert(node != *this);
                 [ -  - ]
    1373                 :            : 
    1374 [ +  + ][ +  + ]:   27778139 :   if (getNumChildren() == 0 || node == replacement)
                 [ +  + ]
    1375                 :            :   {
    1376                 :    6829529 :     return *this;
    1377                 :            :   }
    1378                 :            : 
    1379                 :            :   // in cache?
    1380                 :   20948610 :   typename std::unordered_map<TNode, TNode>::const_iterator i =
    1381                 :   41889218 :       cache.find(*this);
    1382         [ +  + ]:   20948610 :   if (i != cache.end())
    1383                 :            :   {
    1384                 :    6513855 :     return (*i).second;
    1385                 :            :   }
    1386                 :            : 
    1387                 :            :   // otherwise compute
    1388                 :   14434755 :   NodeBuilder nb(getNodeManager(), getKind());
    1389         [ +  + ]:   14434755 :   if (getMetaKind() == kind::metakind::PARAMETERIZED)
    1390                 :            :   {
    1391                 :            :     // push the operator
    1392         [ +  + ]:    1510651 :     if (getOperator() == node)
    1393                 :            :     {
    1394                 :       2270 :       nb << replacement;
    1395                 :            :     }
    1396                 :            :     else
    1397                 :            :     {
    1398                 :    1508381 :       nb << getOperator().substitute(node, replacement, cache);
    1399                 :            :     }
    1400                 :            :   }
    1401         [ +  + ]:   40573766 :   for (const_iterator it = begin(), iend = end(); it != iend; ++it)
    1402                 :            :   {
    1403         [ +  + ]:   26139011 :     if (*it == node)
    1404                 :            :     {
    1405                 :     739864 :       nb << replacement;
    1406                 :            :     }
    1407                 :            :     else
    1408                 :            :     {
    1409                 :   25399147 :       nb << (*it).substitute(node, replacement, cache);
    1410                 :            :     }
    1411                 :            :   }
    1412                 :            : 
    1413                 :            :   // put in cache
    1414                 :   14434755 :   Node n = nb;
    1415                 :   14434755 :   cache[*this] = n;
    1416                 :   14434755 :   return n;
    1417                 :   14434755 : }
    1418                 :            : 
    1419                 :            : template <bool ref_count>
    1420                 :            : template <class Iterator1, class Iterator2>
    1421                 :   22342318 : inline Node NodeTemplate<ref_count>::substitute(Iterator1 nodesBegin,
    1422                 :            :                                                 Iterator1 nodesEnd,
    1423                 :            :                                                 Iterator2 replacementsBegin,
    1424                 :            :                                                 Iterator2 replacementsEnd) const
    1425                 :            : {
    1426                 :   22342318 :   std::unordered_map<TNode, TNode> cache;
    1427                 :            :   return substitute(
    1428                 :   44684636 :       nodesBegin, nodesEnd, replacementsBegin, replacementsEnd, cache);
    1429                 :   22342318 : }
    1430                 :            : 
    1431                 :            : template <bool ref_count>
    1432                 :            : template <class Iterator1, class Iterator2>
    1433                 :  115293190 : Node NodeTemplate<ref_count>::substitute(
    1434                 :            :     Iterator1 nodesBegin,
    1435                 :            :     Iterator1 nodesEnd,
    1436                 :            :     Iterator2 replacementsBegin,
    1437                 :            :     Iterator2 replacementsEnd,
    1438                 :            :     std::unordered_map<TNode, TNode>& cache) const
    1439                 :            : {
    1440                 :            :   // in cache?
    1441                 :  115293190 :   typename std::unordered_map<TNode, TNode>::const_iterator i =
    1442                 :  224297310 :       cache.find(*this);
    1443         [ +  + ]:  115293190 :   if (i != cache.end())
    1444                 :            :   {
    1445                 :    8526240 :     return (*i).second;
    1446                 :            :   }
    1447                 :            : 
    1448                 :            :   // otherwise compute
    1449 [ -  + ][ -  + ]:  106766950 :   Assert(std::distance(nodesBegin, nodesEnd)
                 [ -  - ]
    1450                 :            :          == std::distance(replacementsBegin, replacementsEnd))
    1451                 :          0 :       << "Substitution iterator ranges must be equal size";
    1452                 :  106766950 :   Iterator1 j = std::find(nodesBegin, nodesEnd, TNode(*this));
    1453         [ +  + ]:  106766950 :   if (j != nodesEnd)
    1454                 :            :   {
    1455                 :    5642943 :     Iterator2 b = replacementsBegin;
    1456                 :    5642943 :     std::advance(b, std::distance(nodesBegin, j));
    1457                 :    5642943 :     Node n = *b;
    1458                 :    5642943 :     cache[*this] = n;
    1459                 :    5642943 :     return n;
    1460                 :    5642943 :   }
    1461         [ +  + ]:  101124007 :   else if (getNumChildren() == 0)
    1462                 :            :   {
    1463                 :   50340428 :     cache[*this] = *this;
    1464                 :   50340428 :     return *this;
    1465                 :            :   }
    1466                 :            :   else
    1467                 :            :   {
    1468                 :   50783579 :     NodeBuilder nb(getNodeManager(), getKind());
    1469         [ +  + ]:   50783579 :     if (getMetaKind() == kind::metakind::PARAMETERIZED)
    1470                 :            :     {
    1471                 :            :       // push the operator
    1472                 :    1570986 :       nb << getOperator().substitute(
    1473                 :            :           nodesBegin, nodesEnd, replacementsBegin, replacementsEnd, cache);
    1474                 :            :     }
    1475         [ +  + ]:  142163465 :     for (const_iterator it = begin(), iend = end(); it != iend; ++it)
    1476                 :            :     {
    1477                 :   91379886 :       nb << (*it).substitute(
    1478                 :            :           nodesBegin, nodesEnd, replacementsBegin, replacementsEnd, cache);
    1479                 :            :     }
    1480                 :   50783579 :     Node n = nb;
    1481                 :   50783579 :     cache[*this] = n;
    1482                 :   50783579 :     return n;
    1483                 :   50783579 :   }
    1484                 :            : }
    1485                 :            : 
    1486                 :            : template <bool ref_count>
    1487                 :            : template <class Iterator>
    1488                 :        384 : inline Node NodeTemplate<ref_count>::substitute(Iterator substitutionsBegin,
    1489                 :            :                                                 Iterator substitutionsEnd) const
    1490                 :            : {
    1491                 :        384 :   std::unordered_map<TNode, TNode> cache;
    1492                 :        768 :   return substitute(substitutionsBegin, substitutionsEnd, cache);
    1493                 :        384 : }
    1494                 :            : 
    1495                 :            : template <bool ref_count>
    1496                 :          0 : inline Node NodeTemplate<ref_count>::substitute(
    1497                 :            :     std::unordered_map<TNode, TNode>& cache) const
    1498                 :            : {
    1499                 :            :   // Since no substitution is given (other than what may already be in the
    1500                 :            :   // cache), we pass dummy iterators to conform to the main substitute method,
    1501                 :            :   // giving the same value to substitutionsBegin and substitutionsEnd.
    1502                 :          0 :   return substitute(cache.cend(), cache.cend(), cache);
    1503                 :            : }
    1504                 :            : 
    1505                 :            : template <bool ref_count>
    1506                 :            : template <class Iterator>
    1507                 :       1120 : Node NodeTemplate<ref_count>::substitute(
    1508                 :            :     Iterator substitutionsBegin,
    1509                 :            :     Iterator substitutionsEnd,
    1510                 :            :     std::unordered_map<TNode, TNode>& cache) const
    1511                 :            : {
    1512                 :            :   // in cache?
    1513                 :       1120 :   typename std::unordered_map<TNode, TNode>::const_iterator i =
    1514                 :       2240 :       cache.find(*this);
    1515         [ +  + ]:       1120 :   if (i != cache.end())
    1516                 :            :   {
    1517                 :         18 :     return (*i).second;
    1518                 :            :   }
    1519                 :            : 
    1520                 :            :   // otherwise compute
    1521                 :            :   Iterator j =
    1522                 :      27120 :       find_if(substitutionsBegin, substitutionsEnd, [this](const auto& subst) {
    1523                 :      26264 :         return subst.first == *this;
    1524                 :            :       });
    1525         [ +  + ]:       1102 :   if (j != substitutionsEnd)
    1526                 :            :   {
    1527                 :        558 :     Node n = (*j).second;
    1528                 :        558 :     cache[*this] = n;
    1529                 :        558 :     return n;
    1530                 :        558 :   }
    1531         [ +  + ]:        544 :   else if (getNumChildren() == 0)
    1532                 :            :   {
    1533                 :        306 :     cache[*this] = *this;
    1534                 :        306 :     return *this;
    1535                 :            :   }
    1536                 :            :   else
    1537                 :            :   {
    1538                 :        238 :     NodeBuilder nb(getNodeManager(), getKind());
    1539         [ +  + ]:        238 :     if (getMetaKind() == kind::metakind::PARAMETERIZED)
    1540                 :            :     {
    1541                 :            :       // push the operator
    1542                 :        208 :       nb << getOperator().substitute(
    1543                 :            :           substitutionsBegin, substitutionsEnd, cache);
    1544                 :            :     }
    1545         [ +  + ]:        766 :     for (const_iterator it = begin(), iend = end(); it != iend; ++it)
    1546                 :            :     {
    1547                 :        528 :       nb << (*it).substitute(substitutionsBegin, substitutionsEnd, cache);
    1548                 :            :     }
    1549                 :        238 :     Node n = nb;
    1550                 :        238 :     cache[*this] = n;
    1551                 :        238 :     return n;
    1552                 :        238 :   }
    1553                 :            : }
    1554                 :            : 
    1555                 :            : }  // namespace cvc5::internal
    1556                 :            : 
    1557                 :            : #endif /* CVC5__NODE_H */

Generated by: LCOV version 1.14