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