LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/context - cdinsert_hashmap.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 71 97.2 %
Date: 2026-04-20 10:41:59 Functions: 262 301 87.0 %
Branches: 19 46 41.3 %

           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                 :            :  * Context-dependent insert only hashmap built using trail of edits
      11                 :            :  *
      12                 :            :  * Context-dependent hashmap that only allows for one insertion per element.
      13                 :            :  * This can be viewed as a highly restricted version of CDHashMap.
      14                 :            :  * It is significantly lighter in memory usage than CDHashMap.
      15                 :            :  *
      16                 :            :  * See also:
      17                 :            :  *  CDTrailHashMap : A lightweight CD hash map with poor iteration
      18                 :            :  *    characteristics and some quirks in usage.
      19                 :            :  *  CDHashMap : A fully featured CD hash map. (The closest to <ext/hash_map>)
      20                 :            :  *
      21                 :            :  * Notes:
      22                 :            :  * - To iterate efficiently over the elements use the key_iterators.
      23                 :            :  * - operator[] is only supported as a const derefence (must succeed).
      24                 :            :  * - insert(k) must always work.
      25                 :            :  * - Use insert_safe if you want to check if the element has been inserted
      26                 :            :  *   and only insert if it has not yet been.
      27                 :            :  * - Does not accept TNodes as keys.
      28                 :            :  */
      29                 :            : 
      30                 :            : #include "cvc5parser_public.h"
      31                 :            : 
      32                 :            : #ifndef CVC5__CONTEXT__CDINSERT_HASHMAP_H
      33                 :            : #define CVC5__CONTEXT__CDINSERT_HASHMAP_H
      34                 :            : 
      35                 :            : #include <deque>
      36                 :            : #include <functional>
      37                 :            : #include <unordered_map>
      38                 :            : #include <utility>
      39                 :            : 
      40                 :            : #include "base/check.h"
      41                 :            : #include "base/output.h"
      42                 :            : #include "context/cdinsert_hashmap_forward.h"
      43                 :            : #include "context/context.h"
      44                 :            : 
      45                 :            : namespace cvc5 {
      46                 :            : 
      47                 :            : namespace internal {
      48                 :            : template <bool ref_count>
      49                 :            : class NodeTemplate;
      50                 :            : }
      51                 :            : 
      52                 :            : namespace context {
      53                 :            : 
      54                 :            : template <class Key, class Data, class HashFcn = std::hash<Key> >
      55                 :            : class InsertHashMap
      56                 :            : {
      57                 :            :  private:
      58                 :            :   using KeyVec = std::deque<Key>;
      59                 :            :   /** A list of the keys in the map maintained as a stack. */
      60                 :            :   KeyVec d_keys;
      61                 :            : 
      62                 :            :   using HashMap = std::unordered_map<const Key, const Data, HashFcn>;
      63                 :            :   /** The hash_map used for element lookup. */
      64                 :            :   HashMap d_hashMap;
      65                 :            : 
      66                 :            :  public:
      67                 :            :   /**
      68                 :            :    * An iterator over a list of keys.
      69                 :            :    * Use this to efficiently iterate over the elements.
      70                 :            :    * (See std::deque<>::iterator).
      71                 :            :    */
      72                 :            :   typedef typename KeyVec::const_iterator key_iterator;
      73                 :            : 
      74                 :            :   /**An iterator over the elements in the hash_map. */
      75                 :            :   typedef typename HashMap::const_iterator const_iterator;
      76                 :            : 
      77                 :            :   // The type of the <Key, Data> values in the hashmap.
      78                 :            :   using value_type = typename HashMap::value_type;
      79                 :            : 
      80                 :            :   /**
      81                 :            :    * Returns an iterator to the begining of the HashMap.
      82                 :            :    * Acts like a hash_map::const_iterator.
      83                 :            :    */
      84                 :     352829 :   const_iterator begin() const { return d_hashMap.begin(); }
      85                 :            :   /**
      86                 :            :    * Returns an iterator to the end of the HashMap.
      87                 :            :    * Acts like a hash_map::const_iterator.
      88                 :            :    */
      89                 : 1039513032 :   const_iterator end() const { return d_hashMap.end(); }
      90                 :            : 
      91                 :            :   /**
      92                 :            :    * Returns an iterator to the Key k of the map.
      93                 :            :    * See hash_map::find()
      94                 :            :    */
      95                 : 1039160051 :   const_iterator find(const Key& k) const { return d_hashMap.find(k); }
      96                 :            : 
      97                 :            :   /** Returns an iterator to the start of the set of keys. */
      98                 :        755 :   key_iterator key_begin() const { return d_keys.begin(); }
      99                 :            :   /** Returns an iterator to the end of the set of keys. */
     100                 :        755 :   key_iterator key_end() const { return d_keys.end(); }
     101                 :            : 
     102                 :            :   /** Returns true if the map is empty. */
     103                 :  113304564 :   bool empty() const { return d_keys.empty(); }
     104                 :            :   /** Returns the number of elements in the map. */
     105                 :  266242718 :   size_t size() const { return d_keys.size(); }
     106                 :            : 
     107                 :            :   /** Returns true if k is a mapped key. */
     108                 :  311783807 :   bool contains(const Key& k) const { return find(k) != end(); }
     109                 :            : 
     110                 :            :   /**
     111                 :            :    * Returns a reference the data mapped by k.
     112                 :            :    * This must succeed.
     113                 :            :    */
     114                 :  178641148 :   const Data& operator[](const Key& k) const
     115                 :            :   {
     116                 :  178641148 :     const_iterator ci = find(k);
     117 [ -  + ][ -  + ]:  178641148 :     Assert(ci != end());
                 [ -  - ]
     118                 :  178641148 :     return (*ci).second;
     119                 :            :   }
     120                 :            : 
     121                 :            :   /**
     122                 :            :    * Inserts an element into the map, and pushes its key to the front
     123                 :            :    * of the stack. The key inserted must be not be currently mapped.
     124                 :            :    */
     125                 :            :   void push_front(const Key& k, const Data& d)
     126                 :            :   {
     127                 :            :     Assert(!contains(k));
     128                 :            :     d_hashMap.insert(std::make_pair(k, d));
     129                 :            :     d_keys.push_front(k);
     130                 :            :   }
     131                 :            : 
     132                 :            :   /**
     133                 :            :    * Inserts an element into the map, and pushes its key onto the
     134                 :            :    * back on the stack.  The key inserted must be not be currently mapped.
     135                 :            :    */
     136                 :  131438748 :   void push_back(const Key& k, const Data& d)
     137                 :            :   {
     138 [ -  + ][ -  + ]:  131438748 :     Assert(!contains(k));
                 [ -  - ]
     139                 :  131438748 :     d_hashMap.insert(std::make_pair(k, d));
     140                 :  131438748 :     d_keys.push_back(k);
     141                 :  131438748 :   }
     142                 :            : 
     143                 :            :   /**
     144                 :            :    * Pops the key at the front of the list off and removes its key from the map.
     145                 :            :    */
     146                 :            :   void pop_front()
     147                 :            :   {
     148                 :            :     Assert(!empty());
     149                 :            :     const Key& front = d_keys.front();
     150                 :            :     d_hashMap.erase(front);
     151                 :            : 
     152                 :            :     Trace("TrailHashMap") << "TrailHashMap pop_front " << size() << std::endl;
     153                 :            :     d_keys.pop_front();
     154                 :            :   }
     155                 :            : 
     156                 :            :   /**
     157                 :            :    * Pops the key at the back of the stack off and removes its key from the map.
     158                 :            :    */
     159                 :  113304564 :   void pop_back()
     160                 :            :   {
     161 [ -  + ][ -  + ]:  113304564 :     Assert(!empty());
                 [ -  - ]
     162                 :  113304564 :     const Key& back = d_keys.back();
     163                 :  113304564 :     d_hashMap.erase(back);
     164                 :            : 
     165         [ +  - ]:  113304564 :     Trace("TrailHashMap") << "TrailHashMap pop_back " << size() << std::endl;
     166                 :  113304564 :     d_keys.pop_back();
     167                 :  113304564 :   }
     168                 :            : 
     169                 :            :   /**
     170                 :            :    * Pops the back of the stack until the size is below s.
     171                 :            :    */
     172                 :    7409696 :   void pop_to_size(size_t s)
     173                 :            :   {
     174         [ +  + ]:  120714260 :     while (size() > s)
     175                 :            :     {
     176                 :  113304564 :       pop_back();
     177                 :            :     }
     178                 :    7409696 :   }
     179                 :            : }; /* class TrailHashMap<> */
     180                 :            : 
     181                 :            : template <class Key, class Data, class HashFcn>
     182                 :            : class CDInsertHashMap : public ContextObj
     183                 :            : {
     184                 :            :  private:
     185                 :            :   typedef InsertHashMap<Key, Data, HashFcn> IHM;
     186                 :            : 
     187                 :            :   /** An InsertHashMap that backs all of the data. */
     188                 :            :   IHM* d_insertMap;
     189                 :            : 
     190                 :            :   /** For restores, we need to keep track of the previous size. */
     191                 :            :   size_t d_size;
     192                 :            : 
     193                 :            :   /**
     194                 :            :    * Private copy constructor used only by save().  d_insertMap is
     195                 :            :    * not copied: only the base class information and
     196                 :            :    * d_size are needed in restore.
     197                 :            :    */
     198                 :    7411426 :   CDInsertHashMap(const CDInsertHashMap& l)
     199                 :    7411426 :       : ContextObj(l), d_insertMap(nullptr), d_size(l.d_size)
     200                 :            :   {
     201         [ +  - ]:    7411426 :     Trace("CDInsertHashMap") << "copy ctor: " << this << " from " << &l
     202                 :          0 :                              << " size " << d_size << std::endl;
     203                 :    7411426 :   }
     204                 :            :   CDInsertHashMap& operator=(const CDInsertHashMap&) = delete;
     205                 :            : 
     206                 :            :   /**
     207                 :            :    * Implementation of mandatory ContextObj method save: simply copies
     208                 :            :    * the current size information to a copy using the copy constructor (the
     209                 :            :    * pointer and the allocated size are *not* copied as they are not
     210                 :            :    * restored on a pop).  The saved information is allocated using the
     211                 :            :    * ContextMemoryManager.
     212                 :            :    */
     213                 :    7411426 :   ContextObj* save(ContextMemoryManager* pCMM) override
     214                 :            :   {
     215                 :    7411426 :     ContextObj* data = new (pCMM) CDInsertHashMap<Key, Data, HashFcn>(*this);
     216                 :    7411426 :     return data;
     217                 :            :   }
     218                 :            : 
     219                 :            :  protected:
     220                 :            :   /**
     221                 :            :    * Implementation of mandatory ContextObj method restore:
     222                 :            :    * restore to the previous size taking into account the number
     223                 :            :    * of new pushFront calls have happened since saving.
     224                 :            :    * The d_insertMap is untouched.
     225                 :            :    */
     226                 :    7409696 :   void restore(ContextObj* data) override
     227                 :            :   {
     228                 :    7409696 :     size_t oldSize = ((CDInsertHashMap<Key, Data, HashFcn>*)data)->d_size;
     229                 :            : 
     230                 :            :     // The size to restore to.
     231                 :    7409696 :     size_t restoreSize = oldSize;
     232                 :    7409696 :     d_insertMap->pop_to_size(restoreSize);
     233                 :    7409696 :     d_size = restoreSize;
     234 [ -  + ][ -  + ]:    7409696 :     Assert(d_insertMap->size() == d_size);
                 [ -  - ]
     235                 :    7409696 :   }
     236                 :            : 
     237                 :            :  public:
     238                 :            :   /**
     239                 :            :    * Main constructor: d_insertMap starts as an empty map, with the size is 0
     240                 :            :    */
     241                 :    6680014 :   CDInsertHashMap(Context* context)
     242                 :    6680014 :       : ContextObj(context), d_insertMap(new IHM()), d_size(0)
     243                 :            :   {
     244 [ -  + ][ -  + ]:    6680014 :     Assert(d_insertMap->size() == d_size);
                 [ -  - ]
     245                 :    6680014 :   }
     246                 :            : 
     247                 :            :   /**
     248                 :            :    * Destructor: delete the d_insertMap
     249                 :            :    */
     250                 :    6638275 :   ~CDInsertHashMap()
     251                 :            :   {
     252                 :    6638275 :     this->destroy();
     253         [ +  - ]:    6638275 :     delete d_insertMap;
     254                 :   13276550 :   }
     255                 :            : 
     256                 :            :   /** An iterator over the elements in the hash_map. */
     257                 :            :   typedef typename IHM::const_iterator const_iterator;
     258                 :            : 
     259                 :            :   /**
     260                 :            :    * An iterator over a list of keys.
     261                 :            :    * Use this to efficiently iterate over the elements.
     262                 :            :    * (See std::deque<>::iterator).
     263                 :            :    */
     264                 :            :   typedef typename IHM::key_iterator key_iterator;
     265                 :            : 
     266                 :            :   // The type of the <key, data> values in the hashmap.
     267                 :            :   using value_type = typename IHM::value_type;
     268                 :            : 
     269                 :            :   /** Returns true if the map is empty in the current context. */
     270                 :          0 :   bool empty() const { return d_size == 0; }
     271                 :            : 
     272                 :            :   /** Returns true the size of the map in the current context. */
     273                 :   26067121 :   size_t size() const { return d_size; }
     274                 :            : 
     275                 :            :   /**
     276                 :            :    * Inserts an element into the map.
     277                 :            :    * The key inserted must be not be currently mapped.
     278                 :            :    * This is implemented using d_insertMap.push_back().
     279                 :            :    */
     280                 :  131438748 :   void insert(const Key& k, const Data& d)
     281                 :            :   {
     282                 :  131438748 :     makeCurrent();
     283                 :  131438748 :     ++d_size;
     284                 :  131438748 :     d_insertMap->push_back(k, d);
     285 [ -  + ][ -  + ]:  131438748 :     Assert(d_insertMap->size() == d_size);
                 [ -  - ]
     286                 :  131438748 :   }
     287                 :            : 
     288                 :            :   /**
     289                 :            :    * Checks if the key k is mapped already.
     290                 :            :    * If it is, this returns false.
     291                 :            :    * Otherwise it is inserted and this returns true.
     292                 :            :    */
     293                 :   68198274 :   bool insert_safe(const Key& k, const Data& d)
     294                 :            :   {
     295         [ +  + ]:   68198274 :     if (contains(k))
     296                 :            :     {
     297                 :     554251 :       return false;
     298                 :            :     }
     299                 :            :     else
     300                 :            :     {
     301                 :   67644023 :       insert(k, d);
     302                 :   67644023 :       return true;
     303                 :            :     }
     304                 :            :   }
     305                 :            : 
     306                 :            :   /** Returns true if k is a mapped key in the context. */
     307                 :  180345059 :   bool contains(const Key& k) const { return d_insertMap->contains(k); }
     308                 :            : 
     309                 :            :   /**
     310                 :            :    * Returns a reference the data mapped by k.
     311                 :            :    * k must be in the map in this context.
     312                 :            :    */
     313                 :  178641148 :   const Data& operator[](const Key& k) const { return (*d_insertMap)[k]; }
     314                 :            : 
     315                 :            :   /**
     316                 :            :    * Returns a const_iterator to the value_type if k is a mapped key in
     317                 :            :    * the context.
     318                 :            :    */
     319                 :  548735096 :   const_iterator find(const Key& k) const { return d_insertMap->find(k); }
     320                 :            : 
     321                 :            :   /**
     322                 :            :    * Returns an iterator to the begining of the map.
     323                 :            :    * Acts like a hash_map::const_iterator.
     324                 :            :    */
     325                 :     352829 :   const_iterator begin() const { return d_insertMap->begin(); }
     326                 :            : 
     327                 :            :   /**
     328                 :            :    * Returns an iterator to the end of the map.
     329                 :            :    * Acts like a hash_map::const_iterator.
     330                 :            :    */
     331                 :  549088077 :   const_iterator end() const { return d_insertMap->end(); }
     332                 :            : 
     333                 :            :   /** Returns an iterator to the start of the set of keys. */
     334                 :        755 :   key_iterator key_begin() const { return d_insertMap->key_begin(); }
     335                 :            :   /** Returns an iterator to the end of the set of keys. */
     336                 :        755 :   key_iterator key_end() const { return d_insertMap->key_end(); }
     337                 :            : }; /* class CDInsertHashMap<> */
     338                 :            : 
     339                 :            : template <class Data, class HashFcn>
     340                 :            : class CDInsertHashMap<internal::NodeTemplate<false>, Data, HashFcn>
     341                 :            :     : public ContextObj
     342                 :            : {
     343                 :            :   /* CDInsertHashMap is challenging to get working with TNode.
     344                 :            :    * Consider using CDHashMap<TNode,...> instead.
     345                 :            :    *
     346                 :            :    * Explanation:
     347                 :            :    * CDInsertHashMap uses keys for deallocation.
     348                 :            :    * If the key is a TNode and the backing (the hard node reference)
     349                 :            :    * for the key in another data structure removes the key at the same context
     350                 :            :    * the ref count could drop to 0.  The key would then not be eligible to be
     351                 :            :    * hashed. Getting the order right with a guarantee is too hard.
     352                 :            :    */
     353                 :            : 
     354                 :            :   static_assert(sizeof(Data) == 0,
     355                 :            :                 "Cannot create a CDInsertHashMap with TNode keys");
     356                 :            : };
     357                 :            : 
     358                 :            : }  // namespace context
     359                 :            : }  // namespace cvc5
     360                 :            : 
     361                 :            : #endif

Generated by: LCOV version 1.14