1 /*
2  *  useval.h - Values used in Usecode interpreter.
3  *
4  *  Copyright (C) 1999  Jeffrey S. Freedman
5  *  Copyright (C) 2000-2013  The Exult Team
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #ifndef USEVAL_H
23 #define USEVAL_H    1
24 
25 #include <cassert>
26 #include <cstdlib>
27 #include <cstring>
28 
29 #include <iostream>
30 #include <new>
31 #include <string>   // STL string
32 #include <vector>   // STL container
33 
34 #include "databuf.h"
35 #include "objs.h"
36 
37 class Usecode_class_symbol;
38 
39 /*
40  *  A value that we store can be an integer, string, or array.
41  */
42 class Usecode_value {
43 public:
44 	enum Val_type {         // The types:
45 	    int_type = 0,
46 	    string_type = 1,    // Allocated string.
47 	    array_type = 2,
48 	    pointer_type = 3,
49 	    class_sym_type = 4, // ->Usecode_class_symbol
50 	    class_obj_type = 5  // An 'array_type' for a class obj.
51 	};
52 	using Usecode_vector = std::vector<Usecode_value>;
53 
54 private:
55 	struct ClassRef {
56 		Usecode_value *elems;
57 		short cnt;
58 	};
59 	Val_type type = int_type;      // Type stored here.
60 	union {
61 		long intval;
62 		std::string strval;
63 		Usecode_vector arrayval;
64 		Game_object_shared ptrval;
65 		Usecode_class_symbol *clssym;
66 		ClassRef clsrefval;
67 	};	// Anonymous union member
68 	bool undefined = true;
69 
70 	template <typename Op>
71 	Usecode_value& operate(const Usecode_value &v2);
72 
destroy()73 	void destroy() noexcept {
74 		switch (type) {
75 		case array_type:
76 			arrayval.~Usecode_vector();
77 			break;
78 		case string_type:
79 			using std::string;
80 			strval.~string();
81 			break;
82 		case pointer_type:
83 			ptrval.~Game_object_shared();
84 			break;
85 		default:
86 			break;
87 		}
88 	}
89 	template <typename T, typename... U>
construct(T & var,U &&...newval)90 	void construct(T& var, U&&... newval) {
91 		new (&var) T(std::forward<U>(newval)...);
92 	}
93 	template <typename T, typename U>
94 	void replace(T& var, U&& newval, Val_type newtype, bool newundefined = false) {
95 		if (type == newtype) {
96 			var = std::forward<U>(newval);
97 		} else {
98 			destroy();
99 			type = newtype;
100 			construct(var, std::forward<U>(newval));
101 		}
102 		undefined = newundefined;
103 	}
104 	template <typename T, typename U>
replaceFrom(T var,U && newval,Val_type newtype)105 	void replaceFrom(T var, U&& newval, Val_type newtype) {
106 		replace(this->*var, std::forward<U>(newval).*var, newtype, newval.undefined);
107 	}
108 	template <typename T>
copy_internal(T && v2)109 	void copy_internal(T&& v2) noexcept(std::is_rvalue_reference<T>::value) {
110 		switch (v2.type) {
111 		case int_type:
112 			replaceFrom(&Usecode_value::intval, std::forward<T>(v2), v2.type);
113 			break;
114 		case pointer_type:
115 			replaceFrom(&Usecode_value::ptrval, std::forward<T>(v2), v2.type);
116 			break;
117 		case string_type:
118 			replaceFrom(&Usecode_value::strval, std::forward<T>(v2), v2.type);
119 			break;
120 		case array_type:
121 			replaceFrom(&Usecode_value::arrayval, std::forward<T>(v2), v2.type);
122 			break;
123 		case class_sym_type:
124 			replaceFrom(&Usecode_value::clssym, std::forward<T>(v2), v2.type);
125 			break;
126 		case class_obj_type:
127 			replaceFrom(&Usecode_value::clsrefval, std::forward<T>(v2), v2.type);
128 			break;
129 		}
130 	}
131 
132 public:
Usecode_value()133 	Usecode_value() : intval(0) {}
Usecode_value(int ival)134 	explicit Usecode_value(int ival) : intval(ival), undefined(false) {}
Usecode_value(const std::string & s)135 	explicit Usecode_value(const std::string& s) : type(string_type), strval(s), undefined(false) {}
Usecode_value(std::string && s)136 	explicit Usecode_value(std::string&& s) noexcept : type(string_type), strval(std::move(s)), undefined(false) {}
137 	// Create array with 1st element.
Usecode_value(int size,Usecode_value * elem0)138 	Usecode_value(int size, Usecode_value *elem0)
139 		: type(array_type), arrayval(size), undefined(false) {
140 		if (elem0)
141 			arrayval[0] = *elem0;
142 	}
Usecode_value(Game_object * ptr)143 	explicit Usecode_value(Game_object *ptr)
144 		: type(pointer_type), ptrval(ptr != nullptr ? ptr->shared_from_this() : Game_object_shared()),
145 		  undefined(false) {}
Usecode_value(Game_object_shared ptr)146     explicit Usecode_value(Game_object_shared ptr) : type(pointer_type), ptrval(std::move(ptr)), undefined(false) {}
Usecode_value(Usecode_class_symbol * ptr)147 	explicit Usecode_value(Usecode_class_symbol *ptr) : type(class_sym_type), clssym(ptr), undefined(false) {}
148 	~Usecode_value();
149 	Usecode_value &operator=(const Usecode_value &v2) {
150 		if (&v2 != this) {
151 			copy_internal(v2);
152 		}
153 		return *this;
154 	}
155 	Usecode_value &operator=(Usecode_value &&v2) noexcept {
156 		copy_internal(std::move(v2));
157 		return *this;
158 	}
159 	Usecode_value &operator=(int val) noexcept {
160 		replace(intval, val, int_type);
161 		return *this;
162 	}
163 	Usecode_value &operator=(const std::string& str) {
164 		replace(strval, str, string_type);
165 		return *this;
166 	}
167 	Usecode_value &operator=(std::string&& str) noexcept {
168 		replace(strval, std::move(str), string_type);
169 		return *this;
170 	}
171 	Usecode_value &operator=(Game_object *ptr) noexcept {
172 		replace(ptrval, ptr != nullptr ? ptr->shared_from_this() : Game_object_shared(), pointer_type);
173 		return *this;
174 	}
175 	Usecode_value &operator=(Game_object_shared ptr) noexcept {
176 		replace(ptrval, std::move(ptr), pointer_type);
177 		return *this;
178 	}
179 	Usecode_value &operator=(Usecode_class_symbol *ptr) noexcept {
180 		replace(clssym, ptr, class_sym_type);
181 		return *this;
182 	}
183 	// Copy ctor.
Usecode_value(const Usecode_value & v2)184 	Usecode_value(const Usecode_value &v2) {
185 		*this = v2;
186 	}
187 	// Move ctor.
Usecode_value(Usecode_value && v2)188 	Usecode_value(Usecode_value &&v2) noexcept {
189 		*this = std::move(v2);
190 	}
191 
192 	Usecode_value& operator+=(const Usecode_value &v2);
193 	Usecode_value& operator-=(const Usecode_value &v2);
194 	Usecode_value& operator*=(const Usecode_value &v2);
195 	Usecode_value& operator/=(const Usecode_value &v2);
196 	Usecode_value& operator%=(const Usecode_value &v2);
push_back(int i)197 	void push_back(int i) {
198 		arrayval.emplace_back(i);
199 	}
200 	// Comparator.
201 	bool operator==(const Usecode_value &v2) const;
202 	bool operator!=(const Usecode_value &v2) const {
203 		return !(*this == v2);
204 	}
205 
get_type()206 	Val_type get_type() const {
207 		return type;
208 	}
get_array_size()209 	size_t get_array_size() const {    // Get size of array.
210 		return (type == array_type) ? arrayval.size() : 0;
211 	}
is_array()212 	bool is_array() const {
213 		return type == array_type;
214 	}
is_int()215 	bool is_int() const {
216 		return type == int_type;
217 	}
is_ptr()218 	bool is_ptr() const {
219 		return type == pointer_type;
220 	}
get_int_value()221 	long get_int_value() const { // Get integer value.
222 #ifdef DEBUG
223 		if (type == pointer_type || (type == int_type && (intval > 0x10000 || intval < -0x10000)))
224 			std::cerr << "Probable attempt at getting int value of pointer!!" << std::endl;
225 #endif
226 		return (type == int_type) ? intval : 0;
227 	}
get_ptr_value()228 	Game_object *get_ptr_value() const { // Get pointer value.
229 		return (type == pointer_type) ? ptrval.get() : nullptr;
230 	}
231 	// Get string value.
get_str_value()232 	const char *get_str_value() const {
233 		static char const *emptystr = "";
234 		return (type == string_type) ? strval.c_str() :
235 		        ((undefined ||
236 		          (type == array_type && arrayval.empty())) ? emptystr : nullptr);
237 	}
need_int_value()238 	long need_int_value() const {
239 		// Convert strings.
240 		const char *str = get_str_value();
241 		return str ? std::atoi(str)
242 		       : ((type == array_type && get_array_size())
243 		          ? arrayval[0].need_int_value()
244 		          // Pointer = ref.
245 		          : (type == pointer_type ? (reinterpret_cast<uintptr>(ptrval.get()) & 0x7ffffff)
246 		             : get_int_value()));
247 	}
248 	// Add array element. (No checking!)
put_elem(int i,Usecode_value & val)249 	void put_elem(int i, Usecode_value &val) {
250 		arrayval[i] = val;
251 	}
252 	// Get an array element.
get_elem(int i)253 	Usecode_value &get_elem(int i) {
254 		static Usecode_value zval(0);
255 		return (type == array_type) ? arrayval[i] : zval;
256 	}
257 	// Get an array element.
get_elem(int i)258 	const Usecode_value &get_elem(int i) const {
259 		static const Usecode_value zval(0);
260 		return (type == array_type) ? arrayval[i] : zval;
261 	}
262 	Usecode_value &operator[](int i) {
263 		assert(type == array_type);
264 		return arrayval[i];
265 	}
266 	const Usecode_value &operator[](int i) const {
267 		assert(type == array_type);
268 		return arrayval[i];
269 	}
270 	// Get array elem. 0, or this.
get_elem0()271 	Usecode_value &get_elem0() {
272 		static Usecode_value zval(0);
273 		return (type == array_type) ? (get_array_size() ? arrayval[0]
274 		                               : zval) : *this;
275 	}
276 	// Get array elem. 0, or this.
get_elem0()277 	const Usecode_value &get_elem0() const {
278 		static Usecode_value zval(0);
279 		return (type == array_type) ? (get_array_size() ? arrayval[0]
280 		                               : zval) : *this;
281 	}
282 	void steal_array(Usecode_value &v2);
is_false()283 	bool is_false() const {  // Represents a FALSE value?
284 		switch (type) {
285 		case int_type:
286 			return intval == 0;
287 		case pointer_type:
288 			return ptrval == nullptr;
289 		case array_type:
290 			return arrayval.empty();
291 		default:
292 			return false;
293 		}
294 	}
is_true()295 	bool is_true() const {
296 		return !is_false();
297 	}
298 
is_undefined()299 	bool is_undefined() const {
300 		return undefined;
301 	}
302 
303 	int resize(int new_size);   // Resize array.
304 	// Look in array for given value.
305 	int find_elem(const Usecode_value &val);
306 	// Concat. to end of this array.
307 	Usecode_value &concat(Usecode_value &val2);
308 	void append(int *vals, int cnt);// Append integer values.
309 	// Add value(s) to an array.
310 	int add_values(int index, Usecode_value &val2);
311 	void print(std::ostream &out, bool shortformat = false) const; // Print in ASCII.
312 	// Save/restore.
313 	bool save(ODataSource *out);
314 	bool restore(IDataSource *in);
315 	// Class objects.
316 	void class_new(Usecode_class_symbol *cls, int nvars);
317 	void class_delete();
nth_class_var(int n)318 	Usecode_value &nth_class_var(int n) {
319 		// Note:  Elem. 0 is the ->class.
320 		static Usecode_value zval(0);
321 		return (type == class_obj_type && n + 1 < clsrefval.cnt) ?
322 		       clsrefval.elems[n + 1] : zval;
323 	}
get_class_var_count()324 	int get_class_var_count() {
325 		// Note:  Elem. 0 is the ->class.
326 		return type == class_obj_type ? clsrefval.cnt - 1 : 0;
327 	}
get_class_ptr()328 	Usecode_class_symbol *get_class_ptr() const {
329 		return (type == class_obj_type) ?
330 		       clsrefval.elems[0].clssym : nullptr;
331 	}
332 };
333 
334 inline Usecode_value operator+(Usecode_value v1, const Usecode_value &v2) {
335 	return v1 += v2;
336 }
337 inline Usecode_value operator-(Usecode_value v1, const Usecode_value &v2) {
338 	return v1 -= v2;
339 }
340 inline Usecode_value operator*(Usecode_value v1, const Usecode_value &v2) {
341 	return v1 *= v2;
342 }
343 inline Usecode_value operator/(Usecode_value v1, const Usecode_value &v2) {
344 	return v1 /= v2;
345 }
346 inline Usecode_value operator%(Usecode_value v1, const Usecode_value &v2) {
347 	return v1 %= v2;
348 }
349 
350 std::ostream &operator<<(std::ostream &out, Usecode_value &val);
351 
352 #endif
353