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