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: 84 87 96.6 %
Date: 2024-10-20 11:38:31 Functions: 262 301 87.0 %
Branches: 19 46 41.3 %

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

Generated by: LCOV version 1.14