1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2015 The University of Utah
4 // All rights reserved.
5 //
6 // This file is part of `csmith', a random generator of C programs.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 //
11 // * Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 //
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29
30 #ifndef ENUMERATOR_H
31 #define ENUMERATOR_H
32
33 #include <map>
34 #include <cassert>
35
36 using namespace std;
37
38 template <class Name>
39 class Enumerator {
40 public:
41 Enumerator();
42
43 ~Enumerator();
44
45 void add_elem(Name name, int bound);
46
47 void add_bool_elem(Name name, int value);
48
49 void add_bool_elem_of_bool(Name name, bool value);
50
51 int get_elem(Name name);
52
53 Enumerator *next();
54
end()55 Enumerator *end() { return NULL; }
56
57 Enumerator *begin();
58
59 bool is_changed(Name name);
60
61 private:
62
63 class EnumObject {
64 public:
EnumObject(int bound,bool is_bool,bool bool_value)65 EnumObject(int bound, bool is_bool, bool bool_value)
66 : bound_(bound),
67 current_value_(0),
68 is_bool_(is_bool),
69 bool_value_(bool_value),
70 changed_(false)
71 {
72 assert(bound_ > 0);
73 }
74
~EnumObject()75 ~EnumObject() { }
76
bound()77 int bound() { return bound_; }
78
bool_value()79 bool bool_value() { return bool_value_; }
80
get_current_value()81 int get_current_value() { return current_value_; }
82
is_bool()83 bool is_bool() { return is_bool_; }
84
next()85 bool next()
86 {
87 current_value_++;
88 if (current_value_ < bound_) {
89 changed_ = true;
90 return true;
91 }
92 else {
93 current_value_--;
94 return false;
95 }
96 }
97
good_value()98 bool good_value()
99 {
100 return (current_value_ < bound_);
101 }
102
clear_value()103 void clear_value() { current_value_ = 0; }
104
reset_changed()105 void reset_changed() { changed_ = 0; }
106
is_changed()107 bool is_changed() { return changed_; }
108
109 private:
110 const int bound_;
111
112 int current_value_;
113
114 const bool is_bool_;
115
116 const bool bool_value_;
117
118 bool changed_;
119 };
120
121 void reset_all_changed();
122
123 void reset_pos();
124
125 void reset_after_backward_pos();
126
127 bool roll_back_current_pos();
128
129 std::map<Name, EnumObject*> objs_;
130
131 typename std::map<Name, EnumObject*>::iterator forward_pos_;
132
133 typename std::map<Name, EnumObject*>::iterator backward_pos_;
134
135 };
136
137 /////////////////////////////////////////////////////////////////////////////////////
138
139 template <class Name>
Enumerator()140 Enumerator<Name>::Enumerator()
141 {
142 forward_pos_ = objs_.end();
143 backward_pos_ = objs_.end();
144 }
145
146 template <class Name>
~Enumerator()147 Enumerator<Name>::~Enumerator()
148 {
149 typename map<Name, EnumObject*>::iterator i;
150 for (i = objs_.begin(); i != objs_.end(); ++i) {
151 if ((*i).second != NULL)
152 delete (*i).second;
153 }
154 objs_.clear();
155 }
156
157 template <class Name>
158 void
reset_pos()159 Enumerator<Name>::reset_pos()
160 {
161 forward_pos_ = objs_.end();
162 --forward_pos_;
163 backward_pos_ = forward_pos_;
164 --backward_pos_;
165 }
166
167 template <class Name>
168 Enumerator<Name> *
begin()169 Enumerator<Name>::begin()
170 {
171 reset_pos();
172 EnumObject *obj = (*forward_pos_).second;
173 assert(obj);
174 if (forward_pos_ == objs_.begin() && !obj->good_value())
175 return NULL;
176 return this;
177 }
178
179 template <class Name>
180 void
add_elem(Name name,int bound)181 Enumerator<Name>::add_elem(Name name, int bound)
182 {
183 assert(objs_.find(name) == objs_.end());
184
185 objs_[name] = new EnumObject(bound, false, false);
186 }
187
188 template <class Name>
189 void
add_bool_elem_of_bool(Name name,bool value)190 Enumerator<Name>::add_bool_elem_of_bool(Name name, bool value)
191 {
192 assert(objs_.find(name) == objs_.end());
193
194 int bound = value ? 2 : 1;
195
196 objs_[name] = new EnumObject(bound, true, false);
197 }
198
199 template<class Name>
200 void
add_bool_elem(Name name,int value)201 Enumerator<Name>::add_bool_elem(Name name, int value)
202 {
203 int bound = 0;
204 bool bool_value = false;
205 if (value == 0) {
206 bound = 1;
207 bool_value = false;
208 }
209 else if (value == 100) {
210 bound = 1;
211 bool_value = true;
212 }
213 else {
214 bound = 2;
215 }
216
217 assert(objs_.find(name) == objs_.end());
218
219 objs_[name] = new EnumObject(bound, true, bool_value);
220 }
221
222 template <class Name>
223 int
get_elem(Name name)224 Enumerator<Name>::get_elem(Name name)
225 {
226 assert(objs_.find(name) != objs_.end());
227
228 EnumObject *obj = objs_[name];
229 assert(obj);
230 int rv = obj->get_current_value();
231 assert(rv >= 0);
232 if (obj->is_bool()) {
233 if (obj->bound() == 1)
234 return obj->bool_value();
235 else
236 return (rv != 0);
237 }
238 else {
239 return rv;
240 }
241 }
242
243 template <class Name>
244 void
reset_after_backward_pos()245 Enumerator<Name>::reset_after_backward_pos()
246 {
247 typename map<Name, EnumObject*>::iterator i = backward_pos_;
248 ++i;
249 while(i != objs_.end()) {
250 EnumObject *obj = (*i).second;
251 assert(obj);
252 obj->clear_value();
253 ++i;
254 }
255 forward_pos_ = backward_pos_;
256 ++forward_pos_;
257 }
258
259 template <class Name>
260 bool
roll_back_current_pos()261 Enumerator<Name>::roll_back_current_pos()
262 {
263 if (backward_pos_ == objs_.begin()) {
264 EnumObject *obj = (*backward_pos_).second;
265 assert(obj);
266 bool rv = obj->next();
267 if (!rv)
268 return false;
269 reset_after_backward_pos();
270 reset_pos();
271 return true;
272 }
273 else {
274 EnumObject *obj = (*backward_pos_).second;
275 assert(obj);
276 if (obj->next()) {
277 reset_after_backward_pos();
278 reset_pos();
279 //forward_pos_= backward_pos_;
280 //++forward_pos_;
281 return true;
282 }
283 else {
284 --backward_pos_;
285 return roll_back_current_pos();
286 }
287 }
288 }
289
290 template <class Name>
291 bool
is_changed(Name name)292 Enumerator<Name>::is_changed(Name name)
293 {
294 assert(objs_.find(name) != objs_.end());
295
296 EnumObject *obj = objs_[name];
297 assert(obj);
298 return obj->is_changed();
299 }
300
301 template <class Name>
302 void
reset_all_changed()303 Enumerator<Name>::reset_all_changed()
304 {
305 typename map<Name, EnumObject*>::iterator i;
306 for (i = objs_.begin(); i != objs_.end(); ++i) {
307 EnumObject *obj = (*i).second;
308 assert(obj);
309 obj->reset_changed();
310 }
311 }
312
313 template <class Name>
314 Enumerator<Name> *
next()315 Enumerator<Name>::next()
316 {
317 assert(forward_pos_ != objs_.end());
318
319 reset_all_changed();
320 EnumObject *obj = (*forward_pos_).second;
321 assert(obj);
322 if (obj->next()) {
323 return this;
324 }
325 else {
326 ++forward_pos_;
327 if (forward_pos_ == objs_.end()) {
328 if(roll_back_current_pos())
329 return this;
330 else
331 return NULL;
332 }
333 else {
334 reset_pos();
335 return next();
336 }
337 }
338
339 return NULL;
340 }
341 #endif // ENUMERATOR_H
342