1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Morgan Deters, Mathias Preiner |
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 |
|
* Contains a backtrackable list. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__UTIL__BACKTRACKABLE_H |
19 |
|
#define CVC5__UTIL__BACKTRACKABLE_H |
20 |
|
|
21 |
|
#include <cstdlib> |
22 |
|
#include <vector> |
23 |
|
#include "context/cdo.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
|
27 |
|
template <class T> class List; |
28 |
|
template <class T> class List_iterator; |
29 |
|
template <class T> class Backtracker; |
30 |
|
|
31 |
|
template <class T> |
32 |
|
class ListNode { |
33 |
|
private: |
34 |
|
T data; |
35 |
|
ListNode<T>* next; |
36 |
|
|
37 |
|
bool empty; |
38 |
|
ListNode(const T& t, ListNode<T>* n, bool e = false) : data(t), next(n), empty(e) {} |
39 |
|
~ListNode() { |
40 |
|
// maybe set to NULL |
41 |
|
delete next; |
42 |
|
} |
43 |
|
|
44 |
|
friend class List<T>; |
45 |
|
friend class List_iterator<T>; |
46 |
|
};/* class ListNode<T> */ |
47 |
|
|
48 |
|
template <class T> |
49 |
|
class List_iterator : public std::iterator <std::forward_iterator_tag, T> { |
50 |
|
friend class List<T>; |
51 |
|
|
52 |
|
public: |
53 |
|
const T& operator*(); |
54 |
|
List_iterator<T>& operator++(); |
55 |
|
List_iterator<T> operator++(int); |
56 |
|
bool operator!=(const List_iterator<T> & other) const; |
57 |
|
|
58 |
|
private: |
59 |
|
const ListNode<T>* pointee; |
60 |
|
List_iterator(const ListNode<T>* p) : pointee(p) {} |
61 |
|
|
62 |
|
};/* class List_iterator<T> */ |
63 |
|
|
64 |
|
template <class T> |
65 |
|
const T& List_iterator<T>::operator*() { |
66 |
|
return pointee->data; |
67 |
|
} |
68 |
|
|
69 |
|
template <class T> |
70 |
|
List_iterator<T>& List_iterator<T>::operator++() { |
71 |
|
Assert(pointee != NULL); |
72 |
|
pointee = pointee->next; |
73 |
|
while(pointee != NULL && pointee->empty ) { |
74 |
|
pointee = pointee->next; |
75 |
|
} |
76 |
|
return *this; |
77 |
|
} |
78 |
|
|
79 |
|
template <class T> |
80 |
|
List_iterator<T> List_iterator<T>::operator++(int) { |
81 |
|
List_iterator<T> it = *this; |
82 |
|
++*this; |
83 |
|
return it; |
84 |
|
} |
85 |
|
|
86 |
|
template <class T> |
87 |
|
bool List_iterator<T>::operator!=(const List_iterator<T>& other) const { |
88 |
|
return (this->pointee != other.pointee); |
89 |
|
} |
90 |
|
|
91 |
|
// !! for the backtracking to work the lists must be allocated on the heap |
92 |
|
// therefore the hashmap from TNode to List<TNode> should store pointers! |
93 |
|
template <class T> |
94 |
|
class List { |
95 |
|
ListNode<T>* head; |
96 |
|
ListNode<T>* tail; |
97 |
|
ListNode<T>* ptr_to_head; |
98 |
|
bool uninitialized; |
99 |
|
Backtracker<T>* bck; |
100 |
|
List (const List&) {} |
101 |
|
public: |
102 |
|
List(Backtracker<T>* b) : ptr_to_head(NULL), uninitialized(true), bck(b) { |
103 |
|
head = tail = (ListNode<T>*)calloc(1,sizeof(ListNode<T>)); |
104 |
|
head->next = NULL; |
105 |
|
head->empty = true; |
106 |
|
} |
107 |
|
~List() {delete head;} |
108 |
|
bool empty() { |
109 |
|
bck->checkConsistency(); |
110 |
|
return head == NULL; |
111 |
|
} |
112 |
|
void append(const T& d); |
113 |
|
//typedef List_iterator<T> iterator; |
114 |
|
typedef List_iterator<T> const_iterator; |
115 |
|
|
116 |
|
const_iterator begin() { |
117 |
|
bck->checkConsistency(); |
118 |
|
if(head->empty) { |
119 |
|
ListNode<T>* temp = head; |
120 |
|
// if the head is empty return the first non-empty element or NULL |
121 |
|
while(temp != NULL && temp->empty ) { |
122 |
|
temp = temp->next; |
123 |
|
} |
124 |
|
return List_iterator<T>(temp); |
125 |
|
} |
126 |
|
return List_iterator<T>(head); |
127 |
|
} |
128 |
|
|
129 |
|
const_iterator end() { |
130 |
|
bck->checkConsistency(); |
131 |
|
return List_iterator<T>(NULL); |
132 |
|
} |
133 |
|
void concat(List<T>* other); |
134 |
|
void unconcat(List<T>* other); |
135 |
|
};/* class List */ |
136 |
|
|
137 |
|
template <class T> |
138 |
|
void List<T>::append (const T& d) { |
139 |
|
bck->checkConsistency(); |
140 |
|
|
141 |
|
if(uninitialized) { |
142 |
|
new(head)ListNode<T> (d, head->next); |
143 |
|
//head->data = d; |
144 |
|
head->empty = false; |
145 |
|
//Assert(tail == head); FIXME: do I need this because this list might be empty but append to another one |
146 |
|
uninitialized = false; |
147 |
|
|
148 |
|
} else { |
149 |
|
ListNode<T>* new_node = new ListNode<T>(d, head); |
150 |
|
head = new_node; |
151 |
|
} |
152 |
|
|
153 |
|
if(ptr_to_head != NULL) { |
154 |
|
ptr_to_head->next = head; |
155 |
|
} |
156 |
|
} |
157 |
|
|
158 |
|
template <class T> |
159 |
|
void List<T>::concat (List<T>* other) { |
160 |
|
bck->checkConsistency(); |
161 |
|
bck->notifyConcat(this, other); |
162 |
|
Assert(tail->next == NULL); |
163 |
|
tail->next = other->head; |
164 |
|
Assert(other->ptr_to_head == NULL); |
165 |
|
other->ptr_to_head = tail; |
166 |
|
tail = other->tail; |
167 |
|
} |
168 |
|
|
169 |
|
template <class T> |
170 |
|
void List<T>::unconcat(List<T>* other) { |
171 |
|
// we do not need to check consistency since this is only called by the |
172 |
|
// Backtracker when we are inconsistent |
173 |
|
Assert(other->ptr_to_head != NULL); |
174 |
|
other->ptr_to_head->next = NULL; |
175 |
|
tail = other->ptr_to_head; |
176 |
|
other->ptr_to_head = NULL; |
177 |
|
} |
178 |
|
|
179 |
|
/* Backtrackable Table */ |
180 |
|
|
181 |
|
template <class T> |
182 |
|
class Backtracker { |
183 |
|
friend class List<T>; |
184 |
|
std::vector<std::pair<List<T>*,List<T>*> > undo_stack; |
185 |
|
|
186 |
|
int curr_level; |
187 |
|
context::CDO<int> pop_level; |
188 |
|
|
189 |
|
void checkConsistency(); |
190 |
|
void notifyConcat(List<T>* a, List<T>* b); |
191 |
|
public: |
192 |
9459 |
Backtracker(context::Context* c) : undo_stack(), curr_level(0), pop_level(c, 0) {} |
193 |
9459 |
~Backtracker() {} |
194 |
|
|
195 |
|
};/* class Backtrackable */ |
196 |
|
|
197 |
|
template <class T> void Backtracker<T>::notifyConcat(List<T>* a, List<T>* b) { |
198 |
|
curr_level++; |
199 |
|
pop_level.set(pop_level.get()+1); |
200 |
|
undo_stack.push_back( std::make_pair(a, b)); |
201 |
|
} |
202 |
|
|
203 |
|
template <class T> void Backtracker<T>::checkConsistency() { |
204 |
|
if( curr_level == pop_level || pop_level == -1) { |
205 |
|
return; |
206 |
|
} |
207 |
|
Assert(curr_level > pop_level); |
208 |
|
|
209 |
|
while (curr_level > pop_level) { |
210 |
|
curr_level--; |
211 |
|
List<T>* l1 = undo_stack[curr_level].first; |
212 |
|
List<T>* l2 = undo_stack[curr_level].second; |
213 |
|
l1->unconcat(l2); |
214 |
|
undo_stack.pop_back(); |
215 |
|
} |
216 |
|
Assert(curr_level == pop_level); |
217 |
|
} |
218 |
|
|
219 |
|
} // namespace cvc5 |
220 |
|
|
221 |
|
#endif /* CVC5__UTIL__BACKTRACKABLE_H */ |