LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/expr - attribute_internals.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 194 196 99.0 %
Date: 2026-03-19 10:41:11 Functions: 404 546 74.0 %
Branches: 56 90 62.2 %

           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                 :            :  * Node attributes' internals.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include <algorithm>
      14                 :            : #include <numeric>
      15                 :            : #include <stdint.h>
      16                 :            : 
      17                 :            : #include "cvc5_private.h"
      18                 :            : 
      19                 :            : #ifndef CVC5_ATTRIBUTE_H__INCLUDING__ATTRIBUTE_INTERNALS_H
      20                 :            : #  error expr/attribute_internals.h should only be included by expr/attribute.h
      21                 :            : #endif /* CVC5_ATTRIBUTE_H__INCLUDING__ATTRIBUTE_INTERNALS_H */
      22                 :            : 
      23                 :            : #ifndef CVC5__EXPR__ATTRIBUTE_INTERNALS_H
      24                 :            : #define CVC5__EXPR__ATTRIBUTE_INTERNALS_H
      25                 :            : 
      26                 :            : #include <unordered_map>
      27                 :            : 
      28                 :            : namespace cvc5::internal {
      29                 :            : namespace expr {
      30                 :            : 
      31                 :            : // ATTRIBUTE HASH FUNCTIONS ====================================================
      32                 :            : 
      33                 :            : namespace attr {
      34                 :            : 
      35                 :            : /**
      36                 :            :  * A hash function for attribute table keys.  Attribute table keys are
      37                 :            :  * pairs, (unique-attribute-id, Node).
      38                 :            :  */
      39                 :            : struct AttrHashFunction {
      40                 :            :   enum { LARGE_PRIME = 32452843ul };
      41                 :            :   std::size_t operator()(const std::pair<uint64_t, NodeValue*>& p) const {
      42                 :            :     return p.first * LARGE_PRIME + p.second->getId();
      43                 :            :   }
      44                 :            : };/* struct AttrHashFunction */
      45                 :            : 
      46                 :            : /**
      47                 :            :  * A hash function for boolean-valued attribute table keys; here we
      48                 :            :  * don't have to store a pair as the key, because we use a known bit
      49                 :            :  * in [0..63] for each attribute
      50                 :            :  */
      51                 :            : struct AttrBoolHashFunction {
      52                 : 6493206943 :   std::size_t operator()(NodeValue* nv) const {
      53                 : 6493206943 :     return (size_t)nv->getId();
      54                 :            :   }
      55                 :            : };/* struct AttrBoolHashFunction */
      56                 :            : 
      57                 :            : }  // namespace attr
      58                 :            : 
      59                 :            : // ATTRIBUTE TYPE MAPPINGS =====================================================
      60                 :            : 
      61                 :            : namespace attr {
      62                 :            : 
      63                 :            : /**
      64                 :            :  * KindValueToTableValueMapping is a compile-time-only mechanism to
      65                 :            :  * convert "attribute value types" into "table value types" and back
      66                 :            :  * again.
      67                 :            :  *
      68                 :            :  * Each instantiation < T > is expected to have three members:
      69                 :            :  *
      70                 :            :  *   typename table_value_type
      71                 :            :  *
      72                 :            :  *      A type representing the underlying table's value_type for
      73                 :            :  *      attribute value type (T).  It may be different from T, e.g. T
      74                 :            :  *      could be a pointer-to-Foo, but the underlying table value_type
      75                 :            :  *      might be pointer-to-void.
      76                 :            :  *
      77                 :            :  *   static [convertible-to-table_value_type] convert([convertible-from-T])
      78                 :            :  *
      79                 :            :  *      Converts a T into a table_value_type.  Used to convert an
      80                 :            :  *      attribute value on setting it (and assigning it into the
      81                 :            :  *      underlying table).  See notes on specializations of
      82                 :            :  *      KindValueToTableValueMapping, below.
      83                 :            :  *
      84                 :            :  *   static [convertible-to-T] convertBack([convertible-from-table_value_type])
      85                 :            :  *
      86                 :            :  *      Converts a table_value_type back into a T.  Used to convert an
      87                 :            :  *      underlying table value back into the attribute's expected type
      88                 :            :  *      when retrieving it from the table.  See notes on
      89                 :            :  *      specializations of KindValueToTableValueMapping, below.
      90                 :            :  *
      91                 :            :  * This general (non-specialized) implementation of the template does
      92                 :            :  * nothing.
      93                 :            :  *
      94                 :            :  * The `Enable` template parameter is used to instantiate the template
      95                 :            :  * conditionally: If the template substitution of Enable fails (e.g. when using
      96                 :            :  * `std::enable_if` in the template parameter and the condition is false), the
      97                 :            :  * instantiation is ignored due to the SFINAE rule.
      98                 :            :  */
      99                 :            : template <class T, class Enable = void>
     100                 :            : struct KindValueToTableValueMapping
     101                 :            : {
     102                 :            :   /** Simple case: T == table_value_type */
     103                 :            :   typedef T table_value_type;
     104                 :            :   /** No conversion necessary */
     105                 :  204964229 :   inline static T convert(const T& t) { return t; }
     106                 :            :   /** No conversion necessary */
     107                 : 2392492871 :   inline static T convertBack(const T& t) { return t; }
     108                 :            : };
     109                 :            : 
     110                 :            : /**
     111                 :            :  * This converts arbitrary unsigned integers (up to 64-bit) to and from 64-bit
     112                 :            :  * integers s.t. they can be stored in the hash table for integral-valued
     113                 :            :  * attributes.
     114                 :            :  */
     115                 :            : template <class T>
     116                 :            : struct KindValueToTableValueMapping<
     117                 :            :     T,
     118                 :            :     // Use this specialization only for unsigned integers
     119                 :            :     typename std::enable_if<std::is_unsigned<T>::value>::type>
     120                 :            : {
     121                 :            :   typedef uint64_t table_value_type;
     122                 :            :   /** Convert from unsigned integer to uint64_t */
     123                 :  204824704 :   static uint64_t convert(const T& t)
     124                 :            :   {
     125                 :            :     static_assert(sizeof(T) <= sizeof(uint64_t),
     126                 :            :                   "Cannot store integer attributes of a bit-width that is "
     127                 :            :                   "greater than 64-bits");
     128                 :  204824704 :     return static_cast<uint64_t>(t);
     129                 :            :   }
     130                 :            :   /** Convert from uint64_t to unsigned integer */
     131                 : 1830683917 :   static T convertBack(const uint64_t& t) { return static_cast<T>(t); }
     132                 :            : };
     133                 :            : 
     134                 :            : }  // namespace attr
     135                 :            : 
     136                 :            : // ATTRIBUTE HASH TABLES =======================================================
     137                 :            : 
     138                 :            : namespace attr {
     139                 :            : 
     140                 :            : // Returns a 64 bit integer with a single `bit` set when `bit` < 64.
     141                 :            : // Avoids problems in (1 << x) when sizeof(x) <= sizeof(uint64_t).
     142                 : 2002587997 : inline uint64_t GetBitSet(uint64_t bit)
     143                 :            : {
     144                 : 2002587997 :   constexpr uint64_t kOne = 1;
     145                 : 2002587997 :   return kOne << bit;
     146                 :            : }
     147                 :            : 
     148                 :            : /**
     149                 :            :  * An "AttrHash<V>"---the hash table underlying
     150                 :            :  * attributes---is a mapping of pair<unique-attribute-id, Node>
     151                 :            :  * to V using a two-level hash+flat_map structure. The top level
     152                 :            :  * uses NodeValue* as its key, allowing rapid deletion of matching
     153                 :            :  * collections of entries, while the second level, keyed on Ids
     154                 :            :  * and implemented with a sorted vector, optimizes for size and
     155                 :            :  * speed for small collections.
     156                 :            :  */
     157                 :            : template <class V>
     158                 :            : class AttrHash
     159                 :            : {
     160                 :            :   // Second level flat map uint64_t -> V
     161                 :            :   class IdMap
     162                 :            :   {
     163                 :            :    public:
     164                 :            :     using value_type = std::pair<uint64_t, V>;
     165                 :            :     using Container = std::vector<value_type>;
     166                 :            :     using iterator = typename Container::iterator;
     167                 :            :     using const_iterator = typename Container::const_iterator;
     168                 :            : 
     169                 :            :     // only the methods required by AttrHash<V>:
     170                 :            : 
     171                 :          3 :     const_iterator begin() const { return d_contents.begin(); }
     172                 : 2819197964 :     const_iterator end() const { return d_contents.end(); }
     173                 :            : 
     174                 :         21 :     iterator begin() { return d_contents.begin(); }
     175                 :         82 :     iterator end() { return d_contents.end(); }
     176                 :            : 
     177                 :         36 :     std::size_t size() const { return d_contents.size(); }
     178                 :            : 
     179                 :          5 :     bool empty() const { return d_contents.empty(); }
     180                 :            : 
     181                 :         11 :     void reserve(std::size_t sz) { d_contents.reserve(sz); }
     182                 :            : 
     183                 :         20 :     std::pair<iterator, bool> emplace(uint64_t k, V v)
     184                 :            :     {
     185                 :         20 :       value_type p = std::make_pair(k, std::move(v));
     186                 :            :       auto range =
     187                 :         20 :           std::equal_range(d_contents.begin(),
     188                 :            :                            d_contents.end(),
     189                 :            :                            p,
     190                 :         15 :                            [](const value_type& a, const value_type& b) {
     191                 :         15 :                              return a.first < b.first;
     192                 :            :                            });
     193         [ +  + ]:         20 :       if (range.first != range.second)
     194                 :            :       {
     195                 :            :         // key already present, don't insert
     196                 :          2 :         return std::make_pair(iterator{}, false);
     197                 :            :       }
     198                 :            : 
     199                 :         18 :       return std::make_pair(d_contents.insert(range.first, std::move(p)), true);
     200                 :          0 :     }
     201                 :            : 
     202                 : 2819197958 :     const_iterator find(uint64_t key) const
     203                 :            :     {
     204                 :            :       auto range =
     205                 : 2819197958 :           std::equal_range(d_contents.begin(),
     206                 :            :                            d_contents.end(),
     207                 : 5583051808 :                            std::make_pair(key, V{}),
     208                 : 6059089134 :                            [](const value_type& a, const value_type& b) {
     209                 : 6059089134 :                              return a.first < b.first;
     210                 :            :                            });
     211         [ +  + ]: 2819197958 :       if (range.first == range.second)
     212                 :            :       {
     213                 :            :         // not in map
     214                 :   62622102 :         return d_contents.end();
     215                 :            :       }
     216                 : 2756575856 :       return range.first;
     217                 :            :     }
     218                 :            : 
     219                 :         31 :     iterator find(uint64_t key)
     220                 :            :     {
     221                 :            :       auto range =
     222                 :         31 :           std::equal_range(d_contents.begin(),
     223                 :            :                            d_contents.end(),
     224                 :         31 :                            std::make_pair(key, V{}),
     225                 :         94 :                            [](const value_type& a, const value_type& b) {
     226                 :         94 :                              return a.first < b.first;
     227                 :            :                            });
     228         [ +  + ]:         31 :       if (range.first == range.second)
     229                 :            :       {
     230                 :          2 :         return d_contents.end();
     231                 :            :       }
     232                 :         29 :       return range.first;
     233                 :            :     }
     234                 :            : 
     235                 :          5 :     iterator erase(iterator pos) { return d_contents.erase(pos); }
     236                 :            : 
     237                 :  205856426 :     V& operator[](uint64_t key)
     238                 :            :     {
     239                 :            :       iterator it =
     240                 :  205856426 :           std::lower_bound(d_contents.begin(),
     241                 :            :                            d_contents.end(),
     242                 :  410820655 :                            std::make_pair(key, V{}),
     243                 :   28698408 :                            [](const value_type& a, const value_type& b) {
     244                 :   28698408 :                              return a.first < b.first;
     245                 :            :                            });
     246 [ +  + ][ +  + ]:  205856426 :       if ((it == d_contents.end()) || (it->first != key))
                 [ +  + ]
     247                 :            :       {
     248                 :            :         // not in map
     249                 :  201042737 :         it = d_contents.insert(it, std::make_pair(key, V{}));
     250                 :            :       }
     251                 :  205856426 :       return (*it).second;
     252                 :            :     }
     253                 :            : 
     254                 :            :     // range insert
     255                 :            :     template <typename Iter>
     256                 :            :     void insert(Iter beg, Iter end)
     257                 :            :     {
     258                 :            :       for (Iter it = beg; it != end; ++it)
     259                 :            :       {
     260                 :            :         iterator found_it =
     261                 :            :             std::lower_bound(d_contents.begin(),
     262                 :            :                              d_contents.end(),
     263                 :            :                              it->first,
     264                 :            :                              [](const value_type& a, const value_type& b) {
     265                 :            :                                return a.first < b.first;
     266                 :            :                              });
     267                 :            :         if ((found_it != d_contents.end()) && (it->first == found_it->first))
     268                 :            :         {
     269                 :            :           // this key is already present in the map. replace it:
     270                 :            :           found_it->second = it->second;
     271                 :            :         }
     272                 :            :         else
     273                 :            :         {
     274                 :            :           d_contents.insert(found_it, *it);
     275                 :            :         }
     276                 :            :       }
     277                 :            :     }
     278                 :            : 
     279                 :            :    private:
     280                 :            :     Container d_contents;
     281                 :            :   };
     282                 :            : 
     283                 :            :   // a composite iterator combining a top-level (std::unordered_map)
     284                 :            :   // iterator with a lower-level (IdMap) iterator to preserve the
     285                 :            :   // illusion of a single map. Together they identify a virtual
     286                 :            :   // element pair<pair<uint64_t, NodeValue*>, V> expected by
     287                 :            :   // users of AttrHash<V>.
     288                 :            :   template <typename Parent, typename L1It, typename L2It>
     289                 :            :   class Iterator
     290                 :            :   {
     291                 :            :     // access for AttrHash to implement erase(Iterator)
     292                 :            :     using NonConstParent = typename std::remove_const_t<Parent>;
     293                 :            :     using NonConstIterator = typename NonConstParent::iterator;
     294                 :            :     friend NonConstIterator Parent::erase(NonConstIterator);
     295                 :            : 
     296                 :            :    public:
     297                 :            :     // requirements for ForwardIterator
     298                 :            :     using iterator_category = std::forward_iterator_tag;
     299                 :            :     using value_type = std::pair<std::pair<uint64_t, NodeValue*>, V>;
     300                 :            :     using reference = value_type;  // we don't supply a true reference
     301                 :            :     using pointer = value_type*;
     302                 :            :     using difference_type = std::ptrdiff_t;
     303                 :            : 
     304                 :            :     // default constructor
     305                 : 3643279041 :     Iterator() : d_atEnd{true} {}
     306                 :            : 
     307                 :         13 :     Iterator(Parent* parent)
     308                 :         13 :         : d_parent{parent}, d_l1It(parent->d_storage.begin())
     309                 :            :     {
     310                 :         13 :       d_atEnd = (d_l1It == parent->d_storage.end());
     311         [ +  + ]:         13 :       if (!d_atEnd)
     312                 :            :       {
     313                 :         12 :         d_l2It = d_l1It->second.begin();
     314                 :         12 :         legalize();  // L2 map may be empty
     315                 :            :       }
     316                 :         13 :     }
     317                 :            : 
     318                 :            :     // prerequisite: l1_it and l2_it are valid iterators
     319                 : 2756575890 :     Iterator(Parent* parent, L1It l1_it, L2It l2_it)
     320                 : 2756575890 :         : d_atEnd(l1_it == parent->d_storage.end()),
     321                 : 2756575890 :           d_parent(parent),
     322                 : 2756575890 :           d_l1It(l1_it),
     323                 : 2756575890 :           d_l2It(l2_it)
     324                 :            :     {
     325                 : 2756575890 :     }
     326                 :            : 
     327                 :            :     // increment
     328                 :         28 :     Iterator& operator++()  // pre
     329                 :            :     {
     330                 :         28 :       increment();
     331                 :         28 :       return *this;
     332                 :            :     }
     333                 :            : 
     334                 :            :     Iterator operator++(int)  // post
     335                 :            :     {
     336                 :            :       Iterator tmp = *this;
     337                 :            :       increment();
     338                 :            :       return tmp;
     339                 :            :     }
     340                 :            : 
     341                 :            :     // dereference
     342                 : 2424521325 :     value_type operator*() const
     343                 :            :     {
     344                 : 4849042650 :       return std::make_pair(std::make_pair(d_l2It->first, d_l1It->first),
     345                 : 7273563975 :                             d_l2It->second);
     346                 :            :     }
     347                 :            : 
     348                 :            :     // comparison
     349                 : 3199927494 :     bool operator==(Iterator const& other) const
     350                 :            :     {
     351         [ -  + ]:  443351585 :       return (d_atEnd && other.d_atEnd)
     352 [ +  + ][ +  - ]: 3643279081 :              || (!d_atEnd && !other.d_atEnd && (d_l1It == other.d_l1It)
         [ +  + ][ +  - ]
     353         [ +  - ]: 3199927496 :                  && (d_l2It == other.d_l2It));
     354                 :            :     }
     355                 :         57 :     bool operator!=(Iterator const& other) const { return !(*this == other); }
     356                 :            : 
     357                 :            :    private:
     358                 :         28 :     void increment()
     359                 :            :     {
     360                 :         28 :       ++d_l2It;
     361                 :            : 
     362                 :         28 :       legalize();  // we may be at the end of the current L2 map
     363                 :         28 :     }
     364                 :            : 
     365                 :            :     // if necessary, adjust L1/L2 iterators so they point at a real element
     366                 :            :     // called whenever a change may cause the L2 iterator to point to the end
     367                 :            :     // of the current L2 map, e.g.:
     368                 :            :     // initialization: the first L2 map is empty
     369                 :            :     // increment: the L2 iterator was pointing at the last element
     370                 :            :     // erase: the L2 iterator was pointing at the erased element and there are no more
     371                 :         45 :     void legalize()
     372                 :            :     {
     373                 :            :       // move forward to next valid entry
     374         [ +  + ]:         57 :       while (d_l2It == d_l1It->second.end())
     375                 :            :       {
     376                 :         20 :         ++d_l1It;
     377         [ +  + ]:         20 :         if (d_l1It == d_parent->d_storage.end())
     378                 :            :         {
     379                 :          8 :           d_atEnd = true;
     380                 :          8 :           return;
     381                 :            :         }
     382                 :         12 :         d_l2It = d_l1It->second.begin();
     383                 :            :       }
     384                 :            :     }
     385                 :            : 
     386                 :            :     /** Whether at the end of all entries (matches only other end sentinels) */
     387                 :            :     bool d_atEnd;
     388                 :            : 
     389                 :            :     /** The AttrHash this iterator belongs to */
     390                 :            :     Parent* d_parent;
     391                 :            : 
     392                 :            :     /** Iterator within the top-level std::unordered_map */
     393                 :            :     L1It d_l1It;
     394                 :            : 
     395                 :            :     /** Iterator within the second level IdMap (sorted vector) */
     396                 :            :     L2It d_l2It;
     397                 :            :   };
     398                 :            : 
     399                 :            :   using Storage = std::unordered_map<NodeValue*, IdMap, AttrBoolHashFunction>;
     400                 :            : 
     401                 :            :  public:
     402                 :            :   using iterator = Iterator<AttrHash<V>,
     403                 :            :                             typename Storage::iterator,
     404                 :            :                             typename IdMap::iterator>;
     405                 :            :   using const_iterator = Iterator<const AttrHash<V>,
     406                 :            :                                   typename Storage::const_iterator,
     407                 :            :                                   typename IdMap::const_iterator>;
     408                 :            : 
     409                 :         15 :   std::size_t size() const
     410                 :            :   {
     411                 :         15 :     return std::accumulate(
     412                 :            :         d_storage.begin(),
     413                 :            :         d_storage.end(),
     414                 :            :         0u,
     415                 :         25 :         [](std::size_t sum, const std::pair<NodeValue*, IdMap>& l2) {
     416                 :         25 :           return sum + l2.second.size();
     417                 :         15 :         });
     418                 :            :   }
     419                 :            : 
     420                 :         11 :   iterator begin() { return iterator(this); }
     421                 :         33 :   iterator end() { return iterator(); }
     422                 :            : 
     423                 :          2 :   const_iterator begin() const
     424                 :            :   {
     425                 :          2 :     return const_iterator(const_cast<AttrHash<V>*>(this));
     426                 :            :   }
     427                 : 3199927431 :   const_iterator end() const { return const_iterator(); }
     428                 :            : 
     429                 :          5 :   iterator erase(iterator it)
     430                 :            :   {
     431                 :            :     // reach inside the iterator to get L1/L2 positions
     432                 :          5 :     auto nextL2It = it.d_l1It->second.erase(it.d_l2It);
     433                 :            : 
     434                 :          5 :     iterator nextIt(this, it.d_l1It, nextL2It);
     435                 :          5 :     nextIt.legalize();
     436                 :            : 
     437         [ +  + ]:          5 :     if (it.d_l1It->second.empty())
     438                 :            :     {
     439                 :            :       // this erase has made the L2 map empty. delete it:
     440                 :          2 :       d_storage.erase(it.d_l1It);
     441                 :            :     }
     442                 :            : 
     443                 :         10 :     return nextIt;
     444                 :            :   }
     445                 :            : 
     446                 :            :   template <typename Iter>
     447                 :          5 :   void insert(Iter beg, Iter end)
     448                 :            :   {
     449                 :            :     using Entry = typename std::iterator_traits<Iter>::value_type;
     450                 :            :     using Entries = std::vector<Entry>;
     451                 :            :     using EntryIt = typename Entries::iterator;
     452                 :          5 :     Entries entries(beg, end);
     453                 :            : 
     454                 :            :     // sort by second (NodeValue*) then first (uint64_t)
     455                 :          5 :     std::sort(
     456                 :         36 :         entries.begin(), entries.end(), [](const Entry& a, const Entry& b) {
     457                 :         36 :           return (a.first.second < b.first.second)
     458 [ +  + ][ +  + ]:         50 :                  || ((a.first.second == b.first.second)
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     459 [ -  + ][ -  - ]:         50 :                      && (a.first.first < b.first.first));
         [ -  - ][ -  - ]
                 [ -  - ]
     460                 :            :         });
     461                 :            : 
     462                 :         11 :     auto find_different_nv = [](NodeValue* nv, EntryIt first, EntryIt last) {
     463                 :         11 :       return std::find_if(
     464                 :         37 :           first, last, [nv](const Entry& a) { return a.first.second != nv; });
     465                 :            :     };
     466                 :            : 
     467                 :            :     // determine number of new L1 entries required (count unique NodeValue*s)
     468                 :          5 :     std::size_t l1_unique_count = 0;
     469                 :          5 :     auto last = entries.end();
     470         [ +  + ]:         16 :     for (EntryIt it = entries.begin(); it != last;
     471                 :         11 :          it = find_different_nv(it->first.second, it, entries.end()))
     472                 :            :     {
     473                 :         11 :       ++l1_unique_count;
     474                 :            :     }
     475                 :            :     // pre-allocate enough space for the new L1 entries (for speed)
     476                 :          5 :     d_storage.reserve(d_storage.size() + l1_unique_count);
     477                 :            : 
     478                 :            :     // add new entries one (same NodeValue*) chunk at a time
     479         [ +  + ]:         16 :     for (EntryIt it = entries.begin(); it != last;)
     480                 :            :     {
     481                 :            :       // identify range of entries with the same NodeValue* (a "chunk")
     482                 :         11 :       EntryIt chunk_end = std::find_if(it, entries.end(), [it](const Entry& v) {
     483                 :         26 :         return v.first.second != it->first.second;
     484                 :            :       });
     485                 :            :       // add to corresponding l2 map
     486                 :         11 :       auto& l2 = d_storage[it->first.second];
     487                 :         11 :       l2.reserve(l2.size() + std::distance(it, chunk_end));
     488         [ +  + ]:         31 :       for (; it != chunk_end; ++it)
     489                 :            :       {
     490                 :         20 :         l2.emplace(it->first.first, it->second);
     491                 :            :       }
     492                 :            :     }
     493                 :          5 :   }
     494                 :            : 
     495                 :          0 :   void swap(AttrHash& other) { std::swap(d_storage, other.d_storage); }
     496                 :            : 
     497                 :  205856426 :   V& operator[](std::pair<uint64_t, NodeValue*> p)
     498                 :            :   {
     499                 :  205856426 :     return d_storage[p.second][p.first];
     500                 :            :   }
     501                 :            : 
     502                 :     362891 :   void clear() { d_storage.clear(); }
     503                 :            : 
     504                 : 3199927429 :   const_iterator find(std::pair<uint64_t, NodeValue*> p) const
     505                 :            :   {
     506                 : 3199927429 :     typename Storage::const_iterator it1 = d_storage.find(p.second);
     507         [ +  + ]: 3199927429 :     if (it1 == d_storage.end()) return const_iterator();
     508                 :            : 
     509                 : 2819197958 :     typename IdMap::const_iterator it2 = it1->second.find(p.first);
     510         [ +  + ]: 2819197958 :     if (it2 == it1->second.end()) return const_iterator();
     511                 :            : 
     512                 : 2756575856 :     return const_iterator(this, it1, it2);
     513                 :            :   }
     514                 :            : 
     515                 :         33 :   iterator find(std::pair<uint64_t, NodeValue*> p)
     516                 :            :   {
     517                 :         33 :     typename Storage::iterator it1 = d_storage.find(p.second);
     518         [ +  + ]:         33 :     if (it1 == d_storage.end()) return iterator();
     519                 :            : 
     520                 :         31 :     typename IdMap::iterator it2 = it1->second.find(p.first);
     521         [ +  + ]:         31 :     if (it2 == it1->second.end()) return iterator();
     522                 :            : 
     523                 :         29 :     return iterator(this, it1, it2);
     524                 :            :   }
     525                 :            : 
     526                 :  807588692 :   void eraseBy(NodeValue* nv) { d_storage.erase(nv); }
     527                 :            : 
     528                 :            :  private:
     529                 :            :   Storage d_storage;
     530                 :            : };/* class AttrHash<> */
     531                 :            : 
     532                 :            : /**
     533                 :            :  * In the case of Boolean-valued attributes we have a special
     534                 :            :  * "AttrHash<bool>" to pack bits together in words.
     535                 :            :  */
     536                 :            : template <>
     537                 :            : class AttrHash<bool> :
     538                 :            :     protected std::unordered_map<NodeValue*,
     539                 :            :                                   uint64_t,
     540                 :            :                                   AttrBoolHashFunction> {
     541                 :            : 
     542                 :            :   /** A "super" type, like in Java, for easy reference below. */
     543                 :            :   typedef std::unordered_map<NodeValue*, uint64_t, AttrBoolHashFunction> super;
     544                 :            : 
     545                 :            :   /**
     546                 :            :    * BitAccessor allows us to return a bit "by reference."  Of course,
     547                 :            :    * we don't require bit-addressibility supported by the system, we
     548                 :            :    * do it with a complex type.
     549                 :            :    */
     550                 :            :   class BitAccessor {
     551                 :            : 
     552                 :            :     uint64_t& d_word;
     553                 :            : 
     554                 :            :     uint64_t d_bit;
     555                 :            : 
     556                 :            :    public:
     557                 :  203932527 :     BitAccessor(uint64_t& word, uint64_t bit) : d_word(word), d_bit(bit) {}
     558                 :            : 
     559                 :  203932527 :     BitAccessor& operator=(bool b) {
     560         [ +  + ]:  203932527 :       if(b) {
     561                 :            :         // set the bit
     562                 :  182455642 :         d_word |= GetBitSet(d_bit);
     563                 :            :       } else {
     564                 :            :         // clear the bit
     565                 :   21476885 :         d_word &= ~GetBitSet(d_bit);
     566                 :            :       }
     567                 :            : 
     568                 :  203932527 :       return *this;
     569                 :            :     }
     570                 :            : 
     571                 :            :     operator bool() const { return (d_word & GetBitSet(d_bit)) ? true : false; }
     572                 :            :   };/* class AttrHash<bool>::BitAccessor */
     573                 :            : 
     574                 :            :   /**
     575                 :            :    * A (somewhat degenerate) iterator over boolean-valued attributes.
     576                 :            :    * This iterator doesn't support anything except comparison and
     577                 :            :    * dereference.  It's intended just for the result of find() on the
     578                 :            :    * table.
     579                 :            :    */
     580                 :            :   class BitIterator {
     581                 :            : 
     582                 :            :     std::pair<NodeValue* const, uint64_t>* d_entry;
     583                 :            : 
     584                 :            :     uint64_t d_bit;
     585                 :            : 
     586                 :            :    public:
     587                 :            : 
     588                 :            :     BitIterator() :
     589                 :            :       d_entry(NULL),
     590                 :            :       d_bit(0) {
     591                 :            :     }
     592                 :            : 
     593                 :            :     BitIterator(std::pair<NodeValue* const, uint64_t>& entry, uint64_t bit)
     594                 :            :         : d_entry(&entry), d_bit(bit)
     595                 :            :     {
     596                 :            :     }
     597                 :            : 
     598                 :            :     std::pair<NodeValue* const, BitAccessor> operator*() {
     599                 :            :       return std::make_pair(d_entry->first,
     600                 :            :                             BitAccessor(d_entry->second, d_bit));
     601                 :            :     }
     602                 :            : 
     603                 :            :     bool operator==(const BitIterator& b) {
     604                 :            :       return d_entry == b.d_entry && d_bit == b.d_bit;
     605                 :            :     }
     606                 :            :   };/* class AttrHash<bool>::BitIterator */
     607                 :            : 
     608                 :            :   /**
     609                 :            :    * A (somewhat degenerate) const_iterator over boolean-valued
     610                 :            :    * attributes.  This const_iterator doesn't support anything except
     611                 :            :    * comparison and dereference.  It's intended just for the result of
     612                 :            :    * find() on the table.
     613                 :            :    */
     614                 :            :   class ConstBitIterator {
     615                 :            : 
     616                 :            :     const std::pair<NodeValue* const, uint64_t>* d_entry;
     617                 :            : 
     618                 :            :     uint64_t d_bit;
     619                 :            : 
     620                 :            :    public:
     621                 :            : 
     622                 : 2030112704 :     ConstBitIterator() :
     623                 : 2030112704 :       d_entry(NULL),
     624                 : 2030112704 :       d_bit(0) {
     625                 : 2030112704 :     }
     626                 :            : 
     627                 : 1798655470 :     ConstBitIterator(const std::pair<NodeValue* const, uint64_t>& entry,
     628                 :            :                      uint64_t bit)
     629                 : 1798655470 :         : d_entry(&entry), d_bit(bit)
     630                 :            :     {
     631                 : 1798655470 :     }
     632                 :            : 
     633                 : 1798655470 :     std::pair<NodeValue* const, bool> operator*()
     634                 :            :     {
     635                 : 3597310940 :       return std::make_pair(
     636                 : 1798655470 :           d_entry->first, (d_entry->second & GetBitSet(d_bit)) ? true : false);
     637                 :            :     }
     638                 :            : 
     639                 : 1914384087 :     bool operator==(const ConstBitIterator& b) {
     640 [ +  + ][ +  - ]: 1914384087 :       return d_entry == b.d_entry && d_bit == b.d_bit;
     641                 :            :     }
     642                 :            :   };/* class AttrHash<bool>::ConstBitIterator */
     643                 :            : 
     644                 :            : public:
     645                 :            : 
     646                 :            :   typedef std::pair<uint64_t, NodeValue*> key_type;
     647                 :            :   typedef bool data_type;
     648                 :            :   typedef std::pair<const key_type, data_type> value_type;
     649                 :            : 
     650                 :            :   /** an iterator type; see above for limitations */
     651                 :            :   typedef BitIterator iterator;
     652                 :            :   /** a const_iterator type; see above for limitations */
     653                 :            :   typedef ConstBitIterator const_iterator;
     654                 :            : 
     655                 :            :   /**
     656                 :            :    * Find the boolean value in the hash table.  Returns something ==
     657                 :            :    * end() if not found.
     658                 :            :    */
     659                 :            :   BitIterator find(const std::pair<uint64_t, NodeValue*>& k) {
     660                 :            :     super::iterator i = super::find(k.second);
     661                 :            :     if(i == super::end()) {
     662                 :            :       return BitIterator();
     663                 :            :     }
     664                 :            :     /*
     665                 :            :     Trace.printf("boolattr",
     666                 :            :                  "underlying word at 0x%p looks like 0x%016llx, bit is %u\n",
     667                 :            :                  &(*i).second,
     668                 :            :                  (uint64_t)((*i).second),
     669                 :            :                  uint64_t(k.first));
     670                 :            :     */
     671                 :            :     return BitIterator(*i, k.first);
     672                 :            :   }
     673                 :            : 
     674                 :            :   /** The "off the end" iterator */
     675                 :            :   BitIterator end() {
     676                 :            :     return BitIterator();
     677                 :            :   }
     678                 :            : 
     679                 :            :   /**
     680                 :            :    * Find the boolean value in the hash table.  Returns something ==
     681                 :            :    * end() if not found.
     682                 :            :    */
     683                 : 1914384087 :   ConstBitIterator find(const std::pair<uint64_t, NodeValue*>& k) const {
     684                 : 1914384087 :     super::const_iterator i = super::find(k.second);
     685         [ +  + ]: 1914384087 :     if(i == super::end()) {
     686                 :  115728617 :       return ConstBitIterator();
     687                 :            :     }
     688                 :            :     /*
     689                 :            :     Trace.printf("boolattr",
     690                 :            :                  "underlying word at 0x%p looks like 0x%016llx, bit is %u\n",
     691                 :            :                  &(*i).second,
     692                 :            :                  (uint64_t)((*i).second),
     693                 :            :                  uint64_t(k.first));
     694                 :            :     */
     695                 : 1798655470 :     return ConstBitIterator(*i, k.first);
     696                 :            :   }
     697                 :            : 
     698                 :            :   /** The "off the end" const_iterator */
     699                 : 1914384087 :   ConstBitIterator end() const {
     700                 : 1914384087 :     return ConstBitIterator();
     701                 :            :   }
     702                 :            : 
     703                 :            :   /**
     704                 :            :    * Access the hash table using the underlying operator[].  Inserts
     705                 :            :    * the key into the table (associated to default value) if it's not
     706                 :            :    * already there.
     707                 :            :    */
     708                 :  203932527 :   BitAccessor operator[](const std::pair<uint64_t, NodeValue*>& k) {
     709                 :  203932527 :     uint64_t& word = super::operator[](k.second);
     710                 :  203932527 :     return BitAccessor(word, k.first);
     711                 :            :   }
     712                 :            : 
     713                 :            :   /**
     714                 :            :    * Delete all flags from the given node.
     715                 :            :    */
     716                 :  161517738 :   void erase(NodeValue* nv) {
     717                 :  161517738 :     super::erase(nv);
     718                 :  161517738 :   }
     719                 :            : 
     720                 :            :   /**
     721                 :            :    * Clear the hash table.
     722                 :            :    */
     723                 :      72578 :   void clear() {
     724                 :      72578 :     super::clear();
     725                 :      72578 :   }
     726                 :            : 
     727                 :            :   /** Is the hash table empty? */
     728                 :            :   bool empty() const {
     729                 :            :     return super::empty();
     730                 :            :   }
     731                 :            : 
     732                 :            :   /** This is currently very misleading! */
     733                 :            :   size_t size() const {
     734                 :            :     return super::size();
     735                 :            :   }
     736                 :            : };/* class AttrHash<bool> */
     737                 :            : 
     738                 :            : }  // namespace attr
     739                 :            : 
     740                 :            : // ATTRIBUTE IDENTIFIER ASSIGNMENT TEMPLATE ====================================
     741                 :            : 
     742                 :            : namespace attr {
     743                 :            : 
     744                 :            : /**
     745                 :            :  * This is the last-attribute-assigner.  IDs are not globally
     746                 :            :  * unique; rather, they are unique for each table_value_type.
     747                 :            :  */
     748                 :            : template <class T>
     749                 :            : struct LastAttributeId
     750                 :            : {
     751                 :            :  public:
     752                 :    3354347 :   static uint64_t getNextId() {
     753                 :    3354347 :     uint64_t* id = raw_id();
     754                 :    3354347 :     const uint64_t next_id = *id;
     755                 :    3354347 :     ++(*id);
     756                 :    3354347 :     return next_id;
     757                 :            :   }
     758                 :          3 :   static uint64_t getId() {
     759                 :          3 :     return *raw_id();
     760                 :            :   }
     761                 :            :  private:
     762                 :    3354350 :   static uint64_t* raw_id()
     763                 :            :   {
     764                 :            :     static uint64_t s_id = 0;
     765                 :    3354350 :     return &s_id;
     766                 :            :   }
     767                 :            : };
     768                 :            : 
     769                 :            : }  // namespace attr
     770                 :            : 
     771                 :            : // ATTRIBUTE DEFINITION ========================================================
     772                 :            : 
     773                 :            : /**
     774                 :            :  * An "attribute type" structure.
     775                 :            :  *
     776                 :            :  * @param T the tag for the attribute kind.
     777                 :            :  *
     778                 :            :  * @param value_t the underlying value_type for the attribute kind
     779                 :            :  */
     780                 :            : template <class T, class value_t>
     781                 :            : class Attribute
     782                 :            : {
     783                 :            :   /**
     784                 :            :    * The unique ID associated to this attribute.  Assigned statically,
     785                 :            :    * at load time.
     786                 :            :    */
     787                 :            :   static const uint64_t s_id;
     788                 :            : 
     789                 :            : public:
     790                 :            : 
     791                 :            :   /** The value type for this attribute. */
     792                 :            :   typedef value_t value_type;
     793                 :            : 
     794                 :            :   /** Get the unique ID associated to this attribute. */
     795                 : 3405783835 :   static inline uint64_t getId() { return s_id; }
     796                 :            : 
     797                 :            :   /**
     798                 :            :    * This attribute does not have a default value: calling
     799                 :            :    * hasAttribute() for a Node that hasn't had this attribute set will
     800                 :            :    * return false, and getAttribute() for the Node will return a
     801                 :            :    * default-constructed value_type.
     802                 :            :    */
     803                 :            :   static const bool has_default_value = false;
     804                 :            : 
     805                 :            :   /**
     806                 :            :    * Register this attribute kind and check that the ID is a valid ID
     807                 :            :    * for bool-valued attributes.  Fail an assert if not.  Otherwise
     808                 :            :    * return the id.
     809                 :            :    */
     810                 :    2353925 :   static inline uint64_t registerAttribute() {
     811                 :            :     typedef typename attr::KindValueToTableValueMapping<value_t>::
     812                 :            :                      table_value_type table_value_type;
     813                 :    2353925 :     return attr::LastAttributeId<table_value_type>::getNextId();
     814                 :            :   }
     815                 :            : };/* class Attribute<> */
     816                 :            : 
     817                 :            : /**
     818                 :            :  * An "attribute type" structure for boolean flags (special).
     819                 :            :  */
     820                 :            : template <class T>
     821                 :            : class Attribute<T, bool>
     822                 :            : {
     823                 :            :   /** IDs for bool-valued attributes are actually bit assignments. */
     824                 :            :   static const uint64_t s_id;
     825                 :            : 
     826                 :            : public:
     827                 :            : 
     828                 :            :   /** The value type for this attribute; here, bool. */
     829                 :            :   typedef bool value_type;
     830                 :            : 
     831                 :            :   /** Get the unique ID associated to this attribute. */
     832                 : 2118316614 :   static inline uint64_t getId() { return s_id; }
     833                 :            : 
     834                 :            :   /**
     835                 :            :    * Such bool-valued attributes ("flags") have a default value: they
     836                 :            :    * are false for all nodes on entry.  Calling hasAttribute() for a
     837                 :            :    * Node that hasn't had this attribute set will return true, and
     838                 :            :    * getAttribute() for the Node will return the default_value below.
     839                 :            :    */
     840                 :            :   static const bool has_default_value = true;
     841                 :            : 
     842                 :            :   /**
     843                 :            :    * Default value of the attribute for Nodes without one explicitly
     844                 :            :    * set.
     845                 :            :    */
     846                 :            :   static const bool default_value = false;
     847                 :            : 
     848                 :            :   /**
     849                 :            :    * Register this attribute kind and check that the ID is a valid ID
     850                 :            :    * for bool-valued attributes.  Fail an assert if not.  Otherwise
     851                 :            :    * return the id.
     852                 :            :    */
     853                 :    1000422 :   static inline uint64_t registerAttribute() {
     854                 :    1000422 :     const uint64_t id = attr::LastAttributeId<bool>::getNextId();
     855 [ -  + ][ -  + ]:    1000422 :     AlwaysAssert(id <= 63) << "Too many boolean node attributes registered "
                 [ -  - ]
     856                 :            :                               "during initialization !";
     857                 :    1000422 :     return id;
     858                 :            :   }
     859                 :            : };/* class Attribute<..., bool, ...> */
     860                 :            : 
     861                 :            : // ATTRIBUTE IDENTIFIER ASSIGNMENT =============================================
     862                 :            : 
     863                 :            : /** Assign unique IDs to attributes at load time. */
     864                 :            : template <class T, class value_t>
     865                 :            : const uint64_t Attribute<T, value_t>::s_id =
     866                 :            :     Attribute<T, value_t>::registerAttribute();
     867                 :            : 
     868                 :            : /** Assign unique IDs to attributes at load time. */
     869                 :            : template <class T>
     870                 :            : const uint64_t Attribute<T, bool>::s_id =
     871                 :            :     Attribute<T, bool>::registerAttribute();
     872                 :            : 
     873                 :            : }  // namespace expr
     874                 :            : }  // namespace cvc5::internal
     875                 :            : 
     876                 :            : #endif /* CVC5__EXPR__ATTRIBUTE_INTERNALS_H */

Generated by: LCOV version 1.14