/********************* */ /*! \file backtrackable.h ** \verbatim ** Top contributors (to current version): ** Morgan Deters ** This file is part of the CVC4 project. ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief Contains a backtrackable list ** ** Contains a backtrackable list. **/ #include "cvc4_private.h" #ifndef __CVC4__UTIL__BACKTRACKABLE_H #define __CVC4__UTIL__BACKTRACKABLE_H #include #include #include "context/cdo.h" namespace CVC4 { template class List; template class List_iterator; template class Backtracker; template class ListNode { private: T data; ListNode* next; bool empty; ListNode(const T& t, ListNode* n, bool e = false) : data(t), next(n), empty(e) {} ~ListNode() { // maybe set to NULL delete next; } friend class List; friend class List_iterator; };/* class ListNode */ template class List_iterator : public std::iterator { friend class List; public: const T& operator*(); List_iterator& operator++(); List_iterator operator++(int); bool operator!=(const List_iterator & other) const; private: const ListNode* pointee; List_iterator(const ListNode* p) : pointee(p) {} };/* class List_iterator */ template const T& List_iterator::operator*() { return pointee->data; } template List_iterator& List_iterator::operator++() { Assert(pointee != NULL); pointee = pointee->next; while(pointee != NULL && pointee->empty ) { pointee = pointee->next; } return *this; } template List_iterator List_iterator::operator++(int) { List_iterator it = *this; ++*this; return it; } template bool List_iterator::operator!=(const List_iterator& other) const { return (this->pointee != other.pointee); } // !! for the backtracking to work the lists must be allocated on the heap // therefore the hashmap from TNode to List should store pointers! template class List { ListNode* head; ListNode* tail; ListNode* ptr_to_head; bool uninitialized; Backtracker* bck; List (const List&) {} public: List(Backtracker* b) : ptr_to_head(NULL), uninitialized(true), bck(b) { head = tail = (ListNode*)calloc(1,sizeof(ListNode)); head->next = NULL; head->empty = true; } ~List() {delete head;} bool empty() { bck->checkConsistency(); return head == NULL; } void append(const T& d); //typedef List_iterator iterator; typedef List_iterator const_iterator; const_iterator begin() { bck->checkConsistency(); if(head->empty) { ListNode* temp = head; // if the head is empty return the first non-empty element or NULL while(temp != NULL && temp->empty ) { temp = temp->next; } return List_iterator(temp); } return List_iterator(head); } const_iterator end() { bck->checkConsistency(); return List_iterator(NULL); } void concat(List* other); void unconcat(List* other); };/* class List */ template void List::append (const T& d) { bck->checkConsistency(); if(uninitialized) { new(head)ListNode (d, head->next); //head->data = d; head->empty = false; //Assert(tail == head); FIXME: do I need this because this list might be empty but append to another one uninitialized = false; } else { ListNode* new_node = new ListNode(d, head); head = new_node; } if(ptr_to_head != NULL) { ptr_to_head->next = head; } } template void List::concat (List* other) { bck->checkConsistency(); bck->notifyConcat(this, other); Assert(tail->next==NULL); tail->next = other->head; Assert(other->ptr_to_head == NULL); other->ptr_to_head = tail; tail = other->tail; } template void List::unconcat(List* other) { // we do not need to check consistency since this is only called by the // Backtracker when we are inconsistent Assert(other->ptr_to_head != NULL); other->ptr_to_head->next = NULL; tail = other->ptr_to_head; other->ptr_to_head = NULL; } /* Backtrackable Table */ template class Backtracker { friend class List; std::vector*,List*> > undo_stack; int curr_level; context::CDO pop_level; void checkConsistency(); void notifyConcat(List* a, List* b); public: Backtracker(context::Context* c) : undo_stack(), curr_level(0), pop_level(c, 0) {} ~Backtracker() {} };/* class Backtrackable */ template void Backtracker::notifyConcat(List* a, List* b) { curr_level++; pop_level.set(pop_level.get()+1); undo_stack.push_back( std::make_pair(a, b)); } template void Backtracker::checkConsistency() { if( curr_level == pop_level || pop_level == -1) { return; } Assert(curr_level > pop_level); while (curr_level > pop_level) { curr_level--; List* l1 = undo_stack[curr_level].first; List* l2 = undo_stack[curr_level].second; l1->unconcat(l2); undo_stack.pop_back(); } Assert(curr_level == pop_level); } }/* CVC4 namespace */ #endif /* __CVC4__UTIL__BACKTRACKABLE_H */