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 : : * Context-dependent list class (only supports append). 10 : : * 11 : : * This list only supports appending to the list; on backtrack, the list is 12 : : * simply shortened. 13 : : */ 14 : : 15 : : #include "cvc5parser_public.h" 16 : : 17 : : #ifndef CVC5__CONTEXT__CDLIST_H 18 : : #define CVC5__CONTEXT__CDLIST_H 19 : : 20 : : #include <cstring> 21 : : #include <iterator> 22 : : #include <memory> 23 : : #include <string> 24 : : #include <vector> 25 : : 26 : : #include "base/check.h" 27 : : #include "context/cdlist_forward.h" 28 : : #include "context/context.h" 29 : : #include "context/context_mm.h" 30 : : #include "context/default_clean_up.h" 31 : : 32 : : namespace cvc5::context { 33 : : 34 : : /** 35 : : * Generic context-dependent dynamic array. Note that for efficiency, this 36 : : * implementation makes the following assumption: Over time, objects are only 37 : : * added to the list. Objects are only removed when a pop restores the list to 38 : : * a previous state. 39 : : */ 40 : : template <class T, class CleanUpT, class Allocator> 41 : : class CDList : public ContextObj 42 : : { 43 : : public: 44 : : /** The value type with which this CDList<> was instantiated. */ 45 : : using value_type = T; 46 : : 47 : : /** The cleanup type with which this CDList<> was instantiated. */ 48 : : using CleanUp = CleanUpT; 49 : : 50 : : /** 51 : : * `std::vector<T>::operator[] const` returns an 52 : : * std::vector<T>::const_reference, which does not necessarily have to be a 53 : : * `const T&`. Specifically, in the case of `std::vector<bool>`, the type is 54 : : * specialized to be just a simple `bool`. For our `operator[] const`, we use 55 : : * the same type. 56 : : */ 57 : : using ConstReference = typename std::vector<T>::const_reference; 58 : : 59 : : /** 60 : : * Instead of implementing our own iterators, we just use the iterators of 61 : : * the underlying `std::vector<T>`. 62 : : */ 63 : : using const_iterator = typename std::vector<T>::const_iterator; 64 : : using iterator = typename std::vector<T>::const_iterator; 65 : : 66 : : /** 67 : : * Main constructor: d_list starts with size 0 68 : : * 69 : : * Optionally, a cleanup callback can be specified, which is called on every 70 : : * element that gets removed during a pop. The callback is only used when 71 : : * callCleanup is true. Note: the destructor of the elements in the list is 72 : : * called regardless of whether callCleanup is true or false. 73 : : */ 74 : 17141178 : CDList(Context* context, 75 : : bool callCleanup = true, 76 : : const CleanUp& cleanup = CleanUp()) 77 : : : ContextObj(context), 78 : 17141178 : d_list(), 79 : 17141178 : d_size(0), 80 : 17141178 : d_callCleanup(callCleanup), 81 : 17141178 : d_cleanUp(cleanup) 82 : : { 83 : 17141178 : } 84 : : 85 : : /** 86 : : * Destructor: delete the list 87 : : */ 88 : 17074507 : ~CDList() 89 : : { 90 : 17074507 : this->destroy(); 91 : : 92 [ + + ]: 17074507 : if (this->d_callCleanup) 93 : : { 94 : 16972654 : truncateList(0); 95 : : } 96 : 34149014 : } 97 : : 98 : : /** 99 : : * Return the current size of (i.e. valid number of objects in) the 100 : : * list. 101 : : */ 102 : 483114095 : size_t size() const { return d_list.size(); } 103 : : 104 : : /** 105 : : * Return true iff there are no valid objects in the list. 106 : : */ 107 : 20693844 : bool empty() const { return d_list.empty(); } 108 : : 109 : : /** 110 : : * Add an item to the end of the list. This method uses the copy constructor 111 : : * of T, so the type has to support it. As a result, this method cannot be 112 : : * used with types that do not have a copy constructor such as 113 : : * std::unique_ptr. Use CDList::emplace_back() instead of CDList::push_back() 114 : : * to avoid this issue. 115 : : */ 116 : 194647338 : void push_back(const T& data) 117 : : { 118 [ + - ]: 194647338 : Trace("cdlist") << "push_back " << this << " " << getContext()->getLevel() 119 : 0 : << ": make-current" << std::endl; 120 : 194647338 : makeCurrent(); 121 : 194647338 : d_list.push_back(data); 122 : 194647338 : ++d_size; 123 : 194647338 : } 124 : : 125 : : /** 126 : : * Construct an item to the end of the list. This method constructs the item 127 : : * in-place (similar to std::vector::emplace_back()), so it can be used for 128 : : * types that do not have a copy constructor such as std::unique_ptr. 129 : : */ 130 : : template <typename... Args> 131 : 23905 : void emplace_back(Args&&... args) 132 : : { 133 [ + - ]: 47810 : Trace("cdlist") << "emplace_back " << this << " " 134 : 23905 : << getContext()->getLevel() << ": make-current" 135 : 0 : << std::endl; 136 : 23905 : makeCurrent(); 137 : 23905 : d_list.emplace_back(std::forward<Args>(args)...); 138 : 23905 : ++d_size; 139 : 23905 : } 140 : : 141 : : /** 142 : : * Access to the ith item in the list. 143 : : */ 144 : 280412664 : ConstReference operator[](size_t i) const 145 : : { 146 [ - + ][ - + ]: 280412664 : Assert(i < d_size) << "index out of bounds in CDList::operator[]"; [ - - ] 147 : 280412664 : return d_list[i]; 148 : : } 149 : : 150 : : /** 151 : : * Returns the most recent item added to the list. 152 : : */ 153 : 28930 : ConstReference back() const 154 : : { 155 [ - + ][ - + ]: 28930 : Assert(d_size > 0) << "CDList::back() called on empty list"; [ - - ] 156 : 28930 : return d_list[d_size - 1]; 157 : : } 158 : : 159 : : /** 160 : : * Returns an iterator pointing to the first item in the list. 161 : : */ 162 : 38270596 : const_iterator begin() const { return d_list.begin(); } 163 : : 164 : : /** 165 : : * Returns an iterator pointing one past the last item in the list. 166 : : */ 167 : 41139082 : const_iterator end() const { return d_list.end(); } 168 : : 169 : : protected: 170 : : /** 171 : : * Private copy constructor used only by save(). d_list is not copied: only 172 : : * the base class information and d_size are needed in restore. 173 : : */ 174 : 35277556 : CDList(const CDList& l) 175 : : : ContextObj(l), 176 : 35277556 : d_size(l.d_size), 177 : 35277556 : d_callCleanup(false), 178 : 35277556 : d_cleanUp(l.d_cleanUp) 179 : : { 180 [ + - ]: 35277556 : Trace("cdlist") << "copy ctor: " << this << " from " << &l << " size " 181 : 0 : << d_size << std::endl; 182 : 35277556 : } 183 : : CDList& operator=(const CDList& l) = delete; 184 : : /** 185 : : * Implementation of mandatory ContextObj method restore: simply 186 : : * restores the previous size. Note that the list pointer and the 187 : : * allocated size are not changed. 188 : : */ 189 : : 190 : 35274774 : void restore(ContextObj* data) override 191 : : { 192 : 35274774 : truncateList(((CDList<T, CleanUp, Allocator>*)data)->d_size); 193 : 35274774 : } 194 : : 195 : : /** 196 : : * Given a size parameter smaller than d_size, truncateList() 197 : : * removes the elements from the end of the list until d_size equals size. 198 : : * 199 : : * WARNING! You should only use this function when you know what you are 200 : : * doing. This is a primitive operation with strange context dependent 201 : : * behavior! It is up to the user of the function to ensure that the saved 202 : : * d_size values at lower context levels are less than or equal to size. 203 : : */ 204 : 61623520 : void truncateList(const size_t size) 205 : : { 206 [ - + ][ - + ]: 61623520 : Assert(size <= d_size); [ - - ] 207 [ + + ]: 61623520 : if (d_callCleanup) 208 : : { 209 [ + + ]: 237158151 : while (d_size != size) 210 : : { 211 : 177173677 : --d_size; 212 : 177173677 : typename std::vector<T>::reference elem = d_list[d_size]; 213 : 177173677 : d_cleanUp(elem); 214 : : } 215 : : } 216 : : else 217 : : { 218 : 1639046 : d_size = size; 219 : : } 220 : : // Note that std::vector::resize() would require a default constructor for 221 : : // the elements in std::vector 222 : 61623520 : d_list.erase(d_list.begin() + d_size, d_list.end()); 223 : 61623520 : } 224 : : 225 : : /** 226 : : * d_list is a vector of objects of type T. 227 : : */ 228 : : std::vector<T> d_list; 229 : : 230 : : /** 231 : : * Number of objects in d_list 232 : : */ 233 : : size_t d_size; 234 : : 235 : : private: 236 : : /** 237 : : * Whether to call the destructor when items are popped from the 238 : : * list. True by default, but can be set to false by setting the 239 : : * second argument in the constructor to false. 240 : : */ 241 : : bool d_callCleanup; 242 : : 243 : : /** 244 : : * The CleanUp functor. 245 : : */ 246 : : CleanUp d_cleanUp; 247 : : 248 : : /** 249 : : * Implementation of mandatory ContextObj method save: simply copies 250 : : * the current size to a copy using the copy constructor (the 251 : : * pointer and the allocated size are *not* copied as they are not 252 : : * restored on a pop). The saved information is allocated using the 253 : : * ContextMemoryManager. 254 : : */ 255 : 25257597 : ContextObj* save(ContextMemoryManager* pCMM) override 256 : : { 257 : 25257597 : ContextObj* data = new (pCMM) CDList<T, CleanUp, Allocator>(*this); 258 : 25257597 : return data; 259 : : } 260 : : 261 : : }; /* class CDList<> */ 262 : : 263 : : } // namespace cvc5::context 264 : : 265 : : #endif /* CVC5__CONTEXT__CDLIST_H */