GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/context/context.h Lines: 54 63 85.7 %
Date: 2021-05-24 Branches: 28 82 34.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Clark Barrett, Morgan Deters, Tim King
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 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 class and context manager.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__CONTEXT__CONTEXT_H
19
#define CVC5__CONTEXT__CONTEXT_H
20
21
#include <cstdlib>
22
#include <iostream>
23
#include <memory>
24
#include <typeinfo>
25
#include <vector>
26
27
#include "base/check.h"
28
#include "base/output.h"
29
#include "context/context_mm.h"
30
31
namespace cvc5 {
32
namespace context {
33
34
class Context;
35
class Scope;
36
class ContextObj;
37
class ContextNotifyObj;
38
39
/** Pretty-printing of Contexts (for debugging) */
40
std::ostream& operator<<(std::ostream&, const Context&);
41
42
/** Pretty-printing of Scopes (for debugging) */
43
std::ostream& operator<<(std::ostream&, const Scope&);
44
45
/**
46
 * A Context encapsulates all of the dynamic state of the system.  Its main
47
 * methods are push() and pop().  A call to push() saves the current state,
48
 * and a call to pop() restores the state saved by the most recent call to
49
 * push().
50
 *
51
 * Objects which want to participate in this global save and restore
52
 * mechanism must inherit from ContextObj (see below).
53
 *
54
 * For more flexible context-dependent behavior, objects may implement the
55
 * ContextNotifyObj interface and simply get a notification when a pop has
56
 * occurred.
57
 *
58
 * Context also uses a helper class called Scope which stores information
59
 * specific to the portion of the Context since the last call to push() (see
60
 * below).
61
 *
62
 * Memory allocation in Contexts is done with the help of the
63
 * ContextMemoryManager.  A copy is stored in each Scope object for quick
64
 * access.
65
 */
66
class Context {
67
68
  /**
69
   * Pointer to the ContextMemoryManager for this Context.
70
   */
71
  ContextMemoryManager* d_pCMM;
72
73
  /**
74
   * List of all scopes for this context.
75
   */
76
  std::vector<Scope*> d_scopeList;
77
78
  /**
79
   * Doubly-linked list of objects to notify before every pop.  See
80
   * ContextNotifyObj for structure of linked list.
81
   */
82
  ContextNotifyObj* d_pCNOpre;
83
84
  /**
85
   * Doubly-linked list of objects to notify after every pop.  See
86
   * ContextNotifyObj for structure of linked list.
87
   */
88
  ContextNotifyObj* d_pCNOpost;
89
90
  friend std::ostream& operator<<(std::ostream&, const Context&);
91
92
  // disable copy, assignment
93
  Context(const Context&) = delete;
94
  Context& operator=(const Context&) = delete;
95
96
public:
97
98
  /**
99
   * A mechanism by which a "scoped" bit of contextual speculation can
100
   * be applied.  One might create a Context::ScopedPush in a function
101
   * (as a local variable on the stack), then manipulate some
102
   * context-dependent data structures in some fashion, speculatively.
103
   * When the ScopedPush goes out of scope and is destructed, the
104
   * context-dependent data structures will return to their original
105
   * state.
106
   *
107
   * When such speculation occurs in a lexically-scoped manner, like
108
   * described above, it is FAR preferable to use ScopedPush than to
109
   * call ->push() and ->pop() on the Context directly.  If you do the
110
   * latter, it's extremely easy to forget to pop() on exceptional
111
   * exit of the function, or if a short-circuited "early" return is
112
   * later added to the function, etc.  Further, ScopedPush includes
113
   * an assertion that the Context at the end looks like the Context
114
   * at the beginning (the topmost Scope pointer should be the same).
115
   * This assertion is only an approximate check for correct behavior,
116
   * but should catch egregious mismatches of ->push() and ->pop()
117
   * while the ScopedPush is being applied---egregious mismatches that
118
   * could exist, for example, if a Theory does some speculative
119
   * reasoning but accidently gives control back to some other mechanism
120
   * which does some speculation which isn't properly scoped inside the
121
   * first.
122
   */
123
  class ScopedPush {
124
    Context* const d_context;
125
    const Scope* const d_scope;
126
  public:
127
1820
    ScopedPush(Context* ctxt) :
128
      d_context(ctxt),
129
1820
      d_scope(d_context->getTopScope()) {
130
1820
      d_context->push();
131
1820
    }
132
3640
    ~ScopedPush() noexcept(false) {
133
1820
      d_context->pop();
134
1820
      AlwaysAssert(d_context->getTopScope() == d_scope)
135
          << "Context::ScopedPush observed an uneven Context (at pop, "
136
             "top scope doesn't match what it was at the time the "
137
             "ScopedPush was applied)";
138
1820
    }
139
  };/* Context::ScopedPush */
140
141
  /**
142
   * Constructor: create ContextMemoryManager and initial Scope
143
   */
144
  Context();
145
146
  /**
147
   * Destructor: pop all scopes, delete ContextMemoryManager
148
   */
149
  ~Context();
150
151
  /**
152
   * Return the current (top) scope
153
   */
154
441443988
  Scope* getTopScope() const { return d_scopeList.back(); }
155
156
  /**
157
   * Return the initial (bottom) scope
158
   */
159
66380248
  Scope* getBottomScope() const { return d_scopeList[0]; }
160
161
  /**
162
   * Return the current Scope level.
163
   */
164
482424612
  int getLevel() const { return d_scopeList.size() - 1; }
165
166
  /**
167
   * Return the ContextMemoryManager associated with the context.
168
   */
169
  ContextMemoryManager* getCMM() { return d_pCMM; }
170
171
  /**
172
   * Save the current state, create a new Scope
173
   */
174
  void push();
175
176
  /**
177
   * Restore the previous state, delete the top Scope
178
   */
179
  void pop();
180
181
  /**
182
   * Pop all the way back to given level
183
   */
184
  void popto(int toLevel);
185
186
  /**
187
   * Add pCNO to the list of objects notified before every pop
188
   */
189
  void addNotifyObjPre(ContextNotifyObj* pCNO);
190
191
  /**
192
   * Add pCNO to the list of objects notified after every pop
193
   */
194
  void addNotifyObjPost(ContextNotifyObj* pCNO);
195
196
};/* class Context */
197
198
199
/**
200
 * A UserContext is different from a Context only because it's used for
201
 * different purposes---so separating the two types gives type errors where
202
 * appropriate.
203
 */
204
10155
class UserContext : public Context {
205
private:
206
  // disable copy, assignment
207
  UserContext(const UserContext&) = delete;
208
  UserContext& operator=(const UserContext&) = delete;
209
public:
210
10155
  UserContext() {}
211
};/* class UserContext */
212
213
214
/**
215
 * Conceptually, a Scope encapsulates that portion of the context that
216
 * changes after a call to push() and must be undone on a subsequent call to
217
 * pop().  In particular, each call to push() creates a new Scope object .
218
 * This new Scope object becomes the top scope and it points (via the
219
 * d_pScopePrev member) to the previous top Scope.  Each call to pop()
220
 * deletes the current top scope and restores the previous one.  The main
221
 * purpose of a Scope is to maintain a linked list of ContexObj objects which
222
 * change while the Scope is the top scope and which must be restored when
223
 * the Scope is deleted.
224
 *
225
 * A Scope is also associated with a ContextMemoryManager.  All memory
226
 * allocated by the Scope is allocated in a single region using the
227
 * ContextMemoryManager and released all at once when the Scope is popped.
228
 */
229
class Scope {
230
231
  /**
232
   * Context that created this Scope
233
   */
234
  Context* d_pContext;
235
236
  /**
237
   * Memory manager for this Scope.  Same as in Context, but stored here too
238
   * for faster access by ContextObj objects.
239
   */
240
  ContextMemoryManager* d_pCMM;
241
242
  /**
243
   * Scope level (total number of outstanding push() calls when this Scope was
244
   * created).
245
   */
246
  int d_level;
247
248
  /**
249
   * Linked list of objects which changed in this scope,
250
   * and thus need to be restored when the scope is deleted.
251
   */
252
  ContextObj* d_pContextObjList;
253
254
  /**
255
   * A list of ContextObj to be garbage collected before the destruction of this
256
   * scope. deleteSelf() will be called on each element during ~Scope().
257
   *
258
   * This is either nullptr or list owned by this scope.
259
   */
260
  std::unique_ptr<std::vector<ContextObj*>> d_garbage;
261
262
  friend std::ostream& operator<<(std::ostream&, const Scope&);
263
264
 public:
265
  /**
266
   * Constructor: Create a new Scope; set the level and the previous Scope
267
   * if any.
268
   */
269
4734684
  Scope(Context* pContext, ContextMemoryManager* pCMM, int level)
270
4734684
      : d_pContext(pContext),
271
        d_pCMM(pCMM),
272
        d_level(level),
273
        d_pContextObjList(nullptr),
274
4734684
        d_garbage()
275
  {
276
4734684
  }
277
278
  /**
279
   * Destructor: Clears out all of the garbage and restore all of the objects
280
   * in ContextObjList.
281
   */
282
  ~Scope();
283
284
  /**
285
   * Get the Context for this Scope
286
   */
287
1048207198
  Context* getContext() const { return d_pContext; }
288
289
  /**
290
   * Get the ContextMemoryManager for this Scope
291
   */
292
81696398
  ContextMemoryManager* getCMM() const { return d_pCMM; }
293
294
  /**
295
   * Get the level of the current Scope
296
   */
297
66433435
  int getLevel() const { return d_level; }
298
299
  /**
300
   * Return true iff this Scope is the current top Scope
301
   */
302
359744177
  bool isCurrent() const { return this == d_pContext->getTopScope(); }
303
304
  /**
305
   * When a ContextObj object is modified for the first time in this
306
   * Scope, it should call this method to add itself to the list of
307
   * objects that will need to be restored.  Defined inline below.
308
   */
309
  void addToChain(ContextObj* pContextObj);
310
311
  /**
312
   * Overload operator new for use with ContextMemoryManager to allow
313
   * creation of new Scope objects in the current memory region.
314
   */
315
4734684
  static void* operator new(size_t size, ContextMemoryManager* pCMM)
316
  {
317
4734684
    Trace("context_mm") << "Scope::new " << size << " in " << pCMM << std::endl;
318
4734684
    return pCMM->newData(size);
319
  }
320
321
  /**
322
   * Enqueues a ContextObj to be garbage collected via a call to deleteSelf()
323
   * during the destruction of this scope.
324
   */
325
  void enqueueToGarbageCollect(ContextObj* obj);
326
327
  /**
328
   * Overload operator delete for Scope objects allocated using
329
   * ContextMemoryManager.  No need to do anything because memory is
330
   * freed automatically when the ContextMemoryManager pop() method is
331
   * called.  Include both placement and standard delete for
332
   * completeness.
333
   */
334
  static void operator delete(void* pMem, ContextMemoryManager* pCMM) {}
335
2584978
  static void operator delete(void* pMem) {}
336
337
  //FIXME:  //! Check for memory leaks
338
  //  void check();
339
340
};/* class Scope */
341
342
/**
343
 * This is an abstract base class from which all objects that are
344
 * context-dependent should inherit.  For any data structure that you
345
 * want to have be automatically backtracked, do the following:
346
 *
347
 * 1. Create a class for the data structure that inherits from ContextObj
348
 *
349
 * 2. Implement save()
350
 *    The role of save() is to create a new ContexObj object that contains
351
 *    enough information to restore the object to its current state, even if
352
 *    it gets changed later.  Note that save should call the (default)
353
 *    ContextObj Copy Constructor to copy the information in the base class.
354
 *    It is recommended that any memory allocated by save() should be done
355
 *    through the ContextMemoryManager.  This way, it does not need to be
356
 *    explicitly freed when restore is called.  However, it is only required
357
 *    that the ContextObj itself be allocated using the
358
 *    ContextMemoryManager.  If other memory is allocated not using the
359
 *    ContextMemoryManager, it should be freed when restore() is called.  In
360
 *    fact, any clean-up work on a saved object must be done by restore().
361
 *    This is because the destructor is never called explicitly on saved
362
 *    objects.
363
 *
364
 * 3. Implement restore()
365
 *    The role of restore() is, given the ContextObj returned by a previous
366
 *    call to save(), to restore the current object to the state it was in
367
 *    when save() was called.  Note that the implementation of restore does
368
 *    *not* need to worry about restoring the base class data.  This is done
369
 *    automatically.  Ideally, restore() should not have to free any memory
370
 *    as any memory allocated by save() should have been done using the
371
 *    ContextMemoryManager (see item 2 above).
372
 *
373
 * 4. In the subclass implementation, any time the state is about to be
374
 *    changed, first call makeCurrent().
375
 *
376
 * 5. In the subclass implementation, the destructor should call destroy(),
377
 *    which repeatedly calls restore() until the object is restored to context
378
 *    level 0.  Note, however, that if there is additional cleanup required at
379
 *    level 0, destroy() does not do this.  It has to be implemented in the
380
 *    destructor of the subclass.  The reason the destroy() functionality
381
 *    cannot be in the ContextObj destructor is that it needs to call the
382
 *    subclass-specific restore() method in order to properly clean up saved
383
 *    copies.
384
 *
385
 * GOTCHAS WHEN ALLOCATING CONTEXTUAL OBJECTS WITH NON-STANDARD ALLOCATORS
386
 *
387
 * Be careful if you intend to allocate ContextObj in (for example)
388
 * ContextMemoryManager memory.  ContextMemoryManager doesn't call the
389
 * destructors of contained objects, which means the objects aren't
390
 * properly unregistered from the Context (as in point #5, above).
391
 * This can be remedied by allocating the ContextObj in the "top
392
 * scope" rather than the "bottom scope" (which is what the
393
 * "allocatedInCMM" flag to the special constructor in ContextObj
394
 * does).
395
 *
396
 * But why allocate in CMM if it's so complicated?  There's a big
397
 * advantage: you don't have to track the lifetime of the ContextObj.
398
 * The object simply ceases to exist when the Context is popped.  Thus
399
 * you can create an object in context memory, and if you stow
400
 * pointers to it only in context memory as well, all is cleaned up
401
 * for you when the scope pops.  Here's a list of gotchas:
402
 *
403
 * 1. For data structures intended solely to be allocated in context
404
 *    memory, privately declare (but don't define) an operator
405
 *    new(size_t) and destructor (as currently in the Link class, in
406
 *    src/theory/uf/ecdata.h).
407
 *
408
 * 2. For data structures that may or may not be allocated in context
409
 *    memory, and are designed to be that way (esp. if they contain
410
 *    ContextObj instances), they should be heavily documented --
411
 *    especially the destructor, since it _may_or_may_not_be_called_.
412
 *
413
 * 3. There's also an issue for generic code -- some class Foo<T>
414
 *    might be allocated in context memory, and that might normally be
415
 *    fine, but if T is a ContextObj this requires certain care.
416
 *
417
 * 4. Note that certain care is required for ContextObj inside of data
418
 *    structures.  If the (enclosing) data structure can be allocated
419
 *    in CMM, that means the (enclosed) ContextObj can be, even if it
420
 *    was not designed to be allocated in that way.  In many
421
 *    instances, it may be required that data structures enclosing
422
 *    ContextObj be parameterized with a similar "bool allocatedInCMM"
423
 *    argument as the special constructor in this class (and pass it
424
 *    on to all ContextObj instances).
425
 */
426
81696165
class ContextObj {
427
  /**
428
   * Pointer to Scope in which this object was last modified.
429
   */
430
  Scope* d_pScope;
431
432
  /**
433
   * Pointer to most recent version of same ContextObj in a previous Scope
434
   */
435
  ContextObj* d_pContextObjRestore;
436
437
  /**
438
   * Next link in ContextObjList list maintained by Scope class.
439
   */
440
  ContextObj* d_pContextObjNext;
441
442
  /**
443
   * Previous link in ContextObjList list maintained by Scope class.  We use
444
   * double-indirection here to make element deletion easy.
445
   */
446
  ContextObj** d_ppContextObjPrev;
447
448
  /**
449
   * Helper method for makeCurrent (see below).  Separated out to allow common
450
   * case to be inlined without making a function call.  It calls save() and
451
   * does the necessary bookkeeping to ensure that object can be restored to
452
   * its current state when restore is called.
453
   */
454
  void update();
455
456
  // The rest of the private methods are for the benefit of the Scope.  We make
457
  // Scope our friend so it is the only one that can use them.
458
459
  friend class Scope;
460
461
  friend std::ostream& operator<<(std::ostream&, const Scope&);
462
463
  /**
464
   * Return reference to next link in ContextObjList.  Used by
465
   * Scope::addToChain method.
466
   */
467
1290875139
  ContextObj*& next() { return d_pContextObjNext; }
468
469
  /**
470
   * Return reference to prev link in ContextObjList.  Used by
471
   * Scope::addToChain method.
472
   */
473
1290156116
  ContextObj**& prev() { return d_ppContextObjPrev; }
474
475
  /**
476
   * This method is called by Scope during a pop: it does the necessary work to
477
   * restore the object from its saved copy and then returns the next object in
478
   * the list that needs to be restored.
479
   */
480
  ContextObj* restoreAndContinue();
481
482
 protected:
483
  /**
484
   * This is a method that must be implemented by all classes inheriting from
485
   * ContextObj.  See the comment before the class declaration.
486
   */
487
  virtual ContextObj* save(ContextMemoryManager* pCMM) = 0;
488
489
  /**
490
   * This is a method that must be implemented by all classes inheriting from
491
   * ContextObj.  See the comment before the class declaration.
492
   */
493
  virtual void restore(ContextObj* pContextObjRestore) = 0;
494
495
  /**
496
   * This method checks if the object has been modified in this Scope
497
   * yet.  If not, it calls update().
498
   */
499
  inline void makeCurrent();
500
501
  /**
502
   * Just calls update(), but given a different name for the derived
503
   * class-facing interface.  This is a "forced" makeCurrent(), useful
504
   * for ContextObjs allocated in CMM that need a special "bottom"
505
   * case when they disappear out of existence (kind of a destructor).
506
   * See CDOhash_map (in cdhashmap.h) for an example.
507
   */
508
  inline void makeSaveRestorePoint();
509
510
  /**
511
   * Should be called from sub-class destructor: calls restore until restored
512
   * to initial version (version at context level 0).  Also removes object from
513
   * all Scope lists.  Note that this doesn't actually free the memory
514
   * allocated by the ContextMemoryManager for this object.  This isn't done
515
   * until the corresponding Scope is popped.
516
   */
517
  void destroy();
518
519
  /////
520
  //
521
  //  These next four accessors return properties of the Scope to
522
  //  derived classes without giving them the Scope object directly.
523
  //
524
  /////
525
526
  /**
527
   * Get the Context with which this ContextObj was created.  This is
528
   * part of the protected interface, intended for derived classes to
529
   * use if necessary.
530
   */
531
966511033
  Context* getContext() const { return d_pScope->getContext(); }
532
533
  /**
534
   * Get the ContextMemoryManager with which this ContextObj was
535
   * created.  This is part of the protected interface, intended for
536
   * derived classes to use if necessary.  If a ContextObj-derived
537
   * class needs to allocate memory somewhere other than the save()
538
   * member function (where it is explicitly given a
539
   * ContextMemoryManager), it can use this accessor to get the memory
540
   * manager.
541
   */
542
  ContextMemoryManager* getCMM() const { return d_pScope->getCMM(); }
543
544
  /**
545
   * Get the level associated to this ContextObj.  Useful if a
546
   * ContextObj-derived class needs to compare the level of its last
547
   * update with another ContextObj.
548
   */
549
66433435
  int getLevel() const { return d_pScope->getLevel(); }
550
551
  /**
552
   * Returns true if the object is "current"-- that is, updated in the
553
   * topmost contextual scope.  Useful if a ContextObj-derived class
554
   * needs to determine if it has been modified in the current scope.
555
   * Note that it is always safe to call makeCurrent() without first
556
   * checking if the object is current, so this function need not be
557
   * used under normal circumstances.
558
   */
559
  bool isCurrent() const { return d_pScope->isCurrent(); }
560
561
 public:
562
  /**
563
   * Disable delete: objects allocated with new(ContextMemorymanager) should
564
   * never be deleted.  Objects allocated with new(bool) should be deleted by
565
   * calling deleteSelf().
566
   */
567
  static void operator delete(void* pMem) {
568
    AlwaysAssert(false) << "It is not allowed to delete a ContextObj this way!";
569
  }
570
571
  /**
572
   * operator new using ContextMemoryManager (common case used by
573
   * subclasses during save()).  No delete is required for memory
574
   * allocated this way, since it is automatically released when the
575
   * context is popped.  Also note that allocations using this
576
   * operator never have their destructor called, so any clean-up has
577
   * to be done using the restore method.
578
   */
579
81696165
  static void* operator new(size_t size, ContextMemoryManager* pCMM) {
580
81696165
    Trace("context_mm") << "Context::new " << size << " in " << pCMM << std::endl;
581
81696165
    return pCMM->newData(size);
582
  }
583
584
  /**
585
   * Corresponding placement delete.  Note that this is provided just
586
   * to satisfy the requirement that a placement delete should be
587
   * provided for every placement new.  It would only be called if a
588
   * ContextObj constructor throws an exception after a successful
589
   * call to the above new operator.
590
   */
591
  static void operator delete(void* pMem, ContextMemoryManager* pCMM) {}
592
593
  /**
594
   * Create a new ContextObj.  The initial scope is set to the bottom
595
   * scope of the Context.  Note that in the common case, the copy
596
   * constructor is called to create new ContextObj objects.  The
597
   * default copy constructor does the right thing, so we do not
598
   * explicitly define it.
599
   */
600
  ContextObj(Context* context);
601
602
  /**
603
   * Create a new ContextObj.  This constructor takes an argument that
604
   * specifies whether this ContextObj is itself allocated in context
605
   * memory.  If it is, it's invalid below the current scope level, so
606
   * we don't put it in scope 0.
607
   *
608
   * WARNING: Read the notes above on "Gotchas when allocating
609
   * contextual objects with non-standard allocators."
610
   */
611
  ContextObj(bool allocatedInCMM, Context* context);
612
613
  /**
614
   * Destructor does nothing: subclass must explicitly call destroy() instead.
615
   */
616
66379016
  virtual ~ContextObj() {}
617
618
  /**
619
   * If you want to allocate a ContextObj object on the heap, use this
620
   * special new operator.  To free this memory, instead of
621
   * "delete p", use "p->deleteSelf()".
622
   */
623
58527548
  static void* operator new(size_t size, bool) {
624
58527548
    return ::operator new(size);
625
  }
626
627
  /**
628
   * Corresponding placement delete.  Note that this is provided for
629
   * the compiler in case the ContextObj constructor throws an
630
   * exception.  The client can't call it.
631
   */
632
  static void operator delete(void* pMem, bool) {
633
    ::operator delete(pMem);
634
  }
635
636
  /**
637
   * Use this instead of delete to delete memory allocated using the special
638
   * new function provided above that takes a bool argument.  Do not call this
639
   * function on memory allocated using the new that takes a
640
   * ContextMemoryManager as an argument.
641
   */
642
58527548
  void deleteSelf() {
643
58527548
    Debug("context") << "deleteSelf(" << this << ") " << typeid(*this).name() << std::endl;
644
58527548
    this->~ContextObj();
645
58527548
    ::operator delete(this);
646
58527548
  }
647
648
  /**
649
   * Use this to enqueue calling deleteSelf() at the time of the destruction of
650
   * the enclosing Scope.
651
   */
652
  void enqueueToGarbageCollect();
653
654
};/* class ContextObj */
655
656
/**
657
 * For more flexible context-dependent behavior than that provided by
658
 * ContextObj, objects may implement the ContextNotifyObj interface
659
 * and simply get a notification when a pop has occurred.  See
660
 * Context class for how to register a ContextNotifyObj with the
661
 * Context (you can choose to have notification come before or after
662
 * the ContextObj objects have been restored).
663
 */
664
class ContextNotifyObj {
665
666
  /**
667
   * Context is our friend so that when the Context is deleted, any
668
   * remaining ContextNotifyObj can be removed from the Context list.
669
   */
670
  friend class Context;
671
672
  /**
673
   * Pointer to next ContextNotifyObject in this List
674
   */
675
  ContextNotifyObj* d_pCNOnext;
676
677
  /**
678
   * Pointer to previous ContextNotifyObject in this list
679
   */
680
  ContextNotifyObj** d_ppCNOprev;
681
682
  /**
683
   * Return reference to next link in ContextNotifyObj list.  Used by
684
   * Context::addNotifyObj methods.
685
   */
686
569260
  ContextNotifyObj*& next() { return d_pCNOnext; }
687
688
  /**
689
   * Return reference to prev link in ContextNotifyObj list.  Used by
690
   * Context::addNotifyObj methods.
691
   */
692
569260
  ContextNotifyObj**& prev() { return d_ppCNOprev; }
693
694
 protected:
695
  /**
696
   * This is the method called to notify the object of a pop.  It must be
697
   * implemented by the subclass. It is protected since context is out
698
   * friend.
699
   */
700
  virtual void contextNotifyPop() = 0;
701
702
public:
703
704
  /**
705
   * Constructor for ContextNotifyObj.  Parameters are the context to
706
   * which this notify object will be added, and a flag which, if
707
   * true, tells the context to notify this object *before* the
708
   * ContextObj objects are restored.  Otherwise, the context notifies
709
   * the object after the ContextObj objects are restored.  The
710
   * default is for notification after.
711
   */
712
  ContextNotifyObj(Context* pContext, bool preNotify = false);
713
714
  /**
715
   * Destructor: removes object from list
716
   */
717
  virtual ~ContextNotifyObj();
718
719
};/* class ContextNotifyObj */
720
721
359744177
inline void ContextObj::makeCurrent()
722
{
723
359744177
  if(!(d_pScope->isCurrent())) {
724
81696165
    update();
725
  }
726
359744177
}
727
728
inline void ContextObj::makeSaveRestorePoint() { update(); }
729
730
148076642
inline void Scope::addToChain(ContextObj* pContextObj)
731
{
732
148076642
  if(d_pContextObjList != NULL) {
733
144047720
    d_pContextObjList->prev() = &pContextObj->next();
734
  }
735
736
148076642
  pContextObj->next() = d_pContextObjList;
737
148076642
  pContextObj->prev() = &d_pContextObjList;
738
148076642
  d_pContextObjList = pContextObj;
739
148076642
}
740
741
}  // namespace context
742
}  // namespace cvc5
743
744
#endif /* CVC5__CONTEXT__CONTEXT_H */