Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * Top contributors (to current version): 3 : : * Morgan Deters, Aina Niemetz, Andres Noetzli 4 : : * 5 : : * This file is part of the cvc5 project. 6 : : * 7 : : * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS 8 : : * in the top-level source directory and their institutional affiliations. 9 : : * All rights reserved. See the file COPYING in the top-level source 10 : : * directory for licensing information. 11 : : * **************************************************************************** 12 : : * 13 : : * A node value. 14 : : * 15 : : * The actual node implementation. 16 : : * Instances of this class are generally referenced through cvc5::internal::Node 17 : : * rather than by pointer. Note that cvc5::internal::Node maintains the 18 : : * reference count on NodeValue instances. 19 : : */ 20 : : 21 : : #include "cvc5_private.h" 22 : : 23 : : #ifndef CVC5__EXPR__NODE_VALUE_H 24 : : #define CVC5__EXPR__NODE_VALUE_H 25 : : 26 : : #include <iterator> 27 : : #include <string> 28 : : 29 : : #include "expr/kind.h" 30 : : #include "expr/metakind.h" 31 : : #include "options/language.h" 32 : : 33 : : namespace cvc5::internal { 34 : : 35 : : template <bool ref_count> class NodeTemplate; 36 : : class TypeNode; 37 : : class NodeBuilder; 38 : : class NodeManager; 39 : : 40 : : namespace expr { 41 : : class NodeValue; 42 : : } 43 : : 44 : : namespace kind { 45 : : namespace metakind { 46 : : 47 : : template <cvc5::internal::Kind k, class T, bool pool> 48 : : struct NodeValueConstCompare; 49 : : 50 : : struct NodeValueCompare; 51 : : 52 : : } // namespace metakind 53 : : } // namespace kind 54 : : 55 : : namespace expr { 56 : : 57 : : /** 58 : : * This is a NodeValue. 59 : : */ 60 : : class CVC5_EXPORT NodeValue 61 : : { 62 : : template <bool> 63 : : friend class cvc5::internal::NodeTemplate; 64 : : friend class cvc5::internal::TypeNode; 65 : : friend class cvc5::internal::NodeBuilder; 66 : : friend class cvc5::internal::NodeManager; 67 : : 68 : : template <Kind k, class T, bool pool> 69 : : friend struct kind::metakind::NodeValueConstCompare; 70 : : 71 : : friend struct kind::metakind::NodeValueCompare; 72 : : 73 : : friend void kind::metakind::nodeValueConstantToStream(std::ostream& out, 74 : : const NodeValue* nv); 75 : : friend void kind::metakind::deleteNodeValueConstant(NodeValue* nv); 76 : : 77 : : friend class RefCountGuard; 78 : : 79 : : /* ------------------------------------------------------------------------ */ 80 : : public: 81 : : /* ------------------------------------------------------------------------ */ 82 : : 83 : : using nv_iterator = NodeValue**; 84 : : using const_nv_iterator = NodeValue const* const*; 85 : : 86 : : template <class T> 87 : : class iterator 88 : : { 89 : : public: 90 : : using iterator_category = std::random_access_iterator_tag; 91 : : using value_type = T; 92 : : using difference_type = std::ptrdiff_t; 93 : : using pointer = T*; 94 : : using reference = T; 95 : : 96 : 302195555 : iterator() : d_i(nullptr) {} 97 : 2747089440 : explicit iterator(const_nv_iterator i) : d_i(i) {} 98 : : 99 : : /** Conversion of a TNode iterator to a Node iterator. */ 100 : 313424002 : inline operator NodeValue::iterator<NodeTemplate<true> >() const 101 : : { 102 : 313424002 : return iterator<NodeTemplate<true> >(d_i); 103 : : } 104 : : 105 : 2268066769 : T operator*() const { return T(*d_i); } 106 : : 107 : 599331112 : bool operator==(const iterator& i) const { return d_i == i.d_i; } 108 : : 109 : 3057685556 : bool operator!=(const iterator& i) const { return d_i != i.d_i; } 110 : : 111 : 2008201710 : iterator& operator++() 112 : : { 113 : 2008201710 : ++d_i; 114 : 2008201710 : return *this; 115 : : } 116 : : 117 : 127678 : iterator operator++(int) { return iterator(d_i++); } 118 : : 119 : 37711120 : iterator& operator--() 120 : : { 121 : 37711120 : --d_i; 122 : 37711120 : return *this; 123 : : } 124 : : 125 : : iterator operator--(int) { return iterator(d_i--); } 126 : : 127 : 85037808 : iterator& operator+=(difference_type p) 128 : : { 129 : 85037808 : d_i += p; 130 : 85037808 : return *this; 131 : : } 132 : : 133 : 2296529 : iterator& operator-=(difference_type p) 134 : : { 135 : 2296529 : d_i -= p; 136 : 2296529 : return *this; 137 : : } 138 : : 139 : 957098 : iterator operator+(difference_type p) const { return iterator(d_i + p); } 140 : : 141 : 1957436 : iterator operator-(difference_type p) const { return iterator(d_i - p); } 142 : : 143 : 436996109 : difference_type operator-(iterator i) const { return d_i - i.d_i; } 144 : : 145 : : private: 146 : : const_nv_iterator d_i; 147 : : 148 : : }; /* class NodeValue::iterator<T> */ 149 : : 150 :16175201546 : uint64_t getId() const { return d_id; } 151 : : 152 :16514329771 : Kind getKind() const { return dKindToKind(d_kind); } 153 : : 154 :11729691190 : kind::MetaKind getMetaKind() const { return kind::metaKindOf(getKind()); } 155 : : 156 : 7480926331 : NodeManager* getNodeManager() const { return d_nm; } 157 : : 158 : 2818577645 : uint32_t getNumChildren() const 159 : : { 160 [ + + ]: 2818577645 : return (getMetaKind() == kind::metakind::PARAMETERIZED) ? d_nchildren - 1 161 : 2818577645 : : d_nchildren; 162 : : } 163 : : 164 : : /* ------------------------------ Header ---------------------------------- */ 165 : : /** Number of bits reserved for reference counting. */ 166 : : static constexpr uint32_t NBITS_REFCOUNT = 20; 167 : : /** Number of bits reserved for node kind. */ 168 : : static constexpr uint32_t NBITS_KIND = 10; 169 : : /** Number of bits reserved for node id. */ 170 : : static constexpr uint32_t NBITS_ID = 40; 171 : : /** Number of bits reserved for number of children. */ 172 : : static const uint32_t NBITS_NCHILDREN = 26; 173 : : static_assert(NBITS_REFCOUNT + NBITS_KIND + NBITS_ID + NBITS_NCHILDREN == 96, 174 : : "NodeValue header bit assignment does not sum to 96 !"); 175 : : /* ------------------- This header fits into 96 bits ---------------------- */ 176 : : 177 : : /** Maximum number of children possible. */ 178 : : static constexpr uint32_t MAX_CHILDREN = 179 : : (static_cast<uint32_t>(1) << NBITS_NCHILDREN) - 1; 180 : : 181 : : uint32_t getRefCount() const { return d_rc; } 182 : : 183 : : NodeValue* getOperator() const; 184 : : NodeValue* getChild(int i) const; 185 : : 186 : : /** If this is a CONST_* Node, extract the constant from it. */ 187 : : template <class T> 188 : : const T& getConst() const; 189 : : 190 :18245899003 : static inline NodeValue& null() 191 : : { 192 [ + + ][ + - ]:18245899003 : static NodeValue* s_null = new NodeValue(0); [ - - ] 193 :18245899003 : return *s_null; 194 : : } 195 : : 196 : : /** 197 : : * Hash this NodeValue. For hash_maps, hash_sets, etc.. but this is 198 : : * for expr package internal use only at present! This is likely to 199 : : * be POORLY PERFORMING for other uses! For example, this gives 200 : : * collisions for all VARIABLEs. 201 : : * @return the hash value of this expression. 202 : : */ 203 : 1535570000 : size_t poolHash() const 204 : : { 205 [ + + ]: 1535570000 : if (getMetaKind() == kind::metakind::CONSTANT) 206 : : { 207 : 500380000 : return kind::metakind::NodeValueCompare::constHash(this); 208 : : } 209 : : 210 : 1035190000 : size_t hash = d_kind; 211 : 1035190000 : const_nv_iterator i = nv_begin(); 212 : 1035190000 : const_nv_iterator i_end = nv_end(); 213 [ + + ]: 3736280000 : while (i != i_end) 214 : : { 215 : 2701090000 : hash ^= (*i)->d_id + 0x9e3779b9 + (hash << 6) + (hash >> 2); 216 : 2701090000 : ++i; 217 : : } 218 : 1035190000 : return hash; 219 : : } 220 : : 221 : 669778000 : static inline uint32_t kindToDKind(Kind k) 222 : : { 223 : 669778000 : return ((uint32_t)k) & kindMask; 224 : : } 225 : : 226 :16514329771 : static inline Kind dKindToKind(uint32_t d) 227 : : { 228 [ + + ]:16514329771 : return (d == kindMask) ? Kind::UNDEFINED_KIND : Kind(d); 229 : : } 230 : : 231 : : std::string toString() const; 232 : : 233 : : void toStream(std::ostream& out) const; 234 : : 235 : : void printAst(std::ostream& out, int indent = 0) const; 236 : : 237 : : template <typename T> 238 : : inline iterator<T> begin() const; 239 : : template <typename T> 240 : : inline iterator<T> end() const; 241 : : 242 : : /* ------------------------------------------------------------------------ */ 243 : : private: 244 : : /* ------------------------------------------------------------------------ */ 245 : : 246 : : /** 247 : : * RAII guard that increases the reference count if the reference count to be 248 : : * > 0. Otherwise, this does nothing. This does not just increment the 249 : : * reference count to avoid maxing out the d_rc field. This is only for low 250 : : * level functions. 251 : : */ 252 : : class RefCountGuard 253 : : { 254 : : public: 255 : 7728080 : RefCountGuard(const NodeValue* nv) : d_nv(const_cast<NodeValue*>(nv)) 256 : : { 257 : 7728080 : d_increased = (d_nv->d_rc == 0); 258 [ - + ]: 7728080 : if (d_increased) 259 : : { 260 : 0 : d_nv->d_rc = 1; 261 : : } 262 : 7728080 : } 263 : 7728080 : ~RefCountGuard() 264 : 7728080 : { 265 : : // dec() without marking for deletion: we don't want to garbage 266 : : // collect this NodeValue if ours is the last reference to it. 267 : : // E.g., this can happen when debugging code calls the print 268 : : // routines below. As RefCountGuards are scoped on the stack, 269 : : // this should be fine---but not in multithreaded contexts! 270 [ - + ]: 7728080 : if (d_increased) 271 : : { 272 : 0 : --d_nv->d_rc; 273 : : } 274 : 7728080 : } 275 : : 276 : : private: 277 : : NodeValue* d_nv; 278 : : bool d_increased; 279 : : }; /* NodeValue::RefCountGuard */ 280 : : 281 : : /** Maximum reference count possible. Used for sticky 282 : : * reference-counting. Should be (1 << num_bits(d_rc)) - 1 */ 283 : : static constexpr uint32_t MAX_RC = 284 : : (static_cast<uint32_t>(1) << NBITS_REFCOUNT) - 1; 285 : : 286 : : /** A mask for d_kind */ 287 : : static constexpr uint32_t kindMask = 288 : : (static_cast<uint32_t>(1) << NBITS_KIND) - 1; 289 : : 290 : : /** Uninitializing constructor for NodeBuilder's use. */ 291 : 1121850000 : NodeValue() 292 : 1121850000 : { /* do not initialize! */ 293 : 1121850000 : } 294 : : /** Private constructor for the null value. */ 295 : : NodeValue(int); 296 : : 297 :40043407391 : void inc() 298 : : { 299 [ + + ]:40043407391 : if (__builtin_expect((d_rc < MAX_RC - 1), true)) 300 : : { 301 :31650019030 : ++d_rc; 302 : : } 303 [ + + ]: 8393337367 : else if (__builtin_expect((d_rc == MAX_RC - 1), false)) 304 : : { 305 : 3 : ++d_rc; 306 : 3 : markRefCountMaxedOut(); 307 : : } 308 :40043407391 : } 309 : : 310 :46762451069 : void dec() 311 : : { 312 [ + + ]:46762451069 : if (__builtin_expect((d_rc < MAX_RC), true)) 313 : : { 314 :31644621310 : --d_rc; 315 [ + + ]:31644621310 : if (__builtin_expect((d_rc == 0), false)) 316 : : { 317 : 197079383 : markForDeletion(); 318 : : } 319 : : } 320 :46762451069 : } 321 : : 322 : : void markRefCountMaxedOut(); 323 : : void markForDeletion(); 324 : : 325 : : /** Decrement ref counts of children */ 326 : : inline void decrRefCounts(); 327 : : 328 : : /** Returns true if the reference count is maximized. */ 329 : 6 : inline bool HasMaximizedReferenceCount() { return d_rc == MAX_RC; } 330 : : 331 : : nv_iterator nv_begin(); 332 : : nv_iterator nv_end(); 333 : : 334 : : const_nv_iterator nv_begin() const; 335 : : const_nv_iterator nv_end() const; 336 : : 337 : : /** 338 : : * Indents the given stream a given amount of spaces. 339 : : * @param out the stream to indent 340 : : * @param indent the numer of spaces 341 : : */ 342 : 0 : static inline void indent(std::ostream& out, int indent) 343 : : { 344 [ - - ]: 0 : for (int i = 0; i < indent; i++) 345 : : { 346 : 0 : out << ' '; 347 : : } 348 : 0 : } 349 : : 350 : : /** The ID (0 is reserved for the null value) */ 351 : : uint64_t d_id : NBITS_ID; 352 : : 353 : : /** The expression's reference count. */ 354 : : uint32_t d_rc : NBITS_REFCOUNT; 355 : : 356 : : /** Kind of the expression */ 357 : : uint32_t d_kind : NBITS_KIND; 358 : : 359 : : /** Number of children */ 360 : : uint32_t d_nchildren : NBITS_NCHILDREN; 361 : : 362 : : /** Associated node manager. */ 363 : : NodeManager* d_nm = nullptr; 364 : : 365 : : /** Variable number of child nodes */ 366 : : NodeValue* d_children[0]; 367 : : }; /* class NodeValue */ 368 : : 369 : : /** 370 : : * Provides a symmetric addition operator to that already defined in 371 : : * the iterator class. 372 : : */ 373 : : NodeValue::iterator<NodeTemplate<true> > operator+( 374 : : NodeValue::iterator<NodeTemplate<true> >::difference_type p, 375 : : NodeValue::iterator<NodeTemplate<true> > i); 376 : : 377 : : /** 378 : : * Provides a symmetric addition operator to that already defined in 379 : : * the iterator class. 380 : : */ 381 : : NodeValue::iterator<NodeTemplate<false> > operator+( 382 : : NodeValue::iterator<NodeTemplate<false> >::difference_type p, 383 : : NodeValue::iterator<NodeTemplate<false> > i); 384 : : 385 : : /** 386 : : * For hash_maps, hash_sets, etc.. but this is for expr package 387 : : * internal use only at present! This is likely to be POORLY 388 : : * PERFORMING for other uses! NodeValue::poolHash() will lead to 389 : : * collisions for all VARIABLEs. 390 : : */ 391 : : struct NodeValuePoolHashFunction { 392 : 1535570000 : inline size_t operator()(const NodeValue* nv) const { 393 : 1535570000 : return (size_t) nv->poolHash(); 394 : : } 395 : : };/* struct NodeValuePoolHashFunction */ 396 : : 397 : : /** 398 : : * For hash_maps, hash_sets, etc. 399 : : */ 400 : : struct NodeValueIDHashFunction { 401 : 432330000 : inline size_t operator()(const NodeValue* nv) const { 402 : 432330000 : return (size_t) nv->getId(); 403 : : } 404 : : };/* struct NodeValueIDHashFunction */ 405 : : 406 : : 407 : : /** 408 : : * An equality predicate that is applicable between pointers to fully 409 : : * constructed NodeValues. 410 : : */ 411 : : struct NodeValueIDEquality { 412 : 114513000 : inline bool operator()(const NodeValue* a, const NodeValue* b) const { 413 : 114513000 : return a->getId() == b->getId(); 414 : : } 415 : : }; 416 : : 417 : : std::ostream& operator<<(std::ostream& out, const NodeValue& nv); 418 : : 419 : 29003 : inline NodeValue::NodeValue(int) 420 : : : d_id(0), 421 : : d_rc(MAX_RC), 422 : : d_kind(static_cast<uint32_t>(Kind::NULL_EXPR)), 423 : 29003 : d_nchildren(0) 424 : : { 425 : 29003 : } 426 : : 427 : 157152000 : inline void NodeValue::decrRefCounts() { 428 [ + + ]: 508563000 : for(nv_iterator i = nv_begin(); i != nv_end(); ++i) { 429 : 351411000 : (*i)->dec(); 430 : : } 431 : 157152000 : } 432 : : 433 : 1108000000 : inline NodeValue::nv_iterator NodeValue::nv_begin() { 434 : 1108000000 : return d_children; 435 : : } 436 : : 437 : 2344550000 : inline NodeValue::nv_iterator NodeValue::nv_end() { 438 : 2344550000 : return d_children + d_nchildren; 439 : : } 440 : : 441 : 2440830000 : inline NodeValue::const_nv_iterator NodeValue::nv_begin() const { 442 : 2440830000 : return d_children; 443 : : } 444 : : 445 : 1738010000 : inline NodeValue::const_nv_iterator NodeValue::nv_end() const { 446 : 1738010000 : return d_children + d_nchildren; 447 : : } 448 : : 449 : : template <typename T> 450 : 927167831 : inline NodeValue::iterator<T> NodeValue::begin() const { 451 : 927167831 : NodeValue* const* firstChild = d_children; 452 [ + + ]: 927167831 : if(getMetaKind() == kind::metakind::PARAMETERIZED) { 453 : 69466165 : ++firstChild; 454 : : } 455 : 927167831 : return iterator<T>(firstChild); 456 : : } 457 : : 458 : : template <typename T> 459 : 1503455999 : inline NodeValue::iterator<T> NodeValue::end() const { 460 : 1503455999 : return iterator<T>(d_children + d_nchildren); 461 : : } 462 : : 463 : 0 : inline NodeValue* NodeValue::getOperator() const { 464 : 0 : Assert(getMetaKind() == kind::metakind::PARAMETERIZED); 465 : 0 : return d_children[0]; 466 : : } 467 : : 468 : 2847616003 : inline NodeValue* NodeValue::getChild(int i) const { 469 [ + + ]: 2847616003 : if(getMetaKind() == kind::metakind::PARAMETERIZED) { 470 : 457488006 : ++i; 471 : : } 472 : : 473 [ + - ][ + - ]: 5695222016 : Assert(i >= 0 && unsigned(i) < d_nchildren); [ - + ][ - - ] 474 : 2847616003 : return d_children[i]; 475 : : } 476 : : 477 : : } // namespace expr 478 : : } // namespace cvc5::internal 479 : : 480 : : #endif /* CVC5__EXPR__NODE_VALUE_H */